Drop configs and patches for Linux 6.6.
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+++ /dev/null
-CONFIG_64BIT=y
-# CONFIG_ACPI is not set
-CONFIG_AMBA_PL08X=y
-CONFIG_ARCH_CLOCKSOURCE_INIT=y
-CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-CONFIG_ARCH_MMAP_RND_BITS=18
-CONFIG_ARCH_MMAP_RND_BITS_MAX=24
-CONFIG_ARCH_MMAP_RND_BITS_MIN=18
-CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17
-CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
-CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
-# CONFIG_ARCH_RV32I is not set
-CONFIG_ARCH_RV64I=y
-CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_SIFIVE=y
-CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_STACKWALK=y
-CONFIG_ARCH_STARFIVE=y
-# CONFIG_ARCH_THEAD is not set
-CONFIG_ARCH_WANTS_THP_SWAP=y
-CONFIG_ARM_AMBA=y
-# CONFIG_ARM_MHU_V2 is not set
-CONFIG_ASN1=y
-CONFIG_ASSOCIATIVE_ARRAY=y
-CONFIG_AUXILIARY_BUS=y
-# CONFIG_AX45MP_L2_CACHE 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_CONTIG_ALLOC=y
-CONFIG_CPUFREQ_DT=y
-CONFIG_CPUFREQ_DT_PLATDEV=y
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_ATTR_SET=y
-CONFIG_CPU_FREQ_GOV_COMMON=y
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_STAT=y
-CONFIG_CPU_IDLE=y
-CONFIG_CPU_IDLE_GOV_MENU=y
-CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
-CONFIG_CPU_PM=y
-CONFIG_CPU_RMAP=y
-CONFIG_CRASH_CORE=y
-CONFIG_CRC16=y
-CONFIG_CRC7=y
-CONFIG_CRC_ITU_T=y
-CONFIG_CRYPTO_BLAKE2B=y
-CONFIG_CRYPTO_CMAC=y
-CONFIG_CRYPTO_CRC32C=y
-CONFIG_CRYPTO_DEV_JH7110=y
-CONFIG_CRYPTO_DRBG=y
-CONFIG_CRYPTO_DRBG_HMAC=y
-CONFIG_CRYPTO_DRBG_MENU=y
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_ECC=y
-CONFIG_CRYPTO_ECDH=y
-CONFIG_CRYPTO_ENGINE=y
-CONFIG_CRYPTO_HASH_INFO=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_JITTERENTROPY=y
-CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
-CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
-CONFIG_CRYPTO_LIB_SHA1=y
-CONFIG_CRYPTO_LIB_SHA256=y
-CONFIG_CRYPTO_LIB_UTILS=y
-CONFIG_CRYPTO_RNG=y
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_RNG_DEFAULT=y
-CONFIG_CRYPTO_RSA=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_SHA512=y
-CONFIG_CRYPTO_SM3=y
-CONFIG_CRYPTO_SM3_GENERIC=y
-CONFIG_CRYPTO_USER=y
-CONFIG_CRYPTO_USER_API=y
-CONFIG_CRYPTO_USER_API_AEAD=y
-CONFIG_CRYPTO_USER_API_HASH=y
-CONFIG_CRYPTO_USER_API_RNG=y
-CONFIG_CRYPTO_USER_API_SKCIPHER=y
-CONFIG_CRYPTO_XXHASH=y
-CONFIG_CRYPTO_ZSTD=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_PINCTRL=y
-CONFIG_DEBUG_RODATA_TEST=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_DEBUG_RWSEMS=y
-CONFIG_DEBUG_SECTION_MISMATCH=y
-CONFIG_DEBUG_SG=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_TIMEKEEPING=y
-CONFIG_DEBUG_WX=y
-CONFIG_DECOMPRESS_GZIP=y
-# CONFIG_DEVFREQ_GOV_PASSIVE is not set
-# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set
-# CONFIG_DEVFREQ_GOV_POWERSAVE is not set
-# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set
-# CONFIG_DEVFREQ_GOV_USERSPACE is not set
-# CONFIG_DEVFREQ_THERMAL is not set
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-# CONFIG_DEVTMPFS_SAFE is not set
-CONFIG_DMADEVICES=y
-CONFIG_DMADEVICES_DEBUG=y
-CONFIG_DMADEVICES_VDEBUG=y
-CONFIG_DMA_ENGINE=y
-CONFIG_DMA_OF=y
-CONFIG_DMA_SHARED_BUFFER=y
-CONFIG_DMA_VIRTUAL_CHANNELS=y
-# CONFIG_DPM_WATCHDOG is not set
-CONFIG_DTC=y
-CONFIG_DT_IDLE_GENPD=y
-CONFIG_DT_IDLE_STATES=y
-CONFIG_DWMAC_DWC_QOS_ETH=y
-# CONFIG_DWMAC_GENERIC is not set
-CONFIG_DWMAC_STARFIVE=y
-CONFIG_DW_AXI_DMAC=y
-CONFIG_EDAC_SUPPORT=y
-CONFIG_EEPROM_AT24=y
-CONFIG_EFI=y
-CONFIG_EFIVAR_FS=y
-# CONFIG_EFI_BOOTLOADER_CONTROL is not set
-# CONFIG_EFI_CAPSULE_LOADER is not set
-# CONFIG_EFI_COCO_SECRET is not set
-# CONFIG_EFI_DISABLE_PCI_DMA is not set
-CONFIG_EFI_DISABLE_RUNTIME=y
-CONFIG_EFI_EARLYCON=y
-CONFIG_EFI_ESRT=y
-CONFIG_EFI_GENERIC_STUB=y
-CONFIG_EFI_PARAMS_FROM_FDT=y
-CONFIG_EFI_RUNTIME_WRAPPERS=y
-CONFIG_EFI_STUB=y
-# CONFIG_EFI_TEST is not set
-# CONFIG_EFI_ZBOOT is not set
-# CONFIG_ERRATA_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_FS_IOMAP=y
-CONFIG_FS_MBCACHE=y
-CONFIG_FWNODE_MDIO=y
-CONFIG_FW_LOADER_PAGED_BUF=y
-CONFIG_FW_LOADER_SYSFS=y
-CONFIG_GENERIC_ALLOCATOR=y
-CONFIG_GENERIC_ARCH_TOPOLOGY=y
-CONFIG_GENERIC_BUG=y
-CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
-CONFIG_GENERIC_CSUM=y
-CONFIG_GENERIC_EARLY_IOREMAP=y
-CONFIG_GENERIC_GETTIMEOFDAY=y
-CONFIG_GENERIC_IDLE_POLL_SETUP=y
-CONFIG_GENERIC_IOREMAP=y
-CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
-CONFIG_GENERIC_IRQ_MIGRATION=y
-CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
-CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
-CONFIG_GENERIC_MSI_IRQ=y
-CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
-CONFIG_GENERIC_PCI_IOMAP=y
-CONFIG_GENERIC_PHY=y
-CONFIG_GENERIC_PHY_MIPI_DPHY=y
-CONFIG_GENERIC_PINCONF=y
-CONFIG_GENERIC_PINCTRL_GROUPS=y
-CONFIG_GENERIC_PINMUX_FUNCTIONS=y
-CONFIG_GENERIC_SCHED_CLOCK=y
-CONFIG_GENERIC_SMP_IDLE_THREAD=y
-CONFIG_GENERIC_STRNCPY_FROM_USER=y
-CONFIG_GENERIC_STRNLEN_USER=y
-CONFIG_GENERIC_TIME_VSYSCALL=y
-CONFIG_GLOB=y
-CONFIG_GPIOLIB_FASTPATH_LIMIT=128
-CONFIG_GPIOLIB_IRQCHIP=y
-CONFIG_GPIO_CDEV=y
-CONFIG_GPIO_TPS65086=y
-CONFIG_HARDIRQS_SW_RESEND=y
-CONFIG_HAS_DMA=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT_MAP=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_HUGETLBFS=y
-CONFIG_HUGETLB_PAGE=y
-CONFIG_HVC_DRIVER=y
-CONFIG_HVC_RISCV_SBI=y
-CONFIG_HWMON=y
-CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_JH7110=y
-CONFIG_HW_RANDOM_STARFIVE_VIC=y
-CONFIG_I2C=y
-CONFIG_I2C_ALGOBIT=y
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_DESIGNWARE_CORE=y
-CONFIG_I2C_DESIGNWARE_PLATFORM=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_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_LIBFDT=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_LOCK_DEBUGGING_SUPPORT=y
-CONFIG_LOCK_SPIN_ON_OWNER=y
-CONFIG_LSM=""
-CONFIG_MARVELL_PHY=y
-CONFIG_MDIO_BUS=y
-CONFIG_MDIO_DEVICE=y
-CONFIG_MDIO_DEVRES=y
-CONFIG_MEMFD_CREATE=y
-CONFIG_MEMORY_ISOLATION=y
-CONFIG_MEMTEST=y
-CONFIG_MFD_AXP20X=y
-CONFIG_MFD_AXP20X_I2C=y
-CONFIG_MFD_CORE=y
-CONFIG_MFD_SYSCON=y
-CONFIG_MFD_TPS65086=y
-CONFIG_MICREL_PHY=y
-CONFIG_MICROCHIP_PHY=y
-CONFIG_MIGRATION=y
-CONFIG_MMC=y
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_DEBUG=y
-CONFIG_MMC_DW=y
-# CONFIG_MMC_DW_BLUEFIELD is not set
-# CONFIG_MMC_DW_EXYNOS is not set
-# CONFIG_MMC_DW_HI3798CV200 is not set
-# CONFIG_MMC_DW_K3 is not set
-# CONFIG_MMC_DW_PCI is not set
-CONFIG_MMC_DW_PLTFM=y
-CONFIG_MMC_DW_STARFIVE=y
-CONFIG_MMIOWB=y
-CONFIG_MODULES_TREE_LOOKUP=y
-CONFIG_MODULES_USE_ELF_RELA=y
-CONFIG_MODULE_SECTIONS=y
-CONFIG_MOTORCOMM_PHY=y
-CONFIG_MPILIB=y
-CONFIG_MTD_SPI_NOR=y
-CONFIG_MUTEX_SPIN_ON_OWNER=y
-CONFIG_NAMESPACES=y
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NET_FAILOVER=y
-CONFIG_NET_FLOW_LIMIT=y
-CONFIG_NET_NS=y
-CONFIG_NET_SELFTESTS=y
-CONFIG_NLS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_DEFAULT="iso8859-15"
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NONPORTABLE=y
-CONFIG_NO_HZ_COMMON=y
-CONFIG_NO_HZ_IDLE=y
-CONFIG_NR_CPUS=8
-CONFIG_NVMEM=y
-CONFIG_NVMEM_SYSFS=y
-CONFIG_NVME_CORE=y
-CONFIG_NVME_HWMON=y
-# CONFIG_NVME_MULTIPATH is not set
-CONFIG_OF=y
-CONFIG_OF_ADDRESS=y
-# CONFIG_OF_CONFIGFS is not set
-CONFIG_OF_DMA_DEFAULT_COHERENT=y
-CONFIG_OF_DYNAMIC=y
-CONFIG_OF_EARLY_FLATTREE=y
-CONFIG_OF_FLATTREE=y
-CONFIG_OF_GPIO=y
-CONFIG_OF_IRQ=y
-CONFIG_OF_KOBJ=y
-CONFIG_OF_MDIO=y
-CONFIG_OF_OVERLAY=y
-CONFIG_OF_RESOLVE=y
-CONFIG_OID_REGISTRY=y
-CONFIG_OVERLAY_FS_INDEX=y
-CONFIG_OVERLAY_FS_METACOPY=y
-CONFIG_OVERLAY_FS_REDIRECT_DIR=y
-CONFIG_PADATA=y
-CONFIG_PAGE_EXTENSION=y
-CONFIG_PAGE_OFFSET=0xff60000000000000
-CONFIG_PAGE_POOL=y
-CONFIG_PAGE_REPORTING=y
-CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
-CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
-CONFIG_PCI=y
-CONFIG_PCIE_CADENCE=y
-CONFIG_PCIE_CADENCE_HOST=y
-CONFIG_PCIE_CADENCE_PLAT=y
-CONFIG_PCIE_CADENCE_PLAT_HOST=y
-# CONFIG_PCIE_FU740 is not set
-CONFIG_PCIE_STARFIVE_HOST=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PCI_DOMAINS_GENERIC=y
-CONFIG_PCI_MSI=y
-CONFIG_PCI_MSI_IRQ_DOMAIN=y
-CONFIG_PCS_XPCS=y
-CONFIG_PERF_EVENTS=y
-CONFIG_PGTABLE_LEVELS=5
-CONFIG_PHYLIB=y
-CONFIG_PHYLINK=y
-CONFIG_PHYS_ADDR_T_64BIT=y
-# CONFIG_PHYS_RAM_BASE_FIXED is not set
-CONFIG_PHY_STARFIVE_DPHY_RX=y
-CONFIG_PHY_STARFIVE_JH7110_DPHY_RX=y
-CONFIG_PHY_STARFIVE_JH7110_PCIE=y
-CONFIG_PHY_STARFIVE_JH7110_USB=y
-CONFIG_PINCTRL=y
-CONFIG_PINCTRL_STARFIVE_JH7100=y
-CONFIG_PINCTRL_STARFIVE_JH7110=y
-CONFIG_PINCTRL_STARFIVE_JH7110_AON=y
-CONFIG_PINCTRL_STARFIVE_JH7110_SYS=y
-CONFIG_PM=y
-CONFIG_PM_ADVANCED_DEBUG=y
-CONFIG_PM_CLK=y
-CONFIG_PM_DEBUG=y
-CONFIG_PM_DEVFREQ=y
-# CONFIG_PM_DEVFREQ_EVENT is not set
-CONFIG_PM_GENERIC_DOMAINS=y
-CONFIG_PM_GENERIC_DOMAINS_OF=y
-CONFIG_PM_OPP=y
-CONFIG_PORTABLE=y
-CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_POSIX_MQUEUE_SYSCTL=y
-CONFIG_POWER_RESET=y
-CONFIG_POWER_RESET_GPIO_RESTART=y
-CONFIG_POWER_RESET_SYSCON=y
-CONFIG_POWER_RESET_SYSCON_POWEROFF=y
-# CONFIG_POWER_RESET_TPS65086 is not set
-CONFIG_PPS=y
-CONFIG_PREEMPT_COUNT=y
-CONFIG_PREEMPT_NONE_BUILD=y
-CONFIG_PRINTK_TIME=y
-CONFIG_PROC_CHILDREN=y
-CONFIG_PROC_KCORE=y
-CONFIG_PTDUMP_CORE=y
-CONFIG_PTP_1588_CLOCK=y
-CONFIG_PTP_1588_CLOCK_OPTIONAL=y
-CONFIG_PWM=y
-CONFIG_PWM_OCORES=y
-# CONFIG_PWM_SIFIVE is not set
-CONFIG_PWM_SIFIVE_PTC=y
-CONFIG_PWM_STARFIVE_PTC=y
-CONFIG_PWM_SYSFS=y
-CONFIG_QUEUED_RWLOCKS=y
-CONFIG_RANDSTRUCT_NONE=y
-CONFIG_RATIONAL=y
-CONFIG_RCU_EQS_DEBUG=y
-CONFIG_RD_GZIP=y
-CONFIG_REALTEK_PHY=y
-CONFIG_REGMAP=y
-CONFIG_REGMAP_I2C=y
-CONFIG_REGMAP_IRQ=y
-CONFIG_REGMAP_MMIO=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_AXP20X=y
-CONFIG_REGULATOR_STARFIVE_JH7110=y
-CONFIG_REGULATOR_TPS65086=y
-# CONFIG_RESET_ATTACK_MITIGATION is not set
-CONFIG_RESET_CONTROLLER=y
-CONFIG_RESET_SIMPLE=y
-CONFIG_RESET_STARFIVE_JH7100=y
-CONFIG_RESET_STARFIVE_JH7100_AUDIO=y
-CONFIG_RESET_STARFIVE_JH7110=y
-CONFIG_RESET_STARFIVE_JH71X0=y
-CONFIG_RFS_ACCEL=y
-CONFIG_RISCV=y
-CONFIG_RISCV_ALTERNATIVE=y
-CONFIG_RISCV_BOOT_SPINWAIT=y
-CONFIG_RISCV_DMA_NONCOHERENT=y
-CONFIG_RISCV_INTC=y
-CONFIG_RISCV_ISA_C=y
-CONFIG_RISCV_ISA_FALLBACK=y
-CONFIG_RISCV_ISA_SVNAPOT=y
-# CONFIG_RISCV_ISA_SVPBMT is not set
-CONFIG_RISCV_ISA_V=y
-CONFIG_RISCV_ISA_V_DEFAULT_ENABLE=y
-CONFIG_RISCV_ISA_ZBB=y
-# CONFIG_RISCV_ISA_ZICBOM is not set
-CONFIG_RISCV_ISA_ZICBOZ=y
-CONFIG_RISCV_PMU=y
-CONFIG_RISCV_PMU_LEGACY=y
-CONFIG_RISCV_PMU_SBI=y
-CONFIG_RISCV_SBI=y
-CONFIG_RISCV_SBI_CPUIDLE=y
-CONFIG_RISCV_SBI_V01=y
-CONFIG_RISCV_TIMER=y
-CONFIG_RPMSG=y
-CONFIG_RPMSG_CHAR=y
-# CONFIG_RPMSG_CTRL is not set
-CONFIG_RPMSG_NS=y
-# CONFIG_RPMSG_TTY is not set
-CONFIG_RPMSG_VIRTIO=y
-CONFIG_RPS=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_DRV_EFI is not set
-CONFIG_RTC_DRV_GOLDFISH=y
-CONFIG_RTC_DRV_HYM8563=y
-CONFIG_RTC_DRV_STARFIVE=y
-CONFIG_RTC_I2C_AND_SPI=y
-CONFIG_RWSEM_SPIN_ON_OWNER=y
-CONFIG_SCSI=y
-CONFIG_SCSI_COMMON=y
-CONFIG_SCSI_VIRTIO=y
-CONFIG_SENSORS_SFCTEMP=y
-# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
-CONFIG_SERIAL_8250_DW=y
-CONFIG_SERIAL_8250_DWLIB=y
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_NR_UARTS=6
-CONFIG_SERIAL_8250_RUNTIME_UARTS=6
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
-CONFIG_SERIAL_MCTRL_GPIO=y
-CONFIG_SERIAL_OF_PLATFORM=y
-CONFIG_SERIAL_SIFIVE=y
-CONFIG_SERIAL_SIFIVE_CONSOLE=y
-CONFIG_SGL_ALLOC=y
-CONFIG_SG_POOL=y
-CONFIG_SIFIVE_CCACHE=y
-CONFIG_SIFIVE_PLIC=y
-CONFIG_SMP=y
-# CONFIG_SND_SOC_AC108 is not set
-# CONFIG_SND_SOC_STARFIVE is not set
-CONFIG_SOCK_DIAG=y
-CONFIG_SOCK_RX_QUEUE_MAPPING=y
-# CONFIG_SOC_MICROCHIP_POLARFIRE is not set
-CONFIG_SOC_SIFIVE=y
-CONFIG_SOC_STARFIVE=y
-# CONFIG_SOC_VIRT is not set
-CONFIG_SOFTLOCKUP_DETECTOR=y
-CONFIG_SOUND=y
-CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
-CONFIG_SPARSE_IRQ=y
-CONFIG_SPI=y
-CONFIG_SPI_CADENCE_QUADSPI=y
-CONFIG_SPI_DYNAMIC=y
-CONFIG_SPI_MASTER=y
-CONFIG_SPI_MEM=y
-CONFIG_SPI_SPIDEV=y
-CONFIG_SRCU=y
-CONFIG_STARFIVE_JH7110_TIMER=y
-CONFIG_STARFIVE_TIMER=y
-CONFIG_STARFIVE_WATCHDOG=y
-CONFIG_STMMAC_ETH=y
-CONFIG_STMMAC_PLATFORM=y
-CONFIG_STMMAC_SELFTESTS=y
-CONFIG_SWIOTLB=y
-CONFIG_SWPHY=y
-CONFIG_SYNC_FILE=y
-CONFIG_SYSCTL_EXCEPTION_TRACE=y
-# CONFIG_SYSFB_SIMPLEFB is not set
-CONFIG_THERMAL=y
-CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
-CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
-CONFIG_THERMAL_GOV_STEP_WISE=y
-CONFIG_THERMAL_OF=y
-CONFIG_THREAD_INFO_IN_TASK=y
-CONFIG_THREAD_SIZE_ORDER=2
-CONFIG_TICK_CPU_ACCOUNTING=y
-CONFIG_TIMER_OF=y
-CONFIG_TIMER_PROBE=y
-CONFIG_TOOLCHAIN_HAS_ZICBOM=y
-CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=y
-CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y
-# CONFIG_TOUCHSCREEN_TINKER_FT5406 is not set
-CONFIG_TREE_RCU=y
-CONFIG_TREE_SRCU=y
-CONFIG_TTY_PRINTK=y
-CONFIG_TTY_PRINTK_LEVEL=6
-CONFIG_TUNE_GENERIC=y
-CONFIG_UCS2_STRING=y
-CONFIG_UNINLINE_SPIN_UNLOCK=y
-CONFIG_USB=y
-CONFIG_USB_COMMON=y
-CONFIG_USB_CONFIGFS=y
-# CONFIG_USB_CONFIGFS_ACM is not set
-# CONFIG_USB_CONFIGFS_ECM is not set
-# CONFIG_USB_CONFIGFS_ECM_SUBSET is not set
-# CONFIG_USB_CONFIGFS_EEM is not set
-CONFIG_USB_CONFIGFS_F_FS=y
-# CONFIG_USB_CONFIGFS_F_HID is not set
-# CONFIG_USB_CONFIGFS_F_LB_SS is not set
-# CONFIG_USB_CONFIGFS_F_MIDI is not set
-# CONFIG_USB_CONFIGFS_F_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_PHY=y
-CONFIG_USB_ROLE_SWITCH=y
-CONFIG_USB_SUPPORT=y
-# CONFIG_USB_UHCI_HCD is not set
-CONFIG_USELIB=y
-CONFIG_USER_NS=y
-CONFIG_VFAT_FS=y
-# CONFIG_VIDEO_STF_VIN is not set
-# CONFIG_VIRTIO_BLK is not set
-# CONFIG_VIRTIO_NET is not set
-CONFIG_VMAP_STACK=y
-CONFIG_WATCHDOG_CORE=y
-CONFIG_WATCHDOG_SYSFS=y
-CONFIG_WERROR=y
-CONFIG_WQ_WATCHDOG=y
-CONFIG_XPS=y
-CONFIG_XXHASH=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZONE_DMA32=y
+++ /dev/null
-From 69275b667bd930cf5d5f577ba0ab1987c9d13987 Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Mon, 21 Aug 2023 23:29:15 +0800
-Subject: [PATCH 001/116] clk: starfive: jh7110-sys: Fix lower rate of CPUfreq
- by setting PLL0 rate to 1.5GHz
-
-CPUfreq supports 4 cpu frequency loads on 375/500/750/1500MHz.
-But now PLL0 rate is 1GHz and the cpu frequency loads become
-333/500/500/1000MHz in fact.
-
-So PLL0 rate should be set to 1.5GHz. Change the parent of cpu_root clock
-and the divider of cpu_core before the setting.
-
-Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
-Fixes: e2c510d6d630 ("riscv: dts: starfive: Add cpu scaling for JH7110 SoC")
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
----
- .../clk/starfive/clk-starfive-jh7110-sys.c | 47 ++++++++++++++++++-
- 1 file changed, 46 insertions(+), 1 deletion(-)
-
---- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
-@@ -530,7 +530,52 @@ static int __init jh7110_syscrg_probe(st
- if (ret)
- return ret;
-
-- return jh7110_reset_controller_register(priv, "rst-sys", 0);
-+ ret = jh7110_reset_controller_register(priv, "rst-sys", 0);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * Set PLL0 rate to 1.5GHz
-+ * In order to not affect the cpu when the PLL0 rate is changing,
-+ * we need to switch the parent of cpu_root clock to osc clock first,
-+ * and then switch back after setting the PLL0 rate.
-+ */
-+ pllclk = clk_get(priv->dev, "pll0_out");
-+ if (!IS_ERR(pllclk)) {
-+ struct clk *osc = clk_get(&pdev->dev, "osc");
-+ struct clk *cpu_root = priv->reg[JH7110_SYSCLK_CPU_ROOT].hw.clk;
-+ struct clk *cpu_core = priv->reg[JH7110_SYSCLK_CPU_CORE].hw.clk;
-+
-+ if (IS_ERR(osc)) {
-+ clk_put(pllclk);
-+ return PTR_ERR(osc);
-+ }
-+
-+ /*
-+ * CPU need voltage regulation by CPUfreq if set 1.5GHz.
-+ * So in this driver, cpu_core need to be set the divider to be 2 first
-+ * and will be 750M after setting parent.
-+ */
-+ ret = clk_set_rate(cpu_core, clk_get_rate(cpu_core) / 2);
-+ if (ret)
-+ goto failed_set;
-+
-+ ret = clk_set_parent(cpu_root, osc);
-+ if (ret)
-+ goto failed_set;
-+
-+ ret = clk_set_rate(pllclk, 1500000000);
-+ if (ret)
-+ goto failed_set;
-+
-+ ret = clk_set_parent(cpu_root, pllclk);
-+
-+failed_set:
-+ clk_put(pllclk);
-+ clk_put(osc);
-+ }
-+
-+ return ret;
- }
-
- static const struct of_device_id jh7110_syscrg_match[] = {
+++ /dev/null
-From 7d0dbcbc079e4f72b69f53442b7759da6ebc4f87 Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Thu, 19 Oct 2023 13:34:59 +0800
-Subject: [PATCH 002/116] dt-bindings: timer: Add timer for StarFive JH7110 SoC
-
-Add bindings for the timer on the JH7110 RISC-V SoC
-by StarFive Technology Ltd.
-
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
----
- .../bindings/timer/starfive,jh7110-timer.yaml | 96 +++++++++++++++++++
- 1 file changed, 96 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml
-@@ -0,0 +1,96 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/timer/starfive,jh7110-timer.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: StarFive JH7110 Timer
-+
-+maintainers:
-+ - Xingyu Wu <xingyu.wu@starfivetech.com>
-+ - Samin Guo <samin.guo@starfivetech.com>
-+
-+description:
-+ This timer has four free-running 32 bit counters in StarFive JH7110 SoC.
-+ And each channel(counter) triggers an interrupt when timeout. They support
-+ one-shot mode and continuous-run mode.
-+
-+properties:
-+ compatible:
-+ const: starfive,jh7110-timer
-+
-+ reg:
-+ maxItems: 1
-+
-+ interrupts:
-+ items:
-+ - description: channel 0
-+ - description: channel 1
-+ - description: channel 2
-+ - description: channel 3
-+
-+ clocks:
-+ items:
-+ - description: timer APB
-+ - description: channel 0
-+ - description: channel 1
-+ - description: channel 2
-+ - description: channel 3
-+
-+ clock-names:
-+ items:
-+ - const: apb
-+ - const: ch0
-+ - const: ch1
-+ - const: ch2
-+ - const: ch3
-+
-+ resets:
-+ items:
-+ - description: timer APB
-+ - description: channel 0
-+ - description: channel 1
-+ - description: channel 2
-+ - description: channel 3
-+
-+ reset-names:
-+ items:
-+ - const: apb
-+ - const: ch0
-+ - const: ch1
-+ - const: ch2
-+ - const: ch3
-+
-+required:
-+ - compatible
-+ - reg
-+ - interrupts
-+ - clocks
-+ - clock-names
-+ - resets
-+ - reset-names
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ timer@13050000 {
-+ compatible = "starfive,jh7110-timer";
-+ reg = <0x13050000 0x10000>;
-+ interrupts = <69>, <70>, <71> ,<72>;
-+ clocks = <&clk 124>,
-+ <&clk 125>,
-+ <&clk 126>,
-+ <&clk 127>,
-+ <&clk 128>;
-+ clock-names = "apb", "ch0", "ch1",
-+ "ch2", "ch3";
-+ resets = <&rst 117>,
-+ <&rst 118>,
-+ <&rst 119>,
-+ <&rst 120>,
-+ <&rst 121>;
-+ reset-names = "apb", "ch0", "ch1",
-+ "ch2", "ch3";
-+ };
-+
+++ /dev/null
-From 7cb47848f8a10aed6e050c0ea483b4bb5eaa62a4 Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Thu, 19 Oct 2023 13:35:00 +0800
-Subject: [PATCH 003/116] clocksource: Add JH7110 timer driver
-
-Add timer driver for the StarFive JH7110 SoC.
-
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
----
- drivers/clocksource/Kconfig | 11 +
- drivers/clocksource/Makefile | 1 +
- drivers/clocksource/timer-jh7110.c | 380 +++++++++++++++++++++++++++++
- 3 files changed, 392 insertions(+)
- create mode 100644 drivers/clocksource/timer-jh7110.c
-
---- a/drivers/clocksource/Kconfig
-+++ b/drivers/clocksource/Kconfig
-@@ -642,6 +642,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
-@@ -80,6 +80,7 @@ obj-$(CONFIG_INGENIC_TIMER) += ingenic-
- obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
- obj-$(CONFIG_X86_NUMACHIP) += numachip.o
- obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
-+obj-$(CONFIG_STARFIVE_JH7110_TIMER) += timer-jh7110.o
- obj-$(CONFIG_CLINT_TIMER) += timer-clint.o
- obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
- obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
---- /dev/null
-+++ b/drivers/clocksource/timer-jh7110.c
-@@ -0,0 +1,380 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Starfive JH7110 Timer driver
-+ *
-+ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
-+ *
-+ * Author:
-+ * Xingyu Wu <xingyu.wu@starfivetech.com>
-+ * Samin Guo <samin.guo@starfivetech.com>
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clockchips.h>
-+#include <linux/clocksource.h>
-+#include <linux/err.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/iopoll.h>
-+#include <linux/irq.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/reset.h>
-+#include <linux/sched_clock.h>
-+
-+/* Bias: Ch0-0x0, Ch1-0x40, Ch2-0x80, and so on. */
-+#define JH7110_TIMER_CH_LEN 0x40
-+#define JH7110_TIMER_CH_BASE(x) ((x) * JH7110_TIMER_CH_LEN)
-+#define JH7110_TIMER_CH_MAX 4
-+
-+#define JH7110_CLOCK_SOURCE_RATING 200
-+#define JH7110_VALID_BITS 32
-+#define JH7110_DELAY_US 0
-+#define JH7110_TIMEOUT_US 10000
-+#define JH7110_CLOCKEVENT_RATING 300
-+#define JH7110_TIMER_MAX_TICKS 0xffffffff
-+#define JH7110_TIMER_MIN_TICKS 0xf
-+#define JH7110_TIMER_RELOAD_VALUE 0
-+
-+#define JH7110_TIMER_INT_STATUS 0x00 /* RO[0:4]: Interrupt Status for channel0~4 */
-+#define JH7110_TIMER_CTL 0x04 /* RW[0]: 0-continuous run, 1-single run */
-+#define JH7110_TIMER_LOAD 0x08 /* RW: load value to counter */
-+#define JH7110_TIMER_ENABLE 0x10 /* RW[0]: timer enable register */
-+#define JH7110_TIMER_RELOAD 0x14 /* RW: write 1 or 0 both reload counter */
-+#define JH7110_TIMER_VALUE 0x18 /* RO: timer value register */
-+#define JH7110_TIMER_INT_CLR 0x20 /* RW: timer interrupt clear register */
-+#define JH7110_TIMER_INT_MASK 0x24 /* RW[0]: timer interrupt mask register */
-+
-+#define JH7110_TIMER_INT_CLR_ENA BIT(0)
-+#define JH7110_TIMER_INT_CLR_AVA_MASK BIT(1)
-+
-+struct jh7110_clkevt {
-+ struct clock_event_device evt;
-+ struct clocksource cs;
-+ bool cs_is_valid;
-+ struct clk *clk;
-+ struct reset_control *rst;
-+ u32 rate;
-+ u32 reload_val;
-+ void __iomem *base;
-+ char name[sizeof("jh7110-timer.chX")];
-+};
-+
-+struct jh7110_timer_priv {
-+ struct clk *pclk;
-+ struct reset_control *prst;
-+ struct jh7110_clkevt clkevt[JH7110_TIMER_CH_MAX];
-+};
-+
-+/* 0:continuous-run mode, 1:single-run mode */
-+enum jh7110_timer_mode {
-+ JH7110_TIMER_MODE_CONTIN,
-+ JH7110_TIMER_MODE_SINGLE,
-+};
-+
-+/* Interrupt Mask, 0:Unmask, 1:Mask */
-+enum jh7110_timer_int_mask {
-+ JH7110_TIMER_INT_ENA,
-+ JH7110_TIMER_INT_DIS,
-+};
-+
-+enum jh7110_timer_enable {
-+ JH7110_TIMER_DIS,
-+ JH7110_TIMER_ENA,
-+};
-+
-+static inline struct jh7110_clkevt *to_jh7110_clkevt(struct clock_event_device *evt)
-+{
-+ return container_of(evt, struct jh7110_clkevt, evt);
-+}
-+
-+/*
-+ * BIT(0): Read value represent channel int status.
-+ * Write 1 to this bit to clear interrupt. Write 0 has no effects.
-+ * BIT(1): "1" means that it is clearing interrupt. BIT(0) can not be written.
-+ */
-+static inline int jh7110_timer_int_clear(struct jh7110_clkevt *clkevt)
-+{
-+ u32 value;
-+ int ret;
-+
-+ /* Waiting interrupt can be cleared */
-+ ret = readl_poll_timeout_atomic(clkevt->base + JH7110_TIMER_INT_CLR, value,
-+ !(value & JH7110_TIMER_INT_CLR_AVA_MASK),
-+ JH7110_DELAY_US, JH7110_TIMEOUT_US);
-+ if (!ret)
-+ writel(JH7110_TIMER_INT_CLR_ENA, clkevt->base + JH7110_TIMER_INT_CLR);
-+
-+ return ret;
-+}
-+
-+static int jh7110_timer_start(struct jh7110_clkevt *clkevt)
-+{
-+ int ret;
-+
-+ /* Disable and clear interrupt first */
-+ writel(JH7110_TIMER_INT_DIS, clkevt->base + JH7110_TIMER_INT_MASK);
-+ ret = jh7110_timer_int_clear(clkevt);
-+ if (ret)
-+ return ret;
-+
-+ writel(JH7110_TIMER_INT_ENA, clkevt->base + JH7110_TIMER_INT_MASK);
-+ writel(JH7110_TIMER_ENA, clkevt->base + JH7110_TIMER_ENABLE);
-+
-+ return 0;
-+}
-+
-+static int jh7110_timer_shutdown(struct clock_event_device *evt)
-+{
-+ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
-+
-+ writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE);
-+ return jh7110_timer_int_clear(clkevt);
-+}
-+
-+static void jh7110_timer_suspend(struct clock_event_device *evt)
-+{
-+ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
-+
-+ clkevt->reload_val = readl(clkevt->base + JH7110_TIMER_LOAD);
-+ jh7110_timer_shutdown(evt);
-+}
-+
-+static void jh7110_timer_resume(struct clock_event_device *evt)
-+{
-+ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
-+
-+ writel(clkevt->reload_val, clkevt->base + JH7110_TIMER_LOAD);
-+ writel(JH7110_TIMER_RELOAD_VALUE, clkevt->base + JH7110_TIMER_RELOAD);
-+ jh7110_timer_start(clkevt);
-+}
-+
-+static int jh7110_timer_tick_resume(struct clock_event_device *evt)
-+{
-+ jh7110_timer_resume(evt);
-+
-+ return 0;
-+}
-+
-+/* IRQ handler for the timer */
-+static irqreturn_t jh7110_timer_interrupt(int irq, void *priv)
-+{
-+ struct clock_event_device *evt = (struct clock_event_device *)priv;
-+ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
-+
-+ if (jh7110_timer_int_clear(clkevt))
-+ return IRQ_NONE;
-+
-+ if (evt->event_handler)
-+ evt->event_handler(evt);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int jh7110_timer_set_periodic(struct clock_event_device *evt)
-+{
-+ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
-+ u32 periodic = DIV_ROUND_CLOSEST(clkevt->rate, HZ);
-+
-+ writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL);
-+ writel(periodic, clkevt->base + JH7110_TIMER_LOAD);
-+
-+ return jh7110_timer_start(clkevt);
-+}
-+
-+static int jh7110_timer_set_oneshot(struct clock_event_device *evt)
-+{
-+ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
-+
-+ writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL);
-+ writel(JH7110_TIMER_MAX_TICKS, clkevt->base + JH7110_TIMER_LOAD);
-+
-+ return jh7110_timer_start(clkevt);
-+}
-+
-+static int jh7110_timer_set_next_event(unsigned long next,
-+ struct clock_event_device *evt)
-+{
-+ struct jh7110_clkevt *clkevt = to_jh7110_clkevt(evt);
-+
-+ writel(JH7110_TIMER_MODE_SINGLE, clkevt->base + JH7110_TIMER_CTL);
-+ writel(next, clkevt->base + JH7110_TIMER_LOAD);
-+
-+ return jh7110_timer_start(clkevt);
-+}
-+
-+static void jh7110_set_clockevent(struct clock_event_device *evt)
-+{
-+ evt->features = CLOCK_EVT_FEAT_PERIODIC |
-+ CLOCK_EVT_FEAT_ONESHOT |
-+ CLOCK_EVT_FEAT_DYNIRQ;
-+ evt->set_state_shutdown = jh7110_timer_shutdown;
-+ evt->set_state_periodic = jh7110_timer_set_periodic;
-+ evt->set_state_oneshot = jh7110_timer_set_oneshot;
-+ evt->set_state_oneshot_stopped = jh7110_timer_shutdown;
-+ evt->tick_resume = jh7110_timer_tick_resume;
-+ evt->set_next_event = jh7110_timer_set_next_event;
-+ evt->suspend = jh7110_timer_suspend;
-+ evt->resume = jh7110_timer_resume;
-+ evt->rating = JH7110_CLOCKEVENT_RATING;
-+}
-+
-+static u64 jh7110_timer_clocksource_read(struct clocksource *cs)
-+{
-+ struct jh7110_clkevt *clkevt = container_of(cs, struct jh7110_clkevt, cs);
-+
-+ return (u64)readl(clkevt->base + JH7110_TIMER_VALUE);
-+}
-+
-+static int jh7110_clocksource_init(struct jh7110_clkevt *clkevt)
-+{
-+ int ret;
-+
-+ clkevt->cs.name = clkevt->name;
-+ clkevt->cs.rating = JH7110_CLOCK_SOURCE_RATING;
-+ clkevt->cs.read = jh7110_timer_clocksource_read;
-+ clkevt->cs.mask = CLOCKSOURCE_MASK(JH7110_VALID_BITS);
-+ clkevt->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-+
-+ ret = clocksource_register_hz(&clkevt->cs, clkevt->rate);
-+ if (ret)
-+ return ret;
-+
-+ clkevt->cs_is_valid = true; /* clocksource register done */
-+ writel(JH7110_TIMER_MODE_CONTIN, clkevt->base + JH7110_TIMER_CTL);
-+ writel(JH7110_TIMER_MAX_TICKS, clkevt->base + JH7110_TIMER_LOAD);
-+
-+ return jh7110_timer_start(clkevt);
-+}
-+
-+static void jh7110_clockevents_register(struct jh7110_clkevt *clkevt)
-+{
-+ clkevt->rate = clk_get_rate(clkevt->clk);
-+
-+ jh7110_set_clockevent(&clkevt->evt);
-+ clkevt->evt.name = clkevt->name;
-+ clkevt->evt.cpumask = cpu_possible_mask;
-+
-+ clockevents_config_and_register(&clkevt->evt, clkevt->rate,
-+ JH7110_TIMER_MIN_TICKS, JH7110_TIMER_MAX_TICKS);
-+}
-+
-+static void jh7110_timer_release(void *data)
-+{
-+ struct jh7110_timer_priv *priv = data;
-+ int i;
-+
-+ for (i = 0; i < JH7110_TIMER_CH_MAX; i++) {
-+ /* Disable each channel of timer */
-+ if (priv->clkevt[i].base)
-+ writel(JH7110_TIMER_DIS, priv->clkevt[i].base + JH7110_TIMER_ENABLE);
-+
-+ /* Avoid no initialization in the loop of the probe */
-+ if (!IS_ERR_OR_NULL(priv->clkevt[i].rst))
-+ reset_control_assert(priv->clkevt[i].rst);
-+
-+ if (priv->clkevt[i].cs_is_valid)
-+ clocksource_unregister(&priv->clkevt[i].cs);
-+ }
-+
-+ reset_control_assert(priv->prst);
-+}
-+
-+static int jh7110_timer_probe(struct platform_device *pdev)
-+{
-+ struct jh7110_timer_priv *priv;
-+ struct jh7110_clkevt *clkevt;
-+ char name[sizeof("chX")];
-+ int ch;
-+ int ret;
-+ void __iomem *base;
-+
-+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ base = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(base))
-+ return dev_err_probe(&pdev->dev, PTR_ERR(base),
-+ "failed to map registers\n");
-+
-+ priv->prst = devm_reset_control_get_exclusive(&pdev->dev, "apb");
-+ if (IS_ERR(priv->prst))
-+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->prst),
-+ "failed to get apb reset\n");
-+
-+ priv->pclk = devm_clk_get_enabled(&pdev->dev, "apb");
-+ if (IS_ERR(priv->pclk))
-+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk),
-+ "failed to get & enable apb clock\n");
-+
-+ ret = reset_control_deassert(priv->prst);
-+ if (ret)
-+ return dev_err_probe(&pdev->dev, ret, "failed to deassert apb reset\n");
-+
-+ ret = devm_add_action_or_reset(&pdev->dev, jh7110_timer_release, priv);
-+ if (ret)
-+ return ret;
-+
-+ for (ch = 0; ch < JH7110_TIMER_CH_MAX; ch++) {
-+ clkevt = &priv->clkevt[ch];
-+ snprintf(name, sizeof(name), "ch%d", ch);
-+
-+ clkevt->base = base + JH7110_TIMER_CH_BASE(ch);
-+ /* Ensure timer is disabled */
-+ writel(JH7110_TIMER_DIS, clkevt->base + JH7110_TIMER_ENABLE);
-+
-+ clkevt->rst = devm_reset_control_get_exclusive(&pdev->dev, name);
-+ if (IS_ERR(clkevt->rst))
-+ return PTR_ERR(clkevt->rst);
-+
-+ clkevt->clk = devm_clk_get_enabled(&pdev->dev, name);
-+ if (IS_ERR(clkevt->clk))
-+ return PTR_ERR(clkevt->clk);
-+
-+ ret = reset_control_deassert(clkevt->rst);
-+ if (ret)
-+ return ret;
-+
-+ clkevt->evt.irq = platform_get_irq(pdev, ch);
-+ if (clkevt->evt.irq < 0)
-+ return clkevt->evt.irq;
-+
-+ snprintf(clkevt->name, sizeof(clkevt->name), "jh7110-timer.ch%d", ch);
-+ jh7110_clockevents_register(clkevt);
-+
-+ ret = devm_request_irq(&pdev->dev, clkevt->evt.irq, jh7110_timer_interrupt,
-+ IRQF_TIMER | IRQF_IRQPOLL,
-+ clkevt->name, &clkevt->evt);
-+ if (ret)
-+ return ret;
-+
-+ ret = jh7110_clocksource_init(clkevt);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id jh7110_timer_match[] = {
-+ { .compatible = "starfive,jh7110-timer", },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, jh7110_timer_match);
-+
-+static struct platform_driver jh7110_timer_driver = {
-+ .probe = jh7110_timer_probe,
-+ .driver = {
-+ .name = "jh7110-timer",
-+ .of_match_table = jh7110_timer_match,
-+ },
-+};
-+module_platform_driver(jh7110_timer_driver);
-+
-+MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
-+MODULE_DESCRIPTION("StarFive JH7110 timer driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From b513eb2cabee212ba1a23839f18c0026a21e653e Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Fri, 22 Sep 2023 14:28:32 +0800
-Subject: [PATCH 004/116] dt-bindings: mmc: starfive: Remove properties from
- required
-
-Due to the change of tuning implementation, it's no longer necessary to
-use the "starfive,sysreg" property in dts, so remove it from required.
-
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
-Reviewed-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Link: https://lore.kernel.org/r/20230922062834.39212-2-william.qiu@starfivetech.com
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- Documentation/devicetree/bindings/mmc/starfive,jh7110-mmc.yaml | 2 --
- 1 file changed, 2 deletions(-)
-
---- a/Documentation/devicetree/bindings/mmc/starfive,jh7110-mmc.yaml
-+++ b/Documentation/devicetree/bindings/mmc/starfive,jh7110-mmc.yaml
-@@ -55,7 +55,6 @@ required:
- - clocks
- - clock-names
- - interrupts
-- - starfive,sysreg
-
- unevaluatedProperties: false
-
-@@ -73,5 +72,4 @@ examples:
- fifo-depth = <32>;
- fifo-watermark-aligned;
- data-addr = <0>;
-- starfive,sysreg = <&sys_syscon 0x14 0x1a 0x7c000000>;
- };
+++ /dev/null
-From 3ae8cec8fd28e18847edb67dfea04718c2f3369f Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Fri, 22 Sep 2023 14:28:33 +0800
-Subject: [PATCH 005/116] mmc: starfive: Change tuning implementation
-
-Before, we used syscon to achieve tuning, but the actual measurement
-showed little effect, so the tuning implementation was modified here,
-and it was realized by reading and writing the UHS_REG_EXT register.
-
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
-Reviewed-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Link: https://lore.kernel.org/r/20230922062834.39212-3-william.qiu@starfivetech.com
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- drivers/mmc/host/dw_mmc-starfive.c | 137 +++++++++--------------------
- 1 file changed, 40 insertions(+), 97 deletions(-)
-
---- a/drivers/mmc/host/dw_mmc-starfive.c
-+++ b/drivers/mmc/host/dw_mmc-starfive.c
-@@ -5,6 +5,7 @@
- * Copyright (c) 2022 StarFive Technology Co., Ltd.
- */
-
-+#include <linux/bitfield.h>
- #include <linux/clk.h>
- #include <linux/delay.h>
- #include <linux/mfd/syscon.h>
-@@ -20,13 +21,7 @@
- #define ALL_INT_CLR 0x1ffff
- #define MAX_DELAY_CHAIN 32
-
--struct starfive_priv {
-- struct device *dev;
-- struct regmap *reg_syscon;
-- u32 syscon_offset;
-- u32 syscon_shift;
-- u32 syscon_mask;
--};
-+#define STARFIVE_SMPL_PHASE GENMASK(20, 16)
-
- static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios)
- {
-@@ -44,117 +39,65 @@ static void dw_mci_starfive_set_ios(stru
- }
- }
-
-+static void dw_mci_starfive_set_sample_phase(struct dw_mci *host, u32 smpl_phase)
-+{
-+ /* change driver phase and sample phase */
-+ u32 reg_value = mci_readl(host, UHS_REG_EXT);
-+
-+ /* In UHS_REG_EXT, only 5 bits valid in DRV_PHASE and SMPL_PHASE */
-+ reg_value &= ~STARFIVE_SMPL_PHASE;
-+ reg_value |= FIELD_PREP(STARFIVE_SMPL_PHASE, smpl_phase);
-+ mci_writel(host, UHS_REG_EXT, reg_value);
-+
-+ /* We should delay 1ms wait for timing setting finished. */
-+ mdelay(1);
-+}
-+
- static int dw_mci_starfive_execute_tuning(struct dw_mci_slot *slot,
- u32 opcode)
- {
- static const int grade = MAX_DELAY_CHAIN;
- struct dw_mci *host = slot->host;
-- struct starfive_priv *priv = host->priv;
-- int rise_point = -1, fall_point = -1;
-- int err, prev_err = 0;
-- int i;
-- bool found = 0;
-- u32 regval;
--
-- /*
-- * Use grade as the max delay chain, and use the rise_point and
-- * fall_point to ensure the best sampling point of a data input
-- * signals.
-- */
-- for (i = 0; i < grade; i++) {
-- regval = i << priv->syscon_shift;
-- err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset,
-- priv->syscon_mask, regval);
-- if (err)
-- return err;
-- mci_writel(host, RINTSTS, ALL_INT_CLR);
--
-- err = mmc_send_tuning(slot->mmc, opcode, NULL);
-- if (!err)
-- found = 1;
--
-- if (i > 0) {
-- if (err && !prev_err)
-- fall_point = i - 1;
-- if (!err && prev_err)
-- rise_point = i;
-- }
-+ int smpl_phase, smpl_raise = -1, smpl_fall = -1;
-+ int ret;
-
-- if (rise_point != -1 && fall_point != -1)
-- goto tuning_out;
-+ for (smpl_phase = 0; smpl_phase < grade; smpl_phase++) {
-+ dw_mci_starfive_set_sample_phase(host, smpl_phase);
-+ mci_writel(host, RINTSTS, ALL_INT_CLR);
-
-- prev_err = err;
-- err = 0;
-- }
-+ ret = mmc_send_tuning(slot->mmc, opcode, NULL);
-
--tuning_out:
-- if (found) {
-- if (rise_point == -1)
-- rise_point = 0;
-- if (fall_point == -1)
-- fall_point = grade - 1;
-- if (fall_point < rise_point) {
-- if ((rise_point + fall_point) >
-- (grade - 1))
-- i = fall_point / 2;
-- else
-- i = (rise_point + grade - 1) / 2;
-- } else {
-- i = (rise_point + fall_point) / 2;
-+ if (!ret && smpl_raise < 0) {
-+ smpl_raise = smpl_phase;
-+ } else if (ret && smpl_raise >= 0) {
-+ smpl_fall = smpl_phase - 1;
-+ break;
- }
--
-- regval = i << priv->syscon_shift;
-- err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset,
-- priv->syscon_mask, regval);
-- if (err)
-- return err;
-- mci_writel(host, RINTSTS, ALL_INT_CLR);
--
-- dev_info(host->dev, "Found valid delay chain! use it [delay=%d]\n", i);
-- } else {
-- dev_err(host->dev, "No valid delay chain! use default\n");
-- err = -EINVAL;
- }
-
-- mci_writel(host, RINTSTS, ALL_INT_CLR);
-- return err;
--}
--
--static int dw_mci_starfive_parse_dt(struct dw_mci *host)
--{
-- struct of_phandle_args args;
-- struct starfive_priv *priv;
-- int ret;
-+ if (smpl_phase >= grade)
-+ smpl_fall = grade - 1;
-
-- priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- ret = of_parse_phandle_with_fixed_args(host->dev->of_node,
-- "starfive,sysreg", 3, 0, &args);
-- if (ret) {
-- dev_err(host->dev, "Failed to parse starfive,sysreg\n");
-- return -EINVAL;
-+ if (smpl_raise < 0) {
-+ smpl_phase = 0;
-+ dev_err(host->dev, "No valid delay chain! use default\n");
-+ ret = -EINVAL;
-+ goto out;
- }
-
-- priv->reg_syscon = syscon_node_to_regmap(args.np);
-- of_node_put(args.np);
-- if (IS_ERR(priv->reg_syscon))
-- return PTR_ERR(priv->reg_syscon);
--
-- priv->syscon_offset = args.args[0];
-- priv->syscon_shift = args.args[1];
-- priv->syscon_mask = args.args[2];
--
-- host->priv = priv;
-+ smpl_phase = (smpl_raise + smpl_fall) / 2;
-+ dev_dbg(host->dev, "Found valid delay chain! use it [delay=%d]\n", smpl_phase);
-+ ret = 0;
-
-- return 0;
-+out:
-+ dw_mci_starfive_set_sample_phase(host, smpl_phase);
-+ mci_writel(host, RINTSTS, ALL_INT_CLR);
-+ return ret;
- }
-
- static const struct dw_mci_drv_data starfive_data = {
- .common_caps = MMC_CAP_CMD23,
- .set_ios = dw_mci_starfive_set_ios,
-- .parse_dt = dw_mci_starfive_parse_dt,
- .execute_tuning = dw_mci_starfive_execute_tuning,
- };
-
+++ /dev/null
-From e366df2ff64e9f93a5b35eea6a198b005d5a0911 Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Fri, 22 Dec 2023 17:45:45 +0800
-Subject: [PATCH 006/116] dt-bindings: pwm: Add bindings for OpenCores PWM
- Controller
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add bindings for OpenCores PWM Controller.
-
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
-Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
-Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- .../bindings/pwm/opencores,pwm.yaml | 55 +++++++++++++++++++
- 1 file changed, 55 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
-@@ -0,0 +1,55 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/pwm/opencores,pwm.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: OpenCores PWM controller
-+
-+maintainers:
-+ - William Qiu <william.qiu@starfivetech.com>
-+
-+description:
-+ The OpenCores PTC ip core contains a PWM controller. When operating in PWM
-+ mode, the PTC core generates binary signal with user-programmable low and
-+ high periods. All PTC counters and registers are 32-bit.
-+
-+allOf:
-+ - $ref: pwm.yaml#
-+
-+properties:
-+ compatible:
-+ items:
-+ - enum:
-+ - starfive,jh7100-pwm
-+ - starfive,jh7110-pwm
-+ - const: opencores,pwm-v1
-+
-+ reg:
-+ maxItems: 1
-+
-+ clocks:
-+ maxItems: 1
-+
-+ resets:
-+ maxItems: 1
-+
-+ "#pwm-cells":
-+ const: 3
-+
-+required:
-+ - compatible
-+ - reg
-+ - clocks
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ pwm@12490000 {
-+ compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
-+ reg = <0x12490000 0x10000>;
-+ clocks = <&clkgen 181>;
-+ resets = <&rstgen 109>;
-+ #pwm-cells = <3>;
-+ };
+++ /dev/null
-From 644bfe581dde9b762460a4916da4d71c148be06e Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Fri, 22 Dec 2023 17:45:46 +0800
-Subject: [PATCH 007/116] pwm: opencores: Add PWM driver support
-
-Add driver for OpenCores PWM Controller. And add compatibility code
-which based on StarFive SoC.
-
-Co-developed-by: Hal Feng <hal.feng@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
----
- drivers/pwm/Kconfig | 12 ++
- drivers/pwm/Makefile | 1 +
- drivers/pwm/pwm-ocores.c | 233 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 246 insertions(+)
- create mode 100644 drivers/pwm/pwm-ocores.c
-
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
-@@ -434,6 +434,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
-@@ -39,6 +39,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,233 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * OpenCores PWM Driver
-+ *
-+ * https://opencores.org/projects/ptc
-+ *
-+ * Copyright (C) 2018-2023 StarFive Technology Co., Ltd.
-+ *
-+ * Limitations:
-+ * - The hardware only do inverted polarity.
-+ * - The hardware minimum period / duty_cycle is (1 / pwm_apb clock frequency) ns.
-+ * - The hardware maximum period / duty_cycle is (U32_MAX / pwm_apb clock frequency) ns.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/pwm.h>
-+#include <linux/reset.h>
-+#include <linux/slab.h>
-+
-+/* OCPWM_CTRL register bits*/
-+#define REG_OCPWM_EN BIT(0)
-+#define REG_OCPWM_ECLK BIT(1)
-+#define REG_OCPWM_NEC BIT(2)
-+#define REG_OCPWM_OE BIT(3)
-+#define REG_OCPWM_SIGNLE BIT(4)
-+#define REG_OCPWM_INTE BIT(5)
-+#define REG_OCPWM_INT BIT(6)
-+#define REG_OCPWM_CNTRRST BIT(7)
-+#define REG_OCPWM_CAPTE BIT(8)
-+
-+struct ocores_pwm_device {
-+ struct pwm_chip chip;
-+ 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 container_of(chip, struct ocores_pwm_device, 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)
-+{
-+ const struct of_device_id *id;
-+ struct device *dev = &pdev->dev;
-+ struct ocores_pwm_device *ddata;
-+ struct pwm_chip *chip;
-+ int ret;
-+
-+ id = of_match_device(ocores_pwm_of_match, dev);
-+ if (!id)
-+ return -EINVAL;
-+
-+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
-+ if (!ddata)
-+ return -ENOMEM;
-+
-+ ddata->data = id->data;
-+ chip = &ddata->chip;
-+ chip->dev = dev;
-+ chip->ops = &ocores_pwm_ops;
-+ chip->npwm = 8;
-+ chip->of_pwm_n_cells = 3;
-+
-+ ddata->regs = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(ddata->regs))
-+ return dev_err_probe(dev, PTR_ERR(ddata->regs),
-+ "Unable to map IO resources\n");
-+
-+ ddata->clk = devm_clk_get_enabled(dev, NULL);
-+ if (IS_ERR(ddata->clk))
-+ return dev_err_probe(dev, PTR_ERR(ddata->clk),
-+ "Unable to get pwm's clock\n");
-+
-+ ddata->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
-+ if (IS_ERR(ddata->rst))
-+ return dev_err_probe(dev, PTR_ERR(ddata->rst),
-+ "Unable to get pwm's reset\n");
-+
-+ reset_control_deassert(ddata->rst);
-+
-+ ret = devm_add_action_or_reset(dev, ocores_reset_control_assert, ddata->rst);
-+ if (ret)
-+ return ret;
-+
-+ ddata->clk_rate = clk_get_rate(ddata->clk);
-+ if (ddata->clk_rate <= 0)
-+ return dev_err_probe(dev, ddata->clk_rate,
-+ "Unable to get clock's rate\n");
-+
-+ ret = devm_pwmchip_add(dev, chip);
-+ if (ret < 0)
-+ return dev_err_probe(dev, ret, "Could not register PWM chip\n");
-+
-+ platform_set_drvdata(pdev, ddata);
-+
-+ return ret;
-+}
-+
-+static struct platform_driver ocores_pwm_driver = {
-+ .probe = ocores_pwm_probe,
-+ .driver = {
-+ .name = "ocores-pwm",
-+ .of_match_table = ocores_pwm_of_match,
-+ },
-+};
-+module_platform_driver(ocores_pwm_driver);
-+
-+MODULE_AUTHOR("Jieqin Chen");
-+MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
-+MODULE_DESCRIPTION("OpenCores PWM PTC driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From 7d9521cad6474d45e9056176982e6da54d40bc19 Mon Sep 17 00:00:00 2001
-From: Eric Biggers <ebiggers@google.com>
-Date: Sun, 22 Oct 2023 01:10:42 -0700
-Subject: [PATCH 008/116] crypto: starfive - remove unnecessary alignmask for
- ahashes
-
-The crypto API's support for alignmasks for ahash algorithms is nearly
-useless, as its only effect is to cause the API to align the key and
-result buffers. The drivers that happen to be specifying an alignmask
-for ahash rarely actually need it. When they do, it's easily fixable,
-especially considering that these buffers cannot be used for DMA.
-
-In preparation for removing alignmask support from ahash, this patch
-makes the starfive driver no longer use it. This driver did actually
-rely on it, but only for storing to the result buffer using int stores
-in starfive_hash_copy_hash(). This patch makes
-starfive_hash_copy_hash() use put_unaligned() instead. (It really
-should use a specific endianness, but that's an existing bug.)
-
-Signed-off-by: Eric Biggers <ebiggers@google.com>
-Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
----
- drivers/crypto/starfive/jh7110-hash.c | 13 ++-----------
- 1 file changed, 2 insertions(+), 11 deletions(-)
-
---- a/drivers/crypto/starfive/jh7110-hash.c
-+++ b/drivers/crypto/starfive/jh7110-hash.c
-@@ -209,7 +209,8 @@ static int starfive_hash_copy_hash(struc
- data = (u32 *)req->result;
-
- for (count = 0; count < mlen; count++)
-- data[count] = readl(ctx->cryp->base + STARFIVE_HASH_SHARDR);
-+ put_unaligned(readl(ctx->cryp->base + STARFIVE_HASH_SHARDR),
-+ &data[count]);
-
- return 0;
- }
-@@ -628,7 +629,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA224_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -658,7 +658,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA224_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -687,7 +686,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA256_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -717,7 +715,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA256_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -746,7 +743,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA384_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -776,7 +772,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA384_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -805,7 +800,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA512_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -835,7 +829,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA512_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -864,7 +857,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SM3_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
-@@ -894,7 +886,6 @@ static struct ahash_engine_alg algs_sha2
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SM3_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 3,
- .cra_module = THIS_MODULE,
- }
- },
+++ /dev/null
-From 52de0270ed6453727936b5a793dc367d75280e84 Mon Sep 17 00:00:00 2001
-From: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Date: Wed, 15 Nov 2023 01:12:13 +0800
-Subject: [PATCH 009/116] crypto: starfive - Update driver dependencies
-
-Change AMBA_PL08X to required dependency as the hash ops depends on it
-for data transfer.
-
-Signed-off-by: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
----
- drivers/crypto/starfive/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/crypto/starfive/Kconfig
-+++ b/drivers/crypto/starfive/Kconfig
-@@ -4,7 +4,7 @@
-
- config CRYPTO_DEV_JH7110
- tristate "StarFive JH7110 cryptographic engine driver"
-- depends on SOC_STARFIVE || AMBA_PL08X || COMPILE_TEST
-+ depends on (SOC_STARFIVE && AMBA_PL08X) || COMPILE_TEST
- depends on HAS_DMA
- select CRYPTO_ENGINE
- select CRYPTO_HMAC
+++ /dev/null
-From 68a1bbb99455fd5ea80b7e21ec726f369abc9572 Mon Sep 17 00:00:00 2001
-From: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Date: Wed, 15 Nov 2023 01:12:14 +0800
-Subject: [PATCH 010/116] crypto: starfive - RSA poll csr for done status
-
-Hardware could not clear irq status without resetting the entire module.
-Driver receives irq immediately when mask bit is cleared causing
-intermittent errors in RSA calculations. Switch to use csr polling for
-done status instead.
-
-Signed-off-by: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
----
- drivers/crypto/starfive/jh7110-cryp.c | 8 -----
- drivers/crypto/starfive/jh7110-cryp.h | 10 +++++-
- drivers/crypto/starfive/jh7110-rsa.c | 49 +++++++--------------------
- 3 files changed, 22 insertions(+), 45 deletions(-)
-
---- a/drivers/crypto/starfive/jh7110-cryp.c
-+++ b/drivers/crypto/starfive/jh7110-cryp.c
-@@ -109,12 +109,6 @@ static irqreturn_t starfive_cryp_irq(int
- tasklet_schedule(&cryp->hash_done);
- }
-
-- if (status & STARFIVE_IE_FLAG_PKA_DONE) {
-- mask |= STARFIVE_IE_MASK_PKA_DONE;
-- writel(mask, cryp->base + STARFIVE_IE_MASK_OFFSET);
-- complete(&cryp->pka_done);
-- }
--
- return IRQ_HANDLED;
- }
-
-@@ -159,8 +153,6 @@ static int starfive_cryp_probe(struct pl
- return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst),
- "Error getting hardware reset line\n");
-
-- init_completion(&cryp->pka_done);
--
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
---- a/drivers/crypto/starfive/jh7110-cryp.h
-+++ b/drivers/crypto/starfive/jh7110-cryp.h
-@@ -126,6 +126,15 @@ union starfive_pka_cacr {
- };
- };
-
-+union starfive_pka_casr {
-+ u32 v;
-+ struct {
-+#define STARFIVE_PKA_DONE BIT(0)
-+ u32 done :1;
-+ u32 rsvd_0 :31;
-+ };
-+};
-+
- struct starfive_rsa_key {
- u8 *n;
- u8 *e;
-@@ -184,7 +193,6 @@ struct starfive_cryp_dev {
- struct crypto_engine *engine;
- struct tasklet_struct aes_done;
- struct tasklet_struct hash_done;
-- struct completion pka_done;
- size_t assoclen;
- size_t total_in;
- size_t total_out;
---- a/drivers/crypto/starfive/jh7110-rsa.c
-+++ b/drivers/crypto/starfive/jh7110-rsa.c
-@@ -6,13 +6,7 @@
- */
-
- #include <linux/crypto.h>
--#include <linux/delay.h>
--#include <linux/device.h>
--#include <linux/dma-direct.h>
--#include <linux/interrupt.h>
- #include <linux/iopoll.h>
--#include <linux/io.h>
--#include <linux/mod_devicetable.h>
- #include <crypto/akcipher.h>
- #include <crypto/algapi.h>
- #include <crypto/internal/akcipher.h>
-@@ -28,13 +22,13 @@
- #define STARFIVE_PKA_CAER_OFFSET (STARFIVE_PKA_REGS_OFFSET + 0x108)
- #define STARFIVE_PKA_CANR_OFFSET (STARFIVE_PKA_REGS_OFFSET + 0x208)
-
--// R^2 mod N and N0'
-+/* R ^ 2 mod N and N0' */
- #define CRYPTO_CMD_PRE 0x0
--// A * R mod N ==> A
-+/* A * R mod N ==> A */
- #define CRYPTO_CMD_ARN 0x5
--// A * E * R mod N ==> A
-+/* A * E * R mod N ==> A */
- #define CRYPTO_CMD_AERN 0x6
--// A * A * R mod N ==> A
-+/* A * A * R mod N ==> A */
- #define CRYPTO_CMD_AARN 0x7
-
- #define STARFIVE_RSA_RESET 0x2
-@@ -42,21 +36,10 @@
- static inline int starfive_pka_wait_done(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
-+ u32 status;
-
-- return wait_for_completion_timeout(&cryp->pka_done,
-- usecs_to_jiffies(100000));
--}
--
--static inline void starfive_pka_irq_mask_clear(struct starfive_cryp_ctx *ctx)
--{
-- struct starfive_cryp_dev *cryp = ctx->cryp;
-- u32 stat;
--
-- stat = readl(cryp->base + STARFIVE_IE_MASK_OFFSET);
-- stat &= ~STARFIVE_IE_MASK_PKA_DONE;
-- writel(stat, cryp->base + STARFIVE_IE_MASK_OFFSET);
--
-- reinit_completion(&cryp->pka_done);
-+ return readl_relaxed_poll_timeout(cryp->base + STARFIVE_PKA_CASR_OFFSET, status,
-+ status & STARFIVE_PKA_DONE, 10, 100000);
- }
-
- static void starfive_rsa_free_key(struct starfive_rsa_key *key)
-@@ -113,10 +96,9 @@ static int starfive_rsa_montgomery_form(
- rctx->csr.pka.not_r2 = 1;
- rctx->csr.pka.ie = 1;
-
-- starfive_pka_irq_mask_clear(ctx);
- writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET);
-
-- if (!starfive_pka_wait_done(ctx))
-+ if (starfive_pka_wait_done(ctx))
- return -ETIMEDOUT;
-
- for (loop = 0; loop <= opsize; loop++)
-@@ -135,10 +117,9 @@ static int starfive_rsa_montgomery_form(
- rctx->csr.pka.start = 1;
- rctx->csr.pka.ie = 1;
-
-- starfive_pka_irq_mask_clear(ctx);
- writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET);
-
-- if (!starfive_pka_wait_done(ctx))
-+ if (starfive_pka_wait_done(ctx))
- return -ETIMEDOUT;
- } else {
- rctx->csr.pka.v = 0;
-@@ -150,10 +131,9 @@ static int starfive_rsa_montgomery_form(
- rctx->csr.pka.pre_expf = 1;
- rctx->csr.pka.ie = 1;
-
-- starfive_pka_irq_mask_clear(ctx);
- writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET);
-
-- if (!starfive_pka_wait_done(ctx))
-+ if (starfive_pka_wait_done(ctx))
- return -ETIMEDOUT;
-
- for (loop = 0; loop <= count; loop++)
-@@ -171,10 +151,9 @@ static int starfive_rsa_montgomery_form(
- rctx->csr.pka.start = 1;
- rctx->csr.pka.ie = 1;
-
-- starfive_pka_irq_mask_clear(ctx);
- writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET);
-
-- if (!starfive_pka_wait_done(ctx))
-+ if (starfive_pka_wait_done(ctx))
- return -ETIMEDOUT;
- }
-
-@@ -225,11 +204,10 @@ static int starfive_rsa_cpu_start(struct
- rctx->csr.pka.start = 1;
- rctx->csr.pka.ie = 1;
-
-- starfive_pka_irq_mask_clear(ctx);
- writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET);
-
- ret = -ETIMEDOUT;
-- if (!starfive_pka_wait_done(ctx))
-+ if (starfive_pka_wait_done(ctx))
- goto rsa_err;
-
- if (mlen) {
-@@ -241,10 +219,9 @@ static int starfive_rsa_cpu_start(struct
- rctx->csr.pka.start = 1;
- rctx->csr.pka.ie = 1;
-
-- starfive_pka_irq_mask_clear(ctx);
- writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET);
-
-- if (!starfive_pka_wait_done(ctx))
-+ if (starfive_pka_wait_done(ctx))
- goto rsa_err;
- }
- }
+++ /dev/null
-From eea9f2c55cf944bbd5cdd43eb655416a867846af Mon Sep 17 00:00:00 2001
-From: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Date: Mon, 20 Nov 2023 11:12:42 +0800
-Subject: [PATCH 011/116] crypto: starfive - Pad adata with zeroes
-
-Aad requires padding with zeroes up to 15 bytes in some cases. This
-patch increases the allocated buffer size for aad and prevents the
-driver accessing uninitialized memory region.
-
-v1->v2: Specify reason for alloc size change in descriptions.
-
-Signed-off-by: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
----
- drivers/crypto/starfive/jh7110-aes.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/drivers/crypto/starfive/jh7110-aes.c
-+++ b/drivers/crypto/starfive/jh7110-aes.c
-@@ -500,7 +500,7 @@ static int starfive_aes_prepare_req(stru
- scatterwalk_start(&cryp->out_walk, rctx->out_sg);
-
- if (cryp->assoclen) {
-- rctx->adata = kzalloc(ALIGN(cryp->assoclen, AES_BLOCK_SIZE), GFP_KERNEL);
-+ rctx->adata = kzalloc(cryp->assoclen + AES_BLOCK_SIZE, GFP_KERNEL);
- if (!rctx->adata)
- return dev_err_probe(cryp->dev, -ENOMEM,
- "Failed to alloc memory for adata");
-@@ -569,7 +569,7 @@ static int starfive_aes_aead_do_one_req(
- struct starfive_cryp_ctx *ctx =
- crypto_aead_ctx(crypto_aead_reqtfm(req));
- struct starfive_cryp_dev *cryp = ctx->cryp;
-- struct starfive_cryp_request_ctx *rctx = ctx->rctx;
-+ struct starfive_cryp_request_ctx *rctx;
- u32 block[AES_BLOCK_32];
- u32 stat;
- int err;
-@@ -579,6 +579,8 @@ static int starfive_aes_aead_do_one_req(
- if (err)
- return err;
-
-+ rctx = ctx->rctx;
-+
- if (!cryp->assoclen)
- goto write_text;
-
+++ /dev/null
-From 922b213ad22f93fb2788ce119084622ab3d25bf8 Mon Sep 17 00:00:00 2001
-From: Herbert Xu <herbert@gondor.apana.org.au>
-Date: Thu, 30 Nov 2023 18:12:55 +0800
-Subject: [PATCH 012/116] crypto: starfive - Remove cfb and ofb
-
-Remove the unused CFB/OFB implementation.
-
-Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
----
- drivers/crypto/starfive/jh7110-aes.c | 71 +--------------------------
- drivers/crypto/starfive/jh7110-cryp.h | 2 -
- 2 files changed, 1 insertion(+), 72 deletions(-)
-
---- a/drivers/crypto/starfive/jh7110-aes.c
-+++ b/drivers/crypto/starfive/jh7110-aes.c
-@@ -262,12 +262,7 @@ static int starfive_aes_hw_init(struct s
- rctx->csr.aes.mode = hw_mode;
- rctx->csr.aes.cmode = !is_encrypt(cryp);
- rctx->csr.aes.ie = 1;
--
-- if (hw_mode == STARFIVE_AES_MODE_CFB ||
-- hw_mode == STARFIVE_AES_MODE_OFB)
-- rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_128;
-- else
-- rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1;
-+ rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1;
-
- if (cryp->side_chan) {
- rctx->csr.aes.delay_aes = 1;
-@@ -294,8 +289,6 @@ static int starfive_aes_hw_init(struct s
- starfive_aes_ccm_init(ctx);
- starfive_aes_aead_hw_start(ctx, hw_mode);
- break;
-- case STARFIVE_AES_MODE_OFB:
-- case STARFIVE_AES_MODE_CFB:
- case STARFIVE_AES_MODE_CBC:
- case STARFIVE_AES_MODE_CTR:
- starfive_aes_write_iv(ctx, (void *)cryp->req.sreq->iv);
-@@ -785,26 +778,6 @@ static int starfive_aes_cbc_decrypt(stru
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CBC);
- }
-
--static int starfive_aes_cfb_encrypt(struct skcipher_request *req)
--{
-- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB | FLG_ENCRYPT);
--}
--
--static int starfive_aes_cfb_decrypt(struct skcipher_request *req)
--{
-- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB);
--}
--
--static int starfive_aes_ofb_encrypt(struct skcipher_request *req)
--{
-- return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB | FLG_ENCRYPT);
--}
--
--static int starfive_aes_ofb_decrypt(struct skcipher_request *req)
--{
-- return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB);
--}
--
- static int starfive_aes_ctr_encrypt(struct skcipher_request *req)
- {
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CTR | FLG_ENCRYPT);
-@@ -903,48 +876,6 @@ static struct skcipher_engine_alg skciph
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
-- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 0xf,
-- .cra_module = THIS_MODULE,
-- },
-- .op = {
-- .do_one_request = starfive_aes_do_one_req,
-- },
--}, {
-- .base.init = starfive_aes_init_tfm,
-- .base.setkey = starfive_aes_setkey,
-- .base.encrypt = starfive_aes_cfb_encrypt,
-- .base.decrypt = starfive_aes_cfb_decrypt,
-- .base.min_keysize = AES_MIN_KEY_SIZE,
-- .base.max_keysize = AES_MAX_KEY_SIZE,
-- .base.ivsize = AES_BLOCK_SIZE,
-- .base.base = {
-- .cra_name = "cfb(aes)",
-- .cra_driver_name = "starfive-cfb-aes",
-- .cra_priority = 200,
-- .cra_flags = CRYPTO_ALG_ASYNC,
-- .cra_blocksize = 1,
-- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
-- .cra_alignmask = 0xf,
-- .cra_module = THIS_MODULE,
-- },
-- .op = {
-- .do_one_request = starfive_aes_do_one_req,
-- },
--}, {
-- .base.init = starfive_aes_init_tfm,
-- .base.setkey = starfive_aes_setkey,
-- .base.encrypt = starfive_aes_ofb_encrypt,
-- .base.decrypt = starfive_aes_ofb_decrypt,
-- .base.min_keysize = AES_MIN_KEY_SIZE,
-- .base.max_keysize = AES_MAX_KEY_SIZE,
-- .base.ivsize = AES_BLOCK_SIZE,
-- .base.base = {
-- .cra_name = "ofb(aes)",
-- .cra_driver_name = "starfive-ofb-aes",
-- .cra_priority = 200,
-- .cra_flags = CRYPTO_ALG_ASYNC,
-- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
---- a/drivers/crypto/starfive/jh7110-cryp.h
-+++ b/drivers/crypto/starfive/jh7110-cryp.h
-@@ -51,8 +51,6 @@ union starfive_aes_csr {
- u32 ccm_start :1;
- #define STARFIVE_AES_MODE_ECB 0x0
- #define STARFIVE_AES_MODE_CBC 0x1
--#define STARFIVE_AES_MODE_CFB 0x2
--#define STARFIVE_AES_MODE_OFB 0x3
- #define STARFIVE_AES_MODE_CTR 0x4
- #define STARFIVE_AES_MODE_CCM 0x5
- #define STARFIVE_AES_MODE_GCM 0x6
+++ /dev/null
-From 0dbdc763f10c5cfa968dffc290a7c060ee740172 Mon Sep 17 00:00:00 2001
-From: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Date: Mon, 4 Dec 2023 11:02:39 +0800
-Subject: [PATCH 013/116] crypto: starfive - Remove unneeded NULL checks
-
-NULL check before kfree_sensitive function is not needed.
-
-Signed-off-by: Jia Jie Ho <jiajie.ho@starfivetech.com>
-Reported-by: kernel test robot <lkp@intel.com>
-Closes: https://lore.kernel.org/oe-kbuild-all/202311301702.LxswfETY-lkp@intel.com/
-Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
----
- drivers/crypto/starfive/jh7110-rsa.c | 9 +++------
- 1 file changed, 3 insertions(+), 6 deletions(-)
-
---- a/drivers/crypto/starfive/jh7110-rsa.c
-+++ b/drivers/crypto/starfive/jh7110-rsa.c
-@@ -44,12 +44,9 @@ static inline int starfive_pka_wait_done
-
- static void starfive_rsa_free_key(struct starfive_rsa_key *key)
- {
-- if (key->d)
-- kfree_sensitive(key->d);
-- if (key->e)
-- kfree_sensitive(key->e);
-- if (key->n)
-- kfree_sensitive(key->n);
-+ kfree_sensitive(key->d);
-+ kfree_sensitive(key->e);
-+ kfree_sensitive(key->n);
- memset(key, 0, sizeof(*key));
- }
-
+++ /dev/null
-From 708695ebf1a779de9a1fd2f72f7938afa6c14ada Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:51 +0800
-Subject: [PATCH 014/116] dt-bindings: PCI: Add PLDA XpressRICH PCIe host
- common properties
-
-Add PLDA XpressRICH PCIe host common properties dt-binding doc.
-PolarFire PCIe host using PLDA IP. Move common properties from Microchip
-PolarFire PCIe host to PLDA files.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
-Reviewed-by: Rob Herring <robh@kernel.org>
-Tested-by: John Clark <inindev@gmail.com>
----
- .../bindings/pci/microchip,pcie-host.yaml | 55 +-------------
- .../pci/plda,xpressrich3-axi-common.yaml | 75 +++++++++++++++++++
- 2 files changed, 76 insertions(+), 54 deletions(-)
- create mode 100644 Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml
-
---- a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml
-+++ b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml
-@@ -10,21 +10,13 @@ maintainers:
- - Daire McNamara <daire.mcnamara@microchip.com>
-
- allOf:
-- - $ref: /schemas/pci/pci-bus.yaml#
-+ - $ref: plda,xpressrich3-axi-common.yaml#
- - $ref: /schemas/interrupt-controller/msi-controller.yaml#
-
- properties:
- compatible:
- const: microchip,pcie-host-1.0 # PolarFire
-
-- reg:
-- maxItems: 2
--
-- reg-names:
-- items:
-- - const: cfg
-- - const: apb
--
- clocks:
- description:
- Fabric Interface Controllers, FICs, are the interface between the FPGA
-@@ -52,18 +44,6 @@ properties:
- items:
- pattern: '^fic[0-3]$'
-
-- interrupts:
-- minItems: 1
-- items:
-- - description: PCIe host controller
-- - description: builtin MSI controller
--
-- interrupt-names:
-- minItems: 1
-- items:
-- - const: pcie
-- - const: msi
--
- ranges:
- maxItems: 1
-
-@@ -71,39 +51,6 @@ properties:
- minItems: 1
- maxItems: 6
-
-- msi-controller:
-- description: Identifies the node as an MSI controller.
--
-- msi-parent:
-- description: MSI controller the device is capable of using.
--
-- interrupt-controller:
-- type: object
-- properties:
-- '#address-cells':
-- const: 0
--
-- '#interrupt-cells':
-- const: 1
--
-- interrupt-controller: true
--
-- required:
-- - '#address-cells'
-- - '#interrupt-cells'
-- - interrupt-controller
--
-- additionalProperties: false
--
--required:
-- - reg
-- - reg-names
-- - "#interrupt-cells"
-- - interrupts
-- - interrupt-map-mask
-- - interrupt-map
-- - msi-controller
--
- unevaluatedProperties: false
-
- examples:
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml
-@@ -0,0 +1,75 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/pci/plda,xpressrich3-axi-common.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: PLDA XpressRICH PCIe host common properties
-+
-+maintainers:
-+ - Daire McNamara <daire.mcnamara@microchip.com>
-+ - Kevin Xie <kevin.xie@starfivetech.com>
-+
-+description:
-+ Generic PLDA XpressRICH PCIe host common properties.
-+
-+allOf:
-+ - $ref: /schemas/pci/pci-bus.yaml#
-+
-+properties:
-+ reg:
-+ maxItems: 2
-+
-+ reg-names:
-+ items:
-+ - const: cfg
-+ - const: apb
-+
-+ interrupts:
-+ minItems: 1
-+ items:
-+ - description: PCIe host controller
-+ - description: builtin MSI controller
-+
-+ interrupt-names:
-+ minItems: 1
-+ items:
-+ - const: pcie
-+ - const: msi
-+
-+ msi-controller:
-+ description: Identifies the node as an MSI controller.
-+
-+ msi-parent:
-+ description: MSI controller the device is capable of using.
-+
-+ interrupt-controller:
-+ type: object
-+ properties:
-+ '#address-cells':
-+ const: 0
-+
-+ '#interrupt-cells':
-+ const: 1
-+
-+ interrupt-controller: true
-+
-+ required:
-+ - '#address-cells'
-+ - '#interrupt-cells'
-+ - interrupt-controller
-+
-+ additionalProperties: false
-+
-+required:
-+ - reg
-+ - reg-names
-+ - interrupts
-+ - msi-controller
-+ - "#interrupt-cells"
-+ - interrupt-map-mask
-+ - interrupt-map
-+
-+additionalProperties: true
-+
-+...
+++ /dev/null
-From df67154aa92efdc774a8536ece6f431e7850aca2 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:52 +0800
-Subject: [PATCH 015/116] PCI: microchip: Move pcie-microchip-host.c to plda
- directory
-
-For Microchip Polarfire PCIe host is PLDA XpressRich IP, move to plda
-directory. Prepare for refactoring the codes.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- drivers/pci/controller/Kconfig | 9 +--------
- drivers/pci/controller/Makefile | 2 +-
- drivers/pci/controller/plda/Kconfig | 14 ++++++++++++++
- drivers/pci/controller/plda/Makefile | 2 ++
- .../controller/{ => plda}/pcie-microchip-host.c | 2 +-
- 5 files changed, 19 insertions(+), 10 deletions(-)
- create mode 100644 drivers/pci/controller/plda/Kconfig
- create mode 100644 drivers/pci/controller/plda/Makefile
- rename drivers/pci/controller/{ => plda}/pcie-microchip-host.c (99%)
-
---- a/drivers/pci/controller/Kconfig
-+++ b/drivers/pci/controller/Kconfig
-@@ -215,14 +215,6 @@ config PCIE_MT7621
- help
- This selects a driver for the MediaTek MT7621 PCIe Controller.
-
--config PCIE_MICROCHIP_HOST
-- tristate "Microchip AXI PCIe controller"
-- depends on PCI_MSI && OF
-- select PCI_HOST_COMMON
-- help
-- Say Y here if you want kernel to support the Microchip AXI PCIe
-- Host Bridge driver.
--
- config PCI_HYPERV_INTERFACE
- tristate "Microsoft Hyper-V PCI Interface"
- depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI
-@@ -345,4 +337,5 @@ config PCIE_XILINX_CPM
- source "drivers/pci/controller/cadence/Kconfig"
- source "drivers/pci/controller/dwc/Kconfig"
- source "drivers/pci/controller/mobiveil/Kconfig"
-+source "drivers/pci/controller/plda/Kconfig"
- endmenu
---- a/drivers/pci/controller/Makefile
-+++ b/drivers/pci/controller/Makefile
-@@ -32,7 +32,6 @@ obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-r
- obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
- obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
- obj-$(CONFIG_PCIE_MEDIATEK_GEN3) += pcie-mediatek-gen3.o
--obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
- obj-$(CONFIG_VMD) += vmd.o
- obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
- obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o
-@@ -43,6 +42,7 @@ obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621
- # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
- obj-y += dwc/
- obj-y += mobiveil/
-+obj-y += plda/
-
-
- # The following drivers are for devices that use the generic ACPI
---- /dev/null
-+++ b/drivers/pci/controller/plda/Kconfig
-@@ -0,0 +1,14 @@
-+# SPDX-License-Identifier: GPL-2.0
-+
-+menu "PLDA-based PCIe controllers"
-+ depends on PCI
-+
-+config PCIE_MICROCHIP_HOST
-+ tristate "Microchip AXI PCIe controller"
-+ depends on PCI_MSI && OF
-+ select PCI_HOST_COMMON
-+ help
-+ Say Y here if you want kernel to support the Microchip AXI PCIe
-+ Host Bridge driver.
-+
-+endmenu
---- /dev/null
-+++ b/drivers/pci/controller/plda/Makefile
-@@ -0,0 +1,2 @@
-+# SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
---- a/drivers/pci/controller/pcie-microchip-host.c
-+++ /dev/null
-@@ -1,1216 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/*
-- * Microchip AXI PCIe Bridge host controller driver
-- *
-- * Copyright (c) 2018 - 2020 Microchip Corporation. All rights reserved.
-- *
-- * Author: Daire McNamara <daire.mcnamara@microchip.com>
-- */
--
--#include <linux/bitfield.h>
--#include <linux/clk.h>
--#include <linux/irqchip/chained_irq.h>
--#include <linux/irqdomain.h>
--#include <linux/module.h>
--#include <linux/msi.h>
--#include <linux/of_address.h>
--#include <linux/of_pci.h>
--#include <linux/pci-ecam.h>
--#include <linux/platform_device.h>
--
--#include "../pci.h"
--
--/* Number of MSI IRQs */
--#define MC_MAX_NUM_MSI_IRQS 32
--
--/* PCIe Bridge Phy and Controller Phy offsets */
--#define MC_PCIE1_BRIDGE_ADDR 0x00008000u
--#define MC_PCIE1_CTRL_ADDR 0x0000a000u
--
--#define MC_PCIE_BRIDGE_ADDR (MC_PCIE1_BRIDGE_ADDR)
--#define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR)
--
--/* PCIe Bridge Phy Regs */
--#define PCIE_PCI_IRQ_DW0 0xa8
--#define MSIX_CAP_MASK BIT(31)
--#define NUM_MSI_MSGS_MASK GENMASK(6, 4)
--#define NUM_MSI_MSGS_SHIFT 4
--
--#define IMASK_LOCAL 0x180
--#define DMA_END_ENGINE_0_MASK 0x00000000u
--#define DMA_END_ENGINE_0_SHIFT 0
--#define DMA_END_ENGINE_1_MASK 0x00000000u
--#define DMA_END_ENGINE_1_SHIFT 1
--#define DMA_ERROR_ENGINE_0_MASK 0x00000100u
--#define DMA_ERROR_ENGINE_0_SHIFT 8
--#define DMA_ERROR_ENGINE_1_MASK 0x00000200u
--#define DMA_ERROR_ENGINE_1_SHIFT 9
--#define A_ATR_EVT_POST_ERR_MASK 0x00010000u
--#define A_ATR_EVT_POST_ERR_SHIFT 16
--#define A_ATR_EVT_FETCH_ERR_MASK 0x00020000u
--#define A_ATR_EVT_FETCH_ERR_SHIFT 17
--#define A_ATR_EVT_DISCARD_ERR_MASK 0x00040000u
--#define A_ATR_EVT_DISCARD_ERR_SHIFT 18
--#define A_ATR_EVT_DOORBELL_MASK 0x00000000u
--#define A_ATR_EVT_DOORBELL_SHIFT 19
--#define P_ATR_EVT_POST_ERR_MASK 0x00100000u
--#define P_ATR_EVT_POST_ERR_SHIFT 20
--#define P_ATR_EVT_FETCH_ERR_MASK 0x00200000u
--#define P_ATR_EVT_FETCH_ERR_SHIFT 21
--#define P_ATR_EVT_DISCARD_ERR_MASK 0x00400000u
--#define P_ATR_EVT_DISCARD_ERR_SHIFT 22
--#define P_ATR_EVT_DOORBELL_MASK 0x00000000u
--#define P_ATR_EVT_DOORBELL_SHIFT 23
--#define PM_MSI_INT_INTA_MASK 0x01000000u
--#define PM_MSI_INT_INTA_SHIFT 24
--#define PM_MSI_INT_INTB_MASK 0x02000000u
--#define PM_MSI_INT_INTB_SHIFT 25
--#define PM_MSI_INT_INTC_MASK 0x04000000u
--#define PM_MSI_INT_INTC_SHIFT 26
--#define PM_MSI_INT_INTD_MASK 0x08000000u
--#define PM_MSI_INT_INTD_SHIFT 27
--#define PM_MSI_INT_INTX_MASK 0x0f000000u
--#define PM_MSI_INT_INTX_SHIFT 24
--#define PM_MSI_INT_MSI_MASK 0x10000000u
--#define PM_MSI_INT_MSI_SHIFT 28
--#define PM_MSI_INT_AER_EVT_MASK 0x20000000u
--#define PM_MSI_INT_AER_EVT_SHIFT 29
--#define PM_MSI_INT_EVENTS_MASK 0x40000000u
--#define PM_MSI_INT_EVENTS_SHIFT 30
--#define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
--#define PM_MSI_INT_SYS_ERR_SHIFT 31
--#define NUM_LOCAL_EVENTS 15
--#define ISTATUS_LOCAL 0x184
--#define IMASK_HOST 0x188
--#define ISTATUS_HOST 0x18c
--#define IMSI_ADDR 0x190
--#define ISTATUS_MSI 0x194
--
--/* PCIe Master table init defines */
--#define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u
--#define ATR0_PCIE_ATR_SIZE 0x25
--#define ATR0_PCIE_ATR_SIZE_SHIFT 1
--#define ATR0_PCIE_WIN0_SRC_ADDR 0x604u
--#define ATR0_PCIE_WIN0_TRSL_ADDR_LSB 0x608u
--#define ATR0_PCIE_WIN0_TRSL_ADDR_UDW 0x60cu
--#define ATR0_PCIE_WIN0_TRSL_PARAM 0x610u
--
--/* PCIe AXI slave table init defines */
--#define ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u
--#define ATR_SIZE_SHIFT 1
--#define ATR_IMPL_ENABLE 1
--#define ATR0_AXI4_SLV0_SRC_ADDR 0x804u
--#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u
--#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu
--#define ATR0_AXI4_SLV0_TRSL_PARAM 0x810u
--#define PCIE_TX_RX_INTERFACE 0x00000000u
--#define PCIE_CONFIG_INTERFACE 0x00000001u
--
--#define ATR_ENTRY_SIZE 32
--
--/* PCIe Controller Phy Regs */
--#define SEC_ERROR_EVENT_CNT 0x20
--#define DED_ERROR_EVENT_CNT 0x24
--#define SEC_ERROR_INT 0x28
--#define SEC_ERROR_INT_TX_RAM_SEC_ERR_INT GENMASK(3, 0)
--#define SEC_ERROR_INT_RX_RAM_SEC_ERR_INT GENMASK(7, 4)
--#define SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT GENMASK(11, 8)
--#define SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT GENMASK(15, 12)
--#define SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT GENMASK(15, 0)
--#define NUM_SEC_ERROR_INTS (4)
--#define SEC_ERROR_INT_MASK 0x2c
--#define DED_ERROR_INT 0x30
--#define DED_ERROR_INT_TX_RAM_DED_ERR_INT GENMASK(3, 0)
--#define DED_ERROR_INT_RX_RAM_DED_ERR_INT GENMASK(7, 4)
--#define DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT GENMASK(11, 8)
--#define DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT GENMASK(15, 12)
--#define DED_ERROR_INT_ALL_RAM_DED_ERR_INT GENMASK(15, 0)
--#define NUM_DED_ERROR_INTS (4)
--#define DED_ERROR_INT_MASK 0x34
--#define ECC_CONTROL 0x38
--#define ECC_CONTROL_TX_RAM_INJ_ERROR_0 BIT(0)
--#define ECC_CONTROL_TX_RAM_INJ_ERROR_1 BIT(1)
--#define ECC_CONTROL_TX_RAM_INJ_ERROR_2 BIT(2)
--#define ECC_CONTROL_TX_RAM_INJ_ERROR_3 BIT(3)
--#define ECC_CONTROL_RX_RAM_INJ_ERROR_0 BIT(4)
--#define ECC_CONTROL_RX_RAM_INJ_ERROR_1 BIT(5)
--#define ECC_CONTROL_RX_RAM_INJ_ERROR_2 BIT(6)
--#define ECC_CONTROL_RX_RAM_INJ_ERROR_3 BIT(7)
--#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_0 BIT(8)
--#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_1 BIT(9)
--#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_2 BIT(10)
--#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_3 BIT(11)
--#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_0 BIT(12)
--#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_1 BIT(13)
--#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_2 BIT(14)
--#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_3 BIT(15)
--#define ECC_CONTROL_TX_RAM_ECC_BYPASS BIT(24)
--#define ECC_CONTROL_RX_RAM_ECC_BYPASS BIT(25)
--#define ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS BIT(26)
--#define ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS BIT(27)
--#define PCIE_EVENT_INT 0x14c
--#define PCIE_EVENT_INT_L2_EXIT_INT BIT(0)
--#define PCIE_EVENT_INT_HOTRST_EXIT_INT BIT(1)
--#define PCIE_EVENT_INT_DLUP_EXIT_INT BIT(2)
--#define PCIE_EVENT_INT_MASK GENMASK(2, 0)
--#define PCIE_EVENT_INT_L2_EXIT_INT_MASK BIT(16)
--#define PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK BIT(17)
--#define PCIE_EVENT_INT_DLUP_EXIT_INT_MASK BIT(18)
--#define PCIE_EVENT_INT_ENB_MASK GENMASK(18, 16)
--#define PCIE_EVENT_INT_ENB_SHIFT 16
--#define NUM_PCIE_EVENTS (3)
--
--/* PCIe Config space MSI capability structure */
--#define MC_MSI_CAP_CTRL_OFFSET 0xe0u
--
--/* Events */
--#define EVENT_PCIE_L2_EXIT 0
--#define EVENT_PCIE_HOTRST_EXIT 1
--#define EVENT_PCIE_DLUP_EXIT 2
--#define EVENT_SEC_TX_RAM_SEC_ERR 3
--#define EVENT_SEC_RX_RAM_SEC_ERR 4
--#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 5
--#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 6
--#define EVENT_DED_TX_RAM_DED_ERR 7
--#define EVENT_DED_RX_RAM_DED_ERR 8
--#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 9
--#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 10
--#define EVENT_LOCAL_DMA_END_ENGINE_0 11
--#define EVENT_LOCAL_DMA_END_ENGINE_1 12
--#define EVENT_LOCAL_DMA_ERROR_ENGINE_0 13
--#define EVENT_LOCAL_DMA_ERROR_ENGINE_1 14
--#define EVENT_LOCAL_A_ATR_EVT_POST_ERR 15
--#define EVENT_LOCAL_A_ATR_EVT_FETCH_ERR 16
--#define EVENT_LOCAL_A_ATR_EVT_DISCARD_ERR 17
--#define EVENT_LOCAL_A_ATR_EVT_DOORBELL 18
--#define EVENT_LOCAL_P_ATR_EVT_POST_ERR 19
--#define EVENT_LOCAL_P_ATR_EVT_FETCH_ERR 20
--#define EVENT_LOCAL_P_ATR_EVT_DISCARD_ERR 21
--#define EVENT_LOCAL_P_ATR_EVT_DOORBELL 22
--#define EVENT_LOCAL_PM_MSI_INT_INTX 23
--#define EVENT_LOCAL_PM_MSI_INT_MSI 24
--#define EVENT_LOCAL_PM_MSI_INT_AER_EVT 25
--#define EVENT_LOCAL_PM_MSI_INT_EVENTS 26
--#define EVENT_LOCAL_PM_MSI_INT_SYS_ERR 27
--#define NUM_EVENTS 28
--
--#define PCIE_EVENT_CAUSE(x, s) \
-- [EVENT_PCIE_ ## x] = { __stringify(x), s }
--
--#define SEC_ERROR_CAUSE(x, s) \
-- [EVENT_SEC_ ## x] = { __stringify(x), s }
--
--#define DED_ERROR_CAUSE(x, s) \
-- [EVENT_DED_ ## x] = { __stringify(x), s }
--
--#define LOCAL_EVENT_CAUSE(x, s) \
-- [EVENT_LOCAL_ ## x] = { __stringify(x), s }
--
--#define PCIE_EVENT(x) \
-- .base = MC_PCIE_CTRL_ADDR, \
-- .offset = PCIE_EVENT_INT, \
-- .mask_offset = PCIE_EVENT_INT, \
-- .mask_high = 1, \
-- .mask = PCIE_EVENT_INT_ ## x ## _INT, \
-- .enb_mask = PCIE_EVENT_INT_ENB_MASK
--
--#define SEC_EVENT(x) \
-- .base = MC_PCIE_CTRL_ADDR, \
-- .offset = SEC_ERROR_INT, \
-- .mask_offset = SEC_ERROR_INT_MASK, \
-- .mask = SEC_ERROR_INT_ ## x ## _INT, \
-- .mask_high = 1, \
-- .enb_mask = 0
--
--#define DED_EVENT(x) \
-- .base = MC_PCIE_CTRL_ADDR, \
-- .offset = DED_ERROR_INT, \
-- .mask_offset = DED_ERROR_INT_MASK, \
-- .mask_high = 1, \
-- .mask = DED_ERROR_INT_ ## x ## _INT, \
-- .enb_mask = 0
--
--#define LOCAL_EVENT(x) \
-- .base = MC_PCIE_BRIDGE_ADDR, \
-- .offset = ISTATUS_LOCAL, \
-- .mask_offset = IMASK_LOCAL, \
-- .mask_high = 0, \
-- .mask = x ## _MASK, \
-- .enb_mask = 0
--
--#define PCIE_EVENT_TO_EVENT_MAP(x) \
-- { PCIE_EVENT_INT_ ## x ## _INT, EVENT_PCIE_ ## x }
--
--#define SEC_ERROR_TO_EVENT_MAP(x) \
-- { SEC_ERROR_INT_ ## x ## _INT, EVENT_SEC_ ## x }
--
--#define DED_ERROR_TO_EVENT_MAP(x) \
-- { DED_ERROR_INT_ ## x ## _INT, EVENT_DED_ ## x }
--
--#define LOCAL_STATUS_TO_EVENT_MAP(x) \
-- { x ## _MASK, EVENT_LOCAL_ ## x }
--
--struct event_map {
-- u32 reg_mask;
-- u32 event_bit;
--};
--
--struct mc_msi {
-- struct mutex lock; /* Protect used bitmap */
-- struct irq_domain *msi_domain;
-- struct irq_domain *dev_domain;
-- u32 num_vectors;
-- u64 vector_phy;
-- DECLARE_BITMAP(used, MC_MAX_NUM_MSI_IRQS);
--};
--
--struct mc_pcie {
-- void __iomem *axi_base_addr;
-- struct device *dev;
-- struct irq_domain *intx_domain;
-- struct irq_domain *event_domain;
-- raw_spinlock_t lock;
-- struct mc_msi msi;
--};
--
--struct cause {
-- const char *sym;
-- const char *str;
--};
--
--static const struct cause event_cause[NUM_EVENTS] = {
-- PCIE_EVENT_CAUSE(L2_EXIT, "L2 exit event"),
-- PCIE_EVENT_CAUSE(HOTRST_EXIT, "Hot reset exit event"),
-- PCIE_EVENT_CAUSE(DLUP_EXIT, "DLUP exit event"),
-- SEC_ERROR_CAUSE(TX_RAM_SEC_ERR, "sec error in tx buffer"),
-- SEC_ERROR_CAUSE(RX_RAM_SEC_ERR, "sec error in rx buffer"),
-- SEC_ERROR_CAUSE(PCIE2AXI_RAM_SEC_ERR, "sec error in pcie2axi buffer"),
-- SEC_ERROR_CAUSE(AXI2PCIE_RAM_SEC_ERR, "sec error in axi2pcie buffer"),
-- DED_ERROR_CAUSE(TX_RAM_DED_ERR, "ded error in tx buffer"),
-- DED_ERROR_CAUSE(RX_RAM_DED_ERR, "ded error in rx buffer"),
-- DED_ERROR_CAUSE(PCIE2AXI_RAM_DED_ERR, "ded error in pcie2axi buffer"),
-- DED_ERROR_CAUSE(AXI2PCIE_RAM_DED_ERR, "ded error in axi2pcie buffer"),
-- LOCAL_EVENT_CAUSE(DMA_ERROR_ENGINE_0, "dma engine 0 error"),
-- LOCAL_EVENT_CAUSE(DMA_ERROR_ENGINE_1, "dma engine 1 error"),
-- LOCAL_EVENT_CAUSE(A_ATR_EVT_POST_ERR, "axi write request error"),
-- LOCAL_EVENT_CAUSE(A_ATR_EVT_FETCH_ERR, "axi read request error"),
-- LOCAL_EVENT_CAUSE(A_ATR_EVT_DISCARD_ERR, "axi read timeout"),
-- LOCAL_EVENT_CAUSE(P_ATR_EVT_POST_ERR, "pcie write request error"),
-- LOCAL_EVENT_CAUSE(P_ATR_EVT_FETCH_ERR, "pcie read request error"),
-- LOCAL_EVENT_CAUSE(P_ATR_EVT_DISCARD_ERR, "pcie read timeout"),
-- LOCAL_EVENT_CAUSE(PM_MSI_INT_AER_EVT, "aer event"),
-- LOCAL_EVENT_CAUSE(PM_MSI_INT_EVENTS, "pm/ltr/hotplug event"),
-- LOCAL_EVENT_CAUSE(PM_MSI_INT_SYS_ERR, "system error"),
--};
--
--static struct event_map pcie_event_to_event[] = {
-- PCIE_EVENT_TO_EVENT_MAP(L2_EXIT),
-- PCIE_EVENT_TO_EVENT_MAP(HOTRST_EXIT),
-- PCIE_EVENT_TO_EVENT_MAP(DLUP_EXIT),
--};
--
--static struct event_map sec_error_to_event[] = {
-- SEC_ERROR_TO_EVENT_MAP(TX_RAM_SEC_ERR),
-- SEC_ERROR_TO_EVENT_MAP(RX_RAM_SEC_ERR),
-- SEC_ERROR_TO_EVENT_MAP(PCIE2AXI_RAM_SEC_ERR),
-- SEC_ERROR_TO_EVENT_MAP(AXI2PCIE_RAM_SEC_ERR),
--};
--
--static struct event_map ded_error_to_event[] = {
-- DED_ERROR_TO_EVENT_MAP(TX_RAM_DED_ERR),
-- DED_ERROR_TO_EVENT_MAP(RX_RAM_DED_ERR),
-- DED_ERROR_TO_EVENT_MAP(PCIE2AXI_RAM_DED_ERR),
-- DED_ERROR_TO_EVENT_MAP(AXI2PCIE_RAM_DED_ERR),
--};
--
--static struct event_map local_status_to_event[] = {
-- LOCAL_STATUS_TO_EVENT_MAP(DMA_END_ENGINE_0),
-- LOCAL_STATUS_TO_EVENT_MAP(DMA_END_ENGINE_1),
-- LOCAL_STATUS_TO_EVENT_MAP(DMA_ERROR_ENGINE_0),
-- LOCAL_STATUS_TO_EVENT_MAP(DMA_ERROR_ENGINE_1),
-- LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_POST_ERR),
-- LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_FETCH_ERR),
-- LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_DISCARD_ERR),
-- LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_DOORBELL),
-- LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_POST_ERR),
-- LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_FETCH_ERR),
-- LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_DISCARD_ERR),
-- LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_DOORBELL),
-- LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_INTX),
-- LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_MSI),
-- LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_AER_EVT),
-- LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_EVENTS),
-- LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_SYS_ERR),
--};
--
--static struct {
-- u32 base;
-- u32 offset;
-- u32 mask;
-- u32 shift;
-- u32 enb_mask;
-- u32 mask_high;
-- u32 mask_offset;
--} event_descs[] = {
-- { PCIE_EVENT(L2_EXIT) },
-- { PCIE_EVENT(HOTRST_EXIT) },
-- { PCIE_EVENT(DLUP_EXIT) },
-- { SEC_EVENT(TX_RAM_SEC_ERR) },
-- { SEC_EVENT(RX_RAM_SEC_ERR) },
-- { SEC_EVENT(PCIE2AXI_RAM_SEC_ERR) },
-- { SEC_EVENT(AXI2PCIE_RAM_SEC_ERR) },
-- { DED_EVENT(TX_RAM_DED_ERR) },
-- { DED_EVENT(RX_RAM_DED_ERR) },
-- { DED_EVENT(PCIE2AXI_RAM_DED_ERR) },
-- { DED_EVENT(AXI2PCIE_RAM_DED_ERR) },
-- { LOCAL_EVENT(DMA_END_ENGINE_0) },
-- { LOCAL_EVENT(DMA_END_ENGINE_1) },
-- { LOCAL_EVENT(DMA_ERROR_ENGINE_0) },
-- { LOCAL_EVENT(DMA_ERROR_ENGINE_1) },
-- { LOCAL_EVENT(A_ATR_EVT_POST_ERR) },
-- { LOCAL_EVENT(A_ATR_EVT_FETCH_ERR) },
-- { LOCAL_EVENT(A_ATR_EVT_DISCARD_ERR) },
-- { LOCAL_EVENT(A_ATR_EVT_DOORBELL) },
-- { LOCAL_EVENT(P_ATR_EVT_POST_ERR) },
-- { LOCAL_EVENT(P_ATR_EVT_FETCH_ERR) },
-- { LOCAL_EVENT(P_ATR_EVT_DISCARD_ERR) },
-- { LOCAL_EVENT(P_ATR_EVT_DOORBELL) },
-- { LOCAL_EVENT(PM_MSI_INT_INTX) },
-- { LOCAL_EVENT(PM_MSI_INT_MSI) },
-- { LOCAL_EVENT(PM_MSI_INT_AER_EVT) },
-- { LOCAL_EVENT(PM_MSI_INT_EVENTS) },
-- { LOCAL_EVENT(PM_MSI_INT_SYS_ERR) },
--};
--
--static char poss_clks[][5] = { "fic0", "fic1", "fic2", "fic3" };
--
--static struct mc_pcie *port;
--
--static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
--{
-- struct mc_msi *msi = &port->msi;
-- u16 reg;
-- u8 queue_size;
--
-- /* Fixup MSI enable flag */
-- reg = readw_relaxed(ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS);
-- reg |= PCI_MSI_FLAGS_ENABLE;
-- writew_relaxed(reg, ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS);
--
-- /* Fixup PCI MSI queue flags */
-- queue_size = FIELD_GET(PCI_MSI_FLAGS_QMASK, reg);
-- reg |= FIELD_PREP(PCI_MSI_FLAGS_QSIZE, queue_size);
-- writew_relaxed(reg, ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS);
--
-- /* Fixup MSI addr fields */
-- writel_relaxed(lower_32_bits(msi->vector_phy),
-- ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_LO);
-- writel_relaxed(upper_32_bits(msi->vector_phy),
-- ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
--}
--
--static void mc_handle_msi(struct irq_desc *desc)
--{
-- struct mc_pcie *port = irq_desc_get_handler_data(desc);
-- struct irq_chip *chip = irq_desc_get_chip(desc);
-- struct device *dev = port->dev;
-- struct mc_msi *msi = &port->msi;
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- unsigned long status;
-- u32 bit;
-- int ret;
--
-- chained_irq_enter(chip, desc);
--
-- status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-- if (status & PM_MSI_INT_MSI_MASK) {
-- writel_relaxed(status & PM_MSI_INT_MSI_MASK, bridge_base_addr + ISTATUS_LOCAL);
-- status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
-- for_each_set_bit(bit, &status, msi->num_vectors) {
-- ret = generic_handle_domain_irq(msi->dev_domain, bit);
-- if (ret)
-- dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
-- bit);
-- }
-- }
--
-- chained_irq_exit(chip, desc);
--}
--
--static void mc_msi_bottom_irq_ack(struct irq_data *data)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- u32 bitpos = data->hwirq;
--
-- writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
--}
--
--static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- phys_addr_t addr = port->msi.vector_phy;
--
-- msg->address_lo = lower_32_bits(addr);
-- msg->address_hi = upper_32_bits(addr);
-- msg->data = data->hwirq;
--
-- dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
-- (int)data->hwirq, msg->address_hi, msg->address_lo);
--}
--
--static int mc_msi_set_affinity(struct irq_data *irq_data,
-- const struct cpumask *mask, bool force)
--{
-- return -EINVAL;
--}
--
--static struct irq_chip mc_msi_bottom_irq_chip = {
-- .name = "Microchip MSI",
-- .irq_ack = mc_msi_bottom_irq_ack,
-- .irq_compose_msi_msg = mc_compose_msi_msg,
-- .irq_set_affinity = mc_msi_set_affinity,
--};
--
--static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
-- unsigned int nr_irqs, void *args)
--{
-- struct mc_pcie *port = domain->host_data;
-- struct mc_msi *msi = &port->msi;
-- unsigned long bit;
--
-- mutex_lock(&msi->lock);
-- bit = find_first_zero_bit(msi->used, msi->num_vectors);
-- if (bit >= msi->num_vectors) {
-- mutex_unlock(&msi->lock);
-- return -ENOSPC;
-- }
--
-- set_bit(bit, msi->used);
--
-- irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip,
-- domain->host_data, handle_edge_irq, NULL, NULL);
--
-- mutex_unlock(&msi->lock);
--
-- return 0;
--}
--
--static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
-- unsigned int nr_irqs)
--{
-- struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-- struct mc_pcie *port = irq_data_get_irq_chip_data(d);
-- struct mc_msi *msi = &port->msi;
--
-- mutex_lock(&msi->lock);
--
-- if (test_bit(d->hwirq, msi->used))
-- __clear_bit(d->hwirq, msi->used);
-- else
-- dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
--
-- mutex_unlock(&msi->lock);
--}
--
--static const struct irq_domain_ops msi_domain_ops = {
-- .alloc = mc_irq_msi_domain_alloc,
-- .free = mc_irq_msi_domain_free,
--};
--
--static struct irq_chip mc_msi_irq_chip = {
-- .name = "Microchip PCIe MSI",
-- .irq_ack = irq_chip_ack_parent,
-- .irq_mask = pci_msi_mask_irq,
-- .irq_unmask = pci_msi_unmask_irq,
--};
--
--static struct msi_domain_info mc_msi_domain_info = {
-- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-- MSI_FLAG_PCI_MSIX),
-- .chip = &mc_msi_irq_chip,
--};
--
--static int mc_allocate_msi_domains(struct mc_pcie *port)
--{
-- struct device *dev = port->dev;
-- struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
-- struct mc_msi *msi = &port->msi;
--
-- mutex_init(&port->msi.lock);
--
-- msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
-- &msi_domain_ops, port);
-- if (!msi->dev_domain) {
-- dev_err(dev, "failed to create IRQ domain\n");
-- return -ENOMEM;
-- }
--
-- msi->msi_domain = pci_msi_create_irq_domain(fwnode, &mc_msi_domain_info,
-- msi->dev_domain);
-- if (!msi->msi_domain) {
-- dev_err(dev, "failed to create MSI domain\n");
-- irq_domain_remove(msi->dev_domain);
-- return -ENOMEM;
-- }
--
-- return 0;
--}
--
--static void mc_handle_intx(struct irq_desc *desc)
--{
-- struct mc_pcie *port = irq_desc_get_handler_data(desc);
-- struct irq_chip *chip = irq_desc_get_chip(desc);
-- struct device *dev = port->dev;
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- unsigned long status;
-- u32 bit;
-- int ret;
--
-- chained_irq_enter(chip, desc);
--
-- status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-- if (status & PM_MSI_INT_INTX_MASK) {
-- status &= PM_MSI_INT_INTX_MASK;
-- status >>= PM_MSI_INT_INTX_SHIFT;
-- for_each_set_bit(bit, &status, PCI_NUM_INTX) {
-- ret = generic_handle_domain_irq(port->intx_domain, bit);
-- if (ret)
-- dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
-- bit);
-- }
-- }
--
-- chained_irq_exit(chip, desc);
--}
--
--static void mc_ack_intx_irq(struct irq_data *data)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
--
-- writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
--}
--
--static void mc_mask_intx_irq(struct irq_data *data)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- unsigned long flags;
-- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-- u32 val;
--
-- raw_spin_lock_irqsave(&port->lock, flags);
-- val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-- val &= ~mask;
-- writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-- raw_spin_unlock_irqrestore(&port->lock, flags);
--}
--
--static void mc_unmask_intx_irq(struct irq_data *data)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- unsigned long flags;
-- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-- u32 val;
--
-- raw_spin_lock_irqsave(&port->lock, flags);
-- val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-- val |= mask;
-- writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-- raw_spin_unlock_irqrestore(&port->lock, flags);
--}
--
--static struct irq_chip mc_intx_irq_chip = {
-- .name = "Microchip PCIe INTx",
-- .irq_ack = mc_ack_intx_irq,
-- .irq_mask = mc_mask_intx_irq,
-- .irq_unmask = mc_unmask_intx_irq,
--};
--
--static int mc_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-- irq_hw_number_t hwirq)
--{
-- irq_set_chip_and_handler(irq, &mc_intx_irq_chip, handle_level_irq);
-- irq_set_chip_data(irq, domain->host_data);
--
-- return 0;
--}
--
--static const struct irq_domain_ops intx_domain_ops = {
-- .map = mc_pcie_intx_map,
--};
--
--static inline u32 reg_to_event(u32 reg, struct event_map field)
--{
-- return (reg & field.reg_mask) ? BIT(field.event_bit) : 0;
--}
--
--static u32 pcie_events(struct mc_pcie *port)
--{
-- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-- u32 reg = readl_relaxed(ctrl_base_addr + PCIE_EVENT_INT);
-- u32 val = 0;
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(pcie_event_to_event); i++)
-- val |= reg_to_event(reg, pcie_event_to_event[i]);
--
-- return val;
--}
--
--static u32 sec_errors(struct mc_pcie *port)
--{
-- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-- u32 reg = readl_relaxed(ctrl_base_addr + SEC_ERROR_INT);
-- u32 val = 0;
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(sec_error_to_event); i++)
-- val |= reg_to_event(reg, sec_error_to_event[i]);
--
-- return val;
--}
--
--static u32 ded_errors(struct mc_pcie *port)
--{
-- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-- u32 reg = readl_relaxed(ctrl_base_addr + DED_ERROR_INT);
-- u32 val = 0;
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(ded_error_to_event); i++)
-- val |= reg_to_event(reg, ded_error_to_event[i]);
--
-- return val;
--}
--
--static u32 local_events(struct mc_pcie *port)
--{
-- void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- u32 reg = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-- u32 val = 0;
-- int i;
--
-- for (i = 0; i < ARRAY_SIZE(local_status_to_event); i++)
-- val |= reg_to_event(reg, local_status_to_event[i]);
--
-- return val;
--}
--
--static u32 get_events(struct mc_pcie *port)
--{
-- u32 events = 0;
--
-- events |= pcie_events(port);
-- events |= sec_errors(port);
-- events |= ded_errors(port);
-- events |= local_events(port);
--
-- return events;
--}
--
--static irqreturn_t mc_event_handler(int irq, void *dev_id)
--{
-- struct mc_pcie *port = dev_id;
-- struct device *dev = port->dev;
-- struct irq_data *data;
--
-- data = irq_domain_get_irq_data(port->event_domain, irq);
--
-- if (event_cause[data->hwirq].str)
-- dev_err_ratelimited(dev, "%s\n", event_cause[data->hwirq].str);
-- else
-- dev_err_ratelimited(dev, "bad event IRQ %ld\n", data->hwirq);
--
-- return IRQ_HANDLED;
--}
--
--static void mc_handle_event(struct irq_desc *desc)
--{
-- struct mc_pcie *port = irq_desc_get_handler_data(desc);
-- unsigned long events;
-- u32 bit;
-- struct irq_chip *chip = irq_desc_get_chip(desc);
--
-- chained_irq_enter(chip, desc);
--
-- events = get_events(port);
--
-- for_each_set_bit(bit, &events, NUM_EVENTS)
-- generic_handle_domain_irq(port->event_domain, bit);
--
-- chained_irq_exit(chip, desc);
--}
--
--static void mc_ack_event_irq(struct irq_data *data)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- u32 event = data->hwirq;
-- void __iomem *addr;
-- u32 mask;
--
-- addr = port->axi_base_addr + event_descs[event].base +
-- event_descs[event].offset;
-- mask = event_descs[event].mask;
-- mask |= event_descs[event].enb_mask;
--
-- writel_relaxed(mask, addr);
--}
--
--static void mc_mask_event_irq(struct irq_data *data)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- u32 event = data->hwirq;
-- void __iomem *addr;
-- u32 mask;
-- u32 val;
--
-- addr = port->axi_base_addr + event_descs[event].base +
-- event_descs[event].mask_offset;
-- mask = event_descs[event].mask;
-- if (event_descs[event].enb_mask) {
-- mask <<= PCIE_EVENT_INT_ENB_SHIFT;
-- mask &= PCIE_EVENT_INT_ENB_MASK;
-- }
--
-- if (!event_descs[event].mask_high)
-- mask = ~mask;
--
-- raw_spin_lock(&port->lock);
-- val = readl_relaxed(addr);
-- if (event_descs[event].mask_high)
-- val |= mask;
-- else
-- val &= mask;
--
-- writel_relaxed(val, addr);
-- raw_spin_unlock(&port->lock);
--}
--
--static void mc_unmask_event_irq(struct irq_data *data)
--{
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- u32 event = data->hwirq;
-- void __iomem *addr;
-- u32 mask;
-- u32 val;
--
-- addr = port->axi_base_addr + event_descs[event].base +
-- event_descs[event].mask_offset;
-- mask = event_descs[event].mask;
--
-- if (event_descs[event].enb_mask)
-- mask <<= PCIE_EVENT_INT_ENB_SHIFT;
--
-- if (event_descs[event].mask_high)
-- mask = ~mask;
--
-- if (event_descs[event].enb_mask)
-- mask &= PCIE_EVENT_INT_ENB_MASK;
--
-- raw_spin_lock(&port->lock);
-- val = readl_relaxed(addr);
-- if (event_descs[event].mask_high)
-- val &= mask;
-- else
-- val |= mask;
-- writel_relaxed(val, addr);
-- raw_spin_unlock(&port->lock);
--}
--
--static struct irq_chip mc_event_irq_chip = {
-- .name = "Microchip PCIe EVENT",
-- .irq_ack = mc_ack_event_irq,
-- .irq_mask = mc_mask_event_irq,
-- .irq_unmask = mc_unmask_event_irq,
--};
--
--static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
-- irq_hw_number_t hwirq)
--{
-- irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
-- irq_set_chip_data(irq, domain->host_data);
--
-- return 0;
--}
--
--static const struct irq_domain_ops event_domain_ops = {
-- .map = mc_pcie_event_map,
--};
--
--static inline void mc_pcie_deinit_clk(void *data)
--{
-- struct clk *clk = data;
--
-- clk_disable_unprepare(clk);
--}
--
--static inline struct clk *mc_pcie_init_clk(struct device *dev, const char *id)
--{
-- struct clk *clk;
-- int ret;
--
-- clk = devm_clk_get_optional(dev, id);
-- if (IS_ERR(clk))
-- return clk;
-- if (!clk)
-- return clk;
--
-- ret = clk_prepare_enable(clk);
-- if (ret)
-- return ERR_PTR(ret);
--
-- devm_add_action_or_reset(dev, mc_pcie_deinit_clk, clk);
--
-- return clk;
--}
--
--static int mc_pcie_init_clks(struct device *dev)
--{
-- int i;
-- struct clk *fic;
--
-- /*
-- * PCIe may be clocked via Fabric Interface using between 1 and 4
-- * clocks. Scan DT for clocks and enable them if present
-- */
-- for (i = 0; i < ARRAY_SIZE(poss_clks); i++) {
-- fic = mc_pcie_init_clk(dev, poss_clks[i]);
-- if (IS_ERR(fic))
-- return PTR_ERR(fic);
-- }
--
-- return 0;
--}
--
--static int mc_pcie_init_irq_domains(struct mc_pcie *port)
--{
-- struct device *dev = port->dev;
-- struct device_node *node = dev->of_node;
-- struct device_node *pcie_intc_node;
--
-- /* Setup INTx */
-- pcie_intc_node = of_get_next_child(node, NULL);
-- if (!pcie_intc_node) {
-- dev_err(dev, "failed to find PCIe Intc node\n");
-- return -EINVAL;
-- }
--
-- port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
-- &event_domain_ops, port);
-- if (!port->event_domain) {
-- dev_err(dev, "failed to get event domain\n");
-- of_node_put(pcie_intc_node);
-- return -ENOMEM;
-- }
--
-- irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
--
-- port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
-- &intx_domain_ops, port);
-- if (!port->intx_domain) {
-- dev_err(dev, "failed to get an INTx IRQ domain\n");
-- of_node_put(pcie_intc_node);
-- return -ENOMEM;
-- }
--
-- irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
--
-- of_node_put(pcie_intc_node);
-- raw_spin_lock_init(&port->lock);
--
-- return mc_allocate_msi_domains(port);
--}
--
--static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
-- phys_addr_t axi_addr, phys_addr_t pci_addr,
-- size_t size)
--{
-- u32 atr_sz = ilog2(size) - 1;
-- u32 val;
--
-- if (index == 0)
-- val = PCIE_CONFIG_INTERFACE;
-- else
-- val = PCIE_TX_RX_INTERFACE;
--
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_TRSL_PARAM);
--
-- val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
-- ATR_IMPL_ENABLE;
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_SRCADDR_PARAM);
--
-- val = upper_32_bits(axi_addr);
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_SRC_ADDR);
--
-- val = lower_32_bits(pci_addr);
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
--
-- val = upper_32_bits(pci_addr);
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
--
-- val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-- val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
-- writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-- writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
--}
--
--static int mc_pcie_setup_windows(struct platform_device *pdev,
-- struct mc_pcie *port)
--{
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
-- struct resource_entry *entry;
-- u64 pci_addr;
-- u32 index = 1;
--
-- resource_list_for_each_entry(entry, &bridge->windows) {
-- if (resource_type(entry->res) == IORESOURCE_MEM) {
-- pci_addr = entry->res->start - entry->offset;
-- mc_pcie_setup_window(bridge_base_addr, index,
-- entry->res->start, pci_addr,
-- resource_size(entry->res));
-- index++;
-- }
-- }
--
-- return 0;
--}
--
--static inline void mc_clear_secs(struct mc_pcie *port)
--{
-- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
--
-- writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr +
-- SEC_ERROR_INT);
-- writel_relaxed(0, ctrl_base_addr + SEC_ERROR_EVENT_CNT);
--}
--
--static inline void mc_clear_deds(struct mc_pcie *port)
--{
-- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
--
-- writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr +
-- DED_ERROR_INT);
-- writel_relaxed(0, ctrl_base_addr + DED_ERROR_EVENT_CNT);
--}
--
--static void mc_disable_interrupts(struct mc_pcie *port)
--{
-- void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-- u32 val;
--
-- /* Ensure ECC bypass is enabled */
-- val = ECC_CONTROL_TX_RAM_ECC_BYPASS |
-- ECC_CONTROL_RX_RAM_ECC_BYPASS |
-- ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS |
-- ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS;
-- writel_relaxed(val, ctrl_base_addr + ECC_CONTROL);
--
-- /* Disable SEC errors and clear any outstanding */
-- writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr +
-- SEC_ERROR_INT_MASK);
-- mc_clear_secs(port);
--
-- /* Disable DED errors and clear any outstanding */
-- writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr +
-- DED_ERROR_INT_MASK);
-- mc_clear_deds(port);
--
-- /* Disable local interrupts and clear any outstanding */
-- writel_relaxed(0, bridge_base_addr + IMASK_LOCAL);
-- writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_LOCAL);
-- writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_MSI);
--
-- /* Disable PCIe events and clear any outstanding */
-- val = PCIE_EVENT_INT_L2_EXIT_INT |
-- PCIE_EVENT_INT_HOTRST_EXIT_INT |
-- PCIE_EVENT_INT_DLUP_EXIT_INT |
-- PCIE_EVENT_INT_L2_EXIT_INT_MASK |
-- PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK |
-- PCIE_EVENT_INT_DLUP_EXIT_INT_MASK;
-- writel_relaxed(val, ctrl_base_addr + PCIE_EVENT_INT);
--
-- /* Disable host interrupts and clear any outstanding */
-- writel_relaxed(0, bridge_base_addr + IMASK_HOST);
-- writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
--}
--
--static int mc_init_interrupts(struct platform_device *pdev, struct mc_pcie *port)
--{
-- struct device *dev = &pdev->dev;
-- int irq;
-- int i, intx_irq, msi_irq, event_irq;
-- int ret;
--
-- ret = mc_pcie_init_irq_domains(port);
-- if (ret) {
-- dev_err(dev, "failed creating IRQ domains\n");
-- return ret;
-- }
--
-- irq = platform_get_irq(pdev, 0);
-- if (irq < 0)
-- return -ENODEV;
--
-- for (i = 0; i < NUM_EVENTS; i++) {
-- event_irq = irq_create_mapping(port->event_domain, i);
-- if (!event_irq) {
-- dev_err(dev, "failed to map hwirq %d\n", i);
-- return -ENXIO;
-- }
--
-- ret = devm_request_irq(dev, event_irq, mc_event_handler,
-- 0, event_cause[i].sym, port);
-- if (ret) {
-- dev_err(dev, "failed to request IRQ %d\n", event_irq);
-- return ret;
-- }
-- }
--
-- intx_irq = irq_create_mapping(port->event_domain,
-- EVENT_LOCAL_PM_MSI_INT_INTX);
-- if (!intx_irq) {
-- dev_err(dev, "failed to map INTx interrupt\n");
-- return -ENXIO;
-- }
--
-- /* Plug the INTx chained handler */
-- irq_set_chained_handler_and_data(intx_irq, mc_handle_intx, port);
--
-- msi_irq = irq_create_mapping(port->event_domain,
-- EVENT_LOCAL_PM_MSI_INT_MSI);
-- if (!msi_irq)
-- return -ENXIO;
--
-- /* Plug the MSI chained handler */
-- irq_set_chained_handler_and_data(msi_irq, mc_handle_msi, port);
--
-- /* Plug the main event chained handler */
-- irq_set_chained_handler_and_data(irq, mc_handle_event, port);
--
-- return 0;
--}
--
--static int mc_platform_init(struct pci_config_window *cfg)
--{
-- struct device *dev = cfg->parent;
-- struct platform_device *pdev = to_platform_device(dev);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- int ret;
--
-- /* Configure address translation table 0 for PCIe config space */
-- mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
-- cfg->res.start,
-- resource_size(&cfg->res));
--
-- /* Need some fixups in config space */
-- mc_pcie_enable_msi(port, cfg->win);
--
-- /* Configure non-config space outbound ranges */
-- ret = mc_pcie_setup_windows(pdev, port);
-- if (ret)
-- return ret;
--
-- /* Address translation is up; safe to enable interrupts */
-- ret = mc_init_interrupts(pdev, port);
-- if (ret)
-- return ret;
--
-- return 0;
--}
--
--static int mc_host_probe(struct platform_device *pdev)
--{
-- struct device *dev = &pdev->dev;
-- void __iomem *bridge_base_addr;
-- int ret;
-- u32 val;
--
-- port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
-- if (!port)
-- return -ENOMEM;
--
-- port->dev = dev;
--
-- port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1);
-- if (IS_ERR(port->axi_base_addr))
-- return PTR_ERR(port->axi_base_addr);
--
-- mc_disable_interrupts(port);
--
-- bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
--
-- /* Allow enabling MSI by disabling MSI-X */
-- val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
-- val &= ~MSIX_CAP_MASK;
-- writel(val, bridge_base_addr + PCIE_PCI_IRQ_DW0);
--
-- /* Pick num vectors from bitfile programmed onto FPGA fabric */
-- val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
-- val &= NUM_MSI_MSGS_MASK;
-- val >>= NUM_MSI_MSGS_SHIFT;
--
-- port->msi.num_vectors = 1 << val;
--
-- /* Pick vector address from design */
-- port->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
--
-- ret = mc_pcie_init_clks(dev);
-- if (ret) {
-- dev_err(dev, "failed to get clock resources, error %d\n", ret);
-- return -ENODEV;
-- }
--
-- return pci_host_common_probe(pdev);
--}
--
--static const struct pci_ecam_ops mc_ecam_ops = {
-- .init = mc_platform_init,
-- .pci_ops = {
-- .map_bus = pci_ecam_map_bus,
-- .read = pci_generic_config_read,
-- .write = pci_generic_config_write,
-- }
--};
--
--static const struct of_device_id mc_pcie_of_match[] = {
-- {
-- .compatible = "microchip,pcie-host-1.0",
-- .data = &mc_ecam_ops,
-- },
-- {},
--};
--
--MODULE_DEVICE_TABLE(of, mc_pcie_of_match);
--
--static struct platform_driver mc_pcie_driver = {
-- .probe = mc_host_probe,
-- .driver = {
-- .name = "microchip-pcie",
-- .of_match_table = mc_pcie_of_match,
-- .suppress_bind_attrs = true,
-- },
--};
--
--builtin_platform_driver(mc_pcie_driver);
--MODULE_LICENSE("GPL");
--MODULE_DESCRIPTION("Microchip PCIe host controller driver");
--MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
---- /dev/null
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -0,0 +1,1216 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Microchip AXI PCIe Bridge host controller driver
-+ *
-+ * Copyright (c) 2018 - 2020 Microchip Corporation. All rights reserved.
-+ *
-+ * Author: Daire McNamara <daire.mcnamara@microchip.com>
-+ */
-+
-+#include <linux/bitfield.h>
-+#include <linux/clk.h>
-+#include <linux/irqchip/chained_irq.h>
-+#include <linux/irqdomain.h>
-+#include <linux/module.h>
-+#include <linux/msi.h>
-+#include <linux/of_address.h>
-+#include <linux/of_pci.h>
-+#include <linux/pci-ecam.h>
-+#include <linux/platform_device.h>
-+
-+#include "../../pci.h"
-+
-+/* Number of MSI IRQs */
-+#define MC_MAX_NUM_MSI_IRQS 32
-+
-+/* PCIe Bridge Phy and Controller Phy offsets */
-+#define MC_PCIE1_BRIDGE_ADDR 0x00008000u
-+#define MC_PCIE1_CTRL_ADDR 0x0000a000u
-+
-+#define MC_PCIE_BRIDGE_ADDR (MC_PCIE1_BRIDGE_ADDR)
-+#define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR)
-+
-+/* PCIe Bridge Phy Regs */
-+#define PCIE_PCI_IRQ_DW0 0xa8
-+#define MSIX_CAP_MASK BIT(31)
-+#define NUM_MSI_MSGS_MASK GENMASK(6, 4)
-+#define NUM_MSI_MSGS_SHIFT 4
-+
-+#define IMASK_LOCAL 0x180
-+#define DMA_END_ENGINE_0_MASK 0x00000000u
-+#define DMA_END_ENGINE_0_SHIFT 0
-+#define DMA_END_ENGINE_1_MASK 0x00000000u
-+#define DMA_END_ENGINE_1_SHIFT 1
-+#define DMA_ERROR_ENGINE_0_MASK 0x00000100u
-+#define DMA_ERROR_ENGINE_0_SHIFT 8
-+#define DMA_ERROR_ENGINE_1_MASK 0x00000200u
-+#define DMA_ERROR_ENGINE_1_SHIFT 9
-+#define A_ATR_EVT_POST_ERR_MASK 0x00010000u
-+#define A_ATR_EVT_POST_ERR_SHIFT 16
-+#define A_ATR_EVT_FETCH_ERR_MASK 0x00020000u
-+#define A_ATR_EVT_FETCH_ERR_SHIFT 17
-+#define A_ATR_EVT_DISCARD_ERR_MASK 0x00040000u
-+#define A_ATR_EVT_DISCARD_ERR_SHIFT 18
-+#define A_ATR_EVT_DOORBELL_MASK 0x00000000u
-+#define A_ATR_EVT_DOORBELL_SHIFT 19
-+#define P_ATR_EVT_POST_ERR_MASK 0x00100000u
-+#define P_ATR_EVT_POST_ERR_SHIFT 20
-+#define P_ATR_EVT_FETCH_ERR_MASK 0x00200000u
-+#define P_ATR_EVT_FETCH_ERR_SHIFT 21
-+#define P_ATR_EVT_DISCARD_ERR_MASK 0x00400000u
-+#define P_ATR_EVT_DISCARD_ERR_SHIFT 22
-+#define P_ATR_EVT_DOORBELL_MASK 0x00000000u
-+#define P_ATR_EVT_DOORBELL_SHIFT 23
-+#define PM_MSI_INT_INTA_MASK 0x01000000u
-+#define PM_MSI_INT_INTA_SHIFT 24
-+#define PM_MSI_INT_INTB_MASK 0x02000000u
-+#define PM_MSI_INT_INTB_SHIFT 25
-+#define PM_MSI_INT_INTC_MASK 0x04000000u
-+#define PM_MSI_INT_INTC_SHIFT 26
-+#define PM_MSI_INT_INTD_MASK 0x08000000u
-+#define PM_MSI_INT_INTD_SHIFT 27
-+#define PM_MSI_INT_INTX_MASK 0x0f000000u
-+#define PM_MSI_INT_INTX_SHIFT 24
-+#define PM_MSI_INT_MSI_MASK 0x10000000u
-+#define PM_MSI_INT_MSI_SHIFT 28
-+#define PM_MSI_INT_AER_EVT_MASK 0x20000000u
-+#define PM_MSI_INT_AER_EVT_SHIFT 29
-+#define PM_MSI_INT_EVENTS_MASK 0x40000000u
-+#define PM_MSI_INT_EVENTS_SHIFT 30
-+#define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
-+#define PM_MSI_INT_SYS_ERR_SHIFT 31
-+#define NUM_LOCAL_EVENTS 15
-+#define ISTATUS_LOCAL 0x184
-+#define IMASK_HOST 0x188
-+#define ISTATUS_HOST 0x18c
-+#define IMSI_ADDR 0x190
-+#define ISTATUS_MSI 0x194
-+
-+/* PCIe Master table init defines */
-+#define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u
-+#define ATR0_PCIE_ATR_SIZE 0x25
-+#define ATR0_PCIE_ATR_SIZE_SHIFT 1
-+#define ATR0_PCIE_WIN0_SRC_ADDR 0x604u
-+#define ATR0_PCIE_WIN0_TRSL_ADDR_LSB 0x608u
-+#define ATR0_PCIE_WIN0_TRSL_ADDR_UDW 0x60cu
-+#define ATR0_PCIE_WIN0_TRSL_PARAM 0x610u
-+
-+/* PCIe AXI slave table init defines */
-+#define ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u
-+#define ATR_SIZE_SHIFT 1
-+#define ATR_IMPL_ENABLE 1
-+#define ATR0_AXI4_SLV0_SRC_ADDR 0x804u
-+#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u
-+#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu
-+#define ATR0_AXI4_SLV0_TRSL_PARAM 0x810u
-+#define PCIE_TX_RX_INTERFACE 0x00000000u
-+#define PCIE_CONFIG_INTERFACE 0x00000001u
-+
-+#define ATR_ENTRY_SIZE 32
-+
-+/* PCIe Controller Phy Regs */
-+#define SEC_ERROR_EVENT_CNT 0x20
-+#define DED_ERROR_EVENT_CNT 0x24
-+#define SEC_ERROR_INT 0x28
-+#define SEC_ERROR_INT_TX_RAM_SEC_ERR_INT GENMASK(3, 0)
-+#define SEC_ERROR_INT_RX_RAM_SEC_ERR_INT GENMASK(7, 4)
-+#define SEC_ERROR_INT_PCIE2AXI_RAM_SEC_ERR_INT GENMASK(11, 8)
-+#define SEC_ERROR_INT_AXI2PCIE_RAM_SEC_ERR_INT GENMASK(15, 12)
-+#define SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT GENMASK(15, 0)
-+#define NUM_SEC_ERROR_INTS (4)
-+#define SEC_ERROR_INT_MASK 0x2c
-+#define DED_ERROR_INT 0x30
-+#define DED_ERROR_INT_TX_RAM_DED_ERR_INT GENMASK(3, 0)
-+#define DED_ERROR_INT_RX_RAM_DED_ERR_INT GENMASK(7, 4)
-+#define DED_ERROR_INT_PCIE2AXI_RAM_DED_ERR_INT GENMASK(11, 8)
-+#define DED_ERROR_INT_AXI2PCIE_RAM_DED_ERR_INT GENMASK(15, 12)
-+#define DED_ERROR_INT_ALL_RAM_DED_ERR_INT GENMASK(15, 0)
-+#define NUM_DED_ERROR_INTS (4)
-+#define DED_ERROR_INT_MASK 0x34
-+#define ECC_CONTROL 0x38
-+#define ECC_CONTROL_TX_RAM_INJ_ERROR_0 BIT(0)
-+#define ECC_CONTROL_TX_RAM_INJ_ERROR_1 BIT(1)
-+#define ECC_CONTROL_TX_RAM_INJ_ERROR_2 BIT(2)
-+#define ECC_CONTROL_TX_RAM_INJ_ERROR_3 BIT(3)
-+#define ECC_CONTROL_RX_RAM_INJ_ERROR_0 BIT(4)
-+#define ECC_CONTROL_RX_RAM_INJ_ERROR_1 BIT(5)
-+#define ECC_CONTROL_RX_RAM_INJ_ERROR_2 BIT(6)
-+#define ECC_CONTROL_RX_RAM_INJ_ERROR_3 BIT(7)
-+#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_0 BIT(8)
-+#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_1 BIT(9)
-+#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_2 BIT(10)
-+#define ECC_CONTROL_PCIE2AXI_RAM_INJ_ERROR_3 BIT(11)
-+#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_0 BIT(12)
-+#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_1 BIT(13)
-+#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_2 BIT(14)
-+#define ECC_CONTROL_AXI2PCIE_RAM_INJ_ERROR_3 BIT(15)
-+#define ECC_CONTROL_TX_RAM_ECC_BYPASS BIT(24)
-+#define ECC_CONTROL_RX_RAM_ECC_BYPASS BIT(25)
-+#define ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS BIT(26)
-+#define ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS BIT(27)
-+#define PCIE_EVENT_INT 0x14c
-+#define PCIE_EVENT_INT_L2_EXIT_INT BIT(0)
-+#define PCIE_EVENT_INT_HOTRST_EXIT_INT BIT(1)
-+#define PCIE_EVENT_INT_DLUP_EXIT_INT BIT(2)
-+#define PCIE_EVENT_INT_MASK GENMASK(2, 0)
-+#define PCIE_EVENT_INT_L2_EXIT_INT_MASK BIT(16)
-+#define PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK BIT(17)
-+#define PCIE_EVENT_INT_DLUP_EXIT_INT_MASK BIT(18)
-+#define PCIE_EVENT_INT_ENB_MASK GENMASK(18, 16)
-+#define PCIE_EVENT_INT_ENB_SHIFT 16
-+#define NUM_PCIE_EVENTS (3)
-+
-+/* PCIe Config space MSI capability structure */
-+#define MC_MSI_CAP_CTRL_OFFSET 0xe0u
-+
-+/* Events */
-+#define EVENT_PCIE_L2_EXIT 0
-+#define EVENT_PCIE_HOTRST_EXIT 1
-+#define EVENT_PCIE_DLUP_EXIT 2
-+#define EVENT_SEC_TX_RAM_SEC_ERR 3
-+#define EVENT_SEC_RX_RAM_SEC_ERR 4
-+#define EVENT_SEC_PCIE2AXI_RAM_SEC_ERR 5
-+#define EVENT_SEC_AXI2PCIE_RAM_SEC_ERR 6
-+#define EVENT_DED_TX_RAM_DED_ERR 7
-+#define EVENT_DED_RX_RAM_DED_ERR 8
-+#define EVENT_DED_PCIE2AXI_RAM_DED_ERR 9
-+#define EVENT_DED_AXI2PCIE_RAM_DED_ERR 10
-+#define EVENT_LOCAL_DMA_END_ENGINE_0 11
-+#define EVENT_LOCAL_DMA_END_ENGINE_1 12
-+#define EVENT_LOCAL_DMA_ERROR_ENGINE_0 13
-+#define EVENT_LOCAL_DMA_ERROR_ENGINE_1 14
-+#define EVENT_LOCAL_A_ATR_EVT_POST_ERR 15
-+#define EVENT_LOCAL_A_ATR_EVT_FETCH_ERR 16
-+#define EVENT_LOCAL_A_ATR_EVT_DISCARD_ERR 17
-+#define EVENT_LOCAL_A_ATR_EVT_DOORBELL 18
-+#define EVENT_LOCAL_P_ATR_EVT_POST_ERR 19
-+#define EVENT_LOCAL_P_ATR_EVT_FETCH_ERR 20
-+#define EVENT_LOCAL_P_ATR_EVT_DISCARD_ERR 21
-+#define EVENT_LOCAL_P_ATR_EVT_DOORBELL 22
-+#define EVENT_LOCAL_PM_MSI_INT_INTX 23
-+#define EVENT_LOCAL_PM_MSI_INT_MSI 24
-+#define EVENT_LOCAL_PM_MSI_INT_AER_EVT 25
-+#define EVENT_LOCAL_PM_MSI_INT_EVENTS 26
-+#define EVENT_LOCAL_PM_MSI_INT_SYS_ERR 27
-+#define NUM_EVENTS 28
-+
-+#define PCIE_EVENT_CAUSE(x, s) \
-+ [EVENT_PCIE_ ## x] = { __stringify(x), s }
-+
-+#define SEC_ERROR_CAUSE(x, s) \
-+ [EVENT_SEC_ ## x] = { __stringify(x), s }
-+
-+#define DED_ERROR_CAUSE(x, s) \
-+ [EVENT_DED_ ## x] = { __stringify(x), s }
-+
-+#define LOCAL_EVENT_CAUSE(x, s) \
-+ [EVENT_LOCAL_ ## x] = { __stringify(x), s }
-+
-+#define PCIE_EVENT(x) \
-+ .base = MC_PCIE_CTRL_ADDR, \
-+ .offset = PCIE_EVENT_INT, \
-+ .mask_offset = PCIE_EVENT_INT, \
-+ .mask_high = 1, \
-+ .mask = PCIE_EVENT_INT_ ## x ## _INT, \
-+ .enb_mask = PCIE_EVENT_INT_ENB_MASK
-+
-+#define SEC_EVENT(x) \
-+ .base = MC_PCIE_CTRL_ADDR, \
-+ .offset = SEC_ERROR_INT, \
-+ .mask_offset = SEC_ERROR_INT_MASK, \
-+ .mask = SEC_ERROR_INT_ ## x ## _INT, \
-+ .mask_high = 1, \
-+ .enb_mask = 0
-+
-+#define DED_EVENT(x) \
-+ .base = MC_PCIE_CTRL_ADDR, \
-+ .offset = DED_ERROR_INT, \
-+ .mask_offset = DED_ERROR_INT_MASK, \
-+ .mask_high = 1, \
-+ .mask = DED_ERROR_INT_ ## x ## _INT, \
-+ .enb_mask = 0
-+
-+#define LOCAL_EVENT(x) \
-+ .base = MC_PCIE_BRIDGE_ADDR, \
-+ .offset = ISTATUS_LOCAL, \
-+ .mask_offset = IMASK_LOCAL, \
-+ .mask_high = 0, \
-+ .mask = x ## _MASK, \
-+ .enb_mask = 0
-+
-+#define PCIE_EVENT_TO_EVENT_MAP(x) \
-+ { PCIE_EVENT_INT_ ## x ## _INT, EVENT_PCIE_ ## x }
-+
-+#define SEC_ERROR_TO_EVENT_MAP(x) \
-+ { SEC_ERROR_INT_ ## x ## _INT, EVENT_SEC_ ## x }
-+
-+#define DED_ERROR_TO_EVENT_MAP(x) \
-+ { DED_ERROR_INT_ ## x ## _INT, EVENT_DED_ ## x }
-+
-+#define LOCAL_STATUS_TO_EVENT_MAP(x) \
-+ { x ## _MASK, EVENT_LOCAL_ ## x }
-+
-+struct event_map {
-+ u32 reg_mask;
-+ u32 event_bit;
-+};
-+
-+struct mc_msi {
-+ struct mutex lock; /* Protect used bitmap */
-+ struct irq_domain *msi_domain;
-+ struct irq_domain *dev_domain;
-+ u32 num_vectors;
-+ u64 vector_phy;
-+ DECLARE_BITMAP(used, MC_MAX_NUM_MSI_IRQS);
-+};
-+
-+struct mc_pcie {
-+ void __iomem *axi_base_addr;
-+ struct device *dev;
-+ struct irq_domain *intx_domain;
-+ struct irq_domain *event_domain;
-+ raw_spinlock_t lock;
-+ struct mc_msi msi;
-+};
-+
-+struct cause {
-+ const char *sym;
-+ const char *str;
-+};
-+
-+static const struct cause event_cause[NUM_EVENTS] = {
-+ PCIE_EVENT_CAUSE(L2_EXIT, "L2 exit event"),
-+ PCIE_EVENT_CAUSE(HOTRST_EXIT, "Hot reset exit event"),
-+ PCIE_EVENT_CAUSE(DLUP_EXIT, "DLUP exit event"),
-+ SEC_ERROR_CAUSE(TX_RAM_SEC_ERR, "sec error in tx buffer"),
-+ SEC_ERROR_CAUSE(RX_RAM_SEC_ERR, "sec error in rx buffer"),
-+ SEC_ERROR_CAUSE(PCIE2AXI_RAM_SEC_ERR, "sec error in pcie2axi buffer"),
-+ SEC_ERROR_CAUSE(AXI2PCIE_RAM_SEC_ERR, "sec error in axi2pcie buffer"),
-+ DED_ERROR_CAUSE(TX_RAM_DED_ERR, "ded error in tx buffer"),
-+ DED_ERROR_CAUSE(RX_RAM_DED_ERR, "ded error in rx buffer"),
-+ DED_ERROR_CAUSE(PCIE2AXI_RAM_DED_ERR, "ded error in pcie2axi buffer"),
-+ DED_ERROR_CAUSE(AXI2PCIE_RAM_DED_ERR, "ded error in axi2pcie buffer"),
-+ LOCAL_EVENT_CAUSE(DMA_ERROR_ENGINE_0, "dma engine 0 error"),
-+ LOCAL_EVENT_CAUSE(DMA_ERROR_ENGINE_1, "dma engine 1 error"),
-+ LOCAL_EVENT_CAUSE(A_ATR_EVT_POST_ERR, "axi write request error"),
-+ LOCAL_EVENT_CAUSE(A_ATR_EVT_FETCH_ERR, "axi read request error"),
-+ LOCAL_EVENT_CAUSE(A_ATR_EVT_DISCARD_ERR, "axi read timeout"),
-+ LOCAL_EVENT_CAUSE(P_ATR_EVT_POST_ERR, "pcie write request error"),
-+ LOCAL_EVENT_CAUSE(P_ATR_EVT_FETCH_ERR, "pcie read request error"),
-+ LOCAL_EVENT_CAUSE(P_ATR_EVT_DISCARD_ERR, "pcie read timeout"),
-+ LOCAL_EVENT_CAUSE(PM_MSI_INT_AER_EVT, "aer event"),
-+ LOCAL_EVENT_CAUSE(PM_MSI_INT_EVENTS, "pm/ltr/hotplug event"),
-+ LOCAL_EVENT_CAUSE(PM_MSI_INT_SYS_ERR, "system error"),
-+};
-+
-+static struct event_map pcie_event_to_event[] = {
-+ PCIE_EVENT_TO_EVENT_MAP(L2_EXIT),
-+ PCIE_EVENT_TO_EVENT_MAP(HOTRST_EXIT),
-+ PCIE_EVENT_TO_EVENT_MAP(DLUP_EXIT),
-+};
-+
-+static struct event_map sec_error_to_event[] = {
-+ SEC_ERROR_TO_EVENT_MAP(TX_RAM_SEC_ERR),
-+ SEC_ERROR_TO_EVENT_MAP(RX_RAM_SEC_ERR),
-+ SEC_ERROR_TO_EVENT_MAP(PCIE2AXI_RAM_SEC_ERR),
-+ SEC_ERROR_TO_EVENT_MAP(AXI2PCIE_RAM_SEC_ERR),
-+};
-+
-+static struct event_map ded_error_to_event[] = {
-+ DED_ERROR_TO_EVENT_MAP(TX_RAM_DED_ERR),
-+ DED_ERROR_TO_EVENT_MAP(RX_RAM_DED_ERR),
-+ DED_ERROR_TO_EVENT_MAP(PCIE2AXI_RAM_DED_ERR),
-+ DED_ERROR_TO_EVENT_MAP(AXI2PCIE_RAM_DED_ERR),
-+};
-+
-+static struct event_map local_status_to_event[] = {
-+ LOCAL_STATUS_TO_EVENT_MAP(DMA_END_ENGINE_0),
-+ LOCAL_STATUS_TO_EVENT_MAP(DMA_END_ENGINE_1),
-+ LOCAL_STATUS_TO_EVENT_MAP(DMA_ERROR_ENGINE_0),
-+ LOCAL_STATUS_TO_EVENT_MAP(DMA_ERROR_ENGINE_1),
-+ LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_POST_ERR),
-+ LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_FETCH_ERR),
-+ LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_DISCARD_ERR),
-+ LOCAL_STATUS_TO_EVENT_MAP(A_ATR_EVT_DOORBELL),
-+ LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_POST_ERR),
-+ LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_FETCH_ERR),
-+ LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_DISCARD_ERR),
-+ LOCAL_STATUS_TO_EVENT_MAP(P_ATR_EVT_DOORBELL),
-+ LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_INTX),
-+ LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_MSI),
-+ LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_AER_EVT),
-+ LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_EVENTS),
-+ LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_SYS_ERR),
-+};
-+
-+static struct {
-+ u32 base;
-+ u32 offset;
-+ u32 mask;
-+ u32 shift;
-+ u32 enb_mask;
-+ u32 mask_high;
-+ u32 mask_offset;
-+} event_descs[] = {
-+ { PCIE_EVENT(L2_EXIT) },
-+ { PCIE_EVENT(HOTRST_EXIT) },
-+ { PCIE_EVENT(DLUP_EXIT) },
-+ { SEC_EVENT(TX_RAM_SEC_ERR) },
-+ { SEC_EVENT(RX_RAM_SEC_ERR) },
-+ { SEC_EVENT(PCIE2AXI_RAM_SEC_ERR) },
-+ { SEC_EVENT(AXI2PCIE_RAM_SEC_ERR) },
-+ { DED_EVENT(TX_RAM_DED_ERR) },
-+ { DED_EVENT(RX_RAM_DED_ERR) },
-+ { DED_EVENT(PCIE2AXI_RAM_DED_ERR) },
-+ { DED_EVENT(AXI2PCIE_RAM_DED_ERR) },
-+ { LOCAL_EVENT(DMA_END_ENGINE_0) },
-+ { LOCAL_EVENT(DMA_END_ENGINE_1) },
-+ { LOCAL_EVENT(DMA_ERROR_ENGINE_0) },
-+ { LOCAL_EVENT(DMA_ERROR_ENGINE_1) },
-+ { LOCAL_EVENT(A_ATR_EVT_POST_ERR) },
-+ { LOCAL_EVENT(A_ATR_EVT_FETCH_ERR) },
-+ { LOCAL_EVENT(A_ATR_EVT_DISCARD_ERR) },
-+ { LOCAL_EVENT(A_ATR_EVT_DOORBELL) },
-+ { LOCAL_EVENT(P_ATR_EVT_POST_ERR) },
-+ { LOCAL_EVENT(P_ATR_EVT_FETCH_ERR) },
-+ { LOCAL_EVENT(P_ATR_EVT_DISCARD_ERR) },
-+ { LOCAL_EVENT(P_ATR_EVT_DOORBELL) },
-+ { LOCAL_EVENT(PM_MSI_INT_INTX) },
-+ { LOCAL_EVENT(PM_MSI_INT_MSI) },
-+ { LOCAL_EVENT(PM_MSI_INT_AER_EVT) },
-+ { LOCAL_EVENT(PM_MSI_INT_EVENTS) },
-+ { LOCAL_EVENT(PM_MSI_INT_SYS_ERR) },
-+};
-+
-+static char poss_clks[][5] = { "fic0", "fic1", "fic2", "fic3" };
-+
-+static struct mc_pcie *port;
-+
-+static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
-+{
-+ struct mc_msi *msi = &port->msi;
-+ u16 reg;
-+ u8 queue_size;
-+
-+ /* Fixup MSI enable flag */
-+ reg = readw_relaxed(ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS);
-+ reg |= PCI_MSI_FLAGS_ENABLE;
-+ writew_relaxed(reg, ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS);
-+
-+ /* Fixup PCI MSI queue flags */
-+ queue_size = FIELD_GET(PCI_MSI_FLAGS_QMASK, reg);
-+ reg |= FIELD_PREP(PCI_MSI_FLAGS_QSIZE, queue_size);
-+ writew_relaxed(reg, ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_FLAGS);
-+
-+ /* Fixup MSI addr fields */
-+ writel_relaxed(lower_32_bits(msi->vector_phy),
-+ ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_LO);
-+ writel_relaxed(upper_32_bits(msi->vector_phy),
-+ ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
-+}
-+
-+static void mc_handle_msi(struct irq_desc *desc)
-+{
-+ struct mc_pcie *port = irq_desc_get_handler_data(desc);
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct device *dev = port->dev;
-+ struct mc_msi *msi = &port->msi;
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ unsigned long status;
-+ u32 bit;
-+ int ret;
-+
-+ chained_irq_enter(chip, desc);
-+
-+ status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-+ if (status & PM_MSI_INT_MSI_MASK) {
-+ writel_relaxed(status & PM_MSI_INT_MSI_MASK, bridge_base_addr + ISTATUS_LOCAL);
-+ status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
-+ for_each_set_bit(bit, &status, msi->num_vectors) {
-+ ret = generic_handle_domain_irq(msi->dev_domain, bit);
-+ if (ret)
-+ dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
-+ bit);
-+ }
-+ }
-+
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static void mc_msi_bottom_irq_ack(struct irq_data *data)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ u32 bitpos = data->hwirq;
-+
-+ writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
-+}
-+
-+static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ phys_addr_t addr = port->msi.vector_phy;
-+
-+ msg->address_lo = lower_32_bits(addr);
-+ msg->address_hi = upper_32_bits(addr);
-+ msg->data = data->hwirq;
-+
-+ dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
-+ (int)data->hwirq, msg->address_hi, msg->address_lo);
-+}
-+
-+static int mc_msi_set_affinity(struct irq_data *irq_data,
-+ const struct cpumask *mask, bool force)
-+{
-+ return -EINVAL;
-+}
-+
-+static struct irq_chip mc_msi_bottom_irq_chip = {
-+ .name = "Microchip MSI",
-+ .irq_ack = mc_msi_bottom_irq_ack,
-+ .irq_compose_msi_msg = mc_compose_msi_msg,
-+ .irq_set_affinity = mc_msi_set_affinity,
-+};
-+
-+static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
-+ unsigned int nr_irqs, void *args)
-+{
-+ struct mc_pcie *port = domain->host_data;
-+ struct mc_msi *msi = &port->msi;
-+ unsigned long bit;
-+
-+ mutex_lock(&msi->lock);
-+ bit = find_first_zero_bit(msi->used, msi->num_vectors);
-+ if (bit >= msi->num_vectors) {
-+ mutex_unlock(&msi->lock);
-+ return -ENOSPC;
-+ }
-+
-+ set_bit(bit, msi->used);
-+
-+ irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip,
-+ domain->host_data, handle_edge_irq, NULL, NULL);
-+
-+ mutex_unlock(&msi->lock);
-+
-+ return 0;
-+}
-+
-+static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
-+ unsigned int nr_irqs)
-+{
-+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(d);
-+ struct mc_msi *msi = &port->msi;
-+
-+ mutex_lock(&msi->lock);
-+
-+ if (test_bit(d->hwirq, msi->used))
-+ __clear_bit(d->hwirq, msi->used);
-+ else
-+ dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
-+
-+ mutex_unlock(&msi->lock);
-+}
-+
-+static const struct irq_domain_ops msi_domain_ops = {
-+ .alloc = mc_irq_msi_domain_alloc,
-+ .free = mc_irq_msi_domain_free,
-+};
-+
-+static struct irq_chip mc_msi_irq_chip = {
-+ .name = "Microchip PCIe MSI",
-+ .irq_ack = irq_chip_ack_parent,
-+ .irq_mask = pci_msi_mask_irq,
-+ .irq_unmask = pci_msi_unmask_irq,
-+};
-+
-+static struct msi_domain_info mc_msi_domain_info = {
-+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-+ MSI_FLAG_PCI_MSIX),
-+ .chip = &mc_msi_irq_chip,
-+};
-+
-+static int mc_allocate_msi_domains(struct mc_pcie *port)
-+{
-+ struct device *dev = port->dev;
-+ struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
-+ struct mc_msi *msi = &port->msi;
-+
-+ mutex_init(&port->msi.lock);
-+
-+ msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
-+ &msi_domain_ops, port);
-+ if (!msi->dev_domain) {
-+ dev_err(dev, "failed to create IRQ domain\n");
-+ return -ENOMEM;
-+ }
-+
-+ msi->msi_domain = pci_msi_create_irq_domain(fwnode, &mc_msi_domain_info,
-+ msi->dev_domain);
-+ if (!msi->msi_domain) {
-+ dev_err(dev, "failed to create MSI domain\n");
-+ irq_domain_remove(msi->dev_domain);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static void mc_handle_intx(struct irq_desc *desc)
-+{
-+ struct mc_pcie *port = irq_desc_get_handler_data(desc);
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct device *dev = port->dev;
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ unsigned long status;
-+ u32 bit;
-+ int ret;
-+
-+ chained_irq_enter(chip, desc);
-+
-+ status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-+ if (status & PM_MSI_INT_INTX_MASK) {
-+ status &= PM_MSI_INT_INTX_MASK;
-+ status >>= PM_MSI_INT_INTX_SHIFT;
-+ for_each_set_bit(bit, &status, PCI_NUM_INTX) {
-+ ret = generic_handle_domain_irq(port->intx_domain, bit);
-+ if (ret)
-+ dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
-+ bit);
-+ }
-+ }
-+
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static void mc_ack_intx_irq(struct irq_data *data)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-+
-+ writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
-+}
-+
-+static void mc_mask_intx_irq(struct irq_data *data)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ unsigned long flags;
-+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-+ u32 val;
-+
-+ raw_spin_lock_irqsave(&port->lock, flags);
-+ val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-+ val &= ~mask;
-+ writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-+ raw_spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+static void mc_unmask_intx_irq(struct irq_data *data)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ unsigned long flags;
-+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-+ u32 val;
-+
-+ raw_spin_lock_irqsave(&port->lock, flags);
-+ val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-+ val |= mask;
-+ writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-+ raw_spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+static struct irq_chip mc_intx_irq_chip = {
-+ .name = "Microchip PCIe INTx",
-+ .irq_ack = mc_ack_intx_irq,
-+ .irq_mask = mc_mask_intx_irq,
-+ .irq_unmask = mc_unmask_intx_irq,
-+};
-+
-+static int mc_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-+ irq_hw_number_t hwirq)
-+{
-+ irq_set_chip_and_handler(irq, &mc_intx_irq_chip, handle_level_irq);
-+ irq_set_chip_data(irq, domain->host_data);
-+
-+ return 0;
-+}
-+
-+static const struct irq_domain_ops intx_domain_ops = {
-+ .map = mc_pcie_intx_map,
-+};
-+
-+static inline u32 reg_to_event(u32 reg, struct event_map field)
-+{
-+ return (reg & field.reg_mask) ? BIT(field.event_bit) : 0;
-+}
-+
-+static u32 pcie_events(struct mc_pcie *port)
-+{
-+ void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-+ u32 reg = readl_relaxed(ctrl_base_addr + PCIE_EVENT_INT);
-+ u32 val = 0;
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(pcie_event_to_event); i++)
-+ val |= reg_to_event(reg, pcie_event_to_event[i]);
-+
-+ return val;
-+}
-+
-+static u32 sec_errors(struct mc_pcie *port)
-+{
-+ void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-+ u32 reg = readl_relaxed(ctrl_base_addr + SEC_ERROR_INT);
-+ u32 val = 0;
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(sec_error_to_event); i++)
-+ val |= reg_to_event(reg, sec_error_to_event[i]);
-+
-+ return val;
-+}
-+
-+static u32 ded_errors(struct mc_pcie *port)
-+{
-+ void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-+ u32 reg = readl_relaxed(ctrl_base_addr + DED_ERROR_INT);
-+ u32 val = 0;
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(ded_error_to_event); i++)
-+ val |= reg_to_event(reg, ded_error_to_event[i]);
-+
-+ return val;
-+}
-+
-+static u32 local_events(struct mc_pcie *port)
-+{
-+ void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ u32 reg = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-+ u32 val = 0;
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(local_status_to_event); i++)
-+ val |= reg_to_event(reg, local_status_to_event[i]);
-+
-+ return val;
-+}
-+
-+static u32 get_events(struct mc_pcie *port)
-+{
-+ u32 events = 0;
-+
-+ events |= pcie_events(port);
-+ events |= sec_errors(port);
-+ events |= ded_errors(port);
-+ events |= local_events(port);
-+
-+ return events;
-+}
-+
-+static irqreturn_t mc_event_handler(int irq, void *dev_id)
-+{
-+ struct mc_pcie *port = dev_id;
-+ struct device *dev = port->dev;
-+ struct irq_data *data;
-+
-+ data = irq_domain_get_irq_data(port->event_domain, irq);
-+
-+ if (event_cause[data->hwirq].str)
-+ dev_err_ratelimited(dev, "%s\n", event_cause[data->hwirq].str);
-+ else
-+ dev_err_ratelimited(dev, "bad event IRQ %ld\n", data->hwirq);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void mc_handle_event(struct irq_desc *desc)
-+{
-+ struct mc_pcie *port = irq_desc_get_handler_data(desc);
-+ unsigned long events;
-+ u32 bit;
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+
-+ chained_irq_enter(chip, desc);
-+
-+ events = get_events(port);
-+
-+ for_each_set_bit(bit, &events, NUM_EVENTS)
-+ generic_handle_domain_irq(port->event_domain, bit);
-+
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static void mc_ack_event_irq(struct irq_data *data)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ u32 event = data->hwirq;
-+ void __iomem *addr;
-+ u32 mask;
-+
-+ addr = port->axi_base_addr + event_descs[event].base +
-+ event_descs[event].offset;
-+ mask = event_descs[event].mask;
-+ mask |= event_descs[event].enb_mask;
-+
-+ writel_relaxed(mask, addr);
-+}
-+
-+static void mc_mask_event_irq(struct irq_data *data)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ u32 event = data->hwirq;
-+ void __iomem *addr;
-+ u32 mask;
-+ u32 val;
-+
-+ addr = port->axi_base_addr + event_descs[event].base +
-+ event_descs[event].mask_offset;
-+ mask = event_descs[event].mask;
-+ if (event_descs[event].enb_mask) {
-+ mask <<= PCIE_EVENT_INT_ENB_SHIFT;
-+ mask &= PCIE_EVENT_INT_ENB_MASK;
-+ }
-+
-+ if (!event_descs[event].mask_high)
-+ mask = ~mask;
-+
-+ raw_spin_lock(&port->lock);
-+ val = readl_relaxed(addr);
-+ if (event_descs[event].mask_high)
-+ val |= mask;
-+ else
-+ val &= mask;
-+
-+ writel_relaxed(val, addr);
-+ raw_spin_unlock(&port->lock);
-+}
-+
-+static void mc_unmask_event_irq(struct irq_data *data)
-+{
-+ struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ u32 event = data->hwirq;
-+ void __iomem *addr;
-+ u32 mask;
-+ u32 val;
-+
-+ addr = port->axi_base_addr + event_descs[event].base +
-+ event_descs[event].mask_offset;
-+ mask = event_descs[event].mask;
-+
-+ if (event_descs[event].enb_mask)
-+ mask <<= PCIE_EVENT_INT_ENB_SHIFT;
-+
-+ if (event_descs[event].mask_high)
-+ mask = ~mask;
-+
-+ if (event_descs[event].enb_mask)
-+ mask &= PCIE_EVENT_INT_ENB_MASK;
-+
-+ raw_spin_lock(&port->lock);
-+ val = readl_relaxed(addr);
-+ if (event_descs[event].mask_high)
-+ val &= mask;
-+ else
-+ val |= mask;
-+ writel_relaxed(val, addr);
-+ raw_spin_unlock(&port->lock);
-+}
-+
-+static struct irq_chip mc_event_irq_chip = {
-+ .name = "Microchip PCIe EVENT",
-+ .irq_ack = mc_ack_event_irq,
-+ .irq_mask = mc_mask_event_irq,
-+ .irq_unmask = mc_unmask_event_irq,
-+};
-+
-+static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
-+ irq_hw_number_t hwirq)
-+{
-+ irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
-+ irq_set_chip_data(irq, domain->host_data);
-+
-+ return 0;
-+}
-+
-+static const struct irq_domain_ops event_domain_ops = {
-+ .map = mc_pcie_event_map,
-+};
-+
-+static inline void mc_pcie_deinit_clk(void *data)
-+{
-+ struct clk *clk = data;
-+
-+ clk_disable_unprepare(clk);
-+}
-+
-+static inline struct clk *mc_pcie_init_clk(struct device *dev, const char *id)
-+{
-+ struct clk *clk;
-+ int ret;
-+
-+ clk = devm_clk_get_optional(dev, id);
-+ if (IS_ERR(clk))
-+ return clk;
-+ if (!clk)
-+ return clk;
-+
-+ ret = clk_prepare_enable(clk);
-+ if (ret)
-+ return ERR_PTR(ret);
-+
-+ devm_add_action_or_reset(dev, mc_pcie_deinit_clk, clk);
-+
-+ return clk;
-+}
-+
-+static int mc_pcie_init_clks(struct device *dev)
-+{
-+ int i;
-+ struct clk *fic;
-+
-+ /*
-+ * PCIe may be clocked via Fabric Interface using between 1 and 4
-+ * clocks. Scan DT for clocks and enable them if present
-+ */
-+ for (i = 0; i < ARRAY_SIZE(poss_clks); i++) {
-+ fic = mc_pcie_init_clk(dev, poss_clks[i]);
-+ if (IS_ERR(fic))
-+ return PTR_ERR(fic);
-+ }
-+
-+ return 0;
-+}
-+
-+static int mc_pcie_init_irq_domains(struct mc_pcie *port)
-+{
-+ struct device *dev = port->dev;
-+ struct device_node *node = dev->of_node;
-+ struct device_node *pcie_intc_node;
-+
-+ /* Setup INTx */
-+ pcie_intc_node = of_get_next_child(node, NULL);
-+ if (!pcie_intc_node) {
-+ dev_err(dev, "failed to find PCIe Intc node\n");
-+ return -EINVAL;
-+ }
-+
-+ port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
-+ &event_domain_ops, port);
-+ if (!port->event_domain) {
-+ dev_err(dev, "failed to get event domain\n");
-+ of_node_put(pcie_intc_node);
-+ return -ENOMEM;
-+ }
-+
-+ irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
-+
-+ port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
-+ &intx_domain_ops, port);
-+ if (!port->intx_domain) {
-+ dev_err(dev, "failed to get an INTx IRQ domain\n");
-+ of_node_put(pcie_intc_node);
-+ return -ENOMEM;
-+ }
-+
-+ irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
-+
-+ of_node_put(pcie_intc_node);
-+ raw_spin_lock_init(&port->lock);
-+
-+ return mc_allocate_msi_domains(port);
-+}
-+
-+static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
-+ phys_addr_t axi_addr, phys_addr_t pci_addr,
-+ size_t size)
-+{
-+ u32 atr_sz = ilog2(size) - 1;
-+ u32 val;
-+
-+ if (index == 0)
-+ val = PCIE_CONFIG_INTERFACE;
-+ else
-+ val = PCIE_TX_RX_INTERFACE;
-+
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_TRSL_PARAM);
-+
-+ val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
-+ ATR_IMPL_ENABLE;
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_SRCADDR_PARAM);
-+
-+ val = upper_32_bits(axi_addr);
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_SRC_ADDR);
-+
-+ val = lower_32_bits(pci_addr);
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
-+
-+ val = upper_32_bits(pci_addr);
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
-+
-+ val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-+ val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
-+ writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-+ writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
-+}
-+
-+static int mc_pcie_setup_windows(struct platform_device *pdev,
-+ struct mc_pcie *port)
-+{
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
-+ struct resource_entry *entry;
-+ u64 pci_addr;
-+ u32 index = 1;
-+
-+ resource_list_for_each_entry(entry, &bridge->windows) {
-+ if (resource_type(entry->res) == IORESOURCE_MEM) {
-+ pci_addr = entry->res->start - entry->offset;
-+ mc_pcie_setup_window(bridge_base_addr, index,
-+ entry->res->start, pci_addr,
-+ resource_size(entry->res));
-+ index++;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static inline void mc_clear_secs(struct mc_pcie *port)
-+{
-+ void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-+
-+ writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr +
-+ SEC_ERROR_INT);
-+ writel_relaxed(0, ctrl_base_addr + SEC_ERROR_EVENT_CNT);
-+}
-+
-+static inline void mc_clear_deds(struct mc_pcie *port)
-+{
-+ void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-+
-+ writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr +
-+ DED_ERROR_INT);
-+ writel_relaxed(0, ctrl_base_addr + DED_ERROR_EVENT_CNT);
-+}
-+
-+static void mc_disable_interrupts(struct mc_pcie *port)
-+{
-+ void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-+ u32 val;
-+
-+ /* Ensure ECC bypass is enabled */
-+ val = ECC_CONTROL_TX_RAM_ECC_BYPASS |
-+ ECC_CONTROL_RX_RAM_ECC_BYPASS |
-+ ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS |
-+ ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS;
-+ writel_relaxed(val, ctrl_base_addr + ECC_CONTROL);
-+
-+ /* Disable SEC errors and clear any outstanding */
-+ writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr +
-+ SEC_ERROR_INT_MASK);
-+ mc_clear_secs(port);
-+
-+ /* Disable DED errors and clear any outstanding */
-+ writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr +
-+ DED_ERROR_INT_MASK);
-+ mc_clear_deds(port);
-+
-+ /* Disable local interrupts and clear any outstanding */
-+ writel_relaxed(0, bridge_base_addr + IMASK_LOCAL);
-+ writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_LOCAL);
-+ writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_MSI);
-+
-+ /* Disable PCIe events and clear any outstanding */
-+ val = PCIE_EVENT_INT_L2_EXIT_INT |
-+ PCIE_EVENT_INT_HOTRST_EXIT_INT |
-+ PCIE_EVENT_INT_DLUP_EXIT_INT |
-+ PCIE_EVENT_INT_L2_EXIT_INT_MASK |
-+ PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK |
-+ PCIE_EVENT_INT_DLUP_EXIT_INT_MASK;
-+ writel_relaxed(val, ctrl_base_addr + PCIE_EVENT_INT);
-+
-+ /* Disable host interrupts and clear any outstanding */
-+ writel_relaxed(0, bridge_base_addr + IMASK_HOST);
-+ writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
-+}
-+
-+static int mc_init_interrupts(struct platform_device *pdev, struct mc_pcie *port)
-+{
-+ struct device *dev = &pdev->dev;
-+ int irq;
-+ int i, intx_irq, msi_irq, event_irq;
-+ int ret;
-+
-+ ret = mc_pcie_init_irq_domains(port);
-+ if (ret) {
-+ dev_err(dev, "failed creating IRQ domains\n");
-+ return ret;
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0)
-+ return -ENODEV;
-+
-+ for (i = 0; i < NUM_EVENTS; i++) {
-+ event_irq = irq_create_mapping(port->event_domain, i);
-+ if (!event_irq) {
-+ dev_err(dev, "failed to map hwirq %d\n", i);
-+ return -ENXIO;
-+ }
-+
-+ ret = devm_request_irq(dev, event_irq, mc_event_handler,
-+ 0, event_cause[i].sym, port);
-+ if (ret) {
-+ dev_err(dev, "failed to request IRQ %d\n", event_irq);
-+ return ret;
-+ }
-+ }
-+
-+ intx_irq = irq_create_mapping(port->event_domain,
-+ EVENT_LOCAL_PM_MSI_INT_INTX);
-+ if (!intx_irq) {
-+ dev_err(dev, "failed to map INTx interrupt\n");
-+ return -ENXIO;
-+ }
-+
-+ /* Plug the INTx chained handler */
-+ irq_set_chained_handler_and_data(intx_irq, mc_handle_intx, port);
-+
-+ msi_irq = irq_create_mapping(port->event_domain,
-+ EVENT_LOCAL_PM_MSI_INT_MSI);
-+ if (!msi_irq)
-+ return -ENXIO;
-+
-+ /* Plug the MSI chained handler */
-+ irq_set_chained_handler_and_data(msi_irq, mc_handle_msi, port);
-+
-+ /* Plug the main event chained handler */
-+ irq_set_chained_handler_and_data(irq, mc_handle_event, port);
-+
-+ return 0;
-+}
-+
-+static int mc_platform_init(struct pci_config_window *cfg)
-+{
-+ struct device *dev = cfg->parent;
-+ struct platform_device *pdev = to_platform_device(dev);
-+ void __iomem *bridge_base_addr =
-+ port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ int ret;
-+
-+ /* Configure address translation table 0 for PCIe config space */
-+ mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
-+ cfg->res.start,
-+ resource_size(&cfg->res));
-+
-+ /* Need some fixups in config space */
-+ mc_pcie_enable_msi(port, cfg->win);
-+
-+ /* Configure non-config space outbound ranges */
-+ ret = mc_pcie_setup_windows(pdev, port);
-+ if (ret)
-+ return ret;
-+
-+ /* Address translation is up; safe to enable interrupts */
-+ ret = mc_init_interrupts(pdev, port);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int mc_host_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ void __iomem *bridge_base_addr;
-+ int ret;
-+ u32 val;
-+
-+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
-+ if (!port)
-+ return -ENOMEM;
-+
-+ port->dev = dev;
-+
-+ port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1);
-+ if (IS_ERR(port->axi_base_addr))
-+ return PTR_ERR(port->axi_base_addr);
-+
-+ mc_disable_interrupts(port);
-+
-+ bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+
-+ /* Allow enabling MSI by disabling MSI-X */
-+ val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
-+ val &= ~MSIX_CAP_MASK;
-+ writel(val, bridge_base_addr + PCIE_PCI_IRQ_DW0);
-+
-+ /* Pick num vectors from bitfile programmed onto FPGA fabric */
-+ val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
-+ val &= NUM_MSI_MSGS_MASK;
-+ val >>= NUM_MSI_MSGS_SHIFT;
-+
-+ port->msi.num_vectors = 1 << val;
-+
-+ /* Pick vector address from design */
-+ port->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
-+
-+ ret = mc_pcie_init_clks(dev);
-+ if (ret) {
-+ dev_err(dev, "failed to get clock resources, error %d\n", ret);
-+ return -ENODEV;
-+ }
-+
-+ return pci_host_common_probe(pdev);
-+}
-+
-+static const struct pci_ecam_ops mc_ecam_ops = {
-+ .init = mc_platform_init,
-+ .pci_ops = {
-+ .map_bus = pci_ecam_map_bus,
-+ .read = pci_generic_config_read,
-+ .write = pci_generic_config_write,
-+ }
-+};
-+
-+static const struct of_device_id mc_pcie_of_match[] = {
-+ {
-+ .compatible = "microchip,pcie-host-1.0",
-+ .data = &mc_ecam_ops,
-+ },
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(of, mc_pcie_of_match);
-+
-+static struct platform_driver mc_pcie_driver = {
-+ .probe = mc_host_probe,
-+ .driver = {
-+ .name = "microchip-pcie",
-+ .of_match_table = mc_pcie_of_match,
-+ .suppress_bind_attrs = true,
-+ },
-+};
-+
-+builtin_platform_driver(mc_pcie_driver);
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Microchip PCIe host controller driver");
-+MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
+++ /dev/null
-From eca1b864bb2d4e8d9811506979560a89351c2e37 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:53 +0800
-Subject: [PATCH 016/116] PCI: microchip: Move PLDA IP register macros to
- pcie-plda.h
-
-Move PLDA PCIe host controller IP registers macros to pcie-plda.h,
-including bridge registers and local IRQ event number.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 108 +++---------------
- drivers/pci/controller/plda/pcie-plda.h | 108 ++++++++++++++++++
- 2 files changed, 124 insertions(+), 92 deletions(-)
- create mode 100644 drivers/pci/controller/plda/pcie-plda.h
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -19,6 +19,7 @@
- #include <linux/platform_device.h>
-
- #include "../../pci.h"
-+#include "pcie-plda.h"
-
- /* Number of MSI IRQs */
- #define MC_MAX_NUM_MSI_IRQS 32
-@@ -30,84 +31,6 @@
- #define MC_PCIE_BRIDGE_ADDR (MC_PCIE1_BRIDGE_ADDR)
- #define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR)
-
--/* PCIe Bridge Phy Regs */
--#define PCIE_PCI_IRQ_DW0 0xa8
--#define MSIX_CAP_MASK BIT(31)
--#define NUM_MSI_MSGS_MASK GENMASK(6, 4)
--#define NUM_MSI_MSGS_SHIFT 4
--
--#define IMASK_LOCAL 0x180
--#define DMA_END_ENGINE_0_MASK 0x00000000u
--#define DMA_END_ENGINE_0_SHIFT 0
--#define DMA_END_ENGINE_1_MASK 0x00000000u
--#define DMA_END_ENGINE_1_SHIFT 1
--#define DMA_ERROR_ENGINE_0_MASK 0x00000100u
--#define DMA_ERROR_ENGINE_0_SHIFT 8
--#define DMA_ERROR_ENGINE_1_MASK 0x00000200u
--#define DMA_ERROR_ENGINE_1_SHIFT 9
--#define A_ATR_EVT_POST_ERR_MASK 0x00010000u
--#define A_ATR_EVT_POST_ERR_SHIFT 16
--#define A_ATR_EVT_FETCH_ERR_MASK 0x00020000u
--#define A_ATR_EVT_FETCH_ERR_SHIFT 17
--#define A_ATR_EVT_DISCARD_ERR_MASK 0x00040000u
--#define A_ATR_EVT_DISCARD_ERR_SHIFT 18
--#define A_ATR_EVT_DOORBELL_MASK 0x00000000u
--#define A_ATR_EVT_DOORBELL_SHIFT 19
--#define P_ATR_EVT_POST_ERR_MASK 0x00100000u
--#define P_ATR_EVT_POST_ERR_SHIFT 20
--#define P_ATR_EVT_FETCH_ERR_MASK 0x00200000u
--#define P_ATR_EVT_FETCH_ERR_SHIFT 21
--#define P_ATR_EVT_DISCARD_ERR_MASK 0x00400000u
--#define P_ATR_EVT_DISCARD_ERR_SHIFT 22
--#define P_ATR_EVT_DOORBELL_MASK 0x00000000u
--#define P_ATR_EVT_DOORBELL_SHIFT 23
--#define PM_MSI_INT_INTA_MASK 0x01000000u
--#define PM_MSI_INT_INTA_SHIFT 24
--#define PM_MSI_INT_INTB_MASK 0x02000000u
--#define PM_MSI_INT_INTB_SHIFT 25
--#define PM_MSI_INT_INTC_MASK 0x04000000u
--#define PM_MSI_INT_INTC_SHIFT 26
--#define PM_MSI_INT_INTD_MASK 0x08000000u
--#define PM_MSI_INT_INTD_SHIFT 27
--#define PM_MSI_INT_INTX_MASK 0x0f000000u
--#define PM_MSI_INT_INTX_SHIFT 24
--#define PM_MSI_INT_MSI_MASK 0x10000000u
--#define PM_MSI_INT_MSI_SHIFT 28
--#define PM_MSI_INT_AER_EVT_MASK 0x20000000u
--#define PM_MSI_INT_AER_EVT_SHIFT 29
--#define PM_MSI_INT_EVENTS_MASK 0x40000000u
--#define PM_MSI_INT_EVENTS_SHIFT 30
--#define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
--#define PM_MSI_INT_SYS_ERR_SHIFT 31
--#define NUM_LOCAL_EVENTS 15
--#define ISTATUS_LOCAL 0x184
--#define IMASK_HOST 0x188
--#define ISTATUS_HOST 0x18c
--#define IMSI_ADDR 0x190
--#define ISTATUS_MSI 0x194
--
--/* PCIe Master table init defines */
--#define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u
--#define ATR0_PCIE_ATR_SIZE 0x25
--#define ATR0_PCIE_ATR_SIZE_SHIFT 1
--#define ATR0_PCIE_WIN0_SRC_ADDR 0x604u
--#define ATR0_PCIE_WIN0_TRSL_ADDR_LSB 0x608u
--#define ATR0_PCIE_WIN0_TRSL_ADDR_UDW 0x60cu
--#define ATR0_PCIE_WIN0_TRSL_PARAM 0x610u
--
--/* PCIe AXI slave table init defines */
--#define ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u
--#define ATR_SIZE_SHIFT 1
--#define ATR_IMPL_ENABLE 1
--#define ATR0_AXI4_SLV0_SRC_ADDR 0x804u
--#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u
--#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu
--#define ATR0_AXI4_SLV0_TRSL_PARAM 0x810u
--#define PCIE_TX_RX_INTERFACE 0x00000000u
--#define PCIE_CONFIG_INTERFACE 0x00000001u
--
--#define ATR_ENTRY_SIZE 32
--
- /* PCIe Controller Phy Regs */
- #define SEC_ERROR_EVENT_CNT 0x20
- #define DED_ERROR_EVENT_CNT 0x24
-@@ -179,20 +102,21 @@
- #define EVENT_LOCAL_DMA_END_ENGINE_1 12
- #define EVENT_LOCAL_DMA_ERROR_ENGINE_0 13
- #define EVENT_LOCAL_DMA_ERROR_ENGINE_1 14
--#define EVENT_LOCAL_A_ATR_EVT_POST_ERR 15
--#define EVENT_LOCAL_A_ATR_EVT_FETCH_ERR 16
--#define EVENT_LOCAL_A_ATR_EVT_DISCARD_ERR 17
--#define EVENT_LOCAL_A_ATR_EVT_DOORBELL 18
--#define EVENT_LOCAL_P_ATR_EVT_POST_ERR 19
--#define EVENT_LOCAL_P_ATR_EVT_FETCH_ERR 20
--#define EVENT_LOCAL_P_ATR_EVT_DISCARD_ERR 21
--#define EVENT_LOCAL_P_ATR_EVT_DOORBELL 22
--#define EVENT_LOCAL_PM_MSI_INT_INTX 23
--#define EVENT_LOCAL_PM_MSI_INT_MSI 24
--#define EVENT_LOCAL_PM_MSI_INT_AER_EVT 25
--#define EVENT_LOCAL_PM_MSI_INT_EVENTS 26
--#define EVENT_LOCAL_PM_MSI_INT_SYS_ERR 27
--#define NUM_EVENTS 28
-+#define NUM_MC_EVENTS 15
-+#define EVENT_LOCAL_A_ATR_EVT_POST_ERR (NUM_MC_EVENTS + PLDA_AXI_POST_ERR)
-+#define EVENT_LOCAL_A_ATR_EVT_FETCH_ERR (NUM_MC_EVENTS + PLDA_AXI_FETCH_ERR)
-+#define EVENT_LOCAL_A_ATR_EVT_DISCARD_ERR (NUM_MC_EVENTS + PLDA_AXI_DISCARD_ERR)
-+#define EVENT_LOCAL_A_ATR_EVT_DOORBELL (NUM_MC_EVENTS + PLDA_AXI_DOORBELL)
-+#define EVENT_LOCAL_P_ATR_EVT_POST_ERR (NUM_MC_EVENTS + PLDA_PCIE_POST_ERR)
-+#define EVENT_LOCAL_P_ATR_EVT_FETCH_ERR (NUM_MC_EVENTS + PLDA_PCIE_FETCH_ERR)
-+#define EVENT_LOCAL_P_ATR_EVT_DISCARD_ERR (NUM_MC_EVENTS + PLDA_PCIE_DISCARD_ERR)
-+#define EVENT_LOCAL_P_ATR_EVT_DOORBELL (NUM_MC_EVENTS + PLDA_PCIE_DOORBELL)
-+#define EVENT_LOCAL_PM_MSI_INT_INTX (NUM_MC_EVENTS + PLDA_INTX)
-+#define EVENT_LOCAL_PM_MSI_INT_MSI (NUM_MC_EVENTS + PLDA_MSI)
-+#define EVENT_LOCAL_PM_MSI_INT_AER_EVT (NUM_MC_EVENTS + PLDA_AER_EVENT)
-+#define EVENT_LOCAL_PM_MSI_INT_EVENTS (NUM_MC_EVENTS + PLDA_MISC_EVENTS)
-+#define EVENT_LOCAL_PM_MSI_INT_SYS_ERR (NUM_MC_EVENTS + PLDA_SYS_ERR)
-+#define NUM_EVENTS (NUM_MC_EVENTS + PLDA_INT_EVENT_NUM)
-
- #define PCIE_EVENT_CAUSE(x, s) \
- [EVENT_PCIE_ ## x] = { __stringify(x), s }
---- /dev/null
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -0,0 +1,108 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * PLDA PCIe host controller driver
-+ */
-+
-+#ifndef _PCIE_PLDA_H
-+#define _PCIE_PLDA_H
-+
-+/* PCIe Bridge Phy Regs */
-+#define PCIE_PCI_IRQ_DW0 0xa8
-+#define MSIX_CAP_MASK BIT(31)
-+#define NUM_MSI_MSGS_MASK GENMASK(6, 4)
-+#define NUM_MSI_MSGS_SHIFT 4
-+
-+#define IMASK_LOCAL 0x180
-+#define DMA_END_ENGINE_0_MASK 0x00000000u
-+#define DMA_END_ENGINE_0_SHIFT 0
-+#define DMA_END_ENGINE_1_MASK 0x00000000u
-+#define DMA_END_ENGINE_1_SHIFT 1
-+#define DMA_ERROR_ENGINE_0_MASK 0x00000100u
-+#define DMA_ERROR_ENGINE_0_SHIFT 8
-+#define DMA_ERROR_ENGINE_1_MASK 0x00000200u
-+#define DMA_ERROR_ENGINE_1_SHIFT 9
-+#define A_ATR_EVT_POST_ERR_MASK 0x00010000u
-+#define A_ATR_EVT_POST_ERR_SHIFT 16
-+#define A_ATR_EVT_FETCH_ERR_MASK 0x00020000u
-+#define A_ATR_EVT_FETCH_ERR_SHIFT 17
-+#define A_ATR_EVT_DISCARD_ERR_MASK 0x00040000u
-+#define A_ATR_EVT_DISCARD_ERR_SHIFT 18
-+#define A_ATR_EVT_DOORBELL_MASK 0x00000000u
-+#define A_ATR_EVT_DOORBELL_SHIFT 19
-+#define P_ATR_EVT_POST_ERR_MASK 0x00100000u
-+#define P_ATR_EVT_POST_ERR_SHIFT 20
-+#define P_ATR_EVT_FETCH_ERR_MASK 0x00200000u
-+#define P_ATR_EVT_FETCH_ERR_SHIFT 21
-+#define P_ATR_EVT_DISCARD_ERR_MASK 0x00400000u
-+#define P_ATR_EVT_DISCARD_ERR_SHIFT 22
-+#define P_ATR_EVT_DOORBELL_MASK 0x00000000u
-+#define P_ATR_EVT_DOORBELL_SHIFT 23
-+#define PM_MSI_INT_INTA_MASK 0x01000000u
-+#define PM_MSI_INT_INTA_SHIFT 24
-+#define PM_MSI_INT_INTB_MASK 0x02000000u
-+#define PM_MSI_INT_INTB_SHIFT 25
-+#define PM_MSI_INT_INTC_MASK 0x04000000u
-+#define PM_MSI_INT_INTC_SHIFT 26
-+#define PM_MSI_INT_INTD_MASK 0x08000000u
-+#define PM_MSI_INT_INTD_SHIFT 27
-+#define PM_MSI_INT_INTX_MASK 0x0f000000u
-+#define PM_MSI_INT_INTX_SHIFT 24
-+#define PM_MSI_INT_MSI_MASK 0x10000000u
-+#define PM_MSI_INT_MSI_SHIFT 28
-+#define PM_MSI_INT_AER_EVT_MASK 0x20000000u
-+#define PM_MSI_INT_AER_EVT_SHIFT 29
-+#define PM_MSI_INT_EVENTS_MASK 0x40000000u
-+#define PM_MSI_INT_EVENTS_SHIFT 30
-+#define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
-+#define PM_MSI_INT_SYS_ERR_SHIFT 31
-+#define NUM_LOCAL_EVENTS 15
-+#define ISTATUS_LOCAL 0x184
-+#define IMASK_HOST 0x188
-+#define ISTATUS_HOST 0x18c
-+#define IMSI_ADDR 0x190
-+#define ISTATUS_MSI 0x194
-+
-+/* PCIe Master table init defines */
-+#define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u
-+#define ATR0_PCIE_ATR_SIZE 0x25
-+#define ATR0_PCIE_ATR_SIZE_SHIFT 1
-+#define ATR0_PCIE_WIN0_SRC_ADDR 0x604u
-+#define ATR0_PCIE_WIN0_TRSL_ADDR_LSB 0x608u
-+#define ATR0_PCIE_WIN0_TRSL_ADDR_UDW 0x60cu
-+#define ATR0_PCIE_WIN0_TRSL_PARAM 0x610u
-+
-+/* PCIe AXI slave table init defines */
-+#define ATR0_AXI4_SLV0_SRCADDR_PARAM 0x800u
-+#define ATR_SIZE_SHIFT 1
-+#define ATR_IMPL_ENABLE 1
-+#define ATR0_AXI4_SLV0_SRC_ADDR 0x804u
-+#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB 0x808u
-+#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW 0x80cu
-+#define ATR0_AXI4_SLV0_TRSL_PARAM 0x810u
-+#define PCIE_TX_RX_INTERFACE 0x00000000u
-+#define PCIE_CONFIG_INTERFACE 0x00000001u
-+
-+#define ATR_ENTRY_SIZE 32
-+
-+enum plda_int_event {
-+ PLDA_AXI_POST_ERR,
-+ PLDA_AXI_FETCH_ERR,
-+ PLDA_AXI_DISCARD_ERR,
-+ PLDA_AXI_DOORBELL,
-+ PLDA_PCIE_POST_ERR,
-+ PLDA_PCIE_FETCH_ERR,
-+ PLDA_PCIE_DISCARD_ERR,
-+ PLDA_PCIE_DOORBELL,
-+ PLDA_INTX,
-+ PLDA_MSI,
-+ PLDA_AER_EVENT,
-+ PLDA_MISC_EVENTS,
-+ PLDA_SYS_ERR,
-+ PLDA_INT_EVENT_NUM
-+};
-+
-+#define PLDA_NUM_DMA_EVENTS 16
-+
-+#define PLDA_MAX_INT_NUM (PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
-+
-+#endif
+++ /dev/null
-From 6ee4d4568314425079ae88229bb9abbff9b92b8b Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:54 +0800
-Subject: [PATCH 017/116] PCI: microchip: Add bridge_addr field to struct
- mc_pcie
-
-For bridge address base is common PLDA field, Add this to struct mc_pcie
-first.
-
-INTx and MSI codes interrupts codes will get the bridge base address from
-port->bridge_addr. These codes will be changed to common codes.
-axi_base_addr is Microchip its own data.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 23 ++++++++-----------
- 1 file changed, 9 insertions(+), 14 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -195,6 +195,7 @@ struct mc_pcie {
- struct irq_domain *event_domain;
- raw_spinlock_t lock;
- struct mc_msi msi;
-+ void __iomem *bridge_addr;
- };
-
- struct cause {
-@@ -339,8 +340,7 @@ static void mc_handle_msi(struct irq_des
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct device *dev = port->dev;
- struct mc_msi *msi = &port->msi;
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long status;
- u32 bit;
- int ret;
-@@ -365,8 +365,7 @@ static void mc_handle_msi(struct irq_des
- static void mc_msi_bottom_irq_ack(struct irq_data *data)
- {
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
- u32 bitpos = data->hwirq;
-
- writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
-@@ -488,8 +487,7 @@ static void mc_handle_intx(struct irq_de
- struct mc_pcie *port = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct device *dev = port->dev;
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long status;
- u32 bit;
- int ret;
-@@ -514,8 +512,7 @@ static void mc_handle_intx(struct irq_de
- static void mc_ack_intx_irq(struct irq_data *data)
- {
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-
- writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
-@@ -524,8 +521,7 @@ static void mc_ack_intx_irq(struct irq_d
- static void mc_mask_intx_irq(struct irq_data *data)
- {
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long flags;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
- u32 val;
-@@ -540,8 +536,7 @@ static void mc_mask_intx_irq(struct irq_
- static void mc_unmask_intx_irq(struct irq_data *data)
- {
- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long flags;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
- u32 val;
-@@ -896,8 +891,7 @@ static void mc_pcie_setup_window(void __
- static int mc_pcie_setup_windows(struct platform_device *pdev,
- struct mc_pcie *port)
- {
-- void __iomem *bridge_base_addr =
-- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
- struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
- struct resource_entry *entry;
- u64 pci_addr;
-@@ -1081,6 +1075,7 @@ static int mc_host_probe(struct platform
- mc_disable_interrupts(port);
-
- bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-+ port->bridge_addr = bridge_base_addr;
-
- /* Allow enabling MSI by disabling MSI-X */
- val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
+++ /dev/null
-From 7c1c679bdd0b6b727248edbee77836024c935f91 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:55 +0800
-Subject: [PATCH 018/116] PCI: microchip: Rename two PCIe data structures
-
-Add PLDA PCIe related data structures by rename data structure name from
-mc_* to plda_*.
-
-axi_base_addr is stayed in struct mc_pcie for it's microchip its own data.
-
-The event interrupt codes is still using struct mc_pcie because the event
-interrupt codes can not be re-used.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 96 ++++++++++---------
- 1 file changed, 53 insertions(+), 43 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -22,7 +22,7 @@
- #include "pcie-plda.h"
-
- /* Number of MSI IRQs */
--#define MC_MAX_NUM_MSI_IRQS 32
-+#define PLDA_MAX_NUM_MSI_IRQS 32
-
- /* PCIe Bridge Phy and Controller Phy offsets */
- #define MC_PCIE1_BRIDGE_ADDR 0x00008000u
-@@ -179,25 +179,29 @@ struct event_map {
- u32 event_bit;
- };
-
--struct mc_msi {
-+struct plda_msi {
- struct mutex lock; /* Protect used bitmap */
- struct irq_domain *msi_domain;
- struct irq_domain *dev_domain;
- u32 num_vectors;
- u64 vector_phy;
-- DECLARE_BITMAP(used, MC_MAX_NUM_MSI_IRQS);
-+ DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
- };
-
--struct mc_pcie {
-- void __iomem *axi_base_addr;
-+struct plda_pcie_rp {
- struct device *dev;
- struct irq_domain *intx_domain;
- struct irq_domain *event_domain;
- raw_spinlock_t lock;
-- struct mc_msi msi;
-+ struct plda_msi msi;
- void __iomem *bridge_addr;
- };
-
-+struct mc_pcie {
-+ struct plda_pcie_rp plda;
-+ void __iomem *axi_base_addr;
-+};
-+
- struct cause {
- const char *sym;
- const char *str;
-@@ -313,7 +317,7 @@ static struct mc_pcie *port;
-
- static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
- {
-- struct mc_msi *msi = &port->msi;
-+ struct plda_msi *msi = &port->plda.msi;
- u16 reg;
- u8 queue_size;
-
-@@ -336,10 +340,10 @@ static void mc_pcie_enable_msi(struct mc
-
- static void mc_handle_msi(struct irq_desc *desc)
- {
-- struct mc_pcie *port = irq_desc_get_handler_data(desc);
-+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct device *dev = port->dev;
-- struct mc_msi *msi = &port->msi;
-+ struct plda_msi *msi = &port->msi;
- void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long status;
- u32 bit;
-@@ -364,7 +368,7 @@ static void mc_handle_msi(struct irq_des
-
- static void mc_msi_bottom_irq_ack(struct irq_data *data)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- u32 bitpos = data->hwirq;
-
-@@ -373,7 +377,7 @@ static void mc_msi_bottom_irq_ack(struct
-
- static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- phys_addr_t addr = port->msi.vector_phy;
-
- msg->address_lo = lower_32_bits(addr);
-@@ -400,8 +404,8 @@ static struct irq_chip mc_msi_bottom_irq
- static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
- unsigned int nr_irqs, void *args)
- {
-- struct mc_pcie *port = domain->host_data;
-- struct mc_msi *msi = &port->msi;
-+ struct plda_pcie_rp *port = domain->host_data;
-+ struct plda_msi *msi = &port->msi;
- unsigned long bit;
-
- mutex_lock(&msi->lock);
-@@ -425,8 +429,8 @@ static void mc_irq_msi_domain_free(struc
- unsigned int nr_irqs)
- {
- struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-- struct mc_pcie *port = irq_data_get_irq_chip_data(d);
-- struct mc_msi *msi = &port->msi;
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
-+ struct plda_msi *msi = &port->msi;
-
- mutex_lock(&msi->lock);
-
-@@ -456,11 +460,11 @@ static struct msi_domain_info mc_msi_dom
- .chip = &mc_msi_irq_chip,
- };
-
--static int mc_allocate_msi_domains(struct mc_pcie *port)
-+static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
- {
- struct device *dev = port->dev;
- struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
-- struct mc_msi *msi = &port->msi;
-+ struct plda_msi *msi = &port->msi;
-
- mutex_init(&port->msi.lock);
-
-@@ -484,7 +488,7 @@ static int mc_allocate_msi_domains(struc
-
- static void mc_handle_intx(struct irq_desc *desc)
- {
-- struct mc_pcie *port = irq_desc_get_handler_data(desc);
-+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct device *dev = port->dev;
- void __iomem *bridge_base_addr = port->bridge_addr;
-@@ -511,7 +515,7 @@ static void mc_handle_intx(struct irq_de
-
- static void mc_ack_intx_irq(struct irq_data *data)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-
-@@ -520,7 +524,7 @@ static void mc_ack_intx_irq(struct irq_d
-
- static void mc_mask_intx_irq(struct irq_data *data)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long flags;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-@@ -535,7 +539,7 @@ static void mc_mask_intx_irq(struct irq_
-
- static void mc_unmask_intx_irq(struct irq_data *data)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
- unsigned long flags;
- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-@@ -625,21 +629,22 @@ static u32 local_events(struct mc_pcie *
- return val;
- }
-
--static u32 get_events(struct mc_pcie *port)
-+static u32 get_events(struct plda_pcie_rp *port)
- {
-+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
- u32 events = 0;
-
-- events |= pcie_events(port);
-- events |= sec_errors(port);
-- events |= ded_errors(port);
-- events |= local_events(port);
-+ events |= pcie_events(mc_port);
-+ events |= sec_errors(mc_port);
-+ events |= ded_errors(mc_port);
-+ events |= local_events(mc_port);
-
- return events;
- }
-
- static irqreturn_t mc_event_handler(int irq, void *dev_id)
- {
-- struct mc_pcie *port = dev_id;
-+ struct plda_pcie_rp *port = dev_id;
- struct device *dev = port->dev;
- struct irq_data *data;
-
-@@ -655,7 +660,7 @@ static irqreturn_t mc_event_handler(int
-
- static void mc_handle_event(struct irq_desc *desc)
- {
-- struct mc_pcie *port = irq_desc_get_handler_data(desc);
-+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- unsigned long events;
- u32 bit;
- struct irq_chip *chip = irq_desc_get_chip(desc);
-@@ -672,12 +677,13 @@ static void mc_handle_event(struct irq_d
-
- static void mc_ack_event_irq(struct irq_data *data)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
- u32 event = data->hwirq;
- void __iomem *addr;
- u32 mask;
-
-- addr = port->axi_base_addr + event_descs[event].base +
-+ addr = mc_port->axi_base_addr + event_descs[event].base +
- event_descs[event].offset;
- mask = event_descs[event].mask;
- mask |= event_descs[event].enb_mask;
-@@ -687,13 +693,14 @@ static void mc_ack_event_irq(struct irq_
-
- static void mc_mask_event_irq(struct irq_data *data)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
- u32 event = data->hwirq;
- void __iomem *addr;
- u32 mask;
- u32 val;
-
-- addr = port->axi_base_addr + event_descs[event].base +
-+ addr = mc_port->axi_base_addr + event_descs[event].base +
- event_descs[event].mask_offset;
- mask = event_descs[event].mask;
- if (event_descs[event].enb_mask) {
-@@ -717,13 +724,14 @@ static void mc_mask_event_irq(struct irq
-
- static void mc_unmask_event_irq(struct irq_data *data)
- {
-- struct mc_pcie *port = irq_data_get_irq_chip_data(data);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
- u32 event = data->hwirq;
- void __iomem *addr;
- u32 mask;
- u32 val;
-
-- addr = port->axi_base_addr + event_descs[event].base +
-+ addr = mc_port->axi_base_addr + event_descs[event].base +
- event_descs[event].mask_offset;
- mask = event_descs[event].mask;
-
-@@ -811,7 +819,7 @@ static int mc_pcie_init_clks(struct devi
- return 0;
- }
-
--static int mc_pcie_init_irq_domains(struct mc_pcie *port)
-+static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
- {
- struct device *dev = port->dev;
- struct device_node *node = dev->of_node;
-@@ -889,7 +897,7 @@ static void mc_pcie_setup_window(void __
- }
-
- static int mc_pcie_setup_windows(struct platform_device *pdev,
-- struct mc_pcie *port)
-+ struct plda_pcie_rp *port)
- {
- void __iomem *bridge_base_addr = port->bridge_addr;
- struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
-@@ -970,7 +978,7 @@ static void mc_disable_interrupts(struct
- writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
- }
-
--static int mc_init_interrupts(struct platform_device *pdev, struct mc_pcie *port)
-+static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
- {
- struct device *dev = &pdev->dev;
- int irq;
-@@ -1043,12 +1051,12 @@ static int mc_platform_init(struct pci_c
- mc_pcie_enable_msi(port, cfg->win);
-
- /* Configure non-config space outbound ranges */
-- ret = mc_pcie_setup_windows(pdev, port);
-+ ret = mc_pcie_setup_windows(pdev, &port->plda);
- if (ret)
- return ret;
-
- /* Address translation is up; safe to enable interrupts */
-- ret = mc_init_interrupts(pdev, port);
-+ ret = mc_init_interrupts(pdev, &port->plda);
- if (ret)
- return ret;
-
-@@ -1059,6 +1067,7 @@ static int mc_host_probe(struct platform
- {
- struct device *dev = &pdev->dev;
- void __iomem *bridge_base_addr;
-+ struct plda_pcie_rp *plda;
- int ret;
- u32 val;
-
-@@ -1066,7 +1075,8 @@ static int mc_host_probe(struct platform
- if (!port)
- return -ENOMEM;
-
-- port->dev = dev;
-+ plda = &port->plda;
-+ plda->dev = dev;
-
- port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1);
- if (IS_ERR(port->axi_base_addr))
-@@ -1075,7 +1085,7 @@ static int mc_host_probe(struct platform
- mc_disable_interrupts(port);
-
- bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
-- port->bridge_addr = bridge_base_addr;
-+ plda->bridge_addr = bridge_base_addr;
-
- /* Allow enabling MSI by disabling MSI-X */
- val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
-@@ -1087,10 +1097,10 @@ static int mc_host_probe(struct platform
- val &= NUM_MSI_MSGS_MASK;
- val >>= NUM_MSI_MSGS_SHIFT;
-
-- port->msi.num_vectors = 1 << val;
-+ plda->msi.num_vectors = 1 << val;
-
- /* Pick vector address from design */
-- port->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
-+ plda->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
-
- ret = mc_pcie_init_clks(dev);
- if (ret) {
+++ /dev/null
-From a53cf9b237dd53c9538b51a8df592888935c8411 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:56 +0800
-Subject: [PATCH 019/116] PCI: microchip: Move PCIe host data structures to
- plda-pcie.h
-
-Move the common data structures definition to head file for these two data
-structures can be re-used.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 20 ------------------
- drivers/pci/controller/plda/pcie-plda.h | 21 +++++++++++++++++++
- 2 files changed, 21 insertions(+), 20 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -21,9 +21,6 @@
- #include "../../pci.h"
- #include "pcie-plda.h"
-
--/* Number of MSI IRQs */
--#define PLDA_MAX_NUM_MSI_IRQS 32
--
- /* PCIe Bridge Phy and Controller Phy offsets */
- #define MC_PCIE1_BRIDGE_ADDR 0x00008000u
- #define MC_PCIE1_CTRL_ADDR 0x0000a000u
-@@ -179,23 +176,6 @@ struct event_map {
- u32 event_bit;
- };
-
--struct plda_msi {
-- struct mutex lock; /* Protect used bitmap */
-- struct irq_domain *msi_domain;
-- struct irq_domain *dev_domain;
-- u32 num_vectors;
-- u64 vector_phy;
-- DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
--};
--
--struct plda_pcie_rp {
-- struct device *dev;
-- struct irq_domain *intx_domain;
-- struct irq_domain *event_domain;
-- raw_spinlock_t lock;
-- struct plda_msi msi;
-- void __iomem *bridge_addr;
--};
-
- struct mc_pcie {
- struct plda_pcie_rp plda;
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -6,6 +6,9 @@
- #ifndef _PCIE_PLDA_H
- #define _PCIE_PLDA_H
-
-+/* Number of MSI IRQs */
-+#define PLDA_MAX_NUM_MSI_IRQS 32
-+
- /* PCIe Bridge Phy Regs */
- #define PCIE_PCI_IRQ_DW0 0xa8
- #define MSIX_CAP_MASK BIT(31)
-@@ -105,4 +108,22 @@ enum plda_int_event {
-
- #define PLDA_MAX_INT_NUM (PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
-
-+struct plda_msi {
-+ struct mutex lock; /* Protect used bitmap */
-+ struct irq_domain *msi_domain;
-+ struct irq_domain *dev_domain;
-+ u32 num_vectors;
-+ u64 vector_phy;
-+ DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
-+};
-+
-+struct plda_pcie_rp {
-+ struct device *dev;
-+ struct irq_domain *intx_domain;
-+ struct irq_domain *event_domain;
-+ raw_spinlock_t lock;
-+ struct plda_msi msi;
-+ void __iomem *bridge_addr;
-+};
-+
- #endif
+++ /dev/null
-From d0e56d1ef7398bbf76be6e48d77943cbf644688e Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:57 +0800
-Subject: [PATCH 020/116] PCI: microchip: Rename two setup functions
-
-Rename two setup functions to plda prefix. Prepare to re-use these two
-setup function.
-
-For two setup functions names are similar, rename mc_pcie_setup_windows()
-to plda_pcie_setup_iomems().
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 24 +++++++++----------
- 1 file changed, 12 insertions(+), 12 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -838,9 +838,9 @@ static int mc_pcie_init_irq_domains(stru
- return mc_allocate_msi_domains(port);
- }
-
--static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
-- phys_addr_t axi_addr, phys_addr_t pci_addr,
-- size_t size)
-+static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
-+ phys_addr_t axi_addr, phys_addr_t pci_addr,
-+ size_t size)
- {
- u32 atr_sz = ilog2(size) - 1;
- u32 val;
-@@ -876,8 +876,8 @@ static void mc_pcie_setup_window(void __
- writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
- }
-
--static int mc_pcie_setup_windows(struct platform_device *pdev,
-- struct plda_pcie_rp *port)
-+static int plda_pcie_setup_iomems(struct platform_device *pdev,
-+ struct plda_pcie_rp *port)
- {
- void __iomem *bridge_base_addr = port->bridge_addr;
- struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
-@@ -888,9 +888,9 @@ static int mc_pcie_setup_windows(struct
- resource_list_for_each_entry(entry, &bridge->windows) {
- if (resource_type(entry->res) == IORESOURCE_MEM) {
- pci_addr = entry->res->start - entry->offset;
-- mc_pcie_setup_window(bridge_base_addr, index,
-- entry->res->start, pci_addr,
-- resource_size(entry->res));
-+ plda_pcie_setup_window(bridge_base_addr, index,
-+ entry->res->start, pci_addr,
-+ resource_size(entry->res));
- index++;
- }
- }
-@@ -1023,15 +1023,15 @@ static int mc_platform_init(struct pci_c
- int ret;
-
- /* Configure address translation table 0 for PCIe config space */
-- mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
-- cfg->res.start,
-- resource_size(&cfg->res));
-+ plda_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
-+ cfg->res.start,
-+ resource_size(&cfg->res));
-
- /* Need some fixups in config space */
- mc_pcie_enable_msi(port, cfg->win);
-
- /* Configure non-config space outbound ranges */
-- ret = mc_pcie_setup_windows(pdev, &port->plda);
-+ ret = plda_pcie_setup_iomems(pdev, &port->plda);
- if (ret)
- return ret;
-
+++ /dev/null
-From 2fd7c88ef318fd39023ce1eb73f37a29fbd25d74 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:58 +0800
-Subject: [PATCH 021/116] PCI: microchip: Change the argument of
- plda_pcie_setup_iomems()
-
-If other vendor do not select PCI_HOST_COMMON, the driver data is not
-struct pci_host_bridge.
-
-Move calling platform_get_drvdata() to mc_platform_init().
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- drivers/pci/controller/plda/pcie-microchip-host.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -876,11 +876,10 @@ static void plda_pcie_setup_window(void
- writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
- }
-
--static int plda_pcie_setup_iomems(struct platform_device *pdev,
-+static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
- struct plda_pcie_rp *port)
- {
- void __iomem *bridge_base_addr = port->bridge_addr;
-- struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
- struct resource_entry *entry;
- u64 pci_addr;
- u32 index = 1;
-@@ -1018,6 +1017,7 @@ static int mc_platform_init(struct pci_c
- {
- struct device *dev = cfg->parent;
- struct platform_device *pdev = to_platform_device(dev);
-+ struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
- void __iomem *bridge_base_addr =
- port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
- int ret;
-@@ -1031,7 +1031,7 @@ static int mc_platform_init(struct pci_c
- mc_pcie_enable_msi(port, cfg->win);
-
- /* Configure non-config space outbound ranges */
-- ret = plda_pcie_setup_iomems(pdev, &port->plda);
-+ ret = plda_pcie_setup_iomems(bridge, &port->plda);
- if (ret)
- return ret;
-
+++ /dev/null
-From 201ce99897ff5fff2612cb633406e90c1b2acbcf Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:05:59 +0800
-Subject: [PATCH 022/116] PCI: microchip: Move setup functions to
- pcie-plda-host.c
-
-Move setup functions to common pcie-plda-host.c. So these two functions
-can be re-used.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- drivers/pci/controller/plda/Kconfig | 4 +
- drivers/pci/controller/plda/Makefile | 1 +
- .../pci/controller/plda/pcie-microchip-host.c | 59 ---------------
- drivers/pci/controller/plda/pcie-plda-host.c | 74 +++++++++++++++++++
- drivers/pci/controller/plda/pcie-plda.h | 5 ++
- 5 files changed, 84 insertions(+), 59 deletions(-)
- create mode 100644 drivers/pci/controller/plda/pcie-plda-host.c
-
---- a/drivers/pci/controller/plda/Kconfig
-+++ b/drivers/pci/controller/plda/Kconfig
-@@ -3,10 +3,14 @@
- menu "PLDA-based PCIe controllers"
- depends on PCI
-
-+config PCIE_PLDA_HOST
-+ bool
-+
- config PCIE_MICROCHIP_HOST
- tristate "Microchip AXI PCIe controller"
- depends on PCI_MSI && OF
- select PCI_HOST_COMMON
-+ select PCIE_PLDA_HOST
- help
- Say Y here if you want kernel to support the Microchip AXI PCIe
- Host Bridge driver.
---- a/drivers/pci/controller/plda/Makefile
-+++ b/drivers/pci/controller/plda/Makefile
-@@ -1,2 +1,3 @@
- # SPDX-License-Identifier: GPL-2.0
-+obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
- obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -838,65 +838,6 @@ static int mc_pcie_init_irq_domains(stru
- return mc_allocate_msi_domains(port);
- }
-
--static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
-- phys_addr_t axi_addr, phys_addr_t pci_addr,
-- size_t size)
--{
-- u32 atr_sz = ilog2(size) - 1;
-- u32 val;
--
-- if (index == 0)
-- val = PCIE_CONFIG_INTERFACE;
-- else
-- val = PCIE_TX_RX_INTERFACE;
--
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_TRSL_PARAM);
--
-- val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
-- ATR_IMPL_ENABLE;
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_SRCADDR_PARAM);
--
-- val = upper_32_bits(axi_addr);
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_SRC_ADDR);
--
-- val = lower_32_bits(pci_addr);
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
--
-- val = upper_32_bits(pci_addr);
-- writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-- ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
--
-- val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-- val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
-- writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-- writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
--}
--
--static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
-- struct plda_pcie_rp *port)
--{
-- void __iomem *bridge_base_addr = port->bridge_addr;
-- struct resource_entry *entry;
-- u64 pci_addr;
-- u32 index = 1;
--
-- resource_list_for_each_entry(entry, &bridge->windows) {
-- if (resource_type(entry->res) == IORESOURCE_MEM) {
-- pci_addr = entry->res->start - entry->offset;
-- plda_pcie_setup_window(bridge_base_addr, index,
-- entry->res->start, pci_addr,
-- resource_size(entry->res));
-- index++;
-- }
-- }
--
-- return 0;
--}
--
- static inline void mc_clear_secs(struct mc_pcie *port)
- {
- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
---- /dev/null
-+++ b/drivers/pci/controller/plda/pcie-plda-host.c
-@@ -0,0 +1,74 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * PLDA PCIe XpressRich host controller driver
-+ *
-+ * Copyright (C) 2023 Microchip Co. Ltd
-+ *
-+ * Author: Daire McNamara <daire.mcnamara@microchip.com>
-+ */
-+
-+#include <linux/pci_regs.h>
-+#include <linux/pci-ecam.h>
-+
-+#include "pcie-plda.h"
-+
-+void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
-+ phys_addr_t axi_addr, phys_addr_t pci_addr,
-+ size_t size)
-+{
-+ u32 atr_sz = ilog2(size) - 1;
-+ u32 val;
-+
-+ if (index == 0)
-+ val = PCIE_CONFIG_INTERFACE;
-+ else
-+ val = PCIE_TX_RX_INTERFACE;
-+
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_TRSL_PARAM);
-+
-+ val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
-+ ATR_IMPL_ENABLE;
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_SRCADDR_PARAM);
-+
-+ val = upper_32_bits(axi_addr);
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_SRC_ADDR);
-+
-+ val = lower_32_bits(pci_addr);
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
-+
-+ val = upper_32_bits(pci_addr);
-+ writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
-+ ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
-+
-+ val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-+ val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
-+ writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
-+ writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
-+}
-+EXPORT_SYMBOL_GPL(plda_pcie_setup_window);
-+
-+int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
-+ struct plda_pcie_rp *port)
-+{
-+ void __iomem *bridge_base_addr = port->bridge_addr;
-+ struct resource_entry *entry;
-+ u64 pci_addr;
-+ u32 index = 1;
-+
-+ resource_list_for_each_entry(entry, &bridge->windows) {
-+ if (resource_type(entry->res) == IORESOURCE_MEM) {
-+ pci_addr = entry->res->start - entry->offset;
-+ plda_pcie_setup_window(bridge_base_addr, index,
-+ entry->res->start, pci_addr,
-+ resource_size(entry->res));
-+ index++;
-+ }
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -126,4 +126,9 @@ struct plda_pcie_rp {
- void __iomem *bridge_addr;
- };
-
-+void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
-+ phys_addr_t axi_addr, phys_addr_t pci_addr,
-+ size_t size);
-+int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
-+ struct plda_pcie_rp *port);
- #endif
+++ /dev/null
-From 2a48bc45dcf8cbe736b594d013cfa9d682214c43 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:00 +0800
-Subject: [PATCH 023/116] PCI: microchip: Rename interrupt related functions
-
-Rename mc_* to plda_* for IRQ functions and related IRQ domain ops data
-instances.
-
-MSI, INTx interrupt code and IRQ init code are all can be re-used.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 109 +++++++++---------
- 1 file changed, 57 insertions(+), 52 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -318,7 +318,7 @@ static void mc_pcie_enable_msi(struct mc
- ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
- }
-
--static void mc_handle_msi(struct irq_desc *desc)
-+static void plda_handle_msi(struct irq_desc *desc)
- {
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
-@@ -346,7 +346,7 @@ static void mc_handle_msi(struct irq_des
- chained_irq_exit(chip, desc);
- }
-
--static void mc_msi_bottom_irq_ack(struct irq_data *data)
-+static void plda_msi_bottom_irq_ack(struct irq_data *data)
- {
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
-@@ -355,7 +355,7 @@ static void mc_msi_bottom_irq_ack(struct
- writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
- }
-
--static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-+static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
- {
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- phys_addr_t addr = port->msi.vector_phy;
-@@ -368,21 +368,23 @@ static void mc_compose_msi_msg(struct ir
- (int)data->hwirq, msg->address_hi, msg->address_lo);
- }
-
--static int mc_msi_set_affinity(struct irq_data *irq_data,
-- const struct cpumask *mask, bool force)
-+static int plda_msi_set_affinity(struct irq_data *irq_data,
-+ const struct cpumask *mask, bool force)
- {
- return -EINVAL;
- }
-
--static struct irq_chip mc_msi_bottom_irq_chip = {
-- .name = "Microchip MSI",
-- .irq_ack = mc_msi_bottom_irq_ack,
-- .irq_compose_msi_msg = mc_compose_msi_msg,
-- .irq_set_affinity = mc_msi_set_affinity,
-+static struct irq_chip plda_msi_bottom_irq_chip = {
-+ .name = "PLDA MSI",
-+ .irq_ack = plda_msi_bottom_irq_ack,
-+ .irq_compose_msi_msg = plda_compose_msi_msg,
-+ .irq_set_affinity = plda_msi_set_affinity,
- };
-
--static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
-- unsigned int nr_irqs, void *args)
-+static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
-+ unsigned int virq,
-+ unsigned int nr_irqs,
-+ void *args)
- {
- struct plda_pcie_rp *port = domain->host_data;
- struct plda_msi *msi = &port->msi;
-@@ -397,7 +399,7 @@ static int mc_irq_msi_domain_alloc(struc
-
- set_bit(bit, msi->used);
-
-- irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip,
-+ irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
- domain->host_data, handle_edge_irq, NULL, NULL);
-
- mutex_unlock(&msi->lock);
-@@ -405,8 +407,9 @@ static int mc_irq_msi_domain_alloc(struc
- return 0;
- }
-
--static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
-- unsigned int nr_irqs)
-+static void plda_irq_msi_domain_free(struct irq_domain *domain,
-+ unsigned int virq,
-+ unsigned int nr_irqs)
- {
- struct irq_data *d = irq_domain_get_irq_data(domain, virq);
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
-@@ -423,24 +426,24 @@ static void mc_irq_msi_domain_free(struc
- }
-
- static const struct irq_domain_ops msi_domain_ops = {
-- .alloc = mc_irq_msi_domain_alloc,
-- .free = mc_irq_msi_domain_free,
-+ .alloc = plda_irq_msi_domain_alloc,
-+ .free = plda_irq_msi_domain_free,
- };
-
--static struct irq_chip mc_msi_irq_chip = {
-- .name = "Microchip PCIe MSI",
-+static struct irq_chip plda_msi_irq_chip = {
-+ .name = "PLDA PCIe MSI",
- .irq_ack = irq_chip_ack_parent,
- .irq_mask = pci_msi_mask_irq,
- .irq_unmask = pci_msi_unmask_irq,
- };
-
--static struct msi_domain_info mc_msi_domain_info = {
-+static struct msi_domain_info plda_msi_domain_info = {
- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
- MSI_FLAG_PCI_MSIX),
-- .chip = &mc_msi_irq_chip,
-+ .chip = &plda_msi_irq_chip,
- };
-
--static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
-+static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
- {
- struct device *dev = port->dev;
- struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
-@@ -455,7 +458,8 @@ static int mc_allocate_msi_domains(struc
- return -ENOMEM;
- }
-
-- msi->msi_domain = pci_msi_create_irq_domain(fwnode, &mc_msi_domain_info,
-+ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-+ &plda_msi_domain_info,
- msi->dev_domain);
- if (!msi->msi_domain) {
- dev_err(dev, "failed to create MSI domain\n");
-@@ -466,7 +470,7 @@ static int mc_allocate_msi_domains(struc
- return 0;
- }
-
--static void mc_handle_intx(struct irq_desc *desc)
-+static void plda_handle_intx(struct irq_desc *desc)
- {
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
-@@ -493,7 +497,7 @@ static void mc_handle_intx(struct irq_de
- chained_irq_exit(chip, desc);
- }
-
--static void mc_ack_intx_irq(struct irq_data *data)
-+static void plda_ack_intx_irq(struct irq_data *data)
- {
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
-@@ -502,7 +506,7 @@ static void mc_ack_intx_irq(struct irq_d
- writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
- }
-
--static void mc_mask_intx_irq(struct irq_data *data)
-+static void plda_mask_intx_irq(struct irq_data *data)
- {
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
-@@ -517,7 +521,7 @@ static void mc_mask_intx_irq(struct irq_
- raw_spin_unlock_irqrestore(&port->lock, flags);
- }
-
--static void mc_unmask_intx_irq(struct irq_data *data)
-+static void plda_unmask_intx_irq(struct irq_data *data)
- {
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
- void __iomem *bridge_base_addr = port->bridge_addr;
-@@ -532,24 +536,24 @@ static void mc_unmask_intx_irq(struct ir
- raw_spin_unlock_irqrestore(&port->lock, flags);
- }
-
--static struct irq_chip mc_intx_irq_chip = {
-- .name = "Microchip PCIe INTx",
-- .irq_ack = mc_ack_intx_irq,
-- .irq_mask = mc_mask_intx_irq,
-- .irq_unmask = mc_unmask_intx_irq,
-+static struct irq_chip plda_intx_irq_chip = {
-+ .name = "PLDA PCIe INTx",
-+ .irq_ack = plda_ack_intx_irq,
-+ .irq_mask = plda_mask_intx_irq,
-+ .irq_unmask = plda_unmask_intx_irq,
- };
-
--static int mc_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-- irq_hw_number_t hwirq)
-+static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-+ irq_hw_number_t hwirq)
- {
-- irq_set_chip_and_handler(irq, &mc_intx_irq_chip, handle_level_irq);
-+ irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
- irq_set_chip_data(irq, domain->host_data);
-
- return 0;
- }
-
- static const struct irq_domain_ops intx_domain_ops = {
-- .map = mc_pcie_intx_map,
-+ .map = plda_pcie_intx_map,
- };
-
- static inline u32 reg_to_event(u32 reg, struct event_map field)
-@@ -609,7 +613,7 @@ static u32 local_events(struct mc_pcie *
- return val;
- }
-
--static u32 get_events(struct plda_pcie_rp *port)
-+static u32 mc_get_events(struct plda_pcie_rp *port)
- {
- struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
- u32 events = 0;
-@@ -638,7 +642,7 @@ static irqreturn_t mc_event_handler(int
- return IRQ_HANDLED;
- }
-
--static void mc_handle_event(struct irq_desc *desc)
-+static void plda_handle_event(struct irq_desc *desc)
- {
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
- unsigned long events;
-@@ -647,7 +651,7 @@ static void mc_handle_event(struct irq_d
-
- chained_irq_enter(chip, desc);
-
-- events = get_events(port);
-+ events = mc_get_events(port);
-
- for_each_set_bit(bit, &events, NUM_EVENTS)
- generic_handle_domain_irq(port->event_domain, bit);
-@@ -741,8 +745,8 @@ static struct irq_chip mc_event_irq_chip
- .irq_unmask = mc_unmask_event_irq,
- };
-
--static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
-- irq_hw_number_t hwirq)
-+static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
-+ irq_hw_number_t hwirq)
- {
- irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
- irq_set_chip_data(irq, domain->host_data);
-@@ -750,8 +754,8 @@ static int mc_pcie_event_map(struct irq_
- return 0;
- }
-
--static const struct irq_domain_ops event_domain_ops = {
-- .map = mc_pcie_event_map,
-+static const struct irq_domain_ops plda_event_domain_ops = {
-+ .map = plda_pcie_event_map,
- };
-
- static inline void mc_pcie_deinit_clk(void *data)
-@@ -799,7 +803,7 @@ static int mc_pcie_init_clks(struct devi
- return 0;
- }
-
--static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
-+static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
- {
- struct device *dev = port->dev;
- struct device_node *node = dev->of_node;
-@@ -813,7 +817,8 @@ static int mc_pcie_init_irq_domains(stru
- }
-
- port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
-- &event_domain_ops, port);
-+ &plda_event_domain_ops,
-+ port);
- if (!port->event_domain) {
- dev_err(dev, "failed to get event domain\n");
- of_node_put(pcie_intc_node);
-@@ -835,7 +840,7 @@ static int mc_pcie_init_irq_domains(stru
- of_node_put(pcie_intc_node);
- raw_spin_lock_init(&port->lock);
-
-- return mc_allocate_msi_domains(port);
-+ return plda_allocate_msi_domains(port);
- }
-
- static inline void mc_clear_secs(struct mc_pcie *port)
-@@ -898,14 +903,14 @@ static void mc_disable_interrupts(struct
- writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
- }
-
--static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
-+static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
- {
- struct device *dev = &pdev->dev;
- int irq;
- int i, intx_irq, msi_irq, event_irq;
- int ret;
-
-- ret = mc_pcie_init_irq_domains(port);
-+ ret = plda_pcie_init_irq_domains(port);
- if (ret) {
- dev_err(dev, "failed creating IRQ domains\n");
- return ret;
-@@ -938,7 +943,7 @@ static int mc_init_interrupts(struct pla
- }
-
- /* Plug the INTx chained handler */
-- irq_set_chained_handler_and_data(intx_irq, mc_handle_intx, port);
-+ irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
-
- msi_irq = irq_create_mapping(port->event_domain,
- EVENT_LOCAL_PM_MSI_INT_MSI);
-@@ -946,10 +951,10 @@ static int mc_init_interrupts(struct pla
- return -ENXIO;
-
- /* Plug the MSI chained handler */
-- irq_set_chained_handler_and_data(msi_irq, mc_handle_msi, port);
-+ irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
-
- /* Plug the main event chained handler */
-- irq_set_chained_handler_and_data(irq, mc_handle_event, port);
-+ irq_set_chained_handler_and_data(irq, plda_handle_event, port);
-
- return 0;
- }
-@@ -977,7 +982,7 @@ static int mc_platform_init(struct pci_c
- return ret;
-
- /* Address translation is up; safe to enable interrupts */
-- ret = mc_init_interrupts(pdev, &port->plda);
-+ ret = plda_init_interrupts(pdev, &port->plda);
- if (ret)
- return ret;
-
+++ /dev/null
-From ab04dadb45a4150c9fd55b97fdd7397f4739a629 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:01 +0800
-Subject: [PATCH 024/116] PCI: microchip: Add num_events field to struct
- plda_pcie_rp
-
-The number of events is different across platforms. In order to share
-interrupt processing code, add a variable that defines the number of
-events so that it can be set per-platform instead of hardcoding it.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
----
- drivers/pci/controller/plda/pcie-microchip-host.c | 8 +++++---
- drivers/pci/controller/plda/pcie-plda.h | 1 +
- 2 files changed, 6 insertions(+), 3 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -653,7 +653,7 @@ static void plda_handle_event(struct irq
-
- events = mc_get_events(port);
-
-- for_each_set_bit(bit, &events, NUM_EVENTS)
-+ for_each_set_bit(bit, &events, port->num_events)
- generic_handle_domain_irq(port->event_domain, bit);
-
- chained_irq_exit(chip, desc);
-@@ -816,7 +816,8 @@ static int plda_pcie_init_irq_domains(st
- return -EINVAL;
- }
-
-- port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
-+ port->event_domain = irq_domain_add_linear(pcie_intc_node,
-+ port->num_events,
- &plda_event_domain_ops,
- port);
- if (!port->event_domain) {
-@@ -920,7 +921,7 @@ static int plda_init_interrupts(struct p
- if (irq < 0)
- return -ENODEV;
-
-- for (i = 0; i < NUM_EVENTS; i++) {
-+ for (i = 0; i < port->num_events; i++) {
- event_irq = irq_create_mapping(port->event_domain, i);
- if (!event_irq) {
- dev_err(dev, "failed to map hwirq %d\n", i);
-@@ -1012,6 +1013,7 @@ static int mc_host_probe(struct platform
-
- bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
- plda->bridge_addr = bridge_base_addr;
-+ plda->num_events = NUM_EVENTS;
-
- /* Allow enabling MSI by disabling MSI-X */
- val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -124,6 +124,7 @@ struct plda_pcie_rp {
- raw_spinlock_t lock;
- struct plda_msi msi;
- void __iomem *bridge_addr;
-+ int num_events;
- };
-
- void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
+++ /dev/null
-From 9f202f211cc79eefecbb03715c884e54eb95a62c Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:02 +0800
-Subject: [PATCH 025/116] PCI: microchip: Add request_event_irq() callback
- function
-
-As PLDA dts binding doc(Documentation/devicetree/bindings/pci/
-plda,xpressrich3-axi-common.yaml) showes, PLDA PCIe contains an interrupt
-controller. Microchip Polarfire PCIe add some PCIe interrupts base on
-PLDA IP interrupt controller.
-
-Microchip Polarfire PCIe additional intrerrupts:
-EVENT_PCIE_L2_EXIT
-EVENT_PCIE_HOTRST_EXIT
-EVENT_PCIE_DLUP_EXIT
-EVENT_SEC_TX_RAM_SEC_ERR
-EVENT_SEC_RX_RAM_SEC_ERR
-....
-
-Both codes of register interrupts and mc_event_handler() contain
-additional interrupts symbol names, these can not be re-used. So add a
-new plda_event_handler() functions, which implements PLDA interrupt
-defalt handler. Add request_event_irq() callback function to
-compat Microchip Polorfire PCIe additional interrupts.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 31 ++++++++++++++++---
- drivers/pci/controller/plda/pcie-plda.h | 5 +++
- 2 files changed, 32 insertions(+), 4 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -642,6 +642,11 @@ static irqreturn_t mc_event_handler(int
- return IRQ_HANDLED;
- }
-
-+static irqreturn_t plda_event_handler(int irq, void *dev_id)
-+{
-+ return IRQ_HANDLED;
-+}
-+
- static void plda_handle_event(struct irq_desc *desc)
- {
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-@@ -803,6 +808,17 @@ static int mc_pcie_init_clks(struct devi
- return 0;
- }
-
-+static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
-+ int event)
-+{
-+ return devm_request_irq(plda->dev, event_irq, mc_event_handler,
-+ 0, event_cause[event].sym, plda);
-+}
-+
-+static const struct plda_event mc_event = {
-+ .request_event_irq = mc_request_event_irq,
-+};
-+
- static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
- {
- struct device *dev = port->dev;
-@@ -904,7 +920,9 @@ static void mc_disable_interrupts(struct
- writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
- }
-
--static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
-+static int plda_init_interrupts(struct platform_device *pdev,
-+ struct plda_pcie_rp *port,
-+ const struct plda_event *event)
- {
- struct device *dev = &pdev->dev;
- int irq;
-@@ -928,8 +946,13 @@ static int plda_init_interrupts(struct p
- return -ENXIO;
- }
-
-- ret = devm_request_irq(dev, event_irq, mc_event_handler,
-- 0, event_cause[i].sym, port);
-+ if (event->request_event_irq)
-+ ret = event->request_event_irq(port, event_irq, i);
-+ else
-+ ret = devm_request_irq(dev, event_irq,
-+ plda_event_handler,
-+ 0, NULL, port);
-+
- if (ret) {
- dev_err(dev, "failed to request IRQ %d\n", event_irq);
- return ret;
-@@ -983,7 +1006,7 @@ static int mc_platform_init(struct pci_c
- return ret;
-
- /* Address translation is up; safe to enable interrupts */
-- ret = plda_init_interrupts(pdev, &port->plda);
-+ ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
- if (ret)
- return ret;
-
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -127,6 +127,11 @@ struct plda_pcie_rp {
- int num_events;
- };
-
-+struct plda_event {
-+ int (*request_event_irq)(struct plda_pcie_rp *pcie,
-+ int event_irq, int event);
-+};
-+
- void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
- phys_addr_t axi_addr, phys_addr_t pci_addr,
- size_t size);
+++ /dev/null
-From 3cdc20d9cc029ba9444be111bf4e55fd5331ccbe Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:03 +0800
-Subject: [PATCH 026/116] PCI: microchip: Add INTx and MSI event num to struct
- plda_event
-
-The INTx and MSI interrupt event num is different in Microchip and
-StarFive platform.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
----
- drivers/pci/controller/plda/pcie-microchip-host.c | 6 ++++--
- drivers/pci/controller/plda/pcie-plda.h | 2 ++
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -817,6 +817,8 @@ static int mc_request_event_irq(struct p
-
- static const struct plda_event mc_event = {
- .request_event_irq = mc_request_event_irq,
-+ .intx_event = EVENT_LOCAL_PM_MSI_INT_INTX,
-+ .msi_event = EVENT_LOCAL_PM_MSI_INT_MSI,
- };
-
- static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
-@@ -960,7 +962,7 @@ static int plda_init_interrupts(struct p
- }
-
- intx_irq = irq_create_mapping(port->event_domain,
-- EVENT_LOCAL_PM_MSI_INT_INTX);
-+ event->intx_event);
- if (!intx_irq) {
- dev_err(dev, "failed to map INTx interrupt\n");
- return -ENXIO;
-@@ -970,7 +972,7 @@ static int plda_init_interrupts(struct p
- irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
-
- msi_irq = irq_create_mapping(port->event_domain,
-- EVENT_LOCAL_PM_MSI_INT_MSI);
-+ event->msi_event);
- if (!msi_irq)
- return -ENXIO;
-
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -130,6 +130,8 @@ struct plda_pcie_rp {
- struct plda_event {
- int (*request_event_irq)(struct plda_pcie_rp *pcie,
- int event_irq, int event);
-+ int intx_event;
-+ int msi_event;
- };
-
- void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
+++ /dev/null
-From b4a38ef87661f21fe2fb3e085ae98f25f78aaf99 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:04 +0800
-Subject: [PATCH 027/116] PCI: microchip: Add get_events() callback and add
- PLDA get_event()
-
-As PLDA dts binding doc(Documentation/devicetree/bindings/pci/
-plda,xpressrich3-axi-common.yaml) showes, PLDA PCIe contains an interrupt
-controller.
-
-PolarFire implements its own PCIe interrupts, additional to the regular
-PCIe interrupts, due to lack of an MSI controller, so the interrupt to
-event number mapping is different to the PLDA regular interrupts,
-necessitating a custom get_events() implementation.
-
-Microchip Polarfire PCIe additional intrerrupts:
-EVENT_PCIE_L2_EXIT
-EVENT_PCIE_HOTRST_EXIT
-EVENT_PCIE_DLUP_EXIT
-EVENT_SEC_TX_RAM_SEC_ERR
-EVENT_SEC_RX_RAM_SEC_ERR
-....
-
-plda_get_events() adds interrupt register to PLDA local event num mapping
-codes. All The PLDA interrupts can be seen in new added graph.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 35 ++++++++++++++++++-
- drivers/pci/controller/plda/pcie-plda.h | 32 +++++++++++++++++
- 2 files changed, 66 insertions(+), 1 deletion(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -626,6 +626,26 @@ static u32 mc_get_events(struct plda_pci
- return events;
- }
-
-+static u32 plda_get_events(struct plda_pcie_rp *port)
-+{
-+ u32 events, val, origin;
-+
-+ origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
-+
-+ /* MSI event and sys events */
-+ val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
-+ events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1);
-+
-+ /* INTx events */
-+ if (origin & PM_MSI_INT_INTX_MASK)
-+ events |= BIT(PM_MSI_INT_INTX_SHIFT);
-+
-+ /* remains are same with register */
-+ events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0);
-+
-+ return events;
-+}
-+
- static irqreturn_t mc_event_handler(int irq, void *dev_id)
- {
- struct plda_pcie_rp *port = dev_id;
-@@ -656,7 +676,7 @@ static void plda_handle_event(struct irq
-
- chained_irq_enter(chip, desc);
-
-- events = mc_get_events(port);
-+ events = port->event_ops->get_events(port);
-
- for_each_set_bit(bit, &events, port->num_events)
- generic_handle_domain_irq(port->event_domain, bit);
-@@ -750,6 +770,10 @@ static struct irq_chip mc_event_irq_chip
- .irq_unmask = mc_unmask_event_irq,
- };
-
-+static const struct plda_event_ops plda_event_ops = {
-+ .get_events = plda_get_events,
-+};
-+
- static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
- {
-@@ -815,6 +839,10 @@ static int mc_request_event_irq(struct p
- 0, event_cause[event].sym, plda);
- }
-
-+static const struct plda_event_ops mc_event_ops = {
-+ .get_events = mc_get_events,
-+};
-+
- static const struct plda_event mc_event = {
- .request_event_irq = mc_request_event_irq,
- .intx_event = EVENT_LOCAL_PM_MSI_INT_INTX,
-@@ -931,6 +959,9 @@ static int plda_init_interrupts(struct p
- int i, intx_irq, msi_irq, event_irq;
- int ret;
-
-+ if (!port->event_ops)
-+ port->event_ops = &plda_event_ops;
-+
- ret = plda_pcie_init_irq_domains(port);
- if (ret) {
- dev_err(dev, "failed creating IRQ domains\n");
-@@ -1007,6 +1038,8 @@ static int mc_platform_init(struct pci_c
- if (ret)
- return ret;
-
-+ port->plda.event_ops = &mc_event_ops;
-+
- /* Address translation is up; safe to enable interrupts */
- ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
- if (ret)
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -58,6 +58,7 @@
- #define PM_MSI_INT_EVENTS_SHIFT 30
- #define PM_MSI_INT_SYS_ERR_MASK 0x80000000u
- #define PM_MSI_INT_SYS_ERR_SHIFT 31
-+#define SYS_AND_MSI_MASK GENMASK(31, 28)
- #define NUM_LOCAL_EVENTS 15
- #define ISTATUS_LOCAL 0x184
- #define IMASK_HOST 0x188
-@@ -108,6 +109,36 @@ enum plda_int_event {
-
- #define PLDA_MAX_INT_NUM (PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
-
-+/*
-+ * PLDA interrupt register
-+ *
-+ * 31 27 23 15 7 0
-+ * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
-+ * |12|11|10|9| intx |7|6|5|4|3|2|1|0| DMA error | DMA end |
-+ * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
-+ * bit 0-7 DMA interrupt end : reserved for vendor implement
-+ * bit 8-15 DMA error : reserved for vendor implement
-+ * 0: AXI post error (PLDA_AXI_POST_ERR)
-+ * 1: AXI fetch error (PLDA_AXI_FETCH_ERR)
-+ * 2: AXI discard error (PLDA_AXI_DISCARD_ERR)
-+ * 3: AXI doorbell (PLDA_PCIE_DOORBELL)
-+ * 4: PCIe post error (PLDA_PCIE_POST_ERR)
-+ * 5: PCIe fetch error (PLDA_PCIE_FETCH_ERR)
-+ * 6: PCIe discard error (PLDA_PCIE_DISCARD_ERR)
-+ * 7: PCIe doorbell (PLDA_PCIE_DOORBELL)
-+ * 8: 4 INTx interruts (PLDA_INTX)
-+ * 9: MSI interrupt (PLDA_MSI)
-+ * 10: AER event (PLDA_AER_EVENT)
-+ * 11: PM/LTR/Hotplug (PLDA_MISC_EVENTS)
-+ * 12: System error (PLDA_SYS_ERR)
-+ */
-+
-+struct plda_pcie_rp;
-+
-+struct plda_event_ops {
-+ u32 (*get_events)(struct plda_pcie_rp *pcie);
-+};
-+
- struct plda_msi {
- struct mutex lock; /* Protect used bitmap */
- struct irq_domain *msi_domain;
-@@ -123,6 +154,7 @@ struct plda_pcie_rp {
- struct irq_domain *event_domain;
- raw_spinlock_t lock;
- struct plda_msi msi;
-+ const struct plda_event_ops *event_ops;
- void __iomem *bridge_addr;
- int num_events;
- };
+++ /dev/null
-From 229ea8e7b674eb5c9bc4f70d43df1bd02a79862a Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:05 +0800
-Subject: [PATCH 028/116] PCI: microchip: Add event irqchip field to host port
- and add PLDA irqchip
-
-As PLDA dts binding doc(Documentation/devicetree/bindings/pci/
-plda,xpressrich3-axi-common.yaml) showes, PLDA PCIe contains an interrupt
-controller.
-
-Microchip PolarFire PCIE event IRQs includes PLDA interrupts and
-Polarfire their own interrupts. The interrupt irqchip ops includes
-ack/mask/unmask interrupt ops, which will write correct registers.
-Microchip Polarfire PCIe additional interrupts require to write Polarfire
-SoC self-defined registers. So Microchip PCIe event irqchip ops can not
-be re-used.
-
-To support PLDA its own event IRQ process, implements PLDA irqchip ops and
-add event irqchip field to struct pcie_plda_rp.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 66 ++++++++++++++++++-
- drivers/pci/controller/plda/pcie-plda.h | 5 +-
- 2 files changed, 69 insertions(+), 2 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -770,6 +770,64 @@ static struct irq_chip mc_event_irq_chip
- .irq_unmask = mc_unmask_event_irq,
- };
-
-+static u32 plda_hwirq_to_mask(int hwirq)
-+{
-+ u32 mask;
-+
-+ /* hwirq 23 - 0 are the same with register */
-+ if (hwirq < EVENT_PM_MSI_INT_INTX)
-+ mask = BIT(hwirq);
-+ else if (hwirq == EVENT_PM_MSI_INT_INTX)
-+ mask = PM_MSI_INT_INTX_MASK;
-+ else
-+ mask = BIT(hwirq + PCI_NUM_INTX - 1);
-+
-+ return mask;
-+}
-+
-+static void plda_ack_event_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+
-+ writel_relaxed(plda_hwirq_to_mask(data->hwirq),
-+ port->bridge_addr + ISTATUS_LOCAL);
-+}
-+
-+static void plda_mask_event_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ u32 mask, val;
-+
-+ mask = plda_hwirq_to_mask(data->hwirq);
-+
-+ raw_spin_lock(&port->lock);
-+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
-+ val &= ~mask;
-+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
-+ raw_spin_unlock(&port->lock);
-+}
-+
-+static void plda_unmask_event_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ u32 mask, val;
-+
-+ mask = plda_hwirq_to_mask(data->hwirq);
-+
-+ raw_spin_lock(&port->lock);
-+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
-+ val |= mask;
-+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
-+ raw_spin_unlock(&port->lock);
-+}
-+
-+static struct irq_chip plda_event_irq_chip = {
-+ .name = "PLDA PCIe EVENT",
-+ .irq_ack = plda_ack_event_irq,
-+ .irq_mask = plda_mask_event_irq,
-+ .irq_unmask = plda_unmask_event_irq,
-+};
-+
- static const struct plda_event_ops plda_event_ops = {
- .get_events = plda_get_events,
- };
-@@ -777,7 +835,9 @@ static const struct plda_event_ops plda_
- static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
- {
-- irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
-+ struct plda_pcie_rp *port = (void *)domain->host_data;
-+
-+ irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
- irq_set_chip_data(irq, domain->host_data);
-
- return 0;
-@@ -962,6 +1022,9 @@ static int plda_init_interrupts(struct p
- if (!port->event_ops)
- port->event_ops = &plda_event_ops;
-
-+ if (!port->event_irq_chip)
-+ port->event_irq_chip = &plda_event_irq_chip;
-+
- ret = plda_pcie_init_irq_domains(port);
- if (ret) {
- dev_err(dev, "failed creating IRQ domains\n");
-@@ -1039,6 +1102,7 @@ static int mc_platform_init(struct pci_c
- return ret;
-
- port->plda.event_ops = &mc_event_ops;
-+ port->plda.event_irq_chip = &mc_event_irq_chip;
-
- /* Address translation is up; safe to enable interrupts */
- ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -107,7 +107,9 @@ enum plda_int_event {
-
- #define PLDA_NUM_DMA_EVENTS 16
-
--#define PLDA_MAX_INT_NUM (PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
-+#define EVENT_PM_MSI_INT_INTX (PLDA_NUM_DMA_EVENTS + PLDA_INTX)
-+#define EVENT_PM_MSI_INT_MSI (PLDA_NUM_DMA_EVENTS + PLDA_MSI)
-+#define PLDA_MAX_EVENT_NUM (PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
-
- /*
- * PLDA interrupt register
-@@ -155,6 +157,7 @@ struct plda_pcie_rp {
- raw_spinlock_t lock;
- struct plda_msi msi;
- const struct plda_event_ops *event_ops;
-+ const struct irq_chip *event_irq_chip;
- void __iomem *bridge_addr;
- int num_events;
- };
+++ /dev/null
-From 6be452d8e61594790ae57b282a612ec0df473e61 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:06 +0800
-Subject: [PATCH 029/116] PCI: microchip: Move IRQ functions to
- pcie-plda-host.c
-
-Move IRQ related functions to pcie-plda-host.c for re-use these codes.
-Now Refactoring codes complete.
-
-Including MSI, INTx, event interrupts and IRQ init functions.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../pci/controller/plda/pcie-microchip-host.c | 467 -----------------
- drivers/pci/controller/plda/pcie-plda-host.c | 472 ++++++++++++++++++
- drivers/pci/controller/plda/pcie-plda.h | 3 +
- 3 files changed, 475 insertions(+), 467 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -318,244 +318,6 @@ static void mc_pcie_enable_msi(struct mc
- ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
- }
-
--static void plda_handle_msi(struct irq_desc *desc)
--{
-- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-- struct irq_chip *chip = irq_desc_get_chip(desc);
-- struct device *dev = port->dev;
-- struct plda_msi *msi = &port->msi;
-- void __iomem *bridge_base_addr = port->bridge_addr;
-- unsigned long status;
-- u32 bit;
-- int ret;
--
-- chained_irq_enter(chip, desc);
--
-- status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-- if (status & PM_MSI_INT_MSI_MASK) {
-- writel_relaxed(status & PM_MSI_INT_MSI_MASK, bridge_base_addr + ISTATUS_LOCAL);
-- status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
-- for_each_set_bit(bit, &status, msi->num_vectors) {
-- ret = generic_handle_domain_irq(msi->dev_domain, bit);
-- if (ret)
-- dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
-- bit);
-- }
-- }
--
-- chained_irq_exit(chip, desc);
--}
--
--static void plda_msi_bottom_irq_ack(struct irq_data *data)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr = port->bridge_addr;
-- u32 bitpos = data->hwirq;
--
-- writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
--}
--
--static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-- phys_addr_t addr = port->msi.vector_phy;
--
-- msg->address_lo = lower_32_bits(addr);
-- msg->address_hi = upper_32_bits(addr);
-- msg->data = data->hwirq;
--
-- dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
-- (int)data->hwirq, msg->address_hi, msg->address_lo);
--}
--
--static int plda_msi_set_affinity(struct irq_data *irq_data,
-- const struct cpumask *mask, bool force)
--{
-- return -EINVAL;
--}
--
--static struct irq_chip plda_msi_bottom_irq_chip = {
-- .name = "PLDA MSI",
-- .irq_ack = plda_msi_bottom_irq_ack,
-- .irq_compose_msi_msg = plda_compose_msi_msg,
-- .irq_set_affinity = plda_msi_set_affinity,
--};
--
--static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
-- unsigned int virq,
-- unsigned int nr_irqs,
-- void *args)
--{
-- struct plda_pcie_rp *port = domain->host_data;
-- struct plda_msi *msi = &port->msi;
-- unsigned long bit;
--
-- mutex_lock(&msi->lock);
-- bit = find_first_zero_bit(msi->used, msi->num_vectors);
-- if (bit >= msi->num_vectors) {
-- mutex_unlock(&msi->lock);
-- return -ENOSPC;
-- }
--
-- set_bit(bit, msi->used);
--
-- irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
-- domain->host_data, handle_edge_irq, NULL, NULL);
--
-- mutex_unlock(&msi->lock);
--
-- return 0;
--}
--
--static void plda_irq_msi_domain_free(struct irq_domain *domain,
-- unsigned int virq,
-- unsigned int nr_irqs)
--{
-- struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
-- struct plda_msi *msi = &port->msi;
--
-- mutex_lock(&msi->lock);
--
-- if (test_bit(d->hwirq, msi->used))
-- __clear_bit(d->hwirq, msi->used);
-- else
-- dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
--
-- mutex_unlock(&msi->lock);
--}
--
--static const struct irq_domain_ops msi_domain_ops = {
-- .alloc = plda_irq_msi_domain_alloc,
-- .free = plda_irq_msi_domain_free,
--};
--
--static struct irq_chip plda_msi_irq_chip = {
-- .name = "PLDA PCIe MSI",
-- .irq_ack = irq_chip_ack_parent,
-- .irq_mask = pci_msi_mask_irq,
-- .irq_unmask = pci_msi_unmask_irq,
--};
--
--static struct msi_domain_info plda_msi_domain_info = {
-- .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-- MSI_FLAG_PCI_MSIX),
-- .chip = &plda_msi_irq_chip,
--};
--
--static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
--{
-- struct device *dev = port->dev;
-- struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
-- struct plda_msi *msi = &port->msi;
--
-- mutex_init(&port->msi.lock);
--
-- msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
-- &msi_domain_ops, port);
-- if (!msi->dev_domain) {
-- dev_err(dev, "failed to create IRQ domain\n");
-- return -ENOMEM;
-- }
--
-- msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-- &plda_msi_domain_info,
-- msi->dev_domain);
-- if (!msi->msi_domain) {
-- dev_err(dev, "failed to create MSI domain\n");
-- irq_domain_remove(msi->dev_domain);
-- return -ENOMEM;
-- }
--
-- return 0;
--}
--
--static void plda_handle_intx(struct irq_desc *desc)
--{
-- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-- struct irq_chip *chip = irq_desc_get_chip(desc);
-- struct device *dev = port->dev;
-- void __iomem *bridge_base_addr = port->bridge_addr;
-- unsigned long status;
-- u32 bit;
-- int ret;
--
-- chained_irq_enter(chip, desc);
--
-- status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-- if (status & PM_MSI_INT_INTX_MASK) {
-- status &= PM_MSI_INT_INTX_MASK;
-- status >>= PM_MSI_INT_INTX_SHIFT;
-- for_each_set_bit(bit, &status, PCI_NUM_INTX) {
-- ret = generic_handle_domain_irq(port->intx_domain, bit);
-- if (ret)
-- dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
-- bit);
-- }
-- }
--
-- chained_irq_exit(chip, desc);
--}
--
--static void plda_ack_intx_irq(struct irq_data *data)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr = port->bridge_addr;
-- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
--
-- writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
--}
--
--static void plda_mask_intx_irq(struct irq_data *data)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr = port->bridge_addr;
-- unsigned long flags;
-- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-- u32 val;
--
-- raw_spin_lock_irqsave(&port->lock, flags);
-- val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-- val &= ~mask;
-- writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-- raw_spin_unlock_irqrestore(&port->lock, flags);
--}
--
--static void plda_unmask_intx_irq(struct irq_data *data)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-- void __iomem *bridge_base_addr = port->bridge_addr;
-- unsigned long flags;
-- u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-- u32 val;
--
-- raw_spin_lock_irqsave(&port->lock, flags);
-- val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-- val |= mask;
-- writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-- raw_spin_unlock_irqrestore(&port->lock, flags);
--}
--
--static struct irq_chip plda_intx_irq_chip = {
-- .name = "PLDA PCIe INTx",
-- .irq_ack = plda_ack_intx_irq,
-- .irq_mask = plda_mask_intx_irq,
-- .irq_unmask = plda_unmask_intx_irq,
--};
--
--static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-- irq_hw_number_t hwirq)
--{
-- irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
-- irq_set_chip_data(irq, domain->host_data);
--
-- return 0;
--}
--
--static const struct irq_domain_ops intx_domain_ops = {
-- .map = plda_pcie_intx_map,
--};
--
- static inline u32 reg_to_event(u32 reg, struct event_map field)
- {
- return (reg & field.reg_mask) ? BIT(field.event_bit) : 0;
-@@ -626,26 +388,6 @@ static u32 mc_get_events(struct plda_pci
- return events;
- }
-
--static u32 plda_get_events(struct plda_pcie_rp *port)
--{
-- u32 events, val, origin;
--
-- origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
--
-- /* MSI event and sys events */
-- val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
-- events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1);
--
-- /* INTx events */
-- if (origin & PM_MSI_INT_INTX_MASK)
-- events |= BIT(PM_MSI_INT_INTX_SHIFT);
--
-- /* remains are same with register */
-- events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0);
--
-- return events;
--}
--
- static irqreturn_t mc_event_handler(int irq, void *dev_id)
- {
- struct plda_pcie_rp *port = dev_id;
-@@ -662,28 +404,6 @@ static irqreturn_t mc_event_handler(int
- return IRQ_HANDLED;
- }
-
--static irqreturn_t plda_event_handler(int irq, void *dev_id)
--{
-- return IRQ_HANDLED;
--}
--
--static void plda_handle_event(struct irq_desc *desc)
--{
-- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-- unsigned long events;
-- u32 bit;
-- struct irq_chip *chip = irq_desc_get_chip(desc);
--
-- chained_irq_enter(chip, desc);
--
-- events = port->event_ops->get_events(port);
--
-- for_each_set_bit(bit, &events, port->num_events)
-- generic_handle_domain_irq(port->event_domain, bit);
--
-- chained_irq_exit(chip, desc);
--}
--
- static void mc_ack_event_irq(struct irq_data *data)
- {
- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-@@ -770,83 +490,6 @@ static struct irq_chip mc_event_irq_chip
- .irq_unmask = mc_unmask_event_irq,
- };
-
--static u32 plda_hwirq_to_mask(int hwirq)
--{
-- u32 mask;
--
-- /* hwirq 23 - 0 are the same with register */
-- if (hwirq < EVENT_PM_MSI_INT_INTX)
-- mask = BIT(hwirq);
-- else if (hwirq == EVENT_PM_MSI_INT_INTX)
-- mask = PM_MSI_INT_INTX_MASK;
-- else
-- mask = BIT(hwirq + PCI_NUM_INTX - 1);
--
-- return mask;
--}
--
--static void plda_ack_event_irq(struct irq_data *data)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
--
-- writel_relaxed(plda_hwirq_to_mask(data->hwirq),
-- port->bridge_addr + ISTATUS_LOCAL);
--}
--
--static void plda_mask_event_irq(struct irq_data *data)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-- u32 mask, val;
--
-- mask = plda_hwirq_to_mask(data->hwirq);
--
-- raw_spin_lock(&port->lock);
-- val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
-- val &= ~mask;
-- writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
-- raw_spin_unlock(&port->lock);
--}
--
--static void plda_unmask_event_irq(struct irq_data *data)
--{
-- struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-- u32 mask, val;
--
-- mask = plda_hwirq_to_mask(data->hwirq);
--
-- raw_spin_lock(&port->lock);
-- val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
-- val |= mask;
-- writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
-- raw_spin_unlock(&port->lock);
--}
--
--static struct irq_chip plda_event_irq_chip = {
-- .name = "PLDA PCIe EVENT",
-- .irq_ack = plda_ack_event_irq,
-- .irq_mask = plda_mask_event_irq,
-- .irq_unmask = plda_unmask_event_irq,
--};
--
--static const struct plda_event_ops plda_event_ops = {
-- .get_events = plda_get_events,
--};
--
--static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
-- irq_hw_number_t hwirq)
--{
-- struct plda_pcie_rp *port = (void *)domain->host_data;
--
-- irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
-- irq_set_chip_data(irq, domain->host_data);
--
-- return 0;
--}
--
--static const struct irq_domain_ops plda_event_domain_ops = {
-- .map = plda_pcie_event_map,
--};
--
- static inline void mc_pcie_deinit_clk(void *data)
- {
- struct clk *clk = data;
-@@ -909,47 +552,6 @@ static const struct plda_event mc_event
- .msi_event = EVENT_LOCAL_PM_MSI_INT_MSI,
- };
-
--static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
--{
-- struct device *dev = port->dev;
-- struct device_node *node = dev->of_node;
-- struct device_node *pcie_intc_node;
--
-- /* Setup INTx */
-- pcie_intc_node = of_get_next_child(node, NULL);
-- if (!pcie_intc_node) {
-- dev_err(dev, "failed to find PCIe Intc node\n");
-- return -EINVAL;
-- }
--
-- port->event_domain = irq_domain_add_linear(pcie_intc_node,
-- port->num_events,
-- &plda_event_domain_ops,
-- port);
-- if (!port->event_domain) {
-- dev_err(dev, "failed to get event domain\n");
-- of_node_put(pcie_intc_node);
-- return -ENOMEM;
-- }
--
-- irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
--
-- port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
-- &intx_domain_ops, port);
-- if (!port->intx_domain) {
-- dev_err(dev, "failed to get an INTx IRQ domain\n");
-- of_node_put(pcie_intc_node);
-- return -ENOMEM;
-- }
--
-- irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
--
-- of_node_put(pcie_intc_node);
-- raw_spin_lock_init(&port->lock);
--
-- return plda_allocate_msi_domains(port);
--}
--
- static inline void mc_clear_secs(struct mc_pcie *port)
- {
- void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
-@@ -1010,75 +612,6 @@ static void mc_disable_interrupts(struct
- writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
- }
-
--static int plda_init_interrupts(struct platform_device *pdev,
-- struct plda_pcie_rp *port,
-- const struct plda_event *event)
--{
-- struct device *dev = &pdev->dev;
-- int irq;
-- int i, intx_irq, msi_irq, event_irq;
-- int ret;
--
-- if (!port->event_ops)
-- port->event_ops = &plda_event_ops;
--
-- if (!port->event_irq_chip)
-- port->event_irq_chip = &plda_event_irq_chip;
--
-- ret = plda_pcie_init_irq_domains(port);
-- if (ret) {
-- dev_err(dev, "failed creating IRQ domains\n");
-- return ret;
-- }
--
-- irq = platform_get_irq(pdev, 0);
-- if (irq < 0)
-- return -ENODEV;
--
-- for (i = 0; i < port->num_events; i++) {
-- event_irq = irq_create_mapping(port->event_domain, i);
-- if (!event_irq) {
-- dev_err(dev, "failed to map hwirq %d\n", i);
-- return -ENXIO;
-- }
--
-- if (event->request_event_irq)
-- ret = event->request_event_irq(port, event_irq, i);
-- else
-- ret = devm_request_irq(dev, event_irq,
-- plda_event_handler,
-- 0, NULL, port);
--
-- if (ret) {
-- dev_err(dev, "failed to request IRQ %d\n", event_irq);
-- return ret;
-- }
-- }
--
-- intx_irq = irq_create_mapping(port->event_domain,
-- event->intx_event);
-- if (!intx_irq) {
-- dev_err(dev, "failed to map INTx interrupt\n");
-- return -ENXIO;
-- }
--
-- /* Plug the INTx chained handler */
-- irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
--
-- msi_irq = irq_create_mapping(port->event_domain,
-- event->msi_event);
-- if (!msi_irq)
-- return -ENXIO;
--
-- /* Plug the MSI chained handler */
-- irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
--
-- /* Plug the main event chained handler */
-- irq_set_chained_handler_and_data(irq, plda_handle_event, port);
--
-- return 0;
--}
--
- static int mc_platform_init(struct pci_config_window *cfg)
- {
- struct device *dev = cfg->parent;
---- a/drivers/pci/controller/plda/pcie-plda-host.c
-+++ b/drivers/pci/controller/plda/pcie-plda-host.c
-@@ -7,11 +7,483 @@
- * Author: Daire McNamara <daire.mcnamara@microchip.com>
- */
-
-+#include <linux/irqchip/chained_irq.h>
-+#include <linux/irqdomain.h>
-+#include <linux/msi.h>
- #include <linux/pci_regs.h>
- #include <linux/pci-ecam.h>
-
- #include "pcie-plda.h"
-
-+static void plda_handle_msi(struct irq_desc *desc)
-+{
-+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct device *dev = port->dev;
-+ struct plda_msi *msi = &port->msi;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
-+ unsigned long status;
-+ u32 bit;
-+ int ret;
-+
-+ chained_irq_enter(chip, desc);
-+
-+ status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-+ if (status & PM_MSI_INT_MSI_MASK) {
-+ writel_relaxed(status & PM_MSI_INT_MSI_MASK,
-+ bridge_base_addr + ISTATUS_LOCAL);
-+ status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
-+ for_each_set_bit(bit, &status, msi->num_vectors) {
-+ ret = generic_handle_domain_irq(msi->dev_domain, bit);
-+ if (ret)
-+ dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
-+ bit);
-+ }
-+ }
-+
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static void plda_msi_bottom_irq_ack(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr = port->bridge_addr;
-+ u32 bitpos = data->hwirq;
-+
-+ writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
-+}
-+
-+static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ phys_addr_t addr = port->msi.vector_phy;
-+
-+ msg->address_lo = lower_32_bits(addr);
-+ msg->address_hi = upper_32_bits(addr);
-+ msg->data = data->hwirq;
-+
-+ dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
-+ (int)data->hwirq, msg->address_hi, msg->address_lo);
-+}
-+
-+static int plda_msi_set_affinity(struct irq_data *irq_data,
-+ const struct cpumask *mask, bool force)
-+{
-+ return -EINVAL;
-+}
-+
-+static struct irq_chip plda_msi_bottom_irq_chip = {
-+ .name = "PLDA MSI",
-+ .irq_ack = plda_msi_bottom_irq_ack,
-+ .irq_compose_msi_msg = plda_compose_msi_msg,
-+ .irq_set_affinity = plda_msi_set_affinity,
-+};
-+
-+static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
-+ unsigned int virq,
-+ unsigned int nr_irqs,
-+ void *args)
-+{
-+ struct plda_pcie_rp *port = domain->host_data;
-+ struct plda_msi *msi = &port->msi;
-+ unsigned long bit;
-+
-+ mutex_lock(&msi->lock);
-+ bit = find_first_zero_bit(msi->used, msi->num_vectors);
-+ if (bit >= msi->num_vectors) {
-+ mutex_unlock(&msi->lock);
-+ return -ENOSPC;
-+ }
-+
-+ set_bit(bit, msi->used);
-+
-+ irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
-+ domain->host_data, handle_edge_irq, NULL, NULL);
-+
-+ mutex_unlock(&msi->lock);
-+
-+ return 0;
-+}
-+
-+static void plda_irq_msi_domain_free(struct irq_domain *domain,
-+ unsigned int virq,
-+ unsigned int nr_irqs)
-+{
-+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
-+ struct plda_msi *msi = &port->msi;
-+
-+ mutex_lock(&msi->lock);
-+
-+ if (test_bit(d->hwirq, msi->used))
-+ __clear_bit(d->hwirq, msi->used);
-+ else
-+ dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
-+
-+ mutex_unlock(&msi->lock);
-+}
-+
-+static const struct irq_domain_ops msi_domain_ops = {
-+ .alloc = plda_irq_msi_domain_alloc,
-+ .free = plda_irq_msi_domain_free,
-+};
-+
-+static struct irq_chip plda_msi_irq_chip = {
-+ .name = "PLDA PCIe MSI",
-+ .irq_ack = irq_chip_ack_parent,
-+ .irq_mask = pci_msi_mask_irq,
-+ .irq_unmask = pci_msi_unmask_irq,
-+};
-+
-+static struct msi_domain_info plda_msi_domain_info = {
-+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-+ MSI_FLAG_PCI_MSIX),
-+ .chip = &plda_msi_irq_chip,
-+};
-+
-+static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
-+{
-+ struct device *dev = port->dev;
-+ struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
-+ struct plda_msi *msi = &port->msi;
-+
-+ mutex_init(&port->msi.lock);
-+
-+ msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
-+ &msi_domain_ops, port);
-+ if (!msi->dev_domain) {
-+ dev_err(dev, "failed to create IRQ domain\n");
-+ return -ENOMEM;
-+ }
-+
-+ msi->msi_domain = pci_msi_create_irq_domain(fwnode,
-+ &plda_msi_domain_info,
-+ msi->dev_domain);
-+ if (!msi->msi_domain) {
-+ dev_err(dev, "failed to create MSI domain\n");
-+ irq_domain_remove(msi->dev_domain);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static void plda_handle_intx(struct irq_desc *desc)
-+{
-+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct device *dev = port->dev;
-+ void __iomem *bridge_base_addr = port->bridge_addr;
-+ unsigned long status;
-+ u32 bit;
-+ int ret;
-+
-+ chained_irq_enter(chip, desc);
-+
-+ status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
-+ if (status & PM_MSI_INT_INTX_MASK) {
-+ status &= PM_MSI_INT_INTX_MASK;
-+ status >>= PM_MSI_INT_INTX_SHIFT;
-+ for_each_set_bit(bit, &status, PCI_NUM_INTX) {
-+ ret = generic_handle_domain_irq(port->intx_domain, bit);
-+ if (ret)
-+ dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
-+ bit);
-+ }
-+ }
-+
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static void plda_ack_intx_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr = port->bridge_addr;
-+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-+
-+ writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
-+}
-+
-+static void plda_mask_intx_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr = port->bridge_addr;
-+ unsigned long flags;
-+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-+ u32 val;
-+
-+ raw_spin_lock_irqsave(&port->lock, flags);
-+ val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-+ val &= ~mask;
-+ writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-+ raw_spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+static void plda_unmask_intx_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ void __iomem *bridge_base_addr = port->bridge_addr;
-+ unsigned long flags;
-+ u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
-+ u32 val;
-+
-+ raw_spin_lock_irqsave(&port->lock, flags);
-+ val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
-+ val |= mask;
-+ writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
-+ raw_spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+static struct irq_chip plda_intx_irq_chip = {
-+ .name = "PLDA PCIe INTx",
-+ .irq_ack = plda_ack_intx_irq,
-+ .irq_mask = plda_mask_intx_irq,
-+ .irq_unmask = plda_unmask_intx_irq,
-+};
-+
-+static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
-+ irq_hw_number_t hwirq)
-+{
-+ irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
-+ irq_set_chip_data(irq, domain->host_data);
-+
-+ return 0;
-+}
-+
-+static const struct irq_domain_ops intx_domain_ops = {
-+ .map = plda_pcie_intx_map,
-+};
-+
-+static u32 plda_get_events(struct plda_pcie_rp *port)
-+{
-+ u32 events, val, origin;
-+
-+ origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
-+
-+ /* MSI event and sys events */
-+ val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
-+ events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1);
-+
-+ /* INTx events */
-+ if (origin & PM_MSI_INT_INTX_MASK)
-+ events |= BIT(PM_MSI_INT_INTX_SHIFT);
-+
-+ /* remains are same with register */
-+ events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0);
-+
-+ return events;
-+}
-+
-+static irqreturn_t plda_event_handler(int irq, void *dev_id)
-+{
-+ return IRQ_HANDLED;
-+}
-+
-+static void plda_handle_event(struct irq_desc *desc)
-+{
-+ struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-+ unsigned long events;
-+ u32 bit;
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+
-+ chained_irq_enter(chip, desc);
-+
-+ events = port->event_ops->get_events(port);
-+
-+ for_each_set_bit(bit, &events, port->num_events)
-+ generic_handle_domain_irq(port->event_domain, bit);
-+
-+ chained_irq_exit(chip, desc);
-+}
-+
-+static u32 plda_hwirq_to_mask(int hwirq)
-+{
-+ u32 mask;
-+
-+ /* hwirq 23 - 0 are the same with register */
-+ if (hwirq < EVENT_PM_MSI_INT_INTX)
-+ mask = BIT(hwirq);
-+ else if (hwirq == EVENT_PM_MSI_INT_INTX)
-+ mask = PM_MSI_INT_INTX_MASK;
-+ else
-+ mask = BIT(hwirq + PCI_NUM_INTX - 1);
-+
-+ return mask;
-+}
-+
-+static void plda_ack_event_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+
-+ writel_relaxed(plda_hwirq_to_mask(data->hwirq),
-+ port->bridge_addr + ISTATUS_LOCAL);
-+}
-+
-+static void plda_mask_event_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ u32 mask, val;
-+
-+ mask = plda_hwirq_to_mask(data->hwirq);
-+
-+ raw_spin_lock(&port->lock);
-+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
-+ val &= ~mask;
-+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
-+ raw_spin_unlock(&port->lock);
-+}
-+
-+static void plda_unmask_event_irq(struct irq_data *data)
-+{
-+ struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
-+ u32 mask, val;
-+
-+ mask = plda_hwirq_to_mask(data->hwirq);
-+
-+ raw_spin_lock(&port->lock);
-+ val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
-+ val |= mask;
-+ writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
-+ raw_spin_unlock(&port->lock);
-+}
-+
-+static struct irq_chip plda_event_irq_chip = {
-+ .name = "PLDA PCIe EVENT",
-+ .irq_ack = plda_ack_event_irq,
-+ .irq_mask = plda_mask_event_irq,
-+ .irq_unmask = plda_unmask_event_irq,
-+};
-+
-+static const struct plda_event_ops plda_event_ops = {
-+ .get_events = plda_get_events,
-+};
-+
-+static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
-+ irq_hw_number_t hwirq)
-+{
-+ struct plda_pcie_rp *port = (void *)domain->host_data;
-+
-+ irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
-+ irq_set_chip_data(irq, domain->host_data);
-+
-+ return 0;
-+}
-+
-+static const struct irq_domain_ops plda_event_domain_ops = {
-+ .map = plda_pcie_event_map,
-+};
-+
-+static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
-+{
-+ struct device *dev = port->dev;
-+ struct device_node *node = dev->of_node;
-+ struct device_node *pcie_intc_node;
-+
-+ /* Setup INTx */
-+ pcie_intc_node = of_get_next_child(node, NULL);
-+ if (!pcie_intc_node) {
-+ dev_err(dev, "failed to find PCIe Intc node\n");
-+ return -EINVAL;
-+ }
-+
-+ port->event_domain = irq_domain_add_linear(pcie_intc_node,
-+ port->num_events,
-+ &plda_event_domain_ops,
-+ port);
-+ if (!port->event_domain) {
-+ dev_err(dev, "failed to get event domain\n");
-+ of_node_put(pcie_intc_node);
-+ return -ENOMEM;
-+ }
-+
-+ irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
-+
-+ port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
-+ &intx_domain_ops, port);
-+ if (!port->intx_domain) {
-+ dev_err(dev, "failed to get an INTx IRQ domain\n");
-+ of_node_put(pcie_intc_node);
-+ return -ENOMEM;
-+ }
-+
-+ irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
-+
-+ of_node_put(pcie_intc_node);
-+ raw_spin_lock_init(&port->lock);
-+
-+ return plda_allocate_msi_domains(port);
-+}
-+
-+int plda_init_interrupts(struct platform_device *pdev,
-+ struct plda_pcie_rp *port,
-+ const struct plda_event *event)
-+{
-+ struct device *dev = &pdev->dev;
-+ int irq;
-+ int i, intx_irq, msi_irq, event_irq;
-+ int ret;
-+
-+ if (!port->event_ops)
-+ port->event_ops = &plda_event_ops;
-+
-+ if (!port->event_irq_chip)
-+ port->event_irq_chip = &plda_event_irq_chip;
-+
-+ ret = plda_pcie_init_irq_domains(port);
-+ if (ret) {
-+ dev_err(dev, "failed creating IRQ domains\n");
-+ return ret;
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0)
-+ return -ENODEV;
-+
-+ for (i = 0; i < port->num_events; i++) {
-+ event_irq = irq_create_mapping(port->event_domain, i);
-+ if (!event_irq) {
-+ dev_err(dev, "failed to map hwirq %d\n", i);
-+ return -ENXIO;
-+ }
-+
-+ if (event->request_event_irq)
-+ ret = event->request_event_irq(port, event_irq, i);
-+ else
-+ ret = devm_request_irq(dev, event_irq,
-+ plda_event_handler,
-+ 0, NULL, port);
-+
-+ if (ret) {
-+ dev_err(dev, "failed to request IRQ %d\n", event_irq);
-+ return ret;
-+ }
-+ }
-+
-+ intx_irq = irq_create_mapping(port->event_domain,
-+ event->intx_event);
-+ if (!intx_irq) {
-+ dev_err(dev, "failed to map INTx interrupt\n");
-+ return -ENXIO;
-+ }
-+
-+ /* Plug the INTx chained handler */
-+ irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
-+
-+ msi_irq = irq_create_mapping(port->event_domain,
-+ event->msi_event);
-+ if (!msi_irq)
-+ return -ENXIO;
-+
-+ /* Plug the MSI chained handler */
-+ irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
-+
-+ /* Plug the main event chained handler */
-+ irq_set_chained_handler_and_data(irq, plda_handle_event, port);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(plda_init_interrupts);
-+
- void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
- phys_addr_t axi_addr, phys_addr_t pci_addr,
- size_t size)
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -169,6 +169,9 @@ struct plda_event {
- int msi_event;
- };
-
-+int plda_init_interrupts(struct platform_device *pdev,
-+ struct plda_pcie_rp *port,
-+ const struct plda_event *event);
- void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
- phys_addr_t axi_addr, phys_addr_t pci_addr,
- size_t size);
+++ /dev/null
-From 142fc300fd7511a217783dcfa342031d8ad70188 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:07 +0800
-Subject: [PATCH 030/116] pci: plda: Add event bitmap field to struct
- plda_pcie_rp
-
-For PLDA DMA interrupts are not all implemented. The non-implemented
-interrupts should be masked. So add a bitmap field to mask the non-
-implemented interrupts.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
----
- drivers/pci/controller/plda/pcie-microchip-host.c | 1 +
- drivers/pci/controller/plda/pcie-plda-host.c | 6 ++++--
- drivers/pci/controller/plda/pcie-plda.h | 1 +
- 3 files changed, 6 insertions(+), 2 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-microchip-host.c
-+++ b/drivers/pci/controller/plda/pcie-microchip-host.c
-@@ -636,6 +636,7 @@ static int mc_platform_init(struct pci_c
-
- port->plda.event_ops = &mc_event_ops;
- port->plda.event_irq_chip = &mc_event_irq_chip;
-+ port->plda.events_bitmap = GENMASK(NUM_EVENTS - 1, 0);
-
- /* Address translation is up; safe to enable interrupts */
- ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
---- a/drivers/pci/controller/plda/pcie-plda-host.c
-+++ b/drivers/pci/controller/plda/pcie-plda-host.c
-@@ -290,6 +290,7 @@ static void plda_handle_event(struct irq
-
- events = port->event_ops->get_events(port);
-
-+ events &= port->events_bitmap;
- for_each_set_bit(bit, &events, port->num_events)
- generic_handle_domain_irq(port->event_domain, bit);
-
-@@ -420,8 +421,9 @@ int plda_init_interrupts(struct platform
- {
- struct device *dev = &pdev->dev;
- int irq;
-- int i, intx_irq, msi_irq, event_irq;
-+ int intx_irq, msi_irq, event_irq;
- int ret;
-+ u32 i;
-
- if (!port->event_ops)
- port->event_ops = &plda_event_ops;
-@@ -439,7 +441,7 @@ int plda_init_interrupts(struct platform
- if (irq < 0)
- return -ENODEV;
-
-- for (i = 0; i < port->num_events; i++) {
-+ for_each_set_bit(i, &port->events_bitmap, port->num_events) {
- event_irq = irq_create_mapping(port->event_domain, i);
- if (!event_irq) {
- dev_err(dev, "failed to map hwirq %d\n", i);
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -159,6 +159,7 @@ struct plda_pcie_rp {
- const struct plda_event_ops *event_ops;
- const struct irq_chip *event_irq_chip;
- void __iomem *bridge_addr;
-+ unsigned long events_bitmap;
- int num_events;
- };
-
+++ /dev/null
-From 3b9991438094dc472dacb4555603bdc379653411 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:08 +0800
-Subject: [PATCH 031/116] PCI: plda: Add host init/deinit and map bus functions
-
-Add PLDA host plda_pcie_host_init()/plda_pcie_host_deinit() and map bus
-function. So vendor can use it to init PLDA PCIe host core.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
----
- drivers/pci/controller/plda/pcie-plda-host.c | 131 +++++++++++++++++--
- drivers/pci/controller/plda/pcie-plda.h | 22 ++++
- 2 files changed, 139 insertions(+), 14 deletions(-)
-
---- a/drivers/pci/controller/plda/pcie-plda-host.c
-+++ b/drivers/pci/controller/plda/pcie-plda-host.c
-@@ -3,6 +3,7 @@
- * PLDA PCIe XpressRich host controller driver
- *
- * Copyright (C) 2023 Microchip Co. Ltd
-+ * StarFive Co. Ltd
- *
- * Author: Daire McNamara <daire.mcnamara@microchip.com>
- */
-@@ -15,6 +16,15 @@
-
- #include "pcie-plda.h"
-
-+void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
-+ int where)
-+{
-+ struct plda_pcie_rp *pcie = bus->sysdata;
-+
-+ return pcie->config_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
-+}
-+EXPORT_SYMBOL_GPL(plda_pcie_map_bus);
-+
- static void plda_handle_msi(struct irq_desc *desc)
- {
- struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
-@@ -420,9 +430,7 @@ int plda_init_interrupts(struct platform
- const struct plda_event *event)
- {
- struct device *dev = &pdev->dev;
-- int irq;
-- int intx_irq, msi_irq, event_irq;
-- int ret;
-+ int event_irq, ret;
- u32 i;
-
- if (!port->event_ops)
-@@ -437,8 +445,8 @@ int plda_init_interrupts(struct platform
- return ret;
- }
-
-- irq = platform_get_irq(pdev, 0);
-- if (irq < 0)
-+ port->irq = platform_get_irq(pdev, 0);
-+ if (port->irq < 0)
- return -ENODEV;
-
- for_each_set_bit(i, &port->events_bitmap, port->num_events) {
-@@ -461,26 +469,26 @@ int plda_init_interrupts(struct platform
- }
- }
-
-- intx_irq = irq_create_mapping(port->event_domain,
-- event->intx_event);
-- if (!intx_irq) {
-+ port->intx_irq = irq_create_mapping(port->event_domain,
-+ event->intx_event);
-+ if (!port->intx_irq) {
- dev_err(dev, "failed to map INTx interrupt\n");
- return -ENXIO;
- }
-
- /* Plug the INTx chained handler */
-- irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
-+ irq_set_chained_handler_and_data(port->intx_irq, plda_handle_intx, port);
-
-- msi_irq = irq_create_mapping(port->event_domain,
-- event->msi_event);
-- if (!msi_irq)
-+ port->msi_irq = irq_create_mapping(port->event_domain,
-+ event->msi_event);
-+ if (!port->msi_irq)
- return -ENXIO;
-
- /* Plug the MSI chained handler */
-- irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
-+ irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port);
-
- /* Plug the main event chained handler */
-- irq_set_chained_handler_and_data(irq, plda_handle_event, port);
-+ irq_set_chained_handler_and_data(port->irq, plda_handle_event, port);
-
- return 0;
- }
-@@ -546,3 +554,98 @@ int plda_pcie_setup_iomems(struct pci_ho
- return 0;
- }
- EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
-+
-+static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
-+{
-+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
-+ irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
-+ irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
-+
-+ irq_domain_remove(pcie->msi.msi_domain);
-+ irq_domain_remove(pcie->msi.dev_domain);
-+
-+ irq_domain_remove(pcie->intx_domain);
-+ irq_domain_remove(pcie->event_domain);
-+}
-+
-+int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops,
-+ const struct plda_event *plda_event)
-+{
-+ struct device *dev = port->dev;
-+ struct pci_host_bridge *bridge;
-+ struct platform_device *pdev = to_platform_device(dev);
-+ struct resource *cfg_res;
-+ int ret;
-+
-+ pdev = to_platform_device(dev);
-+
-+ port->bridge_addr =
-+ devm_platform_ioremap_resource_byname(pdev, "apb");
-+
-+ if (IS_ERR(port->bridge_addr))
-+ return dev_err_probe(dev, PTR_ERR(port->bridge_addr),
-+ "failed to map reg memory\n");
-+
-+ cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
-+ if (!cfg_res)
-+ return dev_err_probe(dev, -ENODEV,
-+ "failed to get config memory\n");
-+
-+ port->config_base = devm_ioremap_resource(dev, cfg_res);
-+ if (IS_ERR(port->config_base))
-+ return dev_err_probe(dev, PTR_ERR(port->config_base),
-+ "failed to map config memory\n");
-+
-+ bridge = devm_pci_alloc_host_bridge(dev, 0);
-+ if (!bridge)
-+ return dev_err_probe(dev, -ENOMEM,
-+ "failed to alloc bridge\n");
-+
-+ if (port->host_ops && port->host_ops->host_init) {
-+ ret = port->host_ops->host_init(port);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ port->bridge = bridge;
-+ plda_pcie_setup_window(port->bridge_addr, 0, cfg_res->start, 0,
-+ resource_size(cfg_res));
-+ plda_pcie_setup_iomems(bridge, port);
-+ plda_set_default_msi(&port->msi);
-+ ret = plda_init_interrupts(pdev, port, plda_event);
-+ if (ret)
-+ goto err_host;
-+
-+ /* Set default bus ops */
-+ bridge->ops = ops;
-+ bridge->sysdata = port;
-+
-+ ret = pci_host_probe(bridge);
-+ if (ret < 0) {
-+ dev_err_probe(dev, ret, "failed to probe pci host\n");
-+ goto err_probe;
-+ }
-+
-+ return ret;
-+
-+err_probe:
-+ plda_pcie_irq_domain_deinit(port);
-+err_host:
-+ if (port->host_ops && port->host_ops->host_deinit)
-+ port->host_ops->host_deinit(port);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(plda_pcie_host_init);
-+
-+void plda_pcie_host_deinit(struct plda_pcie_rp *port)
-+{
-+ pci_stop_root_bus(port->bridge->bus);
-+ pci_remove_root_bus(port->bridge->bus);
-+
-+ plda_pcie_irq_domain_deinit(port);
-+
-+ if (port->host_ops && port->host_ops->host_deinit)
-+ port->host_ops->host_deinit(port);
-+}
-+EXPORT_SYMBOL_GPL(plda_pcie_host_deinit);
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -141,6 +141,11 @@ struct plda_event_ops {
- u32 (*get_events)(struct plda_pcie_rp *pcie);
- };
-
-+struct plda_pcie_host_ops {
-+ int (*host_init)(struct plda_pcie_rp *pcie);
-+ void (*host_deinit)(struct plda_pcie_rp *pcie);
-+};
-+
- struct plda_msi {
- struct mutex lock; /* Protect used bitmap */
- struct irq_domain *msi_domain;
-@@ -152,14 +157,20 @@ struct plda_msi {
-
- struct plda_pcie_rp {
- struct device *dev;
-+ struct pci_host_bridge *bridge;
- struct irq_domain *intx_domain;
- struct irq_domain *event_domain;
- raw_spinlock_t lock;
- struct plda_msi msi;
- const struct plda_event_ops *event_ops;
- const struct irq_chip *event_irq_chip;
-+ const struct plda_pcie_host_ops *host_ops;
- void __iomem *bridge_addr;
-+ void __iomem *config_base;
- unsigned long events_bitmap;
-+ int irq;
-+ int msi_irq;
-+ int intx_irq;
- int num_events;
- };
-
-@@ -170,6 +181,8 @@ struct plda_event {
- int msi_event;
- };
-
-+void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
-+ int where);
- int plda_init_interrupts(struct platform_device *pdev,
- struct plda_pcie_rp *port,
- const struct plda_event *event);
-@@ -178,4 +191,13 @@ void plda_pcie_setup_window(void __iomem
- size_t size);
- int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
- struct plda_pcie_rp *port);
-+int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops,
-+ const struct plda_event *plda_event);
-+void plda_pcie_host_deinit(struct plda_pcie_rp *pcie);
-+
-+static inline void plda_set_default_msi(struct plda_msi *msi)
-+{
-+ msi->vector_phy = IMSI_ADDR;
-+ msi->num_vectors = PLDA_MAX_NUM_MSI_IRQS;
-+}
- #endif
+++ /dev/null
-From bc3f8207d9f0af3cb96a7eae232074a644a175f6 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:09 +0800
-Subject: [PATCH 032/116] dt-bindings: PCI: Add StarFive JH7110 PCIe controller
-
-Add StarFive JH7110 SoC PCIe controller dt-bindings. JH7110 using PLDA
-XpressRICH PCIe host controller IP.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
-Reviewed-by: Rob Herring <robh@kernel.org>
----
- .../bindings/pci/starfive,jh7110-pcie.yaml | 120 ++++++++++++++++++
- 1 file changed, 120 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
-@@ -0,0 +1,120 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/pci/starfive,jh7110-pcie.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: StarFive JH7110 PCIe host controller
-+
-+maintainers:
-+ - Kevin Xie <kevin.xie@starfivetech.com>
-+
-+allOf:
-+ - $ref: plda,xpressrich3-axi-common.yaml#
-+
-+properties:
-+ compatible:
-+ const: starfive,jh7110-pcie
-+
-+ clocks:
-+ items:
-+ - description: NOC bus clock
-+ - description: Transport layer clock
-+ - description: AXI MST0 clock
-+ - description: APB clock
-+
-+ clock-names:
-+ items:
-+ - const: noc
-+ - const: tl
-+ - const: axi_mst0
-+ - const: apb
-+
-+ resets:
-+ items:
-+ - description: AXI MST0 reset
-+ - description: AXI SLAVE0 reset
-+ - description: AXI SLAVE reset
-+ - description: PCIE BRIDGE reset
-+ - description: PCIE CORE reset
-+ - description: PCIE APB reset
-+
-+ reset-names:
-+ items:
-+ - const: mst0
-+ - const: slv0
-+ - const: slv
-+ - const: brg
-+ - const: core
-+ - const: apb
-+
-+ starfive,stg-syscon:
-+ $ref: /schemas/types.yaml#/definitions/phandle-array
-+ description:
-+ The phandle to System Register Controller syscon node.
-+
-+ perst-gpios:
-+ description: GPIO controlled connection to PERST# signal
-+ maxItems: 1
-+
-+ phys:
-+ description:
-+ Specified PHY is attached to PCIe controller.
-+ maxItems: 1
-+
-+required:
-+ - clocks
-+ - resets
-+ - starfive,stg-syscon
-+
-+unevaluatedProperties: false
-+
-+examples:
-+ - |
-+ #include <dt-bindings/gpio/gpio.h>
-+ soc {
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+
-+ pcie@940000000 {
-+ compatible = "starfive,jh7110-pcie";
-+ reg = <0x9 0x40000000 0x0 0x10000000>,
-+ <0x0 0x2b000000 0x0 0x1000000>;
-+ reg-names = "cfg", "apb";
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ #interrupt-cells = <1>;
-+ device_type = "pci";
-+ ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>,
-+ <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>;
-+ starfive,stg-syscon = <&stg_syscon>;
-+ bus-range = <0x0 0xff>;
-+ interrupt-parent = <&plic>;
-+ interrupts = <56>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>,
-+ <0x0 0x0 0x0 0x2 &pcie_intc0 0x2>,
-+ <0x0 0x0 0x0 0x3 &pcie_intc0 0x3>,
-+ <0x0 0x0 0x0 0x4 &pcie_intc0 0x4>;
-+ msi-controller;
-+ clocks = <&syscrg 86>,
-+ <&stgcrg 10>,
-+ <&stgcrg 8>,
-+ <&stgcrg 9>;
-+ clock-names = "noc", "tl", "axi_mst0", "apb";
-+ resets = <&stgcrg 11>,
-+ <&stgcrg 12>,
-+ <&stgcrg 13>,
-+ <&stgcrg 14>,
-+ <&stgcrg 15>,
-+ <&stgcrg 16>;
-+ perst-gpios = <&gpios 26 GPIO_ACTIVE_LOW>;
-+ phys = <&pciephy0>;
-+
-+ pcie_intc0: interrupt-controller {
-+ #address-cells = <0>;
-+ #interrupt-cells = <1>;
-+ interrupt-controller;
-+ };
-+ };
-+ };
+++ /dev/null
-From abb20b7b8f5e3a7f36dbd6264e6d346275434154 Mon Sep 17 00:00:00 2001
-From: Kevin Xie <kevin.xie@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:10 +0800
-Subject: [PATCH 033/116] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting
- time value
-
-Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
-waiting time between exit from a conventional reset and sending the
-first configuration request to the device.
-
-As described in PCI base specification r6.0, section 6.6.1 <Conventional
-Reset>, there are two different use cases of the value:
-
- - "With a Downstream Port that does not support Link speeds greater
- than 5.0 GT/s, software must wait a minimum of 100 ms following exit
- from a Conventional Reset before sending a Configuration Request to
- the device immediately below that Port."
-
- - "With a Downstream Port that supports Link speeds greater than
- 5.0 GT/s, software must wait a minimum of 100 ms after Link training
- completes before sending a Configuration Request to the device
- immediately below that Port."
-
-Signed-off-by: Kevin Xie <kevin.xie@starfivetech.com>
-Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
-Acked-by: Bjorn Helgaas <bhelgaas@google.com>
----
- drivers/pci/pci.h | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/drivers/pci/pci.h
-+++ b/drivers/pci/pci.h
-@@ -22,6 +22,22 @@
- */
- #define PCIE_PME_TO_L2_TIMEOUT_US 10000
-
-+/*
-+ * As described in PCI base specification r6.0, section 6.6.1 <Conventional
-+ * Reset>, there are two different use cases of the value:
-+ *
-+ * - "With a Downstream Port that does not support Link speeds greater
-+ * than 5.0 GT/s, software must wait a minimum of 100 ms following exit
-+ * from a Conventional Reset before sending a Configuration Request to
-+ * the device immediately below that Port."
-+ *
-+ * - "With a Downstream Port that supports Link speeds greater than
-+ * 5.0 GT/s, software must wait a minimum of 100 ms after Link training
-+ * completes before sending a Configuration Request to the device
-+ * immediately below that Port."
-+ */
-+#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS 100
-+
- extern const unsigned char pcie_link_speed[];
- extern bool pci_early_dump;
-
+++ /dev/null
-From 323aedef34315b758dc30ba23e2cabca259bb4b2 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 8 Jan 2024 19:06:11 +0800
-Subject: [PATCH 034/116] PCI: starfive: Add JH7110 PCIe controller
-
-Add StarFive JH7110 SoC PCIe controller platform driver codes, JH7110
-with PLDA host PCIe core.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Co-developed-by: Kevin Xie <kevin.xie@starfivetech.com>
-Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
----
- drivers/pci/controller/plda/Kconfig | 12 +
- drivers/pci/controller/plda/Makefile | 1 +
- drivers/pci/controller/plda/pcie-plda.h | 71 ++-
- drivers/pci/controller/plda/pcie-starfive.c | 473 ++++++++++++++++++++
- 4 files changed, 556 insertions(+), 1 deletion(-)
- create mode 100644 drivers/pci/controller/plda/pcie-starfive.c
-
---- a/drivers/pci/controller/plda/Kconfig
-+++ b/drivers/pci/controller/plda/Kconfig
-@@ -15,4 +15,16 @@ config PCIE_MICROCHIP_HOST
- Say Y here if you want kernel to support the Microchip AXI PCIe
- Host Bridge driver.
-
-+config PCIE_STARFIVE_HOST
-+ tristate "StarFive PCIe host controller"
-+ depends on PCI_MSI && OF
-+ depends on ARCH_STARFIVE || COMPILE_TEST
-+ select PCIE_PLDA_HOST
-+ help
-+ Say Y here if you want to support the StarFive PCIe controller in
-+ host mode. StarFive PCIe controller uses PLDA PCIe core.
-+
-+ If you choose to build this driver as module it will be dynamically
-+ linked and module will be called pcie-starfive.ko.
-+
- endmenu
---- a/drivers/pci/controller/plda/Makefile
-+++ b/drivers/pci/controller/plda/Makefile
-@@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
- obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
- obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
-+obj-$(CONFIG_PCIE_STARFIVE_HOST) += pcie-starfive.o
---- a/drivers/pci/controller/plda/pcie-plda.h
-+++ b/drivers/pci/controller/plda/pcie-plda.h
-@@ -10,10 +10,20 @@
- #define PLDA_MAX_NUM_MSI_IRQS 32
-
- /* PCIe Bridge Phy Regs */
-+#define GEN_SETTINGS 0x80
-+#define RP_ENABLE 1
-+#define PCIE_PCI_IDS_DW1 0x9c
-+#define IDS_CLASS_CODE_SHIFT 16
-+#define REVISION_ID_MASK GENMASK(7, 0)
-+#define CLASS_CODE_ID_MASK GENMASK(31, 8)
- #define PCIE_PCI_IRQ_DW0 0xa8
- #define MSIX_CAP_MASK BIT(31)
- #define NUM_MSI_MSGS_MASK GENMASK(6, 4)
- #define NUM_MSI_MSGS_SHIFT 4
-+#define PCI_MISC 0xb4
-+#define PHY_FUNCTION_DIS BIT(15)
-+#define PCIE_WINROM 0xfc
-+#define PREF_MEM_WIN_64_SUPPORT BIT(3)
-
- #define IMASK_LOCAL 0x180
- #define DMA_END_ENGINE_0_MASK 0x00000000u
-@@ -65,6 +75,8 @@
- #define ISTATUS_HOST 0x18c
- #define IMSI_ADDR 0x190
- #define ISTATUS_MSI 0x194
-+#define PMSG_SUPPORT_RX 0x3f0
-+#define PMSG_LTR_SUPPORT BIT(2)
-
- /* PCIe Master table init defines */
- #define ATR0_PCIE_WIN0_SRCADDR_PARAM 0x600u
-@@ -86,6 +98,8 @@
- #define PCIE_TX_RX_INTERFACE 0x00000000u
- #define PCIE_CONFIG_INTERFACE 0x00000001u
-
-+#define CONFIG_SPACE_ADDR_OFFSET 0x1000u
-+
- #define ATR_ENTRY_SIZE 32
-
- enum plda_int_event {
-@@ -200,4 +214,59 @@ static inline void plda_set_default_msi(
- msi->vector_phy = IMSI_ADDR;
- msi->num_vectors = PLDA_MAX_NUM_MSI_IRQS;
- }
--#endif
-+
-+static inline void plda_pcie_enable_root_port(struct plda_pcie_rp *plda)
-+{
-+ u32 value;
-+
-+ value = readl_relaxed(plda->bridge_addr + GEN_SETTINGS);
-+ value |= RP_ENABLE;
-+ writel_relaxed(value, plda->bridge_addr + GEN_SETTINGS);
-+}
-+
-+static inline void plda_pcie_set_standard_class(struct plda_pcie_rp *plda)
-+{
-+ u32 value;
-+
-+ /* set class code and reserve revision id */
-+ value = readl_relaxed(plda->bridge_addr + PCIE_PCI_IDS_DW1);
-+ value &= REVISION_ID_MASK;
-+ value |= (PCI_CLASS_BRIDGE_PCI << IDS_CLASS_CODE_SHIFT);
-+ writel_relaxed(value, plda->bridge_addr + PCIE_PCI_IDS_DW1);
-+}
-+
-+static inline void plda_pcie_set_pref_win_64bit(struct plda_pcie_rp *plda)
-+{
-+ u32 value;
-+
-+ value = readl_relaxed(plda->bridge_addr + PCIE_WINROM);
-+ value |= PREF_MEM_WIN_64_SUPPORT;
-+ writel_relaxed(value, plda->bridge_addr + PCIE_WINROM);
-+}
-+
-+static inline void plda_pcie_disable_ltr(struct plda_pcie_rp *plda)
-+{
-+ u32 value;
-+
-+ value = readl_relaxed(plda->bridge_addr + PMSG_SUPPORT_RX);
-+ value &= ~PMSG_LTR_SUPPORT;
-+ writel_relaxed(value, plda->bridge_addr + PMSG_SUPPORT_RX);
-+}
-+
-+static inline void plda_pcie_disable_func(struct plda_pcie_rp *plda)
-+{
-+ u32 value;
-+
-+ value = readl_relaxed(plda->bridge_addr + PCI_MISC);
-+ value |= PHY_FUNCTION_DIS;
-+ writel_relaxed(value, plda->bridge_addr + PCI_MISC);
-+}
-+
-+static inline void plda_pcie_write_rc_bar(struct plda_pcie_rp *plda, u64 val)
-+{
-+ void __iomem *addr = plda->bridge_addr + CONFIG_SPACE_ADDR_OFFSET;
-+
-+ writel_relaxed(lower_32_bits(val), addr + PCI_BASE_ADDRESS_0);
-+ writel_relaxed(upper_32_bits(val), addr + PCI_BASE_ADDRESS_1);
-+}
-+#endif /* _PCIE_PLDA_H */
---- /dev/null
-+++ b/drivers/pci/controller/plda/pcie-starfive.c
-@@ -0,0 +1,473 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * PCIe host controller driver for StarFive JH7110 Soc.
-+ *
-+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
-+ */
-+
-+#include <linux/bitfield.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_pci.h>
-+#include <linux/pci.h>
-+#include <linux/phy/phy.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+#include "../../pci.h"
-+
-+#include "pcie-plda.h"
-+
-+#define PCIE_FUNC_NUM 4
-+
-+/* system control */
-+#define STG_SYSCON_PCIE0_BASE 0x48
-+#define STG_SYSCON_PCIE1_BASE 0x1f8
-+
-+#define STG_SYSCON_AR_OFFSET 0x78
-+#define STG_SYSCON_AXI4_SLVL_AR_MASK GENMASK(22, 8)
-+#define STG_SYSCON_AXI4_SLVL_PHY_AR(x) FIELD_PREP(GENMASK(20, 17), x)
-+#define STG_SYSCON_AW_OFFSET 0x7c
-+#define STG_SYSCON_AXI4_SLVL_AW_MASK GENMASK(14, 0)
-+#define STG_SYSCON_AXI4_SLVL_PHY_AW(x) FIELD_PREP(GENMASK(12, 9), x)
-+#define STG_SYSCON_CLKREQ BIT(22)
-+#define STG_SYSCON_CKREF_SRC_MASK GENMASK(19, 18)
-+#define STG_SYSCON_RP_NEP_OFFSET 0xe8
-+#define STG_SYSCON_K_RP_NEP BIT(8)
-+#define STG_SYSCON_LNKSTA_OFFSET 0x170
-+#define DATA_LINK_ACTIVE BIT(5)
-+
-+/* Parameters for the waiting for link up routine */
-+#define LINK_WAIT_MAX_RETRIES 10
-+#define LINK_WAIT_USLEEP_MIN 90000
-+#define LINK_WAIT_USLEEP_MAX 100000
-+
-+struct starfive_jh7110_pcie {
-+ struct plda_pcie_rp plda;
-+ struct reset_control *resets;
-+ struct clk_bulk_data *clks;
-+ struct regmap *reg_syscon;
-+ struct gpio_desc *power_gpio;
-+ struct gpio_desc *reset_gpio;
-+ struct phy *phy;
-+
-+ unsigned int stg_pcie_base;
-+ int num_clks;
-+};
-+
-+/*
-+ * The BAR0/1 of bridge should be hidden during enumeration to
-+ * avoid the sizing and resource allocation by PCIe core.
-+ */
-+static bool starfive_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int devfn,
-+ int offset)
-+{
-+ if (pci_is_root_bus(bus) && !devfn &&
-+ (offset == PCI_BASE_ADDRESS_0 || offset == PCI_BASE_ADDRESS_1))
-+ return true;
-+
-+ return false;
-+}
-+
-+static int starfive_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
-+ int where, int size, u32 value)
-+{
-+ if (starfive_pcie_hide_rc_bar(bus, devfn, where))
-+ return PCIBIOS_SUCCESSFUL;
-+
-+ return pci_generic_config_write(bus, devfn, where, size, value);
-+}
-+
-+static int starfive_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
-+ int where, int size, u32 *value)
-+{
-+ if (starfive_pcie_hide_rc_bar(bus, devfn, where)) {
-+ *value = 0;
-+ return PCIBIOS_SUCCESSFUL;
-+ }
-+
-+ return pci_generic_config_read(bus, devfn, where, size, value);
-+}
-+
-+static int starfive_pcie_parse_dt(struct starfive_jh7110_pcie *pcie,
-+ struct device *dev)
-+{
-+ int domain_nr;
-+
-+ pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks);
-+ if (pcie->num_clks < 0)
-+ return dev_err_probe(dev, pcie->num_clks,
-+ "failed to get pcie clocks\n");
-+
-+ pcie->resets = devm_reset_control_array_get_exclusive(dev);
-+ if (IS_ERR(pcie->resets))
-+ return dev_err_probe(dev, PTR_ERR(pcie->resets),
-+ "failed to get pcie resets");
-+
-+ pcie->reg_syscon =
-+ syscon_regmap_lookup_by_phandle(dev->of_node,
-+ "starfive,stg-syscon");
-+
-+ if (IS_ERR(pcie->reg_syscon))
-+ return dev_err_probe(dev, PTR_ERR(pcie->reg_syscon),
-+ "failed to parse starfive,stg-syscon\n");
-+
-+ pcie->phy = devm_phy_optional_get(dev, NULL);
-+ if (IS_ERR(pcie->phy))
-+ return dev_err_probe(dev, PTR_ERR(pcie->phy),
-+ "failed to get pcie phy\n");
-+
-+ domain_nr = of_get_pci_domain_nr(dev->of_node);
-+
-+ if (domain_nr < 0 || domain_nr > 1)
-+ return dev_err_probe(dev, -ENODEV,
-+ "failed to get valid pcie domain\n");
-+
-+ if (domain_nr == 0)
-+ pcie->stg_pcie_base = STG_SYSCON_PCIE0_BASE;
-+ else
-+ pcie->stg_pcie_base = STG_SYSCON_PCIE1_BASE;
-+
-+ pcie->reset_gpio = devm_gpiod_get_optional(dev, "perst",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(pcie->reset_gpio))
-+ return dev_err_probe(dev, PTR_ERR(pcie->reset_gpio),
-+ "failed to get perst-gpio\n");
-+
-+ pcie->power_gpio = devm_gpiod_get_optional(dev, "enable",
-+ GPIOD_OUT_LOW);
-+ if (IS_ERR(pcie->power_gpio))
-+ return dev_err_probe(dev, PTR_ERR(pcie->power_gpio),
-+ "failed to get power-gpio\n");
-+
-+ return 0;
-+}
-+
-+static struct pci_ops starfive_pcie_ops = {
-+ .map_bus = plda_pcie_map_bus,
-+ .read = starfive_pcie_config_read,
-+ .write = starfive_pcie_config_write,
-+};
-+
-+static int starfive_pcie_clk_rst_init(struct starfive_jh7110_pcie *pcie)
-+{
-+ struct device *dev = pcie->plda.dev;
-+ int ret;
-+
-+ ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "failed to enable clocks\n");
-+
-+ ret = reset_control_deassert(pcie->resets);
-+ if (ret) {
-+ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
-+ dev_err_probe(dev, ret, "failed to deassert resets\n");
-+ }
-+
-+ return ret;
-+}
-+
-+static void starfive_pcie_clk_rst_deinit(struct starfive_jh7110_pcie *pcie)
-+{
-+ reset_control_assert(pcie->resets);
-+ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
-+}
-+
-+static bool starfive_pcie_link_up(struct plda_pcie_rp *plda)
-+{
-+ struct starfive_jh7110_pcie *pcie =
-+ container_of(plda, struct starfive_jh7110_pcie, plda);
-+ int ret;
-+ u32 stg_reg_val;
-+
-+ ret = regmap_read(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_LNKSTA_OFFSET,
-+ &stg_reg_val);
-+ if (ret) {
-+ dev_err(pcie->plda.dev, "failed to read link status\n");
-+ return false;
-+ }
-+
-+ return !!(stg_reg_val & DATA_LINK_ACTIVE);
-+}
-+
-+static int starfive_pcie_host_wait_for_link(struct starfive_jh7110_pcie *pcie)
-+{
-+ int retries;
-+
-+ /* Check if the link is up or not */
-+ for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-+ if (starfive_pcie_link_up(&pcie->plda)) {
-+ dev_info(pcie->plda.dev, "port link up\n");
-+ return 0;
-+ }
-+ usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-+ }
-+
-+ return -ETIMEDOUT;
-+}
-+
-+static int starfive_pcie_enable_phy(struct device *dev,
-+ struct starfive_jh7110_pcie *pcie)
-+{
-+ int ret;
-+
-+ if (!pcie->phy)
-+ return 0;
-+
-+ ret = phy_init(pcie->phy);
-+ if (ret)
-+ return dev_err_probe(dev, ret,
-+ "failed to initialize pcie phy\n");
-+
-+ ret = phy_set_mode(pcie->phy, PHY_MODE_PCIE);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "failed to set pcie mode\n");
-+ goto err_phy_on;
-+ }
-+
-+ ret = phy_power_on(pcie->phy);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "failed to power on pcie phy\n");
-+ goto err_phy_on;
-+ }
-+
-+ return 0;
-+
-+err_phy_on:
-+ phy_exit(pcie->phy);
-+ return ret;
-+}
-+
-+static void starfive_pcie_disable_phy(struct starfive_jh7110_pcie *pcie)
-+{
-+ phy_power_off(pcie->phy);
-+ phy_exit(pcie->phy);
-+}
-+
-+static void starfive_pcie_host_deinit(struct plda_pcie_rp *plda)
-+{
-+ struct starfive_jh7110_pcie *pcie =
-+ container_of(plda, struct starfive_jh7110_pcie, plda);
-+
-+ starfive_pcie_clk_rst_deinit(pcie);
-+ if (pcie->power_gpio)
-+ gpiod_set_value_cansleep(pcie->power_gpio, 0);
-+ starfive_pcie_disable_phy(pcie);
-+}
-+
-+static int starfive_pcie_host_init(struct plda_pcie_rp *plda)
-+{
-+ struct starfive_jh7110_pcie *pcie =
-+ container_of(plda, struct starfive_jh7110_pcie, plda);
-+ struct device *dev = plda->dev;
-+ int ret;
-+ int i;
-+
-+ ret = starfive_pcie_enable_phy(dev, pcie);
-+ if (ret)
-+ return ret;
-+
-+ regmap_update_bits(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_RP_NEP_OFFSET,
-+ STG_SYSCON_K_RP_NEP, STG_SYSCON_K_RP_NEP);
-+
-+ regmap_update_bits(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
-+ STG_SYSCON_CKREF_SRC_MASK,
-+ FIELD_PREP(STG_SYSCON_CKREF_SRC_MASK, 2));
-+
-+ regmap_update_bits(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
-+ STG_SYSCON_CLKREQ, STG_SYSCON_CLKREQ);
-+
-+ ret = starfive_pcie_clk_rst_init(pcie);
-+ if (ret)
-+ return ret;
-+
-+ if (pcie->power_gpio)
-+ gpiod_set_value_cansleep(pcie->power_gpio, 1);
-+
-+ if (pcie->reset_gpio)
-+ gpiod_set_value_cansleep(pcie->reset_gpio, 1);
-+
-+ /* Disable physical functions except #0 */
-+ for (i = 1; i < PCIE_FUNC_NUM; i++) {
-+ regmap_update_bits(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_AR_OFFSET,
-+ STG_SYSCON_AXI4_SLVL_AR_MASK,
-+ STG_SYSCON_AXI4_SLVL_PHY_AR(i));
-+
-+ regmap_update_bits(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
-+ STG_SYSCON_AXI4_SLVL_AW_MASK,
-+ STG_SYSCON_AXI4_SLVL_PHY_AW(i));
-+
-+ plda_pcie_disable_func(plda);
-+ }
-+
-+ regmap_update_bits(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_AR_OFFSET,
-+ STG_SYSCON_AXI4_SLVL_AR_MASK, 0);
-+ regmap_update_bits(pcie->reg_syscon,
-+ pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
-+ STG_SYSCON_AXI4_SLVL_AW_MASK, 0);
-+
-+ plda_pcie_enable_root_port(plda);
-+ plda_pcie_write_rc_bar(plda, 0);
-+
-+ /* PCIe PCI Standard Configuration Identification Settings. */
-+ plda_pcie_set_standard_class(plda);
-+
-+ /*
-+ * The LTR message forwarding of PCIe Message Reception was set by core
-+ * as default, but the forward id & addr are also need to be reset.
-+ * If we do not disable LTR message forwarding here, or set a legal
-+ * forwarding address, the kernel will get stuck after the driver probe.
-+ * To workaround, disable the LTR message forwarding support on
-+ * PCIe Message Reception.
-+ */
-+ plda_pcie_disable_ltr(plda);
-+
-+ /* Prefetchable memory window 64-bit addressing support */
-+ plda_pcie_set_pref_win_64bit(plda);
-+
-+ /*
-+ * Ensure that PERST has been asserted for at least 100 ms,
-+ * the sleep value is T_PVPERL from PCIe CEM spec r2.0 (Table 2-4)
-+ */
-+ msleep(100);
-+ if (pcie->reset_gpio)
-+ gpiod_set_value_cansleep(pcie->reset_gpio, 0);
-+
-+ /*
-+ * With a Downstream Port (<=5GT/s), software must wait a minimum
-+ * of 100ms following exit from a conventional reset before
-+ * sending a configuration request to the device.
-+ */
-+ msleep(PCIE_RESET_CONFIG_DEVICE_WAIT_MS);
-+
-+ if (starfive_pcie_host_wait_for_link(pcie))
-+ dev_info(dev, "port link down\n");
-+
-+ return 0;
-+}
-+
-+static const struct plda_pcie_host_ops sf_host_ops = {
-+ .host_init = starfive_pcie_host_init,
-+ .host_deinit = starfive_pcie_host_deinit,
-+};
-+
-+static const struct plda_event stf_pcie_event = {
-+ .intx_event = EVENT_PM_MSI_INT_INTX,
-+ .msi_event = EVENT_PM_MSI_INT_MSI
-+};
-+
-+static int starfive_pcie_probe(struct platform_device *pdev)
-+{
-+ struct starfive_jh7110_pcie *pcie;
-+ struct device *dev = &pdev->dev;
-+ struct plda_pcie_rp *plda;
-+ int ret;
-+
-+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
-+ if (!pcie)
-+ return -ENOMEM;
-+
-+ plda = &pcie->plda;
-+ plda->dev = dev;
-+
-+ ret = starfive_pcie_parse_dt(pcie, dev);
-+ if (ret)
-+ return ret;
-+
-+ plda->host_ops = &sf_host_ops;
-+ plda->num_events = PLDA_MAX_EVENT_NUM;
-+ /* mask doorbell event */
-+ plda->events_bitmap = GENMASK(PLDA_INT_EVENT_NUM - 1, 0)
-+ & ~BIT(PLDA_AXI_DOORBELL)
-+ & ~BIT(PLDA_PCIE_DOORBELL);
-+ plda->events_bitmap <<= PLDA_NUM_DMA_EVENTS;
-+ ret = plda_pcie_host_init(&pcie->plda, &starfive_pcie_ops,
-+ &stf_pcie_event);
-+ if (ret)
-+ return ret;
-+
-+ pm_runtime_enable(&pdev->dev);
-+ pm_runtime_get_sync(&pdev->dev);
-+ platform_set_drvdata(pdev, pcie);
-+
-+ return 0;
-+}
-+
-+static void starfive_pcie_remove(struct platform_device *pdev)
-+{
-+ struct starfive_jh7110_pcie *pcie = platform_get_drvdata(pdev);
-+
-+ pm_runtime_put(&pdev->dev);
-+ pm_runtime_disable(&pdev->dev);
-+ plda_pcie_host_deinit(&pcie->plda);
-+ platform_set_drvdata(pdev, NULL);
-+}
-+
-+static int starfive_pcie_suspend_noirq(struct device *dev)
-+{
-+ struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev);
-+
-+ clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
-+ starfive_pcie_disable_phy(pcie);
-+
-+ return 0;
-+}
-+
-+static int starfive_pcie_resume_noirq(struct device *dev)
-+{
-+ struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev);
-+ int ret;
-+
-+ ret = starfive_pcie_enable_phy(dev, pcie);
-+ if (ret)
-+ return ret;
-+
-+ ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks);
-+ if (ret) {
-+ dev_err(dev, "failed to enable clocks\n");
-+ starfive_pcie_disable_phy(pcie);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct dev_pm_ops starfive_pcie_pm_ops = {
-+ NOIRQ_SYSTEM_SLEEP_PM_OPS(starfive_pcie_suspend_noirq,
-+ starfive_pcie_resume_noirq)
-+};
-+
-+static const struct of_device_id starfive_pcie_of_match[] = {
-+ { .compatible = "starfive,jh7110-pcie", },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, starfive_pcie_of_match);
-+
-+static struct platform_driver starfive_pcie_driver = {
-+ .driver = {
-+ .name = "pcie-starfive",
-+ .of_match_table = of_match_ptr(starfive_pcie_of_match),
-+ .pm = pm_sleep_ptr(&starfive_pcie_pm_ops),
-+ },
-+ .probe = starfive_pcie_probe,
-+ .remove_new = starfive_pcie_remove,
-+};
-+module_platform_driver(starfive_pcie_driver);
-+
-+MODULE_DESCRIPTION("StarFive JH7110 PCIe host driver");
-+MODULE_LICENSE("GPL v2");
+++ /dev/null
-From a306724fd4f32808d1e27efbd87019d56f60db20 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Mon, 14 Aug 2023 16:06:16 +0800
-Subject: [PATCH 035/116] ASoC: dt-bindings: Add StarFive JH7110 PWM-DAC
- controller
-
-Add bindings for the PWM-DAC controller on the JH7110
-RISC-V SoC by StarFive Ltd.
-
-Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
-Link: https://lore.kernel.org/r/20230814080618.10036-2-hal.feng@starfivetech.com
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- .../sound/starfive,jh7110-pwmdac.yaml | 76 +++++++++++++++++++
- 1 file changed, 76 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/sound/starfive,jh7110-pwmdac.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/sound/starfive,jh7110-pwmdac.yaml
-@@ -0,0 +1,76 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/sound/starfive,jh7110-pwmdac.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: StarFive JH7110 PWM-DAC Controller
-+
-+description:
-+ The PWM-DAC Controller uses PWM square wave generators plus RC filters to
-+ form a DAC for audio play in StarFive JH7110 SoC. This audio play controller
-+ supports 16 bit audio format, up to 48K sampling frequency, up to left and
-+ right dual channels.
-+
-+maintainers:
-+ - Hal Feng <hal.feng@starfivetech.com>
-+
-+allOf:
-+ - $ref: dai-common.yaml#
-+
-+properties:
-+ compatible:
-+ const: starfive,jh7110-pwmdac
-+
-+ reg:
-+ maxItems: 1
-+
-+ clocks:
-+ items:
-+ - description: PWMDAC APB
-+ - description: PWMDAC CORE
-+
-+ clock-names:
-+ items:
-+ - const: apb
-+ - const: core
-+
-+ resets:
-+ maxItems: 1
-+ description: PWMDAC APB
-+
-+ dmas:
-+ maxItems: 1
-+ description: TX DMA Channel
-+
-+ dma-names:
-+ const: tx
-+
-+ "#sound-dai-cells":
-+ const: 0
-+
-+required:
-+ - compatible
-+ - reg
-+ - clocks
-+ - clock-names
-+ - resets
-+ - dmas
-+ - dma-names
-+ - "#sound-dai-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ pwmdac@100b0000 {
-+ compatible = "starfive,jh7110-pwmdac";
-+ reg = <0x100b0000 0x1000>;
-+ clocks = <&syscrg 157>,
-+ <&syscrg 158>;
-+ clock-names = "apb", "core";
-+ resets = <&syscrg 96>;
-+ dmas = <&dma 22>;
-+ dma-names = "tx";
-+ #sound-dai-cells = <0>;
-+ };
+++ /dev/null
-From a79d2ec524012e35e32a2c4ae2401d0aa763697d Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Mon, 14 Aug 2023 16:06:17 +0800
-Subject: [PATCH 036/116] ASoC: starfive: Add JH7110 PWM-DAC driver
-
-Add PWM-DAC driver support for the StarFive JH7110 SoC.
-
-Reviewed-by: Walker Chen <walker.chen@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
-Link: https://lore.kernel.org/r/20230814080618.10036-3-hal.feng@starfivetech.com
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- sound/soc/starfive/Kconfig | 9 +
- sound/soc/starfive/Makefile | 1 +
- sound/soc/starfive/jh7110_pwmdac.c | 529 +++++++++++++++++++++++++++++
- 3 files changed, 539 insertions(+)
- create mode 100644 sound/soc/starfive/jh7110_pwmdac.c
-
---- a/sound/soc/starfive/Kconfig
-+++ b/sound/soc/starfive/Kconfig
-@@ -7,6 +7,15 @@ config SND_SOC_STARFIVE
- the Starfive SoCs' Audio interfaces. You will also need to
- select the audio interfaces to support below.
-
-+config SND_SOC_JH7110_PWMDAC
-+ tristate "JH7110 PWM-DAC device driver"
-+ depends on HAVE_CLK && SND_SOC_STARFIVE
-+ select SND_SOC_GENERIC_DMAENGINE_PCM
-+ select SND_SOC_SPDIF
-+ help
-+ Say Y or M if you want to add support for StarFive JH7110
-+ PWM-DAC driver.
-+
- config SND_SOC_JH7110_TDM
- tristate "JH7110 TDM device driver"
- depends on HAVE_CLK && SND_SOC_STARFIVE
---- a/sound/soc/starfive/Makefile
-+++ b/sound/soc/starfive/Makefile
-@@ -1,2 +1,3 @@
- # StarFive Platform Support
-+obj-$(CONFIG_SND_SOC_JH7110_PWMDAC) += jh7110_pwmdac.o
- obj-$(CONFIG_SND_SOC_JH7110_TDM) += jh7110_tdm.o
---- /dev/null
-+++ b/sound/soc/starfive/jh7110_pwmdac.c
-@@ -0,0 +1,529 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * jh7110_pwmdac.c -- StarFive JH7110 PWM-DAC driver
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ * Authors: Jenny Zhang
-+ * Curry Zhang
-+ * Xingyu Wu <xingyu.wu@starfivetech.com>
-+ * Hal Feng <hal.feng@starfivetech.com>
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/device.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/reset.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <sound/dmaengine_pcm.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+
-+#define JH7110_PWMDAC_WDATA 0x00
-+#define JH7110_PWMDAC_CTRL 0x04
-+ #define JH7110_PWMDAC_ENABLE BIT(0)
-+ #define JH7110_PWMDAC_SHIFT BIT(1)
-+ #define JH7110_PWMDAC_DUTY_CYCLE_SHIFT 2
-+ #define JH7110_PWMDAC_DUTY_CYCLE_MASK GENMASK(3, 2)
-+ #define JH7110_PWMDAC_CNT_N_SHIFT 4
-+ #define JH7110_PWMDAC_CNT_N_MASK GENMASK(12, 4)
-+ #define JH7110_PWMDAC_DATA_CHANGE BIT(13)
-+ #define JH7110_PWMDAC_DATA_MODE BIT(14)
-+ #define JH7110_PWMDAC_DATA_SHIFT_SHIFT 15
-+ #define JH7110_PWMDAC_DATA_SHIFT_MASK GENMASK(17, 15)
-+
-+enum JH7110_PWMDAC_SHIFT_VAL {
-+ PWMDAC_SHIFT_8 = 0,
-+ PWMDAC_SHIFT_10,
-+};
-+
-+enum JH7110_PWMDAC_DUTY_CYCLE_VAL {
-+ PWMDAC_CYCLE_LEFT = 0,
-+ PWMDAC_CYCLE_RIGHT,
-+ PWMDAC_CYCLE_CENTER,
-+};
-+
-+enum JH7110_PWMDAC_CNT_N_VAL {
-+ PWMDAC_SAMPLE_CNT_1 = 1,
-+ PWMDAC_SAMPLE_CNT_2,
-+ PWMDAC_SAMPLE_CNT_3,
-+ PWMDAC_SAMPLE_CNT_512 = 512, /* max */
-+};
-+
-+enum JH7110_PWMDAC_DATA_CHANGE_VAL {
-+ NO_CHANGE = 0,
-+ CHANGE,
-+};
-+
-+enum JH7110_PWMDAC_DATA_MODE_VAL {
-+ UNSIGNED_DATA = 0,
-+ INVERTER_DATA_MSB,
-+};
-+
-+enum JH7110_PWMDAC_DATA_SHIFT_VAL {
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_0 = 0,
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_1,
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_2,
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_3,
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_4,
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_5,
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_6,
-+ PWMDAC_DATA_LEFT_SHIFT_BIT_7,
-+};
-+
-+struct jh7110_pwmdac_cfg {
-+ enum JH7110_PWMDAC_SHIFT_VAL shift;
-+ enum JH7110_PWMDAC_DUTY_CYCLE_VAL duty_cycle;
-+ u16 cnt_n;
-+ enum JH7110_PWMDAC_DATA_CHANGE_VAL data_change;
-+ enum JH7110_PWMDAC_DATA_MODE_VAL data_mode;
-+ enum JH7110_PWMDAC_DATA_SHIFT_VAL data_shift;
-+};
-+
-+struct jh7110_pwmdac_dev {
-+ void __iomem *base;
-+ resource_size_t mapbase;
-+ struct jh7110_pwmdac_cfg cfg;
-+
-+ struct clk_bulk_data clks[2];
-+ struct reset_control *rst_apb;
-+ struct device *dev;
-+ struct snd_dmaengine_dai_dma_data play_dma_data;
-+ u32 saved_ctrl;
-+};
-+
-+static inline void jh7110_pwmdac_write_reg(void __iomem *io_base, int reg, u32 val)
-+{
-+ writel(val, io_base + reg);
-+}
-+
-+static inline u32 jh7110_pwmdac_read_reg(void __iomem *io_base, int reg)
-+{
-+ return readl(io_base + reg);
-+}
-+
-+static void jh7110_pwmdac_set_enable(struct jh7110_pwmdac_dev *dev, bool enable)
-+{
-+ u32 value;
-+
-+ value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL);
-+ if (enable)
-+ value |= JH7110_PWMDAC_ENABLE;
-+ else
-+ value &= ~JH7110_PWMDAC_ENABLE;
-+
-+ jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value);
-+}
-+
-+static void jh7110_pwmdac_set_shift(struct jh7110_pwmdac_dev *dev)
-+{
-+ u32 value;
-+
-+ value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL);
-+ if (dev->cfg.shift == PWMDAC_SHIFT_8)
-+ value &= ~JH7110_PWMDAC_SHIFT;
-+ else if (dev->cfg.shift == PWMDAC_SHIFT_10)
-+ value |= JH7110_PWMDAC_SHIFT;
-+
-+ jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value);
-+}
-+
-+static void jh7110_pwmdac_set_duty_cycle(struct jh7110_pwmdac_dev *dev)
-+{
-+ u32 value;
-+
-+ value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL);
-+ value &= ~JH7110_PWMDAC_DUTY_CYCLE_MASK;
-+ value |= (dev->cfg.duty_cycle & 0x3) << JH7110_PWMDAC_DUTY_CYCLE_SHIFT;
-+
-+ jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value);
-+}
-+
-+static void jh7110_pwmdac_set_cnt_n(struct jh7110_pwmdac_dev *dev)
-+{
-+ u32 value;
-+
-+ value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL);
-+ value &= ~JH7110_PWMDAC_CNT_N_MASK;
-+ value |= ((dev->cfg.cnt_n - 1) & 0x1ff) << JH7110_PWMDAC_CNT_N_SHIFT;
-+
-+ jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value);
-+}
-+
-+static void jh7110_pwmdac_set_data_change(struct jh7110_pwmdac_dev *dev)
-+{
-+ u32 value;
-+
-+ value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL);
-+ if (dev->cfg.data_change == NO_CHANGE)
-+ value &= ~JH7110_PWMDAC_DATA_CHANGE;
-+ else if (dev->cfg.data_change == CHANGE)
-+ value |= JH7110_PWMDAC_DATA_CHANGE;
-+
-+ jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value);
-+}
-+
-+static void jh7110_pwmdac_set_data_mode(struct jh7110_pwmdac_dev *dev)
-+{
-+ u32 value;
-+
-+ value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL);
-+ if (dev->cfg.data_mode == UNSIGNED_DATA)
-+ value &= ~JH7110_PWMDAC_DATA_MODE;
-+ else if (dev->cfg.data_mode == INVERTER_DATA_MSB)
-+ value |= JH7110_PWMDAC_DATA_MODE;
-+
-+ jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value);
-+}
-+
-+static void jh7110_pwmdac_set_data_shift(struct jh7110_pwmdac_dev *dev)
-+{
-+ u32 value;
-+
-+ value = jh7110_pwmdac_read_reg(dev->base, JH7110_PWMDAC_CTRL);
-+ value &= ~JH7110_PWMDAC_DATA_SHIFT_MASK;
-+ value |= (dev->cfg.data_shift & 0x7) << JH7110_PWMDAC_DATA_SHIFT_SHIFT;
-+
-+ jh7110_pwmdac_write_reg(dev->base, JH7110_PWMDAC_CTRL, value);
-+}
-+
-+static void jh7110_pwmdac_set(struct jh7110_pwmdac_dev *dev)
-+{
-+ jh7110_pwmdac_set_shift(dev);
-+ jh7110_pwmdac_set_duty_cycle(dev);
-+ jh7110_pwmdac_set_cnt_n(dev);
-+ jh7110_pwmdac_set_enable(dev, true);
-+
-+ jh7110_pwmdac_set_data_change(dev);
-+ jh7110_pwmdac_set_data_mode(dev);
-+ jh7110_pwmdac_set_data_shift(dev);
-+}
-+
-+static void jh7110_pwmdac_stop(struct jh7110_pwmdac_dev *dev)
-+{
-+ jh7110_pwmdac_set_enable(dev, false);
-+}
-+
-+static int jh7110_pwmdac_startup(struct snd_pcm_substream *substream,
-+ struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
-+
-+ dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC;
-+
-+ return 0;
-+}
-+
-+static int jh7110_pwmdac_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *dai)
-+{
-+ struct jh7110_pwmdac_dev *dev = dev_get_drvdata(dai->dev);
-+ unsigned long core_clk_rate;
-+ int ret;
-+
-+ switch (params_rate(params)) {
-+ case 8000:
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_3;
-+ core_clk_rate = 6144000;
-+ break;
-+ case 11025:
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_2;
-+ core_clk_rate = 5644800;
-+ break;
-+ case 16000:
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_3;
-+ core_clk_rate = 12288000;
-+ break;
-+ case 22050:
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1;
-+ core_clk_rate = 5644800;
-+ break;
-+ case 32000:
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1;
-+ core_clk_rate = 8192000;
-+ break;
-+ case 44100:
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1;
-+ core_clk_rate = 11289600;
-+ break;
-+ case 48000:
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1;
-+ core_clk_rate = 12288000;
-+ break;
-+ default:
-+ dev_err(dai->dev, "%d rate not supported\n",
-+ params_rate(params));
-+ return -EINVAL;
-+ }
-+
-+ switch (params_channels(params)) {
-+ case 1:
-+ dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-+ break;
-+ case 2:
-+ dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ break;
-+ default:
-+ dev_err(dai->dev, "%d channels not supported\n",
-+ params_channels(params));
-+ return -EINVAL;
-+ }
-+
-+ /*
-+ * The clock rate always rounds down when using clk_set_rate()
-+ * so increase the rate a bit
-+ */
-+ core_clk_rate += 64;
-+ jh7110_pwmdac_set(dev);
-+
-+ ret = clk_set_rate(dev->clks[1].clk, core_clk_rate);
-+ if (ret)
-+ return dev_err_probe(dai->dev, ret,
-+ "failed to set rate %lu for core clock\n",
-+ core_clk_rate);
-+
-+ return 0;
-+}
-+
-+static int jh7110_pwmdac_trigger(struct snd_pcm_substream *substream, int cmd,
-+ struct snd_soc_dai *dai)
-+{
-+ struct jh7110_pwmdac_dev *dev = snd_soc_dai_get_drvdata(dai);
-+ int ret = 0;
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ case SNDRV_PCM_TRIGGER_RESUME:
-+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+ jh7110_pwmdac_set(dev);
-+ break;
-+
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ case SNDRV_PCM_TRIGGER_SUSPEND:
-+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+ jh7110_pwmdac_stop(dev);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int jh7110_pwmdac_crg_enable(struct jh7110_pwmdac_dev *dev, bool enable)
-+{
-+ int ret;
-+
-+ if (enable) {
-+ ret = clk_bulk_prepare_enable(ARRAY_SIZE(dev->clks), dev->clks);
-+ if (ret)
-+ return dev_err_probe(dev->dev, ret,
-+ "failed to enable pwmdac clocks\n");
-+
-+ ret = reset_control_deassert(dev->rst_apb);
-+ if (ret) {
-+ dev_err(dev->dev, "failed to deassert pwmdac apb reset\n");
-+ goto err_rst_apb;
-+ }
-+ } else {
-+ clk_bulk_disable_unprepare(ARRAY_SIZE(dev->clks), dev->clks);
-+ }
-+
-+ return 0;
-+
-+err_rst_apb:
-+ clk_bulk_disable_unprepare(ARRAY_SIZE(dev->clks), dev->clks);
-+
-+ return ret;
-+}
-+
-+static int jh7110_pwmdac_dai_probe(struct snd_soc_dai *dai)
-+{
-+ struct jh7110_pwmdac_dev *dev = dev_get_drvdata(dai->dev);
-+
-+ snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, NULL);
-+ snd_soc_dai_set_drvdata(dai, dev);
-+
-+ return 0;
-+}
-+
-+static const struct snd_soc_dai_ops jh7110_pwmdac_dai_ops = {
-+ .startup = jh7110_pwmdac_startup,
-+ .hw_params = jh7110_pwmdac_hw_params,
-+ .trigger = jh7110_pwmdac_trigger,
-+};
-+
-+static const struct snd_soc_component_driver jh7110_pwmdac_component = {
-+ .name = "jh7110-pwmdac",
-+};
-+
-+static struct snd_soc_dai_driver jh7110_pwmdac_dai = {
-+ .name = "jh7110-pwmdac",
-+ .id = 0,
-+ .probe = jh7110_pwmdac_dai_probe,
-+ .playback = {
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .rates = SNDRV_PCM_RATE_8000_48000,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
-+ },
-+ .ops = &jh7110_pwmdac_dai_ops,
-+};
-+
-+static int jh7110_pwmdac_runtime_suspend(struct device *dev)
-+{
-+ struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
-+
-+ return jh7110_pwmdac_crg_enable(pwmdac, false);
-+}
-+
-+static int jh7110_pwmdac_runtime_resume(struct device *dev)
-+{
-+ struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
-+
-+ return jh7110_pwmdac_crg_enable(pwmdac, true);
-+}
-+
-+static int jh7110_pwmdac_system_suspend(struct device *dev)
-+{
-+ struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
-+
-+ /* save the CTRL register value */
-+ pwmdac->saved_ctrl = jh7110_pwmdac_read_reg(pwmdac->base,
-+ JH7110_PWMDAC_CTRL);
-+ return pm_runtime_force_suspend(dev);
-+}
-+
-+static int jh7110_pwmdac_system_resume(struct device *dev)
-+{
-+ struct jh7110_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
-+ int ret;
-+
-+ ret = pm_runtime_force_resume(dev);
-+ if (ret)
-+ return ret;
-+
-+ /* restore the CTRL register value */
-+ jh7110_pwmdac_write_reg(pwmdac->base, JH7110_PWMDAC_CTRL,
-+ pwmdac->saved_ctrl);
-+ return 0;
-+}
-+
-+static const struct dev_pm_ops jh7110_pwmdac_pm_ops = {
-+ RUNTIME_PM_OPS(jh7110_pwmdac_runtime_suspend,
-+ jh7110_pwmdac_runtime_resume, NULL)
-+ SYSTEM_SLEEP_PM_OPS(jh7110_pwmdac_system_suspend,
-+ jh7110_pwmdac_system_resume)
-+};
-+
-+static void jh7110_pwmdac_init_params(struct jh7110_pwmdac_dev *dev)
-+{
-+ dev->cfg.shift = PWMDAC_SHIFT_8;
-+ dev->cfg.duty_cycle = PWMDAC_CYCLE_CENTER;
-+ dev->cfg.cnt_n = PWMDAC_SAMPLE_CNT_1;
-+ dev->cfg.data_change = NO_CHANGE;
-+ dev->cfg.data_mode = INVERTER_DATA_MSB;
-+ dev->cfg.data_shift = PWMDAC_DATA_LEFT_SHIFT_BIT_0;
-+
-+ dev->play_dma_data.addr = dev->mapbase + JH7110_PWMDAC_WDATA;
-+ dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dev->play_dma_data.fifo_size = 1;
-+ dev->play_dma_data.maxburst = 16;
-+}
-+
-+static int jh7110_pwmdac_probe(struct platform_device *pdev)
-+{
-+ struct jh7110_pwmdac_dev *dev;
-+ struct resource *res;
-+ int ret;
-+
-+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-+ if (!dev)
-+ return -ENOMEM;
-+
-+ dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-+ if (IS_ERR(dev->base))
-+ return PTR_ERR(dev->base);
-+
-+ dev->mapbase = res->start;
-+
-+ dev->clks[0].id = "apb";
-+ dev->clks[1].id = "core";
-+
-+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(dev->clks), dev->clks);
-+ if (ret)
-+ return dev_err_probe(&pdev->dev, ret,
-+ "failed to get pwmdac clocks\n");
-+
-+ dev->rst_apb = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-+ if (IS_ERR(dev->rst_apb))
-+ return dev_err_probe(&pdev->dev, PTR_ERR(dev->rst_apb),
-+ "failed to get pwmdac apb reset\n");
-+
-+ jh7110_pwmdac_init_params(dev);
-+
-+ dev->dev = &pdev->dev;
-+ dev_set_drvdata(&pdev->dev, dev);
-+ ret = devm_snd_soc_register_component(&pdev->dev,
-+ &jh7110_pwmdac_component,
-+ &jh7110_pwmdac_dai, 1);
-+ if (ret)
-+ return dev_err_probe(&pdev->dev, ret, "failed to register dai\n");
-+
-+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
-+ if (ret)
-+ return dev_err_probe(&pdev->dev, ret, "failed to register pcm\n");
-+
-+ pm_runtime_enable(dev->dev);
-+ if (!pm_runtime_enabled(&pdev->dev)) {
-+ ret = jh7110_pwmdac_runtime_resume(&pdev->dev);
-+ if (ret)
-+ goto err_pm_disable;
-+ }
-+
-+ return 0;
-+
-+err_pm_disable:
-+ pm_runtime_disable(&pdev->dev);
-+
-+ return ret;
-+}
-+
-+static int jh7110_pwmdac_remove(struct platform_device *pdev)
-+{
-+ pm_runtime_disable(&pdev->dev);
-+ return 0;
-+}
-+
-+static const struct of_device_id jh7110_pwmdac_of_match[] = {
-+ { .compatible = "starfive,jh7110-pwmdac" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, jh7110_pwmdac_of_match);
-+
-+static struct platform_driver jh7110_pwmdac_driver = {
-+ .driver = {
-+ .name = "jh7110-pwmdac",
-+ .of_match_table = jh7110_pwmdac_of_match,
-+ .pm = pm_ptr(&jh7110_pwmdac_pm_ops),
-+ },
-+ .probe = jh7110_pwmdac_probe,
-+ .remove = jh7110_pwmdac_remove,
-+};
-+module_platform_driver(jh7110_pwmdac_driver);
-+
-+MODULE_AUTHOR("Jenny Zhang");
-+MODULE_AUTHOR("Curry Zhang");
-+MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
-+MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
-+MODULE_DESCRIPTION("StarFive JH7110 PWM-DAC driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From c6b693f990e1f89ab5af0a139da31401b8cda74f Mon Sep 17 00:00:00 2001
-From: Mark Brown <broonie@kernel.org>
-Date: Mon, 11 Sep 2023 23:48:39 +0100
-Subject: [PATCH 037/116] ASoC: Update jh7110 PWM DAC for ops move
-
-For some reason the JH7110 PWM DAC driver made it through build testing
-in spite of not being updated for the move of probe() to the ops struct.
-Make the required update.
-
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- sound/soc/starfive/jh7110_pwmdac.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/sound/soc/starfive/jh7110_pwmdac.c
-+++ b/sound/soc/starfive/jh7110_pwmdac.c
-@@ -357,6 +357,7 @@ static int jh7110_pwmdac_dai_probe(struc
- }
-
- static const struct snd_soc_dai_ops jh7110_pwmdac_dai_ops = {
-+ .probe = jh7110_pwmdac_dai_probe,
- .startup = jh7110_pwmdac_startup,
- .hw_params = jh7110_pwmdac_hw_params,
- .trigger = jh7110_pwmdac_trigger,
-@@ -369,7 +370,6 @@ static const struct snd_soc_component_dr
- static struct snd_soc_dai_driver jh7110_pwmdac_dai = {
- .name = "jh7110-pwmdac",
- .id = 0,
-- .probe = jh7110_pwmdac_dai_probe,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
+++ /dev/null
-From 312c3c407c363f0ec7417d2d389cbe936c503729 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
-Date: Sat, 14 Oct 2023 00:19:49 +0200
-Subject: [PATCH 038/116] ASoC: starfive/jh7110-pwmdac: Convert to platform
- remove callback returning void
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The .remove() callback for a platform driver returns an int which makes
-many driver authors wrongly assume it's possible to do error handling by
-returning an error code. However the value returned is ignored (apart
-from emitting a warning) and this typically results in resource leaks.
-
-To improve here there is a quest to make the remove callback return
-void. In the first step of this quest all drivers are converted to
-.remove_new(), which already returns void. Eventually after all drivers
-are converted, .remove_new() will be renamed to .remove().
-
-Trivially convert this driver from always returning zero in the remove
-callback to the void returning variant.
-
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-Link: https://lore.kernel.org/r/20231013221945.1489203-12-u.kleine-koenig@pengutronix.de
-Signed-off-by: Mark Brown <broonie@kernel.org>
----
- sound/soc/starfive/jh7110_pwmdac.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
---- a/sound/soc/starfive/jh7110_pwmdac.c
-+++ b/sound/soc/starfive/jh7110_pwmdac.c
-@@ -498,10 +498,9 @@ err_pm_disable:
- return ret;
- }
-
--static int jh7110_pwmdac_remove(struct platform_device *pdev)
-+static void jh7110_pwmdac_remove(struct platform_device *pdev)
- {
- pm_runtime_disable(&pdev->dev);
-- return 0;
- }
-
- static const struct of_device_id jh7110_pwmdac_of_match[] = {
-@@ -517,7 +516,7 @@ static struct platform_driver jh7110_pwm
- .pm = pm_ptr(&jh7110_pwmdac_pm_ops),
- },
- .probe = jh7110_pwmdac_probe,
-- .remove = jh7110_pwmdac_remove,
-+ .remove_new = jh7110_pwmdac_remove,
- };
- module_platform_driver(jh7110_pwmdac_driver);
-
+++ /dev/null
-From 8d84bac6d7471ba2e29b33d19a2ef887822e9cce Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Wed, 13 Sep 2023 14:54:25 +0100
-Subject: [PATCH 039/116] dt-bindings: power: Add power-domain header for
- JH7110
-
-Add power-domain header for JH7110 SoC, it can use to operate dphy
-power.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
-Link: https://lore.kernel.org/r/20230913-grumbly-rewrite-34c85539f2ed@spud
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- include/dt-bindings/power/starfive,jh7110-pmu.h | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/include/dt-bindings/power/starfive,jh7110-pmu.h
-+++ b/include/dt-bindings/power/starfive,jh7110-pmu.h
-@@ -1,6 +1,6 @@
- /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
- /*
-- * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
- * Author: Walker Chen <walker.chen@starfivetech.com>
- */
- #ifndef __DT_BINDINGS_POWER_JH7110_POWER_H__
-@@ -14,4 +14,7 @@
- #define JH7110_PD_ISP 5
- #define JH7110_PD_VENC 6
-
-+#define JH7110_PD_DPHY_TX 0
-+#define JH7110_PD_DPHY_RX 1
-+
- #endif
+++ /dev/null
-From 0ac8e8b0e65d242f455401df0cc6c6d4772216e6 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Wed, 13 Sep 2023 14:54:26 +0100
-Subject: [PATCH 040/116] pmdomain: starfive: Replace SOC_STARFIVE with
- ARCH_STARFIVE
-
-Using ARCH_FOO symbol is preferred than SOC_FOO.
-
-Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
-Reviewed-by: Walker Chen <walker.chen@starfivetech.com>
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
-Link: https://lore.kernel.org/r/20230913-legibly-treachery-567cffcb5604@spud
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- drivers/soc/starfive/Kconfig | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/soc/starfive/Kconfig
-+++ b/drivers/soc/starfive/Kconfig
-@@ -3,8 +3,8 @@
- config JH71XX_PMU
- bool "Support PMU for StarFive JH71XX Soc"
- depends on PM
-- depends on SOC_STARFIVE || COMPILE_TEST
-- default SOC_STARFIVE
-+ depends on ARCH_STARFIVE || COMPILE_TEST
-+ default ARCH_STARFIVE
- select PM_GENERIC_DOMAINS
- help
- Say 'y' here to enable support power domain support.
+++ /dev/null
-From a1ba60e35ca7f1b85243054556ecde2e259619e1 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Wed, 13 Sep 2023 14:54:27 +0100
-Subject: [PATCH 041/116] pmdomain: starfive: Extract JH7110 pmu private
- operations
-
-Move JH7110 private operation into private data of compatible. Convenient
-to add AON PMU which would not have interrupts property.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
-Reviewed-by: Walker Chen <walker.chen@starfivetech.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
-Link: https://lore.kernel.org/r/20230913-slideshow-luckiness-38ff17de84c6@spud
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- drivers/pmdomain/starfive/jh71xx-pmu.c | 89 ++++++++++++++++++--------
- 1 file changed, 62 insertions(+), 27 deletions(-)
-
---- a/drivers/pmdomain/starfive/jh71xx-pmu.c
-+++ b/drivers/pmdomain/starfive/jh71xx-pmu.c
-@@ -51,9 +51,17 @@ struct jh71xx_domain_info {
- u8 bit;
- };
-
-+struct jh71xx_pmu;
-+struct jh71xx_pmu_dev;
-+
- struct jh71xx_pmu_match_data {
- const struct jh71xx_domain_info *domain_info;
- int num_domains;
-+ unsigned int pmu_status;
-+ int (*pmu_parse_irq)(struct platform_device *pdev,
-+ struct jh71xx_pmu *pmu);
-+ int (*pmu_set_state)(struct jh71xx_pmu_dev *pmd,
-+ u32 mask, bool on);
- };
-
- struct jh71xx_pmu {
-@@ -79,12 +87,12 @@ static int jh71xx_pmu_get_state(struct j
- if (!mask)
- return -EINVAL;
-
-- *is_on = readl(pmu->base + JH71XX_PMU_CURR_POWER_MODE) & mask;
-+ *is_on = readl(pmu->base + pmu->match_data->pmu_status) & mask;
-
- return 0;
- }
-
--static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on)
-+static int jh7110_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on)
- {
- struct jh71xx_pmu *pmu = pmd->pmu;
- unsigned long flags;
-@@ -92,22 +100,8 @@ static int jh71xx_pmu_set_state(struct j
- u32 mode;
- u32 encourage_lo;
- u32 encourage_hi;
-- bool is_on;
- int ret;
-
-- ret = jh71xx_pmu_get_state(pmd, mask, &is_on);
-- if (ret) {
-- dev_dbg(pmu->dev, "unable to get current state for %s\n",
-- pmd->genpd.name);
-- return ret;
-- }
--
-- if (is_on == on) {
-- dev_dbg(pmu->dev, "pm domain [%s] is already %sable status.\n",
-- pmd->genpd.name, on ? "en" : "dis");
-- return 0;
-- }
--
- spin_lock_irqsave(&pmu->lock, flags);
-
- /*
-@@ -166,6 +160,29 @@ static int jh71xx_pmu_set_state(struct j
- return 0;
- }
-
-+static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on)
-+{
-+ struct jh71xx_pmu *pmu = pmd->pmu;
-+ const struct jh71xx_pmu_match_data *match_data = pmu->match_data;
-+ bool is_on;
-+ int ret;
-+
-+ ret = jh71xx_pmu_get_state(pmd, mask, &is_on);
-+ if (ret) {
-+ dev_dbg(pmu->dev, "unable to get current state for %s\n",
-+ pmd->genpd.name);
-+ return ret;
-+ }
-+
-+ if (is_on == on) {
-+ dev_dbg(pmu->dev, "pm domain [%s] is already %sable status.\n",
-+ pmd->genpd.name, on ? "en" : "dis");
-+ return 0;
-+ }
-+
-+ return match_data->pmu_set_state(pmd, mask, on);
-+}
-+
- static int jh71xx_pmu_on(struct generic_pm_domain *genpd)
- {
- struct jh71xx_pmu_dev *pmd = container_of(genpd,
-@@ -226,6 +243,25 @@ static irqreturn_t jh71xx_pmu_interrupt(
- return IRQ_HANDLED;
- }
-
-+static int jh7110_pmu_parse_irq(struct platform_device *pdev, struct jh71xx_pmu *pmu)
-+{
-+ struct device *dev = &pdev->dev;
-+ int ret;
-+
-+ pmu->irq = platform_get_irq(pdev, 0);
-+ if (pmu->irq < 0)
-+ return pmu->irq;
-+
-+ ret = devm_request_irq(dev, pmu->irq, jh71xx_pmu_interrupt,
-+ 0, pdev->name, pmu);
-+ if (ret)
-+ dev_err(dev, "failed to request irq\n");
-+
-+ jh71xx_pmu_int_enable(pmu, JH71XX_PMU_INT_ALL_MASK & ~JH71XX_PMU_INT_PCH_FAIL, true);
-+
-+ return 0;
-+}
-+
- static int jh71xx_pmu_init_domain(struct jh71xx_pmu *pmu, int index)
- {
- struct jh71xx_pmu_dev *pmd;
-@@ -275,19 +311,18 @@ static int jh71xx_pmu_probe(struct platf
- if (IS_ERR(pmu->base))
- return PTR_ERR(pmu->base);
-
-- pmu->irq = platform_get_irq(pdev, 0);
-- if (pmu->irq < 0)
-- return pmu->irq;
--
-- ret = devm_request_irq(dev, pmu->irq, jh71xx_pmu_interrupt,
-- 0, pdev->name, pmu);
-- if (ret)
-- dev_err(dev, "failed to request irq\n");
-+ spin_lock_init(&pmu->lock);
-
- match_data = of_device_get_match_data(dev);
- if (!match_data)
- return -EINVAL;
-
-+ ret = match_data->pmu_parse_irq(pdev, pmu);
-+ if (ret) {
-+ dev_err(dev, "failed to parse irq\n");
-+ return ret;
-+ }
-+
- pmu->genpd = devm_kcalloc(dev, match_data->num_domains,
- sizeof(struct generic_pm_domain *),
- GFP_KERNEL);
-@@ -307,9 +342,6 @@ static int jh71xx_pmu_probe(struct platf
- }
- }
-
-- spin_lock_init(&pmu->lock);
-- jh71xx_pmu_int_enable(pmu, JH71XX_PMU_INT_ALL_MASK & ~JH71XX_PMU_INT_PCH_FAIL, true);
--
- ret = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
- if (ret) {
- dev_err(dev, "failed to register genpd driver: %d\n", ret);
-@@ -357,6 +389,9 @@ static const struct jh71xx_domain_info j
- static const struct jh71xx_pmu_match_data jh7110_pmu = {
- .num_domains = ARRAY_SIZE(jh7110_power_domains),
- .domain_info = jh7110_power_domains,
-+ .pmu_status = JH71XX_PMU_CURR_POWER_MODE,
-+ .pmu_parse_irq = jh7110_pmu_parse_irq,
-+ .pmu_set_state = jh7110_pmu_set_state,
- };
-
- static const struct of_device_id jh71xx_pmu_of_match[] = {
+++ /dev/null
-From 1bf849b606d0b4cae643f96685d3d3981643683d Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Wed, 13 Sep 2023 14:54:28 +0100
-Subject: [PATCH 042/116] pmdomain: starfive: Add JH7110 AON PMU support
-
-Add AON PMU for StarFive JH7110 SoC. It can be used to turn on/off the
-dphy rx/tx power switch.
-
-Reviewed-by: Walker Chen <walker.chen@starfivetech.com>
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
-Link: https://lore.kernel.org/r/20230913-dude-imprecise-fc32622bc947@spud
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- drivers/pmdomain/starfive/jh71xx-pmu.c | 57 +++++++++++++++++++++++---
- 1 file changed, 52 insertions(+), 5 deletions(-)
-
---- a/drivers/pmdomain/starfive/jh71xx-pmu.c
-+++ b/drivers/pmdomain/starfive/jh71xx-pmu.c
-@@ -2,7 +2,7 @@
- /*
- * StarFive JH71XX PMU (Power Management Unit) Controller Driver
- *
-- * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ * Copyright (C) 2022-2023 StarFive Technology Co., Ltd.
- */
-
- #include <linux/interrupt.h>
-@@ -24,6 +24,9 @@
- #define JH71XX_PMU_EVENT_STATUS 0x88
- #define JH71XX_PMU_INT_STATUS 0x8C
-
-+/* aon pmu register offset */
-+#define JH71XX_AON_PMU_SWITCH 0x00
-+
- /* sw encourage cfg */
- #define JH71XX_PMU_SW_ENCOURAGE_EN_LO 0x05
- #define JH71XX_PMU_SW_ENCOURAGE_EN_HI 0x50
-@@ -160,6 +163,26 @@ static int jh7110_pmu_set_state(struct j
- return 0;
- }
-
-+static int jh7110_aon_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on)
-+{
-+ struct jh71xx_pmu *pmu = pmd->pmu;
-+ unsigned long flags;
-+ u32 val;
-+
-+ spin_lock_irqsave(&pmu->lock, flags);
-+ val = readl(pmu->base + JH71XX_AON_PMU_SWITCH);
-+
-+ if (on)
-+ val |= mask;
-+ else
-+ val &= ~mask;
-+
-+ writel(val, pmu->base + JH71XX_AON_PMU_SWITCH);
-+ spin_unlock_irqrestore(&pmu->lock, flags);
-+
-+ return 0;
-+}
-+
- static int jh71xx_pmu_set_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool on)
- {
- struct jh71xx_pmu *pmu = pmd->pmu;
-@@ -317,10 +340,12 @@ static int jh71xx_pmu_probe(struct platf
- if (!match_data)
- return -EINVAL;
-
-- ret = match_data->pmu_parse_irq(pdev, pmu);
-- if (ret) {
-- dev_err(dev, "failed to parse irq\n");
-- return ret;
-+ if (match_data->pmu_parse_irq) {
-+ ret = match_data->pmu_parse_irq(pdev, pmu);
-+ if (ret) {
-+ dev_err(dev, "failed to parse irq\n");
-+ return ret;
-+ }
- }
-
- pmu->genpd = devm_kcalloc(dev, match_data->num_domains,
-@@ -394,11 +419,32 @@ static const struct jh71xx_pmu_match_dat
- .pmu_set_state = jh7110_pmu_set_state,
- };
-
-+static const struct jh71xx_domain_info jh7110_aon_power_domains[] = {
-+ [JH7110_PD_DPHY_TX] = {
-+ .name = "DPHY-TX",
-+ .bit = 30,
-+ },
-+ [JH7110_PD_DPHY_RX] = {
-+ .name = "DPHY-RX",
-+ .bit = 31,
-+ },
-+};
-+
-+static const struct jh71xx_pmu_match_data jh7110_aon_pmu = {
-+ .num_domains = ARRAY_SIZE(jh7110_aon_power_domains),
-+ .domain_info = jh7110_aon_power_domains,
-+ .pmu_status = JH71XX_AON_PMU_SWITCH,
-+ .pmu_set_state = jh7110_aon_pmu_set_state,
-+};
-+
- static const struct of_device_id jh71xx_pmu_of_match[] = {
- {
- .compatible = "starfive,jh7110-pmu",
- .data = (void *)&jh7110_pmu,
- }, {
-+ .compatible = "starfive,jh7110-aon-syscon",
-+ .data = (void *)&jh7110_aon_pmu,
-+ }, {
- /* sentinel */
- }
- };
-@@ -414,5 +460,6 @@ static struct platform_driver jh71xx_pmu
- builtin_platform_driver(jh71xx_pmu_driver);
-
- MODULE_AUTHOR("Walker Chen <walker.chen@starfivetech.com>");
-+MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>");
- MODULE_DESCRIPTION("StarFive JH71XX PMU Driver");
- MODULE_LICENSE("GPL");
+++ /dev/null
-From dff6605dcd1fc1e2af1437e59187a6f71ce389cd Mon Sep 17 00:00:00 2001
-From: Ulf Hansson <ulf.hansson@linaro.org>
-Date: Mon, 11 Sep 2023 17:22:15 +0200
-Subject: [PATCH 043/116] pmdomain: Prepare to move Kconfig files into the
- pmdomain subsystem
-
-Rather than having the various Kconfig files for the genpd providers
-sprinkled across subsystems, let's prepare to move them into the pmdomain
-subsystem along with the implementations.
-
-Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- drivers/Kconfig | 2 ++
- drivers/pmdomain/Kconfig | 4 ++++
- 2 files changed, 6 insertions(+)
- create mode 100644 drivers/pmdomain/Kconfig
-
---- a/drivers/Kconfig
-+++ b/drivers/Kconfig
-@@ -175,6 +175,8 @@ source "drivers/soundwire/Kconfig"
-
- source "drivers/soc/Kconfig"
-
-+source "drivers/pmdomain/Kconfig"
-+
- source "drivers/devfreq/Kconfig"
-
- source "drivers/extcon/Kconfig"
---- /dev/null
-+++ b/drivers/pmdomain/Kconfig
-@@ -0,0 +1,4 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+menu "PM Domains"
-+
-+endmenu
+++ /dev/null
-From de12fe43dbd0ea9fa980ffa05822bd7fd5eed330 Mon Sep 17 00:00:00 2001
-From: Ulf Hansson <ulf.hansson@linaro.org>
-Date: Tue, 12 Sep 2023 13:31:44 +0200
-Subject: [PATCH 044/116] pmdomain: starfive: Move Kconfig file to the pmdomain
- subsystem
-
-The Kconfig belongs closer to the corresponding implementation, hence let's
-move it from the soc subsystem to the pmdomain subsystem.
-
-Cc: Walker Chen <walker.chen@starfivetech.com>
-Cc: Conor Dooley <conor@kernel.org>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- drivers/pmdomain/Kconfig | 2 ++
- drivers/{soc => pmdomain}/starfive/Kconfig | 0
- drivers/soc/Kconfig | 1 -
- 3 files changed, 2 insertions(+), 1 deletion(-)
- rename drivers/{soc => pmdomain}/starfive/Kconfig (100%)
-
---- a/drivers/pmdomain/Kconfig
-+++ b/drivers/pmdomain/Kconfig
-@@ -1,4 +1,6 @@
- # SPDX-License-Identifier: GPL-2.0-only
- menu "PM Domains"
-
-+source "drivers/pmdomain/starfive/Kconfig"
-+
- endmenu
---- a/drivers/soc/Kconfig
-+++ b/drivers/soc/Kconfig
-@@ -24,7 +24,6 @@ source "drivers/soc/renesas/Kconfig"
- source "drivers/soc/rockchip/Kconfig"
- source "drivers/soc/samsung/Kconfig"
- source "drivers/soc/sifive/Kconfig"
--source "drivers/soc/starfive/Kconfig"
- source "drivers/soc/sunxi/Kconfig"
- source "drivers/soc/tegra/Kconfig"
- source "drivers/soc/ti/Kconfig"
---- /dev/null
-+++ b/drivers/pmdomain/starfive/Kconfig
-@@ -0,0 +1,12 @@
-+# SPDX-License-Identifier: GPL-2.0
-+
-+config JH71XX_PMU
-+ bool "Support PMU for StarFive JH71XX Soc"
-+ depends on PM
-+ depends on ARCH_STARFIVE || COMPILE_TEST
-+ default ARCH_STARFIVE
-+ select PM_GENERIC_DOMAINS
-+ help
-+ Say 'y' here to enable support power domain support.
-+ In order to meet low power requirements, a Power Management Unit (PMU)
-+ is designed for controlling power resources in StarFive JH71XX SoCs.
---- a/drivers/soc/starfive/Kconfig
-+++ /dev/null
-@@ -1,12 +0,0 @@
--# SPDX-License-Identifier: GPL-2.0
--
--config JH71XX_PMU
-- bool "Support PMU for StarFive JH71XX Soc"
-- depends on PM
-- depends on ARCH_STARFIVE || COMPILE_TEST
-- default ARCH_STARFIVE
-- select PM_GENERIC_DOMAINS
-- help
-- Say 'y' here to enable support power domain support.
-- In order to meet low power requirements, a Power Management Unit (PMU)
-- is designed for controlling power resources in StarFive JH71XX SoCs.
+++ /dev/null
-From cac9ce9c7f388a741389b1ec47af65420254db55 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Wed, 27 Sep 2023 06:07:33 -0700
-Subject: [PATCH 045/116] dt-bindings: power: Update prefixes for AON power
- domain
-
-Use "JH7110_AON_PD_" prefix for AON power domain for JH7110 SoC.
-
-Reviewed-by: Walker Chen <walker.chen@starfivetech.com>
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
-Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
-Link: https://lore.kernel.org/r/20230927130734.9921-2-changhuang.liang@starfivetech.com
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- include/dt-bindings/power/starfive,jh7110-pmu.h | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
---- a/include/dt-bindings/power/starfive,jh7110-pmu.h
-+++ b/include/dt-bindings/power/starfive,jh7110-pmu.h
-@@ -14,7 +14,8 @@
- #define JH7110_PD_ISP 5
- #define JH7110_PD_VENC 6
-
--#define JH7110_PD_DPHY_TX 0
--#define JH7110_PD_DPHY_RX 1
-+/* AON Power Domain */
-+#define JH7110_AON_PD_DPHY_TX 0
-+#define JH7110_AON_PD_DPHY_RX 1
-
- #endif
+++ /dev/null
-From 3ea89ffbd6cc5a15acca6bc2130572f8bd85b9d4 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Wed, 27 Sep 2023 06:07:34 -0700
-Subject: [PATCH 046/116] pmdomain: starfive: Update prefixes for AON power
- domain
-
-Use "JH7110_AON_PD_" prefix for AON power doamin for JH7110 SoC.
-
-Reviewed-by: Walker Chen <walker.chen@starfivetech.com>
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
-Link: https://lore.kernel.org/r/20230927130734.9921-3-changhuang.liang@starfivetech.com
-Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
----
- drivers/pmdomain/starfive/jh71xx-pmu.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/pmdomain/starfive/jh71xx-pmu.c
-+++ b/drivers/pmdomain/starfive/jh71xx-pmu.c
-@@ -420,11 +420,11 @@ static const struct jh71xx_pmu_match_dat
- };
-
- static const struct jh71xx_domain_info jh7110_aon_power_domains[] = {
-- [JH7110_PD_DPHY_TX] = {
-+ [JH7110_AON_PD_DPHY_TX] = {
- .name = "DPHY-TX",
- .bit = 30,
- },
-- [JH7110_PD_DPHY_RX] = {
-+ [JH7110_AON_PD_DPHY_RX] = {
- .name = "DPHY-RX",
- .bit = 31,
- },
+++ /dev/null
-From e7e3d62b7a470ddf15e30574232b52b2e23ba606 Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Mon, 21 Aug 2023 22:41:50 +0800
-Subject: [PATCH 047/116] riscv: dts: starfive: pinfunc: Fix the pins name of
- I2STX1
-
-These pins are actually I2STX1 clock input, not I2STX0,
-so their names should be changed.
-
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-Reviewed-by: Walker Chen <walker.chen@starfivetech.com>
-Acked-by: Rob Herring <robh@kernel.org>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- arch/riscv/boot/dts/starfive/jh7110-pinfunc.h | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/riscv/boot/dts/starfive/jh7110-pinfunc.h
-+++ b/arch/riscv/boot/dts/starfive/jh7110-pinfunc.h
-@@ -240,8 +240,8 @@
- #define GPI_SYS_MCLK_EXT 30
- #define GPI_SYS_I2SRX_BCLK 31
- #define GPI_SYS_I2SRX_LRCK 32
--#define GPI_SYS_I2STX0_BCLK 33
--#define GPI_SYS_I2STX0_LRCK 34
-+#define GPI_SYS_I2STX1_BCLK 33
-+#define GPI_SYS_I2STX1_LRCK 34
- #define GPI_SYS_TDM_CLK 35
- #define GPI_SYS_TDM_RXD 36
- #define GPI_SYS_TDM_SYNC 37
+++ /dev/null
-From a3d3f611f31fa2dca3deefa7cd443abca02e03fa Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Tue, 11 Apr 2023 16:31:15 +0800
-Subject: [PATCH 048/116] riscv: dts: starfive: Add full support (except VIN
- and VOUT) for JH7110 and VisionFive 2 board
-
-Merge all StarFive dts patches together except VIN and VOUT.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- .../jh7110-starfive-visionfive-2.dtsi | 199 +++++++++++++++
- arch/riscv/boot/dts/starfive/jh7110.dtsi | 233 ++++++++++++++++++
- 2 files changed, 432 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-@@ -19,6 +19,8 @@
- i2c6 = &i2c6;
- mmc0 = &mmc0;
- mmc1 = &mmc1;
-+ pcie0 = &pcie0;
-+ pcie1 = &pcie1;
- serial0 = &uart0;
- };
-
-@@ -40,6 +42,33 @@
- gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>;
- priority = <224>;
- };
-+
-+ pwmdac_codec: pwmdac-codec {
-+ compatible = "linux,spdif-dit";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ sound-pwmdac {
-+ compatible = "simple-audio-card";
-+ simple-audio-card,name = "StarFive-PWMDAC-Sound-Card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "left_j";
-+ bitclock-master = <&sndcpu0>;
-+ frame-master = <&sndcpu0>;
-+
-+ sndcpu0: cpu {
-+ sound-dai = <&pwmdac>;
-+ };
-+
-+ codec {
-+ sound-dai = <&pwmdac_codec>;
-+ };
-+ };
-+ };
- };
-
- &dvp_clk {
-@@ -202,6 +231,24 @@
- status = "okay";
- };
-
-+&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 {
- max-frequency = <100000000>;
- assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-@@ -235,6 +282,34 @@
- status = "okay";
- };
-
-+&pcie0 {
-+ perst-gpios = <&sysgpio 26 GPIO_ACTIVE_LOW>;
-+ phys = <&pciephy0>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pcie0_pins>;
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ perst-gpios = <&sysgpio 28 GPIO_ACTIVE_LOW>;
-+ phys = <&pciephy1>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pcie1_pins>;
-+ status = "okay";
-+};
-+
-+&pwm {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm_pins>;
-+ status = "okay";
-+};
-+
-+&pwmdac {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwmdac_pins>;
-+ status = "okay";
-+};
-+
- &qspi {
- #address-cells = <1>;
- #size-cells = <0>;
-@@ -340,6 +415,46 @@
- };
- };
-
-+ i2srx_pins: i2srx-0 {
-+ clk-sd-pins {
-+ pinmux = <GPIOMUX(38, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2SRX_BCLK)>,
-+ <GPIOMUX(63, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2SRX_LRCK)>,
-+ <GPIOMUX(38, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2STX1_BCLK)>,
-+ <GPIOMUX(63, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2STX1_LRCK)>,
-+ <GPIOMUX(61, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2SRX_SDIN0)>;
-+ input-enable;
-+ };
-+ };
-+
-+ i2stx1_pins: i2stx1-0 {
-+ sd-pins {
-+ pinmux = <GPIOMUX(44, GPOUT_SYS_I2STX1_SDO0,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ };
-+ };
-+
-+ mclk_ext_pins: mclk-ext-0 {
-+ mclk-ext-pins {
-+ pinmux = <GPIOMUX(4, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_MCLK_EXT)>;
-+ input-enable;
-+ };
-+ };
-+
- mmc0_pins: mmc0-0 {
- rst-pins {
- pinmux = <GPIOMUX(62, GPOUT_SYS_SDIO0_RST,
-@@ -404,6 +519,86 @@
- slew-rate = <0>;
- };
- };
-+
-+ pcie0_pins: pcie0-0 {
-+ clkreq-pins {
-+ pinmux = <GPIOMUX(27, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_NONE)>;
-+ bias-pull-down;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ wake-pins {
-+ pinmux = <GPIOMUX(32, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_NONE)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ pcie1_pins: pcie1-0 {
-+ clkreq-pins {
-+ pinmux = <GPIOMUX(29, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_NONE)>;
-+ bias-pull-down;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ wake-pins {
-+ pinmux = <GPIOMUX(21, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_NONE)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ pwm_pins: pwm-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(46, GPOUT_SYS_PWM_CHANNEL0,
-+ GPOEN_SYS_PWM0_CHANNEL0,
-+ GPI_NONE)>,
-+ <GPIOMUX(59, GPOUT_SYS_PWM_CHANNEL1,
-+ GPOEN_SYS_PWM0_CHANNEL1,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ pwmdac_pins: pwmdac-0 {
-+ pwmdac-pins {
-+ pinmux = <GPIOMUX(33, GPOUT_SYS_PWMDAC_LEFT,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(34, GPOUT_SYS_PWMDAC_RIGHT,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <2>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ };
-
- spi0_pins: spi0-0 {
- mosi-pins {
---- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
-@@ -244,6 +244,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";
-@@ -512,6 +513,43 @@
- status = "disabled";
- };
-
-+ pwmdac: pwmdac@100b0000 {
-+ compatible = "starfive,jh7110-pwmdac";
-+ reg = <0x0 0x100b0000 0x0 0x1000>;
-+ clocks = <&syscrg JH7110_SYSCLK_PWMDAC_APB>,
-+ <&syscrg JH7110_SYSCLK_PWMDAC_CORE>;
-+ clock-names = "apb", "core";
-+ resets = <&syscrg JH7110_SYSRST_PWMDAC_APB>;
-+ dmas = <&dma 22>;
-+ dma-names = "tx";
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2srx: i2s@100e0000 {
-+ compatible = "starfive,jh7110-i2srx";
-+ reg = <0x0 0x100e0000 0x0 0x1000>;
-+ clocks = <&syscrg JH7110_SYSCLK_I2SRX_BCLK_MST>,
-+ <&syscrg JH7110_SYSCLK_I2SRX_APB>,
-+ <&syscrg JH7110_SYSCLK_MCLK>,
-+ <&syscrg JH7110_SYSCLK_MCLK_INNER>,
-+ <&mclk_ext>,
-+ <&syscrg JH7110_SYSCLK_I2SRX_BCLK>,
-+ <&syscrg JH7110_SYSCLK_I2SRX_LRCK>,
-+ <&i2srx_bclk_ext>,
-+ <&i2srx_lrck_ext>;
-+ clock-names = "i2sclk", "apb", "mclk",
-+ "mclk_inner", "mclk_ext", "bclk",
-+ "lrck", "bclk_ext", "lrck_ext";
-+ resets = <&syscrg JH7110_SYSRST_I2SRX_APB>,
-+ <&syscrg JH7110_SYSRST_I2SRX_BCLK>;
-+ dmas = <0>, <&dma 24>;
-+ dma-names = "tx", "rx";
-+ starfive,syscon = <&sys_syscon 0x18 0x2>;
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
- usb0: usb@10100000 {
- compatible = "starfive,jh7110-usb";
- ranges = <0x0 0x0 0x10100000 0x100000>;
-@@ -736,6 +774,56 @@
- status = "disabled";
- };
-
-+ i2stx0: i2s@120b0000 {
-+ compatible = "starfive,jh7110-i2stx0";
-+ reg = <0x0 0x120b0000 0x0 0x1000>;
-+ clocks = <&syscrg JH7110_SYSCLK_I2STX0_BCLK_MST>,
-+ <&syscrg JH7110_SYSCLK_I2STX0_APB>,
-+ <&syscrg JH7110_SYSCLK_MCLK>,
-+ <&syscrg JH7110_SYSCLK_MCLK_INNER>,
-+ <&mclk_ext>;
-+ clock-names = "i2sclk", "apb", "mclk",
-+ "mclk_inner","mclk_ext";
-+ resets = <&syscrg JH7110_SYSRST_I2STX0_APB>,
-+ <&syscrg JH7110_SYSRST_I2STX0_BCLK>;
-+ dmas = <&dma 47>;
-+ dma-names = "tx";
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2stx1: i2s@120c0000 {
-+ compatible = "starfive,jh7110-i2stx1";
-+ reg = <0x0 0x120c0000 0x0 0x1000>;
-+ clocks = <&syscrg JH7110_SYSCLK_I2STX1_BCLK_MST>,
-+ <&syscrg JH7110_SYSCLK_I2STX1_APB>,
-+ <&syscrg JH7110_SYSCLK_MCLK>,
-+ <&syscrg JH7110_SYSCLK_MCLK_INNER>,
-+ <&mclk_ext>,
-+ <&syscrg JH7110_SYSCLK_I2STX1_BCLK>,
-+ <&syscrg JH7110_SYSCLK_I2STX1_LRCK>,
-+ <&i2stx_bclk_ext>,
-+ <&i2stx_lrck_ext>;
-+ clock-names = "i2sclk", "apb", "mclk",
-+ "mclk_inner", "mclk_ext", "bclk",
-+ "lrck", "bclk_ext", "lrck_ext";
-+ resets = <&syscrg JH7110_SYSRST_I2STX1_APB>,
-+ <&syscrg JH7110_SYSRST_I2STX1_BCLK>;
-+ dmas = <&dma 48>;
-+ dma-names = "tx";
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ pwm: pwm@120d0000 {
-+ compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
-+ reg = <0x0 0x120d0000 0x0 0x10000>;
-+ clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
-+ resets = <&syscrg JH7110_SYSRST_PWM_APB>;
-+ #pwm-cells = <3>;
-+ status = "disabled";
-+ };
-+
- sfctemp: temperature-sensor@120e0000 {
- compatible = "starfive,jh7110-temp";
- reg = <0x0 0x120e0000 0x0 0x10000>;
-@@ -811,6 +899,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>;
-@@ -1011,6 +1119,32 @@
- #power-domain-cells = <1>;
- };
-
-+ csi2rx: csi-bridge@19800000 {
-+ compatible = "starfive,jh7110-csi2rx";
-+ reg = <0x0 0x19800000 0x0 0x10000>;
-+ clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>,
-+ <&ispcrg JH7110_ISPCLK_VIN_APB>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF0>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF1>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF2>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF3>;
-+ clock-names = "sys_clk", "p_clk",
-+ "pixel_if0_clk", "pixel_if1_clk",
-+ "pixel_if2_clk", "pixel_if3_clk";
-+ resets = <&ispcrg JH7110_ISPRST_VIN_SYS>,
-+ <&ispcrg JH7110_ISPRST_VIN_APB>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF0>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF1>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF2>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF3>;
-+ reset-names = "sys", "reg_bank",
-+ "pixel_if0", "pixel_if1",
-+ "pixel_if2", "pixel_if3";
-+ phys = <&csi_phy>;
-+ phy-names = "dphy";
-+ status = "disabled";
-+ };
-+
- ispcrg: clock-controller@19810000 {
- compatible = "starfive,jh7110-ispcrg";
- reg = <0x0 0x19810000 0x0 0x10000>;
-@@ -1028,6 +1162,19 @@
- power-domains = <&pwrc JH7110_PD_ISP>;
- };
-
-+ csi_phy: phy@19820000 {
-+ compatible = "starfive,jh7110-dphy-rx";
-+ reg = <0x0 0x19820000 0x0 0x10000>;
-+ clocks = <&ispcrg JH7110_ISPCLK_M31DPHY_CFG_IN>,
-+ <&ispcrg JH7110_ISPCLK_M31DPHY_REF_IN>,
-+ <&ispcrg JH7110_ISPCLK_M31DPHY_TX_ESC_LAN0>;
-+ clock-names = "cfg", "ref", "tx";
-+ resets = <&ispcrg JH7110_ISPRST_M31DPHY_HW>,
-+ <&ispcrg JH7110_ISPRST_M31DPHY_B09_AON>;
-+ power-domains = <&aon_syscon JH7110_AON_PD_DPHY_RX>;
-+ #phy-cells = <0>;
-+ };
-+
- voutcrg: clock-controller@295c0000 {
- compatible = "starfive,jh7110-voutcrg";
- reg = <0x0 0x295c0000 0x0 0x10000>;
-@@ -1045,5 +1192,91 @@
- #reset-cells = <1>;
- power-domains = <&pwrc JH7110_PD_VOUT>;
- };
-+
-+ pcie0: pcie@940000000 {
-+ compatible = "starfive,jh7110-pcie";
-+ reg = <0x9 0x40000000 0x0 0x1000000>,
-+ <0x0 0x2b000000 0x0 0x100000>;
-+ reg-names = "cfg", "apb";
-+ linux,pci-domain = <0>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ #interrupt-cells = <1>;
-+ ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>,
-+ <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>;
-+ interrupts = <56>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>,
-+ <0x0 0x0 0x0 0x2 &pcie_intc0 0x2>,
-+ <0x0 0x0 0x0 0x3 &pcie_intc0 0x3>,
-+ <0x0 0x0 0x0 0x4 &pcie_intc0 0x4>;
-+ msi-controller;
-+ device_type = "pci";
-+ starfive,stg-syscon = <&stg_syscon>;
-+ bus-range = <0x0 0xff>;
-+ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>,
-+ <&stgcrg JH7110_STGCLK_PCIE0_TL>,
-+ <&stgcrg JH7110_STGCLK_PCIE0_AXI_MST0>,
-+ <&stgcrg JH7110_STGCLK_PCIE0_APB>;
-+ clock-names = "noc", "tl", "axi_mst0", "apb";
-+ resets = <&stgcrg JH7110_STGRST_PCIE0_AXI_MST0>,
-+ <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV0>,
-+ <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV>,
-+ <&stgcrg JH7110_STGRST_PCIE0_BRG>,
-+ <&stgcrg JH7110_STGRST_PCIE0_CORE>,
-+ <&stgcrg JH7110_STGRST_PCIE0_APB>;
-+ reset-names = "mst0", "slv0", "slv", "brg",
-+ "core", "apb";
-+ status = "disabled";
-+
-+ pcie_intc0: interrupt-controller {
-+ #address-cells = <0>;
-+ #interrupt-cells = <1>;
-+ interrupt-controller;
-+ };
-+ };
-+
-+ pcie1: pcie@9c0000000 {
-+ compatible = "starfive,jh7110-pcie";
-+ reg = <0x9 0xc0000000 0x0 0x1000000>,
-+ <0x0 0x2c000000 0x0 0x100000>;
-+ reg-names = "cfg", "apb";
-+ linux,pci-domain = <1>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ #interrupt-cells = <1>;
-+ ranges = <0x82000000 0x0 0x38000000 0x0 0x38000000 0x0 0x08000000>,
-+ <0xc3000000 0x9 0x80000000 0x9 0x80000000 0x0 0x40000000>;
-+ interrupts = <57>;
-+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
-+ interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc1 0x1>,
-+ <0x0 0x0 0x0 0x2 &pcie_intc1 0x2>,
-+ <0x0 0x0 0x0 0x3 &pcie_intc1 0x3>,
-+ <0x0 0x0 0x0 0x4 &pcie_intc1 0x4>;
-+ msi-controller;
-+ device_type = "pci";
-+ starfive,stg-syscon = <&stg_syscon>;
-+ bus-range = <0x0 0xff>;
-+ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>,
-+ <&stgcrg JH7110_STGCLK_PCIE1_TL>,
-+ <&stgcrg JH7110_STGCLK_PCIE1_AXI_MST0>,
-+ <&stgcrg JH7110_STGCLK_PCIE1_APB>;
-+ clock-names = "noc", "tl", "axi_mst0", "apb";
-+ resets = <&stgcrg JH7110_STGRST_PCIE1_AXI_MST0>,
-+ <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV0>,
-+ <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV>,
-+ <&stgcrg JH7110_STGRST_PCIE1_BRG>,
-+ <&stgcrg JH7110_STGRST_PCIE1_CORE>,
-+ <&stgcrg JH7110_STGRST_PCIE1_APB>;
-+ reset-names = "mst0", "slv0", "slv", "brg",
-+ "core", "apb";
-+ status = "disabled";
-+
-+ pcie_intc1: interrupt-controller {
-+ #address-cells = <0>;
-+ #interrupt-cells = <1>;
-+ interrupt-controller;
-+ };
-+ };
- };
- };
+++ /dev/null
-From ae7b57a0c69953f5ec06a378aedeed4c86637998 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Tue, 11 Apr 2023 16:25:57 +0800
-Subject: [PATCH 049/116] MAINTAINERS: Update all StarFive entries
-
-Merge all StarFive maintainers changes together.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- MAINTAINERS | 61 +++++++++++++++++++++++++++++++++++++++++++++++++----
- 1 file changed, 57 insertions(+), 4 deletions(-)
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -7054,6 +7054,14 @@ T: git git://anongit.freedesktop.org/drm
- F: Documentation/devicetree/bindings/display/rockchip/
- F: drivers/gpu/drm/rockchip/
-
-+DRM DRIVERS FOR STARFIVE
-+M: Keith Zhao <keith.zhao@starfivetech.com>
-+L: dri-devel@lists.freedesktop.org
-+S: Maintained
-+T: git git://anongit.freedesktop.org/drm/drm-misc
-+F: Documentation/devicetree/bindings/display/starfive/
-+F: drivers/gpu/drm/verisilicon/
-+
- DRM DRIVERS FOR STI
- M: Alain Volmat <alain.volmat@foss.st.com>
- L: dri-devel@lists.freedesktop.org
-@@ -16018,6 +16026,13 @@ F: Documentation/i2c/busses/i2c-ocores.r
- F: drivers/i2c/busses/i2c-ocores.c
- F: include/linux/platform_data/i2c-ocores.h
-
-+OPENCORES PWM DRIVER
-+M: William Qiu <william.qiu@starfivetech.com>
-+M: Hal Feng <hal.feng@starfivetech.com>
-+S: Supported
-+F: Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
-+F: drivers/pwm/pwm-ocores.c
-+
- OPENRISC ARCHITECTURE
- M: Jonas Bonn <jonas@southpole.se>
- M: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
-@@ -16429,6 +16444,14 @@ S: Maintained
- F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
- F: drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
-
-+PCI DRIVER FOR PLDA PCIE IP
-+M: Daire McNamara <daire.mcnamara@microchip.com>
-+M: Kevin Xie <kevin.xie@starfivetech.com>
-+L: linux-pci@vger.kernel.org
-+S: Maintained
-+F: Documentation/devicetree/bindings/pci/plda,*
-+F: drivers/pci/controller/plda/*plda*
-+
- PCI DRIVER FOR RENESAS R-CAR
- M: Marek Vasut <marek.vasut+renesas@gmail.com>
- M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
-@@ -16660,7 +16683,7 @@ M: Daire McNamara <daire.mcnamara@microc
- L: linux-pci@vger.kernel.org
- S: Supported
- F: Documentation/devicetree/bindings/pci/microchip*
--F: drivers/pci/controller/*microchip*
-+F: drivers/pci/controller/plda/*microchip*
-
- PCIE DRIVER FOR QUALCOMM MSM
- M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
-@@ -16684,6 +16707,13 @@ S: Maintained
- F: Documentation/devicetree/bindings/pci/socionext,uniphier-pcie*
- F: drivers/pci/controller/dwc/pcie-uniphier*
-
-+PCIE DRIVER FOR STARFIVE JH71x0
-+M: Kevin Xie <kevin.xie@starfivetech.com>
-+L: linux-pci@vger.kernel.org
-+S: Maintained
-+F: Documentation/devicetree/bindings/pci/starfive*
-+F: drivers/pci/controller/plda/pcie-starfive.c
-+
- PCIE DRIVER FOR ST SPEAR13XX
- M: Pratyush Anand <pratyush.anand@gmail.com>
- L: linux-pci@vger.kernel.org
-@@ -18456,7 +18486,7 @@ F: drivers/char/hw_random/mpfs-rng.c
- F: drivers/clk/microchip/clk-mpfs*.c
- F: drivers/i2c/busses/i2c-microchip-corei2c.c
- F: drivers/mailbox/mailbox-mpfs.c
--F: drivers/pci/controller/pcie-microchip-host.c
-+F: drivers/pci/controller/plda/pcie-microchip-host.c
- F: drivers/pwm/pwm-microchip-core.c
- F: drivers/reset/reset-mpfs.c
- F: drivers/rtc/rtc-mpfs.c
-@@ -20437,6 +20467,15 @@ M: Ion Badulescu <ionut@badula.org>
- S: Odd Fixes
- F: drivers/net/ethernet/adaptec/starfire*
-
-+STARFIVE CAMERA SUBSYSTEM DRIVER
-+M: Jack Zhu <jack.zhu@starfivetech.com>
-+M: Changhuang Liang <changhuang.liang@starfivetech.com>
-+L: linux-media@vger.kernel.org
-+S: Maintained
-+F: Documentation/admin-guide/media/starfive_camss.rst
-+F: Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml
-+F: drivers/staging/media/starfive/camss
-+
- STARFIVE CRYPTO DRIVER
- M: Jia Jie Ho <jiajie.ho@starfivetech.com>
- M: William Qiu <william.qiu@starfivetech.com>
-@@ -20475,6 +20514,13 @@ S: Supported
- F: Documentation/devicetree/bindings/clock/starfive,jh7110-pll.yaml
- F: drivers/clk/starfive/clk-starfive-jh7110-pll.c
-
-+STARFIVE JH7110 PWMDAC DRIVER
-+M: Hal Feng <hal.feng@starfivetech.com>
-+M: Xingyu Wu <xingyu.wu@starfivetech.com>
-+S: Supported
-+F: Documentation/devicetree/bindings/sound/starfive,jh7110-pwmdac.yaml
-+F: sound/soc/starfive/jh7110_pwmdac.c
-+
- STARFIVE JH7110 SYSCON
- M: William Qiu <william.qiu@starfivetech.com>
- M: Xingyu Wu <xingyu.wu@starfivetech.com>
-@@ -20522,9 +20568,10 @@ F: drivers/usb/cdns3/cdns3-starfive.c
-
- STARFIVE JH71XX PMU CONTROLLER DRIVER
- M: Walker Chen <walker.chen@starfivetech.com>
-+M: Changhuang Liang <changhuang.liang@starfivetech.com>
- S: Supported
- F: Documentation/devicetree/bindings/power/starfive*
--F: drivers/pmdomain/starfive/jh71xx-pmu.c
-+F: drivers/pmdomain/starfive/
- F: include/dt-bindings/power/starfive,jh7110-pmu.h
-
- STARFIVE SOC DRIVERS
-@@ -20532,7 +20579,13 @@ M: Conor Dooley <conor@kernel.org>
- S: Maintained
- T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
- F: Documentation/devicetree/bindings/soc/starfive/
--F: drivers/soc/starfive/
-+
-+STARFIVE JH7110 TIMER DRIVER
-+M: Samin Guo <samin.guo@starfivetech.com>
-+M: Xingyu Wu <xingyu.wu@starfivetech.com>
-+S: Supported
-+F: Documentation/devicetree/bindings/timer/starfive,jh7110-timer.yaml
-+F: drivers/clocksource/timer-jh7110.c
-
- STARFIVE TRNG DRIVER
- M: Jia Jie Ho <jiajie.ho@starfivetech.com>
+++ /dev/null
-From e394195396995456ef98f52ac123c0cb64687748 Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Mon, 9 Oct 2023 10:59:03 +0800
-Subject: [PATCH 050/116] mmc: starfive: Change the voltage to adapt to JH7110
- EVB
-
-Change the voltage, so the driver can adapt to JH7110 EVB.
-
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/mmc/host/dw_mmc-starfive.c | 30 ++++++++++++++++++++++++++++++
- 1 file changed, 30 insertions(+)
-
---- a/drivers/mmc/host/dw_mmc-starfive.c
-+++ b/drivers/mmc/host/dw_mmc-starfive.c
-@@ -8,6 +8,7 @@
- #include <linux/bitfield.h>
- #include <linux/clk.h>
- #include <linux/delay.h>
-+#include <linux/gpio.h>
- #include <linux/mfd/syscon.h>
- #include <linux/mmc/host.h>
- #include <linux/module.h>
-@@ -95,10 +96,39 @@ out:
- return ret;
- }
-
-+static int dw_mci_starfive_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
-+{
-+
-+ struct dw_mci_slot *slot = mmc_priv(mmc);
-+ struct dw_mci *host = slot->host;
-+ u32 ret;
-+
-+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
-+ ret = gpio_direction_output(25, 0);
-+ else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
-+ ret = gpio_direction_output(25, 1);
-+ if (ret)
-+ return ret;
-+
-+ if (!IS_ERR(mmc->supply.vqmmc)) {
-+ ret = mmc_regulator_set_vqmmc(mmc, ios);
-+ if (ret < 0) {
-+ dev_err(host->dev, "Regulator set error %d\n", ret);
-+ return ret;
-+ }
-+ }
-+
-+ /* We should delay 20ms wait for timing setting finished. */
-+ mdelay(20);
-+
-+ return 0;
-+}
-+
- static const struct dw_mci_drv_data starfive_data = {
- .common_caps = MMC_CAP_CMD23,
- .set_ios = dw_mci_starfive_set_ios,
- .execute_tuning = dw_mci_starfive_execute_tuning,
-+ .switch_voltage = dw_mci_starfive_switch_voltage,
- };
-
- static const struct of_device_id dw_mci_starfive_match[] = {
+++ /dev/null
-From 2cd3e51cb76d49d8db6274ebdc1ba1eb5c872f10 Mon Sep 17 00:00:00 2001
-From: "ziv.xu" <ziv.xu@starfivetech.com>
-Date: Sun, 4 Feb 2024 10:35:24 +0800
-Subject: [PATCH 051/116] spi: spl022: Get and deassert reset in probe()
-
-This fix spi1~6 communication time out.
-
-Signed-off-by: ziv.xu <ziv.xu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/spi/spi-pl022.c | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
---- a/drivers/spi/spi-pl022.c
-+++ b/drivers/spi/spi-pl022.c
-@@ -33,6 +33,7 @@
- #include <linux/pm_runtime.h>
- #include <linux/of.h>
- #include <linux/pinctrl/consumer.h>
-+#include <linux/reset.h>
-
- /*
- * This macro is used to define some register default values.
-@@ -370,6 +371,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;
- /* Message per-transfer pump */
-@@ -2181,6 +2183,19 @@ static int pl022_probe(struct amba_devic
- goto err_no_clk_en;
- }
-
-+ 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;
-+ }
-+
- /* Initialize transfer pump */
- tasklet_init(&pl022->pump_transfers, pump_transfers,
- (unsigned long)pl022);
-@@ -2240,6 +2255,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:
- clk_disable_unprepare(pl022->clk);
- err_no_clk_en:
- err_no_clk:
+++ /dev/null
-From 9cc8de0cdc1600f460f618e342e1f524adad07c4 Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Wed, 21 Feb 2024 10:23:48 +0800
-Subject: [PATCH 052/116] ASoC: dwc: i2s: Fix getting platform data error for
- StarFive JH7110
-
-JH7110 need to use a DT specific function to get the platform data,
-otherwise, it fails in probe().
-
-Fixes: 9c97790a07dc ("ASoC: dwc: Fix non-DT instantiation")
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- sound/soc/dwc/dwc-i2s.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/sound/soc/dwc/dwc-i2s.c
-+++ b/sound/soc/dwc/dwc-i2s.c
-@@ -916,7 +916,11 @@ static int jh7110_i2stx0_clk_cfg(struct
-
- static int dw_i2s_probe(struct platform_device *pdev)
- {
-+#ifdef CONFIG_OF
-+ const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev);
-+#else
- const struct i2s_platform_data *pdata = pdev->dev.platform_data;
-+#endif
- struct dw_i2s_dev *dev;
- struct resource *res;
- int ret, irq;
+++ /dev/null
-From 1be9bd37fdb5f50162dba0158e1fee295ebca9aa Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Tue, 17 Oct 2023 17:22:52 +0800
-Subject: [PATCH 053/116] ASoC: dwc: i2s: Add RX master support for StarFive
- JH7110 SoC
-
-Add JH7110 I2S RX master support, so the PDM can work on JH7110
-EVB board.
-
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- sound/soc/dwc/dwc-i2s.c | 31 +++++++++++++++++++++++++++++++
- 1 file changed, 31 insertions(+)
-
---- a/sound/soc/dwc/dwc-i2s.c
-+++ b/sound/soc/dwc/dwc-i2s.c
-@@ -905,6 +905,27 @@ static int jh7110_i2srx_crg_init(struct
- return jh7110_i2s_crg_slave_init(dev);
- }
-
-+/* Special syscon initialization about RX channel with master mode on JH7110 SoC */
-+static int jh7110_i2srx_mst_crg_init(struct dw_i2s_dev *dev)
-+{
-+ struct regmap *regmap;
-+ unsigned int args[5];
-+
-+ regmap = syscon_regmap_lookup_by_phandle_args(dev->dev->of_node,
-+ "starfive,syscon",
-+ 5, args);
-+ if (IS_ERR(regmap))
-+ return dev_err_probe(dev->dev, PTR_ERR(regmap), "getting the regmap failed\n");
-+
-+ /* Enable I2Srx with syscon register, args[0]: offset, args[1]: mask */
-+ regmap_update_bits(regmap, args[0], args[1], args[1]);
-+
-+ /* Change I2Srx source (PDM) with syscon register, args[0]: offset, args[1]: mask */
-+ regmap_update_bits(regmap, args[2], args[3], args[4]);
-+
-+ return jh7110_i2s_crg_master_init(dev);
-+}
-+
- static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config)
- {
- struct dw_i2s_dev *dev = container_of(config, struct dw_i2s_dev, config);
-@@ -1085,11 +1106,21 @@ static const struct i2s_platform_data jh
- .i2s_pd_init = jh7110_i2srx_crg_init,
- };
-
-+static const struct i2s_platform_data jh7110_i2srx_mst_data = {
-+ .cap = DWC_I2S_RECORD | DW_I2S_MASTER,
-+ .channel = TWO_CHANNEL_SUPPORT,
-+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
-+ .snd_rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000,
-+ .i2s_clk_cfg = jh7110_i2stx0_clk_cfg,
-+ .i2s_pd_init = jh7110_i2srx_mst_crg_init,
-+};
-+
- static const struct of_device_id dw_i2s_of_match[] = {
- { .compatible = "snps,designware-i2s", },
- { .compatible = "starfive,jh7110-i2stx0", .data = &jh7110_i2stx0_data, },
- { .compatible = "starfive,jh7110-i2stx1", .data = &jh7110_i2stx1_data,},
- { .compatible = "starfive,jh7110-i2srx", .data = &jh7110_i2srx_data,},
-+ { .compatible = "starfive,jh7110-i2srx-master", .data = &jh7110_i2srx_mst_data,},
- {},
- };
-
+++ /dev/null
-From 1ec26ba377d8ae59cd09811ec78623a750a9c150 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Mon, 26 Feb 2024 11:35:44 +0800
-Subject: [PATCH 054/116] pinctrl: starfive: jh7110: Unset .strict in
- pinmux_ops
-
-Allow simultaneous use of the same pin for GPIO and another function.
-This feature is used in HDMI hot plug detect.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
-+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
-@@ -327,7 +327,6 @@ static const struct pinmux_ops jh7110_pi
- .get_function_name = pinmux_generic_get_function_name,
- .get_function_groups = pinmux_generic_get_function_groups,
- .set_mux = jh7110_set_mux,
-- .strict = true,
- };
-
- static const u8 jh7110_drive_strength_mA[4] = { 2, 4, 8, 12 };
+++ /dev/null
-From 005549a2bd839335b0e3dc4152f00f642b524f07 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Sat, 7 Oct 2023 18:10:20 +0800
-Subject: [PATCH 055/116] mm/pgtable-generic.c: Export symbol __pte_offset_map
-
-So JH7110 vdec can call pte_offset_map() when it is built as a module.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- mm/pgtable-generic.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/mm/pgtable-generic.c
-+++ b/mm/pgtable-generic.c
-@@ -304,6 +304,7 @@ nomap:
- rcu_read_unlock();
- return NULL;
- }
-+EXPORT_SYMBOL(__pte_offset_map);
-
- pte_t *pte_offset_map_nolock(struct mm_struct *mm, pmd_t *pmd,
- unsigned long addr, spinlock_t **ptlp)
+++ /dev/null
-From 9f46b0d43f8945ff3a8b81ddc6567df370b60911 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Fri, 28 Jul 2023 17:19:12 +0800
-Subject: [PATCH 056/116] riscv: dts: starfive: Add JH7110 EVB device tree
-
-Add JH7110 evaluation board device tree.
-The code is ported from tag JH7110_SDK_6.1_v5.11.3
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/Makefile | 3 +
- arch/riscv/boot/dts/starfive/jh7110-clk.dtsi | 80 ++
- .../boot/dts/starfive/jh7110-evb-pinctrl.dtsi | 997 ++++++++++++++++++
- arch/riscv/boot/dts/starfive/jh7110-evb.dts | 35 +
- arch/riscv/boot/dts/starfive/jh7110-evb.dtsi | 854 +++++++++++++++
- arch/riscv/boot/dts/starfive/jh7110.dtsi | 482 ++++++++-
- 6 files changed, 2444 insertions(+), 7 deletions(-)
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-clk.dtsi
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-pinctrl.dtsi
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb.dtsi
-
---- a/arch/riscv/boot/dts/starfive/Makefile
-+++ b/arch/riscv/boot/dts/starfive/Makefile
-@@ -4,9 +4,12 @@ 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 := -@
-+DTC_FLAGS_jh7110-evb := -@
-
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight.dtb
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb
-
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb
-+
-+dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-evb.dtb
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-clk.dtsi
-@@ -0,0 +1,80 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
-+ */
-+
-+/ {
-+ ac108_mclk: ac108_mclk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24000000>;
-+ };
-+
-+ clk_ext_camera: clk-ext-camera {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24000000>;
-+ };
-+
-+ wm8960_mclk: wm8960_mclk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24576000>;
-+ };
-+};
-+
-+&dvp_clk {
-+ clock-frequency = <74250000>;
-+};
-+
-+&gmac0_rgmii_rxin {
-+ clock-frequency = <125000000>;
-+};
-+
-+&gmac0_rmii_refin {
-+ clock-frequency = <50000000>;
-+};
-+
-+&gmac1_rgmii_rxin {
-+ clock-frequency = <125000000>;
-+};
-+
-+&gmac1_rmii_refin {
-+ clock-frequency = <50000000>;
-+};
-+
-+&hdmitx0_pixelclk {
-+ clock-frequency = <297000000>;
-+};
-+
-+&i2srx_bclk_ext {
-+ clock-frequency = <12288000>;
-+};
-+
-+&i2srx_lrck_ext {
-+ clock-frequency = <192000>;
-+};
-+
-+&i2stx_bclk_ext {
-+ clock-frequency = <12288000>;
-+};
-+
-+&i2stx_lrck_ext {
-+ clock-frequency = <192000>;
-+};
-+
-+&mclk_ext {
-+ clock-frequency = <12288000>;
-+};
-+
-+&osc {
-+ clock-frequency = <24000000>;
-+};
-+
-+&rtc_osc {
-+ clock-frequency = <32768>;
-+};
-+
-+&tdm_ext {
-+ clock-frequency = <49152000>;
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-pinctrl.dtsi
-@@ -0,0 +1,997 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
-+ * Author: Hal Feng <hal.feng@starfivetech.com>
-+ */
-+
-+#include "jh7110-pinfunc.h"
-+
-+&sysgpio {
-+ can0_pins: can0-0 {
-+ can-pins {
-+ pinmux = <GPIOMUX(30, GPOUT_SYS_CAN0_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(31, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_CAN0_RXD)>,
-+ <GPIOMUX(32, GPOUT_SYS_CAN0_STBY,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ input-enable;
-+ };
-+ };
-+
-+ can1_pins: can1-0 {
-+ can-pins {
-+ pinmux = <GPIOMUX(29, GPOUT_SYS_CAN1_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(27, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_CAN1_RXD)>,
-+ <GPIOMUX(45, GPOUT_SYS_CAN1_STBY,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ drive-strength = <12>;
-+ input-enable;
-+ };
-+ };
-+
-+ dvp_pins: dvp-0 {
-+ dvp-pins{
-+ pinmux = <PINMUX(21, 2)>,
-+ <PINMUX(22, 2)>,
-+ <PINMUX(23, 2)>,
-+ <PINMUX(24, 2)>,
-+ <PINMUX(25, 2)>,
-+ <PINMUX(26, 2)>,
-+ <PINMUX(27, 2)>,
-+ <PINMUX(28, 2)>,
-+ <PINMUX(29, 2)>,
-+ <PINMUX(30, 2)>,
-+ <PINMUX(31, 2)>,
-+ <PINMUX(32, 2)>,
-+ <PINMUX(33, 2)>,
-+ <PINMUX(34, 2)>,
-+ <PINMUX(35, 2)>;
-+ input-enable;
-+ };
-+ };
-+
-+ emmc0_pins: emmc0-0 {
-+ emmc-pins {
-+ pinmux = <GPIOMUX(22, GPOUT_SYS_SDIO0_RST,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <PINMUX(64, 0)>,
-+ <PINMUX(65, 0)>,
-+ <PINMUX(66, 0)>,
-+ <PINMUX(67, 0)>,
-+ <PINMUX(68, 0)>,
-+ <PINMUX(69, 0)>,
-+ <PINMUX(70, 0)>,
-+ <PINMUX(71, 0)>,
-+ <PINMUX(72, 0)>,
-+ <PINMUX(73, 0)>;
-+ bias-pull-up;
-+ drive-strength = <12>;
-+ input-enable;
-+ slew-rate = <1>;
-+ };
-+ };
-+
-+ emmc1_pins: emmc1-0 {
-+ emmc-pins {
-+ pinmux = <GPIOMUX(51, GPOUT_SYS_SDIO1_RST,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(38, GPOUT_SYS_SDIO1_CLK,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(36, GPOUT_SYS_SDIO1_CMD,
-+ GPOEN_SYS_SDIO1_CMD,
-+ GPI_SYS_SDIO1_CMD)>,
-+ <GPIOMUX(43, GPOUT_SYS_SDIO1_DATA0,
-+ GPOEN_SYS_SDIO1_DATA0,
-+ GPI_SYS_SDIO1_DATA0)>,
-+ <GPIOMUX(48, GPOUT_SYS_SDIO1_DATA1,
-+ GPOEN_SYS_SDIO1_DATA1,
-+ GPI_SYS_SDIO1_DATA1)>,
-+ <GPIOMUX(53, GPOUT_SYS_SDIO1_DATA2,
-+ GPOEN_SYS_SDIO1_DATA2,
-+ GPI_SYS_SDIO1_DATA2)>,
-+ <GPIOMUX(63, GPOUT_SYS_SDIO1_DATA3,
-+ GPOEN_SYS_SDIO1_DATA3,
-+ GPI_SYS_SDIO1_DATA3)>,
-+ <GPIOMUX(52, GPOUT_SYS_SDIO1_DATA4,
-+ GPOEN_SYS_SDIO1_DATA4,
-+ GPI_SYS_SDIO1_DATA4)>,
-+ <GPIOMUX(39, GPOUT_SYS_SDIO1_DATA5,
-+ GPOEN_SYS_SDIO1_DATA5,
-+ GPI_SYS_SDIO1_DATA5)>,
-+ <GPIOMUX(46, GPOUT_SYS_SDIO1_DATA6,
-+ GPOEN_SYS_SDIO1_DATA6,
-+ GPI_SYS_SDIO1_DATA6)>,
-+ <GPIOMUX(47, GPOUT_SYS_SDIO1_DATA7,
-+ GPOEN_SYS_SDIO1_DATA7,
-+ GPI_SYS_SDIO1_DATA7)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+ };
-+
-+ gmac0_pins: gmac0-0 {
-+ reset-pins {
-+ pinmux = <GPIOMUX(13, GPOUT_HIGH,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-pull-up;
-+ };
-+ };
-+
-+ gmac1_pins: gmac1-0 {
-+ mdc-pins {
-+ pinmux = <PINMUX(75, 0)>;
-+ };
-+ };
-+
-+ hdmi_pins: hdmi-0 {
-+ scl-pins {
-+ pinmux = <GPIOMUX(7, GPOUT_SYS_HDMI_DDC_SCL,
-+ GPOEN_SYS_HDMI_DDC_SCL,
-+ GPI_SYS_HDMI_DDC_SCL)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+
-+ sda-pins {
-+ pinmux = <GPIOMUX(8, GPOUT_SYS_HDMI_DDC_SDA,
-+ GPOEN_SYS_HDMI_DDC_SDA,
-+ GPI_SYS_HDMI_DDC_SDA)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+
-+ cec-pins {
-+ pinmux = <GPIOMUX(14, GPOUT_SYS_HDMI_CEC_SDA,
-+ GPOEN_SYS_HDMI_CEC_SDA,
-+ GPI_SYS_HDMI_CEC_SDA)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+
-+ hpd-pins {
-+ pinmux = <GPIOMUX(15, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_HDMI_HPD)>;
-+ bias-disable; /* external pull-up */
-+ input-enable;
-+ };
-+ };
-+
-+ i2c0_pins: i2c0-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(57, GPOUT_LOW,
-+ GPOEN_SYS_I2C0_CLK,
-+ GPI_SYS_I2C0_CLK)>,
-+ <GPIOMUX(58, GPOUT_LOW,
-+ GPOEN_SYS_I2C0_DATA,
-+ GPI_SYS_I2C0_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ i2c1_pins: i2c1-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(49, GPOUT_LOW,
-+ GPOEN_SYS_I2C1_CLK,
-+ GPI_SYS_I2C1_CLK)>,
-+ <GPIOMUX(50, GPOUT_LOW,
-+ GPOEN_SYS_I2C1_DATA,
-+ GPI_SYS_I2C1_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ i2c2_pins: i2c2-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(11, GPOUT_LOW,
-+ GPOEN_SYS_I2C2_CLK,
-+ GPI_SYS_I2C2_CLK)>,
-+ <GPIOMUX(9, GPOUT_LOW,
-+ GPOEN_SYS_I2C2_DATA,
-+ GPI_SYS_I2C2_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ i2c3_pins: i2c3-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(51, GPOUT_LOW,
-+ GPOEN_SYS_I2C3_CLK,
-+ GPI_SYS_I2C3_CLK)>,
-+ <GPIOMUX(52, GPOUT_LOW,
-+ GPOEN_SYS_I2C3_DATA,
-+ GPI_SYS_I2C3_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ i2c4_pins: i2c4-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(18, GPOUT_LOW,
-+ GPOEN_SYS_I2C4_CLK,
-+ GPI_SYS_I2C4_CLK)>,
-+ <GPIOMUX(12, GPOUT_LOW,
-+ GPOEN_SYS_I2C4_DATA,
-+ GPI_SYS_I2C4_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ i2c5_pins: i2c5-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(19, GPOUT_LOW,
-+ GPOEN_SYS_I2C5_CLK,
-+ GPI_SYS_I2C5_CLK)>,
-+ <GPIOMUX(20, GPOUT_LOW,
-+ GPOEN_SYS_I2C5_DATA,
-+ GPI_SYS_I2C5_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ i2c6_pins: i2c6-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(16, GPOUT_LOW,
-+ GPOEN_SYS_I2C6_CLK,
-+ GPI_SYS_I2C6_CLK)>,
-+ <GPIOMUX(17, GPOUT_LOW,
-+ GPOEN_SYS_I2C6_DATA,
-+ GPI_SYS_I2C6_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ i2s_clk_pins: i2s-clk-0 {
-+ bclk-lrck-pins {
-+ pinmux = <GPIOMUX(38, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2STX1_BCLK)>,
-+ <GPIOMUX(38, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2SRX_BCLK)>,
-+ <GPIOMUX(63, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2STX1_LRCK)>,
-+ <GPIOMUX(63, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2SRX_LRCK)>;
-+ input-enable;
-+ };
-+ };
-+
-+ i2srx_clk_pins: i2srx-clk-0 {
-+ mclk-pins {
-+ pinmux = <GPIOMUX(58, GPOUT_SYS_MCLK,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ input-enable;
-+ };
-+ };
-+
-+ i2srx_pins: i2srx-0 {
-+ i2srx-pins {
-+ pinmux = <GPIOMUX(61, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_I2SRX_SDIN0)>;
-+ input-enable;
-+ };
-+ };
-+
-+ i2stx_pins: i2stx-0 {
-+ i2stx-pins {
-+ pinmux = <GPIOMUX(44, GPOUT_SYS_I2STX1_SDO0,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ input-enable;
-+ };
-+ };
-+
-+ mclk_ext_pins: mclk-ext-0 {
-+ mclk-ext-pins {
-+ pinmux = <GPIOMUX(4, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_MCLK_EXT)>;
-+ input-enable;
-+ };
-+ };
-+
-+ pdm_pins: pdm-0 {
-+ pdm-pins {
-+ pinmux = <GPIOMUX(54, GPOUT_SYS_PDM_MCLK,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(60, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_PDM_DMIC0)>;
-+ input-enable;
-+ };
-+ };
-+
-+ pwm_ch0to3_pins: pwm-ch0to3-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(45, GPOUT_SYS_PWM_CHANNEL0,
-+ GPOEN_SYS_PWM0_CHANNEL0,
-+ GPI_NONE)>,
-+ <GPIOMUX(46, GPOUT_SYS_PWM_CHANNEL1,
-+ GPOEN_SYS_PWM0_CHANNEL1,
-+ GPI_NONE)>,
-+ <GPIOMUX(47, GPOUT_SYS_PWM_CHANNEL2,
-+ GPOEN_SYS_PWM0_CHANNEL2,
-+ GPI_NONE)>,
-+ <GPIOMUX(48, GPOUT_SYS_PWM_CHANNEL3,
-+ GPOEN_SYS_PWM0_CHANNEL3,
-+ GPI_NONE)>;
-+ drive-strength = <12>;
-+ };
-+ };
-+
-+ pwmdac_pins: pwmdac-0 {
-+ pwmdac-pins {
-+ pinmux = <GPIOMUX(57, GPOUT_SYS_PWMDAC_LEFT,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(42, GPOUT_SYS_PWMDAC_RIGHT,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ };
-+ };
-+
-+ rgb_pad_pins: rgb-pad-pins {
-+ rgb-0-pins {
-+ pinmux = <PINMUX(36, 1)>;
-+ drive-strength = <12>;
-+ input-disable;
-+ slew-rate = <1>;
-+ };
-+
-+ rgb-pins {
-+ pinmux = <PINMUX(37, 1)>,
-+ <PINMUX(38, 1)>,
-+ <PINMUX(39, 1)>,
-+ <PINMUX(40, 1)>,
-+ <PINMUX(41, 1)>,
-+ <PINMUX(42, 1)>,
-+ <PINMUX(43, 1)>,
-+ <PINMUX(44, 1)>,
-+ <PINMUX(45, 1)>,
-+ <PINMUX(46, 1)>,
-+ <PINMUX(47, 1)>,
-+ <PINMUX(48, 1)>,
-+ <PINMUX(49, 1)>,
-+ <PINMUX(50, 1)>,
-+ <PINMUX(51, 1)>,
-+ <PINMUX(52, 1)>,
-+ <PINMUX(53, 1)>,
-+ <PINMUX(54, 1)>,
-+ <PINMUX(55, 1)>,
-+ <PINMUX(56, 1)>,
-+ <PINMUX(57, 1)>,
-+ <PINMUX(58, 1)>,
-+ <PINMUX(59, 1)>,
-+ <PINMUX(60, 1)>,
-+ <PINMUX(61, 1)>,
-+ <PINMUX(62, 1)>,
-+ <PINMUX(63, 1)>;
-+ drive-strength = <12>;
-+ input-disable;
-+ };
-+ };
-+
-+ sdcard0_pins: sdcard0-0 {
-+ sdcard-pins {
-+ pinmux = <GPIOMUX(24, GPOUT_SYS_SDIO0_RST,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <PINMUX(64, 0)>,
-+ <PINMUX(65, 0)>,
-+ <PINMUX(66, 0)>,
-+ <PINMUX(67, 0)>,
-+ <PINMUX(68, 0)>,
-+ <PINMUX(69, 0)>;
-+ bias-pull-up;
-+ drive-strength = <12>;
-+ input-enable;
-+ slew-rate = <1>;
-+ };
-+ };
-+
-+ sdcard1_pins: sdcard1-0 {
-+ sdcard-pins {
-+ pinmux = <GPIOMUX(56, GPOUT_SYS_SDIO1_CLK,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(50, GPOUT_SYS_SDIO1_CMD,
-+ GPOEN_SYS_SDIO1_CMD,
-+ GPI_SYS_SDIO1_CMD)>,
-+ <GPIOMUX(49, GPOUT_SYS_SDIO1_DATA0,
-+ GPOEN_SYS_SDIO1_DATA0,
-+ GPI_SYS_SDIO1_DATA0)>,
-+ <GPIOMUX(45, GPOUT_SYS_SDIO1_DATA1,
-+ GPOEN_SYS_SDIO1_DATA1,
-+ GPI_SYS_SDIO1_DATA1)>,
-+ <GPIOMUX(62, GPOUT_SYS_SDIO1_DATA2,
-+ GPOEN_SYS_SDIO1_DATA2,
-+ GPI_SYS_SDIO1_DATA2)>,
-+ <GPIOMUX(40, GPOUT_SYS_SDIO1_DATA3,
-+ GPOEN_SYS_SDIO1_DATA3,
-+ GPI_SYS_SDIO1_DATA3)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+ };
-+
-+ spdif_pins: spdif-0 {
-+ spdif-pins {
-+ pinmux = <GPIOMUX(57, GPOUT_SYS_SPDIF,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+ };
-+
-+ spi0_pins: spi0-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(38, GPOUT_SYS_SPI0_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ miso-pins {
-+ pinmux = <GPIOMUX(39, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_SPI0_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+
-+ sck-pins {
-+ pinmux = <GPIOMUX(36, GPOUT_SYS_SPI0_CLK,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI0_CLK)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ ss-pins {
-+ pinmux = <GPIOMUX(37, GPOUT_SYS_SPI0_FSS,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI0_FSS)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ spi1_pins: spi1-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(42, GPOUT_SYS_SPI1_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ miso-pins {
-+ pinmux = <GPIOMUX(43, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_SPI1_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+
-+ sck-pins {
-+ pinmux = <GPIOMUX(40, GPOUT_SYS_SPI1_CLK,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI1_CLK)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ ss-pins {
-+ pinmux = <GPIOMUX(41, GPOUT_SYS_SPI1_FSS,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI1_FSS)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ spi2_pins: spi2-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(46, GPOUT_SYS_SPI2_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ miso-pins {
-+ pinmux = <GPIOMUX(47, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_SPI2_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+
-+ sck-pins {
-+ pinmux = <GPIOMUX(44, GPOUT_SYS_SPI2_CLK,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI2_CLK)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ ss-pins {
-+ pinmux = <GPIOMUX(45, GPOUT_SYS_SPI2_FSS,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI2_FSS)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ spi3_pins: spi3-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(50, GPOUT_SYS_SPI3_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ miso-pins {
-+ pinmux = <GPIOMUX(51, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_SPI3_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+
-+ sck-pins {
-+ pinmux = <GPIOMUX(48, GPOUT_SYS_SPI3_CLK,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI3_CLK)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ ss-pins {
-+ pinmux = <GPIOMUX(49, GPOUT_SYS_SPI3_FSS,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI3_FSS)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ spi4_pins: spi4-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(54, GPOUT_SYS_SPI4_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ miso-pins {
-+ pinmux = <GPIOMUX(55, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_SPI4_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+
-+ sck-pins {
-+ pinmux = <GPIOMUX(52, GPOUT_SYS_SPI4_CLK,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI4_CLK)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ ss-pins {
-+ pinmux = <GPIOMUX(53, GPOUT_SYS_SPI4_FSS,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI4_FSS)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ spi5_pins: spi5-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(58, GPOUT_SYS_SPI5_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ miso-pins {
-+ pinmux = <GPIOMUX(59, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_SPI5_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+
-+ sck-pins {
-+ pinmux = <GPIOMUX(56, GPOUT_SYS_SPI5_CLK,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI5_CLK)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ ss-pins {
-+ pinmux = <GPIOMUX(57, GPOUT_SYS_SPI5_FSS,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI5_FSS)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ spi6_pins: spi6-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(62, GPOUT_SYS_SPI6_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ miso-pins {
-+ pinmux = <GPIOMUX(63, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_SPI6_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+
-+ sck-pins {
-+ pinmux = <GPIOMUX(60, GPOUT_SYS_SPI6_CLK,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI6_CLK)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+
-+ ss-pins {
-+ pinmux = <GPIOMUX(61, GPOUT_SYS_SPI6_FSS,
-+ GPOEN_ENABLE,
-+ GPI_SYS_SPI6_FSS)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ tdm_pins: tdm-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(44, GPOUT_SYS_TDM_TXD,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(61, GPOUT_HIGH,
-+ GPOEN_DISABLE,
-+ GPI_SYS_TDM_RXD)>;
-+ input-enable;
-+ };
-+
-+ sync-pins {
-+ pinmux = <GPIOMUX(63, GPOUT_HIGH,
-+ GPOEN_DISABLE,
-+ GPI_SYS_TDM_SYNC)>;
-+ input-enable;
-+ };
-+
-+ pcmclk-pins {
-+ pinmux = <GPIOMUX(38, GPOUT_HIGH,
-+ GPOEN_DISABLE,
-+ GPI_SYS_TDM_CLK)>;
-+ input-enable;
-+ };
-+ };
-+
-+ uart0_pins: uart0-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(5, GPOUT_SYS_UART0_TX,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(6, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART0_RX)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ uart1_pins: uart1-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(30, GPOUT_SYS_UART1_TX,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(31, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART1_RX)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+
-+ cts-pins {
-+ pinmux = <GPIOMUX(29, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART1_CTS)>;
-+ input-enable;
-+ };
-+
-+ rts-pins {
-+ pinmux = <GPIOMUX(27, GPOUT_SYS_UART1_RTS,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ input-enable;
-+ };
-+ };
-+
-+ uart2_pins: uart2-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(30, GPOUT_SYS_UART2_TX,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(31, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART2_RX)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+
-+ cts-pins {
-+ pinmux = <GPIOMUX(29, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART2_CTS)>;
-+ input-enable;
-+ };
-+
-+ rts-pins {
-+ pinmux = <GPIOMUX(27, GPOUT_SYS_UART2_RTS,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ input-enable;
-+ };
-+ };
-+
-+ uart3_pins: uart3-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(30, GPOUT_SYS_UART3_TX,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(31, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART3_RX)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ uart4_pins: uart4-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(30, GPOUT_SYS_UART4_TX,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(31, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART4_RX)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+
-+ cts-pins {
-+ pinmux = <GPIOMUX(29, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART4_CTS)>;
-+ input-enable;
-+ };
-+
-+ rts-pins {
-+ pinmux = <GPIOMUX(27, GPOUT_SYS_UART4_RTS,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ input-enable;
-+ };
-+ };
-+
-+ uart5_pins: uart5-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(30, GPOUT_SYS_UART5_TX,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(31, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART5_RX)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+
-+ cts-pins {
-+ pinmux = <GPIOMUX(29, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART5_CTS)>;
-+ input-enable;
-+ };
-+
-+ rts-pins {
-+ pinmux = <GPIOMUX(27, GPOUT_SYS_UART5_RTS,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ input-enable;
-+ };
-+ };
-+
-+ usb_pins: usb-0 {
-+ usb-pins {
-+ pinmux = <GPIOMUX(33, GPOUT_HIGH,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(34, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_USB_OVERCURRENT)>;
-+ input-enable;
-+ };
-+ };
-+};
-+
-+&aongpio {
-+ pwm_ch4to5_pins: pwm-ch4to5-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(1, GPOUT_AON_PTC0_PWM4, /* PAD_RGPIO0 */
-+ GPOEN_AON_PTC0_OE_N_4,
-+ GPI_NONE)>,
-+ <GPIOMUX(2, GPOUT_AON_PTC0_PWM5, /* PAD_RGPIO1 */
-+ GPOEN_AON_PTC0_OE_N_5,
-+ GPI_NONE)>;
-+ drive-strength = <12>;
-+ };
-+ };
-+
-+ pwm_ch6to7_pins: pwm-ch6to7-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(1, GPOUT_AON_PTC0_PWM6, /* PAD_RGPIO0 */
-+ GPOEN_AON_PTC0_OE_N_6,
-+ GPI_NONE)>,
-+ <GPIOMUX(2, GPOUT_AON_PTC0_PWM7, /* PAD_RGPIO1 */
-+ GPOEN_AON_PTC0_OE_N_7,
-+ GPI_NONE)>;
-+ drive-strength = <12>;
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb.dts
-@@ -0,0 +1,35 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ no-sdio;
-+ no-mmc;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
-+
-+&usb0 {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb.dtsi
-@@ -0,0 +1,854 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2023 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110.dtsi"
-+#include "jh7110-clk.dtsi"
-+#include "jh7110-evb-pinctrl.dtsi"
-+#include <dt-bindings/gpio/gpio.h>
-+
-+/ {
-+ aliases {
-+ ethernet0 = &gmac0;
-+ ethernet1 = &gmac1;
-+ i2c0 = &i2c0;
-+ i2c1 = &i2c1;
-+ i2c2 = &i2c2;
-+ i2c3 = &i2c3;
-+ i2c4 = &i2c4;
-+ i2c5 = &i2c5;
-+ i2c6 = &i2c6;
-+ pcie0 = &pcie0;
-+ pcie1 = &pcie1;
-+ serial0 = &uart0;
-+ serial3 = &uart3;
-+ };
-+
-+ chosen {
-+ stdout-path = "serial0:115200n8";
-+ };
-+
-+ cpus {
-+ timebase-frequency = <4000000>;
-+ };
-+
-+ memory@40000000 {
-+ device_type = "memory";
-+ reg = <0x0 0x40000000 0x1 0x0>;
-+ };
-+
-+ reserved-memory {
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+ ranges;
-+
-+ linux,cma {
-+ compatible = "shared-dma-pool";
-+ reusable;
-+ size = <0x0 0x20000000>;
-+ alignment = <0x0 0x1000>;
-+ alloc-ranges = <0x0 0x70000000 0x0 0x20000000>;
-+ linux,cma-default;
-+ };
-+
-+ e24_mem: e24@c0000000 {
-+ reg = <0x0 0x6ce00000 0x0 0x1600000>;
-+ };
-+
-+ xrp_reserved: xrpbuffer@f0000000 {
-+ reg = <0x0 0x69c00000 0x0 0x01ffffff
-+ 0x0 0x6bc00000 0x0 0x00001000
-+ 0x0 0x6bc01000 0x0 0x00fff000
-+ 0x0 0x6cc00000 0x0 0x00001000>;
-+ };
-+ };
-+
-+ /* i2s + hdmi */
-+ sound1: snd-card1 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-HDMI-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "i2s";
-+ bitclock-master = <&sndi2s0>;
-+ frame-master = <&sndi2s0>;
-+ mclk-fs = <256>;
-+ status = "okay";
-+
-+ sndi2s0: cpu {
-+ sound-dai = <&i2stx0>;
-+ };
-+
-+ codec {
-+ sound-dai = <&hdmi>;
-+ };
-+ };
-+ };
-+};
-+
-+&U74_1 {
-+ /delete-property/ clocks;
-+ /delete-property/ clock-names;
-+};
-+
-+&U74_2 {
-+ /delete-property/ clocks;
-+ /delete-property/ clock-names;
-+};
-+
-+&U74_3 {
-+ /delete-property/ clocks;
-+ /delete-property/ clock-names;
-+};
-+
-+&U74_4 {
-+ /delete-property/ clocks;
-+ /delete-property/ clock-names;
-+};
-+
-+&can0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&can0_pins>;
-+ status = "disabled";
-+};
-+
-+&can1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&can1_pins>;
-+ status = "disabled";
-+};
-+
-+&co_process {
-+ memory-region = <&e24_mem>;
-+ status = "okay";
-+};
-+
-+&dc8200 {
-+ status = "okay";
-+
-+ dc_out: port {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ dc_out_dpi0: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&hdmi_input0>;
-+ };
-+ dc_out_dpi1: endpoint@1 {
-+ reg = <1>;
-+ remote-endpoint = <&hdmi_in_lcdc>;
-+ };
-+ dc_out_dpi2: endpoint@2 {
-+ reg = <2>;
-+ remote-endpoint = <&mipi_in>;
-+ };
-+ };
-+};
-+
-+&display {
-+ ports = <&dc_out_dpi0>;
-+ status = "okay";
-+};
-+
-+&dsi_output {
-+ status = "okay";
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ reg = <0>;
-+ mipi_in: endpoint {
-+ remote-endpoint = <&dc_out_dpi2>;
-+ };
-+ };
-+
-+ port@1 {
-+ reg = <1>;
-+ mipi_out: endpoint {
-+ remote-endpoint = <&dsi_in_port>;
-+ };
-+ };
-+ };
-+};
-+
-+&gmac0 {
-+ phy-handle = <&phy0>;
-+ phy-mode = "rgmii-id";
-+ status = "okay";
-+
-+ mdio {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ compatible = "snps,dwmac-mdio";
-+
-+ phy0: ethernet-phy@0 {
-+ reg = <0>;
-+ rx-internal-delay-ps = <1900>;
-+ tx-internal-delay-ps = <1650>;
-+ };
-+ };
-+};
-+
-+&gmac1 {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ phy1: ethernet-phy@1 {
-+ reg = <0>;
-+ rxc-skew-ps = <1060>;
-+ txc-skew-ps = <1800>;
-+ };
-+};
-+
-+&gpu {
-+ status = "okay";
-+};
-+
-+&hdmi {
-+ status = "okay";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&hdmi_pins>;
-+ hpd-gpio = <&sysgpio 15 GPIO_ACTIVE_HIGH>;
-+
-+ hdmi_in: port {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ hdmi_in_lcdc: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&dc_out_dpi1>;
-+ };
-+ };
-+};
-+
-+&i2c0 {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c0_pins>;
-+ status = "disabled";
-+
-+ wm8960: codec@1a {
-+ compatible = "wlf,wm8960";
-+ reg = <0x1a>;
-+ wlf,shared-lrclk;
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ ac108: ac108@3b {
-+ compatible = "x-power,ac108_0";
-+ reg = <0x3b>;
-+ #sound-dai-cells = <0>;
-+ data-protocol = <0>;
-+ };
-+};
-+
-+&i2c1 {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c1_pins>;
-+ status = "disabled";
-+};
-+
-+&i2c2 {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c2_pins>;
-+ status = "okay";
-+
-+ tinker_ft5406: tinker_ft5406@38 {
-+ compatible = "tinker_ft5406";
-+ reg = <0x38>;
-+ };
-+
-+ seeed_plane_i2c@45 {
-+ compatible = "seeed_panel";
-+ reg = <0x45>;
-+
-+ port {
-+ panel_dsi_port: endpoint {
-+ remote-endpoint = <&dsi_out_port>;
-+ };
-+ };
-+ };
-+};
-+
-+&i2c3 {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c3_pins>;
-+ status = "disabled";
-+};
-+
-+&i2c4 {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c4_pins>;
-+ status = "okay";
-+
-+ sc2235: sc2235@30 {
-+ compatible = "smartsens,sc2235";
-+ reg = <0x30>;
-+ clocks = <&clk_ext_camera>;
-+ clock-names = "xclk";
-+
-+ port {
-+ /* Parallel bus endpoint */
-+ sc2235_to_parallel: endpoint {
-+ remote-endpoint = <¶llel_from_sc2235>;
-+ bus-type = <5>; /* Parallel */
-+ bus-width = <8>;
-+ data-shift = <2>; /* lines 13:6 are used */
-+ hsync-active = <1>;
-+ vsync-active = <1>;
-+ pclk-sample = <1>;
-+ };
-+ };
-+ };
-+
-+ tda998x@70 {
-+ compatible = "nxp,tda998x";
-+ reg = <0x70>;
-+
-+ port {
-+ tda998x_0_input: endpoint {
-+ remote-endpoint = <&hdmi_out>;
-+ };
-+ };
-+ };
-+};
-+
-+&i2c5 {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c5_pins>;
-+ status = "okay";
-+
-+ pmic: jh7110_evb_reg@50 {
-+ compatible = "starfive,jh7110-evb-regulator";
-+ reg = <0x50>;
-+
-+ regulators {
-+ hdmi_1p8: LDO_REG1 {
-+ regulator-name = "hdmi_1p8";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <1800000>;
-+ };
-+ mipitx_1p8: LDO_REG2 {
-+ regulator-name = "mipitx_1p8";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <1800000>;
-+ };
-+ mipirx_1p8: LDO_REG3 {
-+ regulator-name = "mipirx_1p8";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <1800000>;
-+ };
-+ hdmi_0p9: LDO_REG4 {
-+ regulator-name = "hdmi_0p9";
-+ regulator-min-microvolt = <900000>;
-+ regulator-max-microvolt = <900000>;
-+ };
-+ mipitx_0p9: LDO_REG5 {
-+ regulator-name = "mipitx_0p9";
-+ regulator-min-microvolt = <900000>;
-+ regulator-max-microvolt = <900000>;
-+ };
-+ mipirx_0p9: LDO_REG6 {
-+ regulator-name = "mipirx_0p9";
-+ regulator-min-microvolt = <900000>;
-+ regulator-max-microvolt = <900000>;
-+ };
-+ sdio_vdd: LDO_REG7 {
-+ regulator-name = "sdio_vdd";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <3300000>;
-+ };
-+ };
-+ };
-+};
-+
-+&i2c6 {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2c6_pins>;
-+ status = "okay";
-+
-+ ov4689: ov4689@36 {
-+ compatible = "ovti,ov4689";
-+ reg = <0x36>;
-+ clocks = <&clk_ext_camera>;
-+ clock-names = "xclk";
-+ //reset-gpio = <&sysgpio 18 0>;
-+ rotation = <180>;
-+
-+ port {
-+ /* Parallel bus endpoint */
-+ ov4689_to_csi2rx0: endpoint {
-+ remote-endpoint = <&csi2rx0_from_ov4689>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <0>;
-+ data-lanes = <1 2 3 4>;
-+ };
-+ };
-+ };
-+
-+ imx219: imx219@10 {
-+ compatible = "sony,imx219";
-+ reg = <0x10>;
-+ clocks = <&clk_ext_camera>;
-+ clock-names = "xclk";
-+ reset-gpio = <&sysgpio 10 0>;
-+ //DOVDD-supply = <&v2v8>;
-+ rotation = <0>;
-+ orientation = <1>; //CAMERA_ORIENTATION_BACK
-+
-+ port {
-+ /* CSI2 bus endpoint */
-+ imx219_to_csi2rx0: endpoint {
-+ remote-endpoint = <&csi2rx0_from_imx219>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <0>;
-+ data-lanes = <2 1>;
-+ lane-polarities = <1 1 1>;
-+ link-frequencies = /bits/ 64 <456000000>;
-+ };
-+ };
-+ };
-+
-+ imx708: imx708@1a {
-+ compatible = "sony,imx708";
-+ reg = <0x1a>;
-+ clocks = <&clk_ext_camera>;
-+ reset-gpio = <&sysgpio 10 0>;
-+
-+ port {
-+ imx708_to_csi2rx0: endpoint {
-+ remote-endpoint = <&csi2rx0_from_imx708>;
-+ data-lanes = <1 2>;
-+ clock-noncontinuous;
-+ link-frequencies = /bits/ 64 <450000000>;
-+ };
-+ };
-+ };
-+};
-+
-+&i2srx {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2s_clk_pins &i2srx_pins>;
-+};
-+
-+&i2srx_mst {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2srx_clk_pins>;
-+};
-+
-+&i2stx0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&mclk_ext_pins>;
-+ status = "okay";
-+};
-+
-+&i2stx1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&i2stx_pins>;
-+};
-+
-+&jpu {
-+ status = "okay";
-+};
-+
-+&mailbox_contrl0 {
-+ status = "okay";
-+};
-+
-+&mailbox_client0 {
-+ status = "okay";
-+};
-+
-+&mipi_dphy {
-+ status = "okay";
-+};
-+
-+&mipi_dsi {
-+ status = "okay";
-+
-+ port {
-+ dsi_out_port: endpoint@0 {
-+ remote-endpoint = <&panel_dsi_port>;
-+ };
-+ dsi_in_port: endpoint@1 {
-+ remote-endpoint = <&mipi_out>;
-+ };
-+ };
-+
-+ mipi_panel: panel@0 {
-+ /*compatible = "";*/
-+ status = "okay";
-+ };
-+};
-+
-+&pcie0 {
-+ enable-gpios = <&sysgpio 32 GPIO_ACTIVE_HIGH>;
-+ perst-gpios = <&sysgpio 26 GPIO_ACTIVE_LOW>;
-+ phys = <&pciephy0>;
-+ status = "disabled";
-+};
-+
-+&pcie1 {
-+ enable-gpios = <&sysgpio 21 GPIO_ACTIVE_HIGH>;
-+ perst-gpios = <&sysgpio 28 GPIO_ACTIVE_LOW>;
-+ phys = <&pciephy1>;
-+ status = "disabled";
-+};
-+
-+&pciephy0 {
-+ starfive,sys-syscon = <&sys_syscon 0x18>;
-+ starfive,stg-syscon = <&stg_syscon 0x148 0x1f4>;
-+};
-+
-+&pdm {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pdm_pins>;
-+ status = "disabled";
-+};
-+
-+&pwmdac {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwmdac_pins>;
-+};
-+
-+&qspi {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "okay";
-+
-+ nor_flash: flash@0 {
-+ compatible = "jedec,spi-nor";
-+ reg=<0>;
-+ cdns,read-delay = <5>;
-+ spi-max-frequency = <4687500>;
-+ cdns,tshsl-ns = <1>;
-+ cdns,tsd2d-ns = <1>;
-+ cdns,tchsh-ns = <1>;
-+ cdns,tslch-ns = <1>;
-+
-+ partitions {
-+ compatible = "fixed-partitions";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ spl@0 {
-+ reg = <0x0 0x40000>;
-+ };
-+ uboot@100000 {
-+ reg = <0x100000 0x300000>;
-+ };
-+ data@f00000 {
-+ reg = <0xf00000 0x100000>;
-+ };
-+ };
-+ };
-+};
-+
-+&rgb_output {
-+ status = "okay";
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ reg = <0>;
-+
-+ hdmi_input0:endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&dc_out_dpi0>;
-+ };
-+ };
-+
-+ port@1 {
-+ reg = <1>;
-+
-+ hdmi_out:endpoint {
-+ remote-endpoint = <&tda998x_0_input>;
-+ };
-+ };
-+ };
-+};
-+
-+&spdif {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spdif_pins>;
-+};
-+
-+&spi0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi0_pins>;
-+ status = "disabled";
-+
-+ spi_dev0: spi_dev@0 {
-+ compatible = "rohm,dh2228fv";
-+ reg = <0>;
-+ pl022,com-mode = <1>;
-+ spi-max-frequency = <10000000>;
-+ };
-+};
-+
-+&spi1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi1_pins>;
-+ status = "disabled";
-+
-+ spi_dev1: spi_dev@0 {
-+ compatible = "rohm,dh2228fv";
-+ reg = <0>;
-+ pl022,com-mode = <1>;
-+ spi-max-frequency = <10000000>;
-+ };
-+};
-+
-+&spi2 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi2_pins>;
-+ status = "disabled";
-+
-+ spi_dev2: spi_dev@0 {
-+ compatible = "rohm,dh2228fv";
-+ reg = <0>;
-+ pl022,com-mode = <1>;
-+ spi-max-frequency = <10000000>;
-+ };
-+};
-+
-+&spi3 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi3_pins>;
-+ status = "disabled";
-+
-+ spi_dev3: spi_dev@0 {
-+ compatible = "rohm,dh2228fv";
-+ reg = <0>;
-+ pl022,com-mode = <1>;
-+ spi-max-frequency = <10000000>;
-+ };
-+};
-+
-+&spi4 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi4_pins>;
-+ status = "disabled";
-+
-+ spi_dev4: spi_dev@0 {
-+ compatible = "rohm,dh2228fv";
-+ reg = <0>;
-+ pl022,com-mode = <1>;
-+ spi-max-frequency = <10000000>;
-+ };
-+};
-+
-+&spi5 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi5_pins>;
-+ status = "disabled";
-+
-+ spi_dev5: spi_dev@0 {
-+ compatible = "rohm,dh2228fv";
-+ reg = <0>;
-+ pl022,com-mode = <1>;
-+ spi-max-frequency = <10000000>;
-+ };
-+};
-+
-+&spi6 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi6_pins>;
-+ status = "disabled";
-+
-+ spi_dev6: spi_dev@0 {
-+ compatible = "rohm,dh2228fv";
-+ reg = <0>;
-+ pl022,com-mode = <1>;
-+ spi-max-frequency = <10000000>;
-+ };
-+};
-+
-+&tda988x_pin {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&rgb_pad_pins>;
-+ status = "disabled";
-+};
-+
-+&tdm {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&tdm_pins>;
-+ status = "disabled";
-+};
-+
-+&uart0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_pins>;
-+ status = "okay";
-+};
-+
-+&uart1 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart1_pins>;
-+ status = "disabled";
-+};
-+
-+&uart2 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart2_pins>;
-+ status = "disabled";
-+};
-+
-+&uart3 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart3_pins>;
-+ status = "disabled";
-+};
-+
-+&uart4 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart4_pins>;
-+ status = "disabled";
-+};
-+
-+&uart5 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart5_pins>;
-+ status = "disabled";
-+};
-+
-+&usb0 {
-+ clocks = <&stgcrg JH7110_STGCLK_USB0_LPM>,
-+ <&stgcrg JH7110_STGCLK_USB0_STB>,
-+ <&stgcrg JH7110_STGCLK_USB0_APB>,
-+ <&stgcrg JH7110_STGCLK_USB0_AXI>,
-+ <&stgcrg JH7110_STGCLK_USB0_UTMI_APB>,
-+ <&stgcrg JH7110_STGCLK_PCIE0_APB>;
-+ clock-names = "lpm", "stb", "apb", "axi", "utmi_apb", "phy";
-+ resets = <&stgcrg JH7110_STGRST_USB0_PWRUP>,
-+ <&stgcrg JH7110_STGRST_USB0_APB>,
-+ <&stgcrg JH7110_STGRST_USB0_AXI>,
-+ <&stgcrg JH7110_STGRST_USB0_UTMI_APB>,
-+ <&stgcrg JH7110_STGRST_PCIE0_APB>;
-+ reset-names = "pwrup", "apb", "axi", "utmi_apb", "phy";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&usb_pins>;
-+ dr_mode = "host"; /* host or peripheral */
-+ status = "disabled";
-+};
-+
-+&usb_cdns3 {
-+ phys = <&usbphy0>, <&pciephy0>;
-+ phy-names = "cdns3,usb2-phy", "cdns3,usb3-phy";
-+};
-+
-+&vin_sysctl {
-+ status = "okay";
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ reg = <0>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ /* Parallel bus endpoint */
-+ parallel_from_sc2235: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&sc2235_to_parallel>;
-+ bus-type = <5>; /* Parallel */
-+ bus-width = <8>;
-+ data-shift = <2>; /* lines 9:2 are used */
-+ hsync-active = <1>;
-+ vsync-active = <0>;
-+ pclk-sample = <1>;
-+ status = "okay";
-+ };
-+ };
-+
-+ port@1 {
-+ reg = <1>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ /* CSI2 bus endpoint */
-+ csi2rx0_from_ov4689: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&ov4689_to_csi2rx0>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <0>;
-+ data-lanes = <1 2 3 4>;
-+ status = "okay";
-+ };
-+
-+ /* CSI2 bus endpoint */
-+ csi2rx0_from_imx219: endpoint@1 {
-+ reg = <1>;
-+ remote-endpoint = <&imx219_to_csi2rx0>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <0>;
-+ data-lanes = <2 1>;
-+ lane-polarities = <1 1 1>;
-+ status = "okay";
-+ };
-+
-+ csi2rx0_from_imx708: endpoint@2 {
-+ reg = <2>;
-+ remote-endpoint = <&imx708_to_csi2rx0>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <0>;
-+ data-lanes = <2 1>;
-+ lane-polarities = <1 1 1>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
-+
-+&vpu_dec {
-+ status = "okay";
-+};
-+
-+&vpu_enc {
-+ status = "okay";
-+};
-+
-+&xrp {
-+ memory-region = <&xrp_reserved>;
-+ status = "okay";
-+};
---- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
-@@ -196,11 +196,60 @@
- opp-750000000 {
- opp-hz = /bits/ 64 <750000000>;
- opp-microvolt = <800000>;
-+ opp-suspend;
- };
- opp-1500000000 {
- opp-hz = /bits/ 64 <1500000000>;
- opp-microvolt = <1040000>;
- };
-+ /* CPU opp table for 1.25GHz */
-+ opp-312500000 {
-+ opp-hz = /bits/ 64 <312500000>;
-+ opp-microvolt = <800000>;
-+ };
-+ opp-417000000 {
-+ opp-hz = /bits/ 64 <417000000>;
-+ opp-microvolt = <800000>;
-+ };
-+ opp-625000000 {
-+ opp-hz = /bits/ 64 <625000000>;
-+ opp-microvolt = <800000>;
-+ opp-suspend;
-+ };
-+ opp-1250000000 {
-+ opp-hz = /bits/ 64 <1250000000>;
-+ opp-microvolt = <1000000>;
-+ };
-+ };
-+
-+ display: display-subsystem {
-+ compatible = "starfive,jh7110-display","verisilicon,display-subsystem";
-+ status = "disabled";
-+ };
-+
-+ dsi_output: dsi-output {
-+ compatible = "starfive,jh7110-display-encoder","verisilicon,dsi-encoder";
-+ status = "disabled";
-+ };
-+
-+ mailbox_client0: mailbox_client {
-+ compatible = "starfive,mailbox-test";
-+ mbox-names = "rx", "tx";
-+ mboxes = <&mailbox_contrl0 0 1>,<&mailbox_contrl0 1 0>;
-+ status = "disabled";
-+ };
-+
-+ rgb_output: rgb-output {
-+ compatible = "starfive,jh7110-rgb_output","verisilicon,rgb-encoder";
-+ //verisilicon,dss-syscon = <&dssctrl>;
-+ //verisilicon,mux-mask = <0x70 0x380>;
-+ //verisilicon,mux-val = <0x40 0x280>;
-+ status = "disabled";
-+ };
-+
-+ tda988x_pin: tda988x_pin {
-+ compatible = "starfive,tda998x_rgb_pin";
-+ status = "disabled";
- };
-
- thermal-zones {
-@@ -349,7 +398,9 @@
-
- ccache: cache-controller@2010000 {
- compatible = "starfive,jh7110-ccache", "sifive,ccache0", "cache";
-- reg = <0x0 0x2010000 0x0 0x4000>;
-+ reg = <0x0 0x2010000 0x0 0x4000>,
-+ <0x0 0x8000000 0x0 0x2000000>,
-+ <0x0 0xa000000 0x0 0x2000000>;
- interrupts = <1>, <3>, <4>, <2>;
- cache-block-size = <64>;
- cache-level = <2>;
-@@ -378,7 +429,8 @@
- clocks = <&syscrg JH7110_SYSCLK_UART0_CORE>,
- <&syscrg JH7110_SYSCLK_UART0_APB>;
- clock-names = "baudclk", "apb_pclk";
-- resets = <&syscrg JH7110_SYSRST_UART0_APB>;
-+ resets = <&syscrg JH7110_SYSRST_UART0_APB>,
-+ <&syscrg JH7110_SYSRST_UART0_CORE>;
- interrupts = <32>;
- reg-io-width = <4>;
- reg-shift = <2>;
-@@ -391,7 +443,8 @@
- clocks = <&syscrg JH7110_SYSCLK_UART1_CORE>,
- <&syscrg JH7110_SYSCLK_UART1_APB>;
- clock-names = "baudclk", "apb_pclk";
-- resets = <&syscrg JH7110_SYSRST_UART1_APB>;
-+ resets = <&syscrg JH7110_SYSRST_UART1_APB>,
-+ <&syscrg JH7110_SYSRST_UART1_CORE>;
- interrupts = <33>;
- reg-io-width = <4>;
- reg-shift = <2>;
-@@ -404,7 +457,8 @@
- clocks = <&syscrg JH7110_SYSCLK_UART2_CORE>,
- <&syscrg JH7110_SYSCLK_UART2_APB>;
- clock-names = "baudclk", "apb_pclk";
-- resets = <&syscrg JH7110_SYSRST_UART2_APB>;
-+ resets = <&syscrg JH7110_SYSRST_UART2_APB>,
-+ <&syscrg JH7110_SYSRST_UART2_CORE>;
- interrupts = <34>;
- reg-io-width = <4>;
- reg-shift = <2>;
-@@ -513,6 +567,25 @@
- status = "disabled";
- };
-
-+ spdif: spdif@100a0000 {
-+ compatible = "starfive,jh7110-spdif";
-+ reg = <0x0 0x100a0000 0x0 0x1000>;
-+ clocks = <&syscrg JH7110_SYSCLK_SPDIF_APB>,
-+ <&syscrg JH7110_SYSCLK_SPDIF_CORE>,
-+ <&syscrg JH7110_SYSCLK_AUDIO_ROOT>,
-+ <&syscrg JH7110_SYSCLK_MCLK_INNER>,
-+ <&mclk_ext>, <&syscrg JH7110_SYSCLK_MCLK>;
-+ clock-names = "apb", "core",
-+ "audroot", "mclk_inner",
-+ "mclk_ext", "mclk";
-+ resets = <&syscrg JH7110_SYSRST_SPDIF_APB>;
-+ reset-names = "apb";
-+ interrupts = <84>;
-+ interrupt-names = "tx";
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
- pwmdac: pwmdac@100b0000 {
- compatible = "starfive,jh7110-pwmdac";
- reg = <0x0 0x100b0000 0x0 0x1000>;
-@@ -526,6 +599,42 @@
- status = "disabled";
- };
-
-+ pdm: pdm@100d0000 {
-+ compatible = "starfive,jh7110-pdm";
-+ reg = <0x0 0x100d0000 0x0 0x1000>;
-+ reg-names = "pdm";
-+ clocks = <&syscrg JH7110_SYSCLK_PDM_DMIC>,
-+ <&syscrg JH7110_SYSCLK_PDM_APB>,
-+ <&syscrg JH7110_SYSCLK_MCLK>,
-+ <&mclk_ext>;
-+ clock-names = "pdm_mclk", "pdm_apb",
-+ "clk_mclk", "mclk_ext";
-+ resets = <&syscrg JH7110_SYSRST_PDM_DMIC>,
-+ <&syscrg JH7110_SYSRST_PDM_APB>;
-+ reset-names = "pdm_dmic", "pdm_apb";
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2srx_mst: i2srx_mst@100e0000 {
-+ compatible = "starfive,jh7110-i2srx-master";
-+ reg = <0x0 0x100e0000 0x0 0x1000>;
-+ clocks = <&syscrg JH7110_SYSCLK_I2SRX_BCLK_MST>,
-+ <&syscrg JH7110_SYSCLK_I2SRX_APB>,
-+ <&syscrg JH7110_SYSCLK_MCLK>,
-+ <&syscrg JH7110_SYSCLK_MCLK_INNER>,
-+ <&mclk_ext>;
-+ clock-names = "i2sclk", "apb", "mclk",
-+ "mclk_inner","mclk_ext";
-+ resets = <&syscrg JH7110_SYSRST_I2SRX_APB>,
-+ <&syscrg JH7110_SYSRST_I2SRX_BCLK>;
-+ dmas = <&dma 24>;
-+ dma-names = "rx";
-+ starfive,syscon = <&sys_syscon 0x18 0x2 0x34 0x3FC00 0x24400>;
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
- i2srx: i2s@100e0000 {
- compatible = "starfive,jh7110-i2srx";
- reg = <0x0 0x100e0000 0x0 0x1000>;
-@@ -622,6 +731,26 @@
- #reset-cells = <1>;
- };
-
-+ xrp: xrp@10230000 {
-+ compatible = "cdns,xrp";
-+ dma-coherent;
-+ reg = <0x0 0x10230000 0x0 0x00010000
-+ 0x0 0x10240000 0x0 0x00010000>;
-+ clocks = <&stgcrg JH7110_STGCLK_HIFI4_CLK_CORE>;
-+ clock-names = "core_clk";
-+ resets = <&stgcrg JH7110_STGRST_HIFI4_CORE>,
-+ <&stgcrg JH7110_STGRST_HIFI4_AXI>;
-+ reset-names = "rst_core","rst_axi";
-+ starfive,stg-syscon = <&stg_syscon>;
-+ firmware-name = "hifi4_elf";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges = <0x40000000 0x0 0x20000000 0x040000
-+ 0x69c00000 0x0 0x69c00000 0x03000000>;
-+ status = "disabled";
-+ dsp@0 {};
-+ };
-+
- stg_syscon: syscon@10240000 {
- compatible = "starfive,jh7110-stg-syscon", "syscon";
- reg = <0x0 0x10240000 0x0 0x1000>;
-@@ -633,7 +762,8 @@
- clocks = <&syscrg JH7110_SYSCLK_UART3_CORE>,
- <&syscrg JH7110_SYSCLK_UART3_APB>;
- clock-names = "baudclk", "apb_pclk";
-- resets = <&syscrg JH7110_SYSRST_UART3_APB>;
-+ resets = <&syscrg JH7110_SYSRST_UART3_APB>,
-+ <&syscrg JH7110_SYSRST_UART3_CORE>;
- interrupts = <45>;
- reg-io-width = <4>;
- reg-shift = <2>;
-@@ -646,7 +776,8 @@
- clocks = <&syscrg JH7110_SYSCLK_UART4_CORE>,
- <&syscrg JH7110_SYSCLK_UART4_APB>;
- clock-names = "baudclk", "apb_pclk";
-- resets = <&syscrg JH7110_SYSRST_UART4_APB>;
-+ resets = <&syscrg JH7110_SYSRST_UART4_APB>,
-+ <&syscrg JH7110_SYSRST_UART4_CORE>;
- interrupts = <46>;
- reg-io-width = <4>;
- reg-shift = <2>;
-@@ -659,7 +790,8 @@
- clocks = <&syscrg JH7110_SYSCLK_UART5_CORE>,
- <&syscrg JH7110_SYSCLK_UART5_APB>;
- clock-names = "baudclk", "apb_pclk";
-- resets = <&syscrg JH7110_SYSRST_UART5_APB>;
-+ resets = <&syscrg JH7110_SYSRST_UART5_APB>,
-+ <&syscrg JH7110_SYSRST_UART5_CORE>;
- interrupts = <47>;
- reg-io-width = <4>;
- reg-shift = <2>;
-@@ -919,6 +1051,18 @@
- "ch2", "ch3";
- };
-
-+ mailbox_contrl0: mailbox@13060000 {
-+ compatible = "starfive,mail_box";
-+ reg = <0x0 0x13060000 0x0 0x0001000>;
-+ clocks = <&syscrg JH7110_SYSCLK_MAILBOX_APB>;
-+ clock-names = "clk_apb";
-+ resets = <&syscrg JH7110_SYSRST_MAILBOX_APB>;
-+ reset-names = "mbx_rre";
-+ interrupts = <26 27>;
-+ #mbox-cells = <2>;
-+ status = "disabled";
-+ };
-+
- watchdog@13070000 {
- compatible = "starfive,jh7110-wdt";
- reg = <0x0 0x13070000 0x0 0x10000>;
-@@ -929,6 +1073,112 @@
- <&syscrg JH7110_SYSRST_WDT_CORE>;
- };
-
-+ jpu: jpu@13090000 {
-+ compatible = "starfive,jpu";
-+ dma-coherent;
-+ reg = <0x0 0x13090000 0x0 0x300>;
-+ interrupts = <14>;
-+ clocks = <&syscrg JH7110_SYSCLK_CODAJ12_AXI>,
-+ <&syscrg JH7110_SYSCLK_CODAJ12_CORE>,
-+ <&syscrg JH7110_SYSCLK_CODAJ12_APB>,
-+ <&syscrg JH7110_SYSCLK_NOC_BUS_VDEC_AXI>,
-+ <&syscrg JH7110_SYSCLK_VDEC_MAIN>,
-+ <&syscrg JH7110_SYSCLK_VDEC_JPG>;
-+ clock-names = "axi_clk", "core_clk", "apb_clk",
-+ "noc_bus", "main_clk", "dec_clk";
-+ resets = <&syscrg JH7110_SYSRST_CODAJ12_AXI>,
-+ <&syscrg JH7110_SYSRST_CODAJ12_CORE>,
-+ <&syscrg JH7110_SYSRST_CODAJ12_APB>;
-+ reset-names = "rst_axi", "rst_core", "rst_apb";
-+ power-domains = <&pwrc JH7110_PD_VDEC>;
-+ status = "disabled";
-+ };
-+
-+ vpu_dec: vpu_dec@130a0000 {
-+ compatible = "starfive,vdec";
-+ dma-coherent;
-+ reg = <0x0 0x130a0000 0x0 0x10000>;
-+ interrupts = <13>;
-+ clocks = <&syscrg JH7110_SYSCLK_WAVE511_AXI>,
-+ <&syscrg JH7110_SYSCLK_WAVE511_BPU>,
-+ <&syscrg JH7110_SYSCLK_WAVE511_VCE>,
-+ <&syscrg JH7110_SYSCLK_WAVE511_APB>,
-+ <&syscrg JH7110_SYSCLK_NOC_BUS_VDEC_AXI>,
-+ <&syscrg JH7110_SYSCLK_VDEC_MAIN>;
-+ clock-names = "axi_clk", "bpu_clk", "vce_clk",
-+ "apb_clk", "noc_bus", "main_clk";
-+ resets = <&syscrg JH7110_SYSRST_WAVE511_AXI>,
-+ <&syscrg JH7110_SYSRST_WAVE511_BPU>,
-+ <&syscrg JH7110_SYSRST_WAVE511_VCE>,
-+ <&syscrg JH7110_SYSRST_WAVE511_APB>,
-+ <&syscrg JH7110_SYSRST_AXIMEM0_AXI>;
-+ reset-names = "rst_axi", "rst_bpu", "rst_vce",
-+ "rst_apb", "rst_sram";
-+ starfive,vdec_noc_ctrl;
-+ power-domains = <&pwrc JH7110_PD_VDEC>;
-+ status = "disabled";
-+ };
-+
-+ vpu_enc: vpu_enc@130b0000 {
-+ compatible = "starfive,venc";
-+ dma-coherent;
-+ reg = <0x0 0x130b0000 0x0 0x10000>;
-+ interrupts = <15>;
-+ clocks = <&syscrg JH7110_SYSCLK_WAVE420L_AXI>,
-+ <&syscrg JH7110_SYSCLK_WAVE420L_BPU>,
-+ <&syscrg JH7110_SYSCLK_WAVE420L_VCE>,
-+ <&syscrg JH7110_SYSCLK_WAVE420L_APB>,
-+ <&syscrg JH7110_SYSCLK_NOC_BUS_VENC_AXI>;
-+ clock-names = "axi_clk", "bpu_clk", "vce_clk",
-+ "apb_clk", "noc_bus";
-+ resets = <&syscrg JH7110_SYSRST_WAVE420L_AXI>,
-+ <&syscrg JH7110_SYSRST_WAVE420L_BPU>,
-+ <&syscrg JH7110_SYSRST_WAVE420L_VCE>,
-+ <&syscrg JH7110_SYSRST_WAVE420L_APB>,
-+ <&syscrg JH7110_SYSRST_AXIMEM1_AXI>;
-+ reset-names = "rst_axi", "rst_bpu", "rst_vce",
-+ "rst_apb", "rst_sram";
-+ starfive,venc_noc_ctrl;
-+ power-domains = <&pwrc JH7110_PD_VENC>;
-+ status = "disabled";
-+ };
-+
-+ can0: can@130d0000 {
-+ compatible = "starfive,jh7110-can", "ipms,can";
-+ reg = <0x0 0x130d0000 0x0 0x1000>;
-+ interrupts = <112>;
-+ clocks = <&syscrg JH7110_SYSCLK_CAN0_APB>,
-+ <&syscrg JH7110_SYSCLK_CAN0_CAN>,
-+ <&syscrg JH7110_SYSCLK_CAN0_TIMER>;
-+ clock-names = "apb_clk", "core_clk", "timer_clk";
-+ resets = <&syscrg JH7110_SYSRST_CAN0_APB>,
-+ <&syscrg JH7110_SYSRST_CAN0_CORE>,
-+ <&syscrg JH7110_SYSRST_CAN0_TIMER>;
-+ reset-names = "rst_apb", "rst_core", "rst_timer";
-+ frequency = <40000000>;
-+ starfive,sys-syscon = <&sys_syscon 0x10 0x3 0x8>;
-+ syscon,can_or_canfd = <0>;
-+ status = "disabled";
-+ };
-+
-+ can1: can@130e0000 {
-+ compatible = "starfive,jh7110-can", "ipms,can";
-+ reg = <0x0 0x130e0000 0x0 0x1000>;
-+ interrupts = <113>;
-+ clocks = <&syscrg JH7110_SYSCLK_CAN1_APB>,
-+ <&syscrg JH7110_SYSCLK_CAN1_CAN>,
-+ <&syscrg JH7110_SYSCLK_CAN1_TIMER>;
-+ clock-names = "apb_clk", "core_clk", "timer_clk";
-+ resets = <&syscrg JH7110_SYSRST_CAN1_APB>,
-+ <&syscrg JH7110_SYSRST_CAN1_CORE>,
-+ <&syscrg JH7110_SYSRST_CAN1_TIMER>;
-+ reset-names = "rst_apb", "rst_core", "rst_timer";
-+ frequency = <40000000>;
-+ starfive,sys-syscon = <&sys_syscon 0x88 0x12 0x40000>;
-+ syscon,can_or_canfd = <0>;
-+ status = "disabled";
-+ };
-+
- crypto: crypto@16000000 {
- compatible = "starfive,jh7110-crypto";
- reg = <0x0 0x16000000 0x0 0x4000>;
-@@ -1119,6 +1369,42 @@
- #power-domain-cells = <1>;
- };
-
-+ rtc: rtc@17040000 {
-+ compatible = "starfive,jh7110-rtc";
-+ reg = <0x0 0x17040000 0x0 0x10000>;
-+ interrupts = <10>, <11>, <12>;
-+ interrupt-names = "rtc_ms_pulse", "rtc_sec_pulse", "rtc";
-+ clocks = <&aoncrg JH7110_AONCLK_RTC_APB>,
-+ <&aoncrg JH7110_AONCLK_RTC_CAL>;
-+ clock-names = "pclk", "cal_clk";
-+ resets = <&aoncrg JH7110_AONRST_RTC_32K>,
-+ <&aoncrg JH7110_AONRST_RTC_APB>,
-+ <&aoncrg JH7110_AONRST_RTC_CAL>;
-+ reset-names = "rst_osc", "rst_apb", "rst_cal";
-+ rtc,cal-clock-freq = <1000000>;
-+ };
-+
-+ gpu: gpu@18000000 {
-+ compatible = "img-gpu";
-+ reg = <0x0 0x18000000 0x0 0x100000>,
-+ <0x0 0x130C000 0x0 0x10000>;
-+ clocks = <&syscrg JH7110_SYSCLK_GPU_CORE>,
-+ <&syscrg JH7110_SYSCLK_GPU_APB>,
-+ <&syscrg JH7110_SYSCLK_GPU_RTC_TOGGLE>,
-+ <&syscrg JH7110_SYSCLK_GPU_CORE_CLK>,
-+ <&syscrg JH7110_SYSCLK_GPU_SYS_CLK>,
-+ <&syscrg JH7110_SYSCLK_NOC_BUS_GPU_AXI>;
-+ clock-names = "clk_bv", "clk_apb", "clk_rtc",
-+ "clk_core", "clk_sys", "clk_axi";
-+ resets = <&syscrg JH7110_SYSRST_GPU_APB>,
-+ <&syscrg JH7110_SYSRST_GPU_DOMA>;
-+ reset-names = "rst_apb", "rst_doma";
-+ power-domains = <&pwrc JH7110_PD_GPUA>;
-+ interrupts = <82>;
-+ current-clock = <8000000>;
-+ status = "disabled";
-+ };
-+
- csi2rx: csi-bridge@19800000 {
- compatible = "starfive,jh7110-csi2rx";
- reg = <0x0 0x19800000 0x0 0x10000>;
-@@ -1145,6 +1431,67 @@
- status = "disabled";
- };
-
-+ vin_sysctl: vin_sysctl@19800000 {
-+ compatible = "starfive,jh7110-vin";
-+ reg = <0x0 0x19800000 0x0 0x10000>,
-+ <0x0 0x19810000 0x0 0x10000>,
-+ <0x0 0x19820000 0x0 0x10000>,
-+ <0x0 0x19840000 0x0 0x10000>,
-+ <0x0 0x19870000 0x0 0x30000>,
-+ <0x0 0x11840000 0x0 0x10000>,
-+ <0x0 0x17030000 0x0 0x10000>,
-+ <0x0 0x13020000 0x0 0x10000>;
-+ reg-names = "csi2rx", "vclk", "vrst", "sctrl",
-+ "isp", "trst", "pmu", "syscrg";
-+ clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>,
-+ <&ispcrg JH7110_ISPCLK_VIN_APB>,
-+ <&ispcrg JH7110_ISPCLK_VIN_SYS>,
-+ <&ispcrg JH7110_ISPCLK_ISPV2_TOP_WRAPPER_C>,
-+ <&ispcrg JH7110_ISPCLK_DVP_INV>,
-+ <&ispcrg JH7110_ISPCLK_VIN_P_AXI_WR>,
-+ <&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF0>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF1>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF2>,
-+ <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF3>,
-+ <&ispcrg JH7110_ISPCLK_M31DPHY_CFG_IN>,
-+ <&ispcrg JH7110_ISPCLK_M31DPHY_REF_IN>,
-+ <&ispcrg JH7110_ISPCLK_M31DPHY_TX_ESC_LAN0>,
-+ <&syscrg JH7110_SYSCLK_ISP_TOP_CORE>,
-+ <&syscrg JH7110_SYSCLK_ISP_TOP_AXI>;
-+ clock-names = "clk_apb_func", "clk_pclk", "clk_sys_clk",
-+ "clk_wrapper_clk_c", "clk_dvp_inv", "clk_axiwr",
-+ "clk_mipi_rx0_pxl", "clk_pixel_clk_if0",
-+ "clk_pixel_clk_if1", "clk_pixel_clk_if2",
-+ "clk_pixel_clk_if3", "clk_m31dphy_cfgclk_in",
-+ "clk_m31dphy_refclk_in", "clk_m31dphy_txclkesc_lan0",
-+ "clk_ispcore_2x", "clk_isp_axi";
-+ resets = <&ispcrg JH7110_ISPRST_ISPV2_TOP_WRAPPER_P>,
-+ <&ispcrg JH7110_ISPRST_ISPV2_TOP_WRAPPER_C>,
-+ <&ispcrg JH7110_ISPRST_VIN_APB>,
-+ <&ispcrg JH7110_ISPRST_VIN_SYS>,
-+ <&ispcrg JH7110_ISPRST_VIN_P_AXI_RD>,
-+ <&ispcrg JH7110_ISPRST_VIN_P_AXI_WR>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF0>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF1>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF2>,
-+ <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF3>,
-+ <&ispcrg JH7110_ISPRST_M31DPHY_HW>,
-+ <&ispcrg JH7110_ISPRST_M31DPHY_B09_AON>,
-+ <&syscrg JH7110_SYSRST_ISP_TOP>,
-+ <&syscrg JH7110_SYSRST_ISP_TOP_AXI>;
-+ reset-names = "rst_wrapper_p", "rst_wrapper_c", "rst_pclk",
-+ "rst_sys_clk", "rst_axird", "rst_axiwr", "rst_pixel_clk_if0",
-+ "rst_pixel_clk_if1", "rst_pixel_clk_if2", "rst_pixel_clk_if3",
-+ "rst_m31dphy_hw", "rst_m31dphy_b09_always_on",
-+ "rst_isp_top_n", "rst_isp_top_axi";
-+ starfive,aon-syscon = <&aon_syscon 0x00>;
-+ power-domains = <&pwrc JH7110_PD_ISP>;
-+ /* irq nr: vin, isp, isp_csi, isp_scd, isp_csiline */
-+ interrupts = <92 87 88 89 90>;
-+ status = "disabled";
-+ };
-+
- ispcrg: clock-controller@19810000 {
- compatible = "starfive,jh7110-ispcrg";
- reg = <0x0 0x19810000 0x0 0x10000>;
-@@ -1175,6 +1522,66 @@
- #phy-cells = <0>;
- };
-
-+ dc8200: dc8200@29400000 {
-+ compatible = "starfive,jh7110-dc8200","verisilicon,dc8200";
-+ verisilicon,dss-syscon = <&dssctrl>;//20220624 panel syscon
-+ reg = <0x0 0x29400000 0x0 0x100>,
-+ <0x0 0x29400800 0x0 0x2000>,
-+ <0x0 0x17030000 0x0 0x1000>;
-+ interrupts = <95>;
-+ clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_DISP_AXI>,
-+ <&syscrg JH7110_SYSCLK_VOUT_SRC>,
-+ <&syscrg JH7110_SYSCLK_VOUT_TOP_AXI>,
-+ <&syscrg JH7110_SYSCLK_VOUT_TOP_AHB>,
-+ <&voutcrg JH7110_VOUTCLK_DC8200_PIX0>,
-+ <&voutcrg JH7110_VOUTCLK_DC8200_PIX1>,
-+ <&voutcrg JH7110_VOUTCLK_DC8200_AXI>,
-+ <&voutcrg JH7110_VOUTCLK_DC8200_CORE>,
-+ <&voutcrg JH7110_VOUTCLK_DC8200_AHB>,
-+ <&syscrg JH7110_SYSCLK_VOUT_TOP_AXI>,
-+ <&voutcrg JH7110_VOUTCLK_DOM_VOUT_TOP_LCD>,
-+ <&hdmitx0_pixelclk>,
-+ <&voutcrg JH7110_VOUTCLK_DC8200_PIX>;
-+ clock-names = "noc_disp","vout_src",
-+ "top_vout_axi","top_vout_ahb",
-+ "pix_clk","vout_pix1",
-+ "axi_clk","core_clk","vout_ahb",
-+ "vout_top_axi","vout_top_lcd","hdmitx0_pixelclk","dc8200_pix0";
-+ resets = <&syscrg JH7110_SYSRST_VOUT_TOP_SRC>,
-+ <&voutcrg JH7110_VOUTRST_DC8200_AXI>,
-+ <&voutcrg JH7110_VOUTRST_DC8200_AHB>,
-+ <&voutcrg JH7110_VOUTRST_DC8200_CORE>,
-+ <&syscrg JH7110_SYSRST_NOC_BUS_DISP_AXI>;
-+ reset-names = "rst_vout_src","rst_axi","rst_ahb","rst_core",
-+ "rst_noc_disp";
-+ status = "disabled";
-+ };
-+
-+ hdmi: hdmi@29590000 {
-+ compatible = "starfive,jh7110-hdmi","inno,hdmi";
-+ reg = <0x0 0x29590000 0x0 0x4000>;
-+ interrupts = <99>;
-+ /*interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;*/
-+ /*clocks = <&cru PCLK_HDMI>;*/
-+ /*clock-names = "pclk";*/
-+ /*pinctrl-names = "default";*/
-+ /*pinctrl-0 = <&hdmi_ctl>;*/
-+ clocks = <&voutcrg JH7110_VOUTCLK_HDMI_TX_SYS>,
-+ <&voutcrg JH7110_VOUTCLK_HDMI_TX_MCLK>,
-+ <&voutcrg JH7110_VOUTCLK_HDMI_TX_BCLK>,
-+ <&hdmitx0_pixelclk>;
-+ clock-names = "sysclk", "mclk","bclk","pclk";
-+ resets = <&voutcrg JH7110_VOUTRST_HDMI_TX_HDMI>;
-+ reset-names = "hdmi_tx";
-+ #sound-dai-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ dssctrl: dssctrl@295B0000 {
-+ compatible = "starfive,jh7110-dssctrl","verisilicon,dss-ctrl", "syscon";
-+ reg = <0 0x295B0000 0 0x90>;
-+ };
-+
- voutcrg: clock-controller@295c0000 {
- compatible = "starfive,jh7110-voutcrg";
- reg = <0x0 0x295c0000 0x0 0x10000>;
-@@ -1193,6 +1600,67 @@
- power-domains = <&pwrc JH7110_PD_VOUT>;
- };
-
-+ mipi_dsi: mipi@295d0000 {
-+ compatible = "starfive,jh7110-mipi_dsi","cdns,dsi";
-+ reg = <0x0 0x295d0000 0x0 0x10000>;
-+ interrupts = <98>;
-+ reg-names = "dsi";
-+ clocks = <&voutcrg JH7110_VOUTCLK_DSITX_SYS>,
-+ <&voutcrg JH7110_VOUTCLK_DSITX_APB>,
-+ <&voutcrg JH7110_VOUTCLK_DSITX_TXESC>,
-+ <&voutcrg JH7110_VOUTCLK_DSITX_DPI>;
-+ clock-names = "dpi", "apb", "txesc", "sys";
-+ resets = <&voutcrg JH7110_VOUTRST_DSITX_DPI>,
-+ <&voutcrg JH7110_VOUTRST_DSITX_APB>,
-+ <&voutcrg JH7110_VOUTRST_DSITX_RXESC>,
-+ <&voutcrg JH7110_VOUTRST_DSITX_SYS>,
-+ <&voutcrg JH7110_VOUTRST_DSITX_TXBYTEHS>,
-+ <&voutcrg JH7110_VOUTRST_DSITX_TXESC>;
-+ reset-names = "dsi_dpi", "dsi_apb", "dsi_rxesc",
-+ "dsi_sys", "dsi_txbytehs", "dsi_txesc";
-+ phys = <&mipi_dphy>;
-+ phy-names = "dphy";
-+ status = "disabled";
-+ };
-+
-+ mipi_dphy: mipi-dphy@295e0000{
-+ compatible = "starfive,jh7110-mipi-dphy-tx","m31,mipi-dphy-tx";
-+ reg = <0x0 0x295e0000 0x0 0x10000>;
-+ clocks = <&voutcrg JH7110_VOUTCLK_MIPITX_DPHY_TXESC>;
-+ clock-names = "dphy_txesc";
-+ resets = <&voutcrg JH7110_VOUTRST_MIPITX_DPHY_SYS>,
-+ <&voutcrg JH7110_VOUTRST_MIPITX_DPHY_TXBYTEHS>;
-+ reset-names = "dphy_sys", "dphy_txbytehs";
-+ #phy-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ co_process: e24@6e210000 {
-+ compatible = "starfive,e24";
-+ dma-coherent;
-+ reg = <0x0 0x6e210000 0x0 0x00001000>,
-+ <0x0 0x6e211000 0x0 0x0003f000>;
-+ reg-names = "ecmd", "espace";
-+ clocks = <&stgcrg JH7110_STGCLK_E2_RTC>,
-+ <&stgcrg JH7110_STGCLK_E2_CORE>,
-+ <&stgcrg JH7110_STGCLK_E2_DBG>;
-+ clock-names = "clk_rtc", "clk_core", "clk_dbg";
-+ resets = <&stgcrg JH7110_STGRST_E24_CORE>;
-+ reset-names = "e24_core";
-+ starfive,stg-syscon = <&stg_syscon>;
-+ interrupt-parent = <&plic>;
-+ firmware-name = "e24_elf";
-+ irq-mode = <1>;
-+ mbox-names = "tx", "rx";
-+ mboxes = <&mailbox_contrl0 0 2>,
-+ <&mailbox_contrl0 2 0>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges = <0x6ce00000 0x0 0x6ce00000 0x1600000>;
-+ status = "disabled";
-+ dsp@0 {};
-+ };
-+
- pcie0: pcie@940000000 {
- compatible = "starfive,jh7110-pcie";
- reg = <0x9 0x40000000 0x0 0x1000000>,
+++ /dev/null
-From cae7550054ca0cd940bbc1501ae5611f5d2957e6 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Wed, 20 Sep 2023 14:53:22 +0800
-Subject: [PATCH 057/116] riscv: dts: starfive: Add JH7110 EVB expanded device
- tree
-
-Add JH7110 EVB expanded device tree.
-The code is ported from tag JH7110_SDK_6.1_v5.11.3
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/Makefile | 11 +-
- .../starfive/jh7110-evb-can-pdm-pwmdac.dts | 102 ++++++++++++++++
- .../dts/starfive/jh7110-evb-dvp-rgb2hdmi.dts | 37 ++++++
- .../dts/starfive/jh7110-evb-i2s-ac108.dts | 72 ++++++++++++
- .../dts/starfive/jh7110-evb-pcie-i2s-sd.dts | 111 ++++++++++++++++++
- .../dts/starfive/jh7110-evb-spi-uart2.dts | 65 ++++++++++
- .../starfive/jh7110-evb-uart1-rgb2hdmi.dts | 57 +++++++++
- .../starfive/jh7110-evb-uart4-emmc-spdif.dts | 78 ++++++++++++
- .../starfive/jh7110-evb-uart5-pwm-i2c-tdm.dts | 95 +++++++++++++++
- .../dts/starfive/jh7110-evb-usbdevice.dts | 35 ++++++
- 10 files changed, 662 insertions(+), 1 deletion(-)
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-can-pdm-pwmdac.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-dvp-rgb2hdmi.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-i2s-ac108.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-pcie-i2s-sd.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-spi-uart2.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-uart1-rgb2hdmi.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-uart4-emmc-spdif.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-uart5-pwm-i2c-tdm.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-evb-usbdevice.dts
-
---- a/arch/riscv/boot/dts/starfive/Makefile
-+++ b/arch/riscv/boot/dts/starfive/Makefile
-@@ -12,4 +12,13 @@ dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-st
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb
-
--dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-evb.dtb
-+dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-evb.dtb \
-+ jh7110-evb-pcie-i2s-sd.dtb \
-+ jh7110-evb-spi-uart2.dtb \
-+ jh7110-evb-uart4-emmc-spdif.dtb \
-+ jh7110-evb-uart5-pwm-i2c-tdm.dtb \
-+ jh7110-evb-dvp-rgb2hdmi.dtb \
-+ jh7110-evb-can-pdm-pwmdac.dtb \
-+ jh7110-evb-i2s-ac108.dtb \
-+ jh7110-evb-usbdevice.dtb \
-+ jh7110-evb-uart1-rgb2hdmi.dtb
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-can-pdm-pwmdac.dts
-@@ -0,0 +1,102 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+
-+ sound2: snd-card2 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-PDM-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "i2s";
-+ bitclock-master = <&dailink_master>;
-+ frame-master = <&dailink_master>;
-+
-+ dailink_master:cpu {
-+ sound-dai = <&i2srx_mst>;
-+ };
-+
-+ dailink_slave:codec {
-+ sound-dai = <&pdm>;
-+ };
-+ };
-+ };
-+
-+ pwmdac_codec: pwmdac-codec {
-+ compatible = "linux,spdif-dit";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ sound3: snd-card3 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-PWMDAC-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "left_j";
-+ bitclock-master = <&sndcpu0>;
-+ frame-master = <&sndcpu0>;
-+
-+ sndcpu0: cpu {
-+ sound-dai = <&pwmdac>;
-+ };
-+
-+ codec {
-+ sound-dai = <&pwmdac_codec>;
-+ };
-+ };
-+ };
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&usb0 {
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
-+
-+&can0 {
-+ status = "okay";
-+};
-+
-+&can1 {
-+ status = "okay";
-+};
-+
-+&i2srx_mst {
-+ status = "okay";
-+};
-+
-+&pwmdac {
-+ status = "okay";
-+};
-+
-+&pdm {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-dvp-rgb2hdmi.dts
-@@ -0,0 +1,37 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+};
-+
-+&vin_sysctl {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dvp_pins>;
-+};
-+
-+&rgb_output {
-+ status = "okay";
-+};
-+
-+&tda988x_pin {
-+ status = "okay";
-+};
-+
-+&dsi_output {
-+ status = "disabled";
-+};
-+
-+&mipi_dsi {
-+ status = "disabled";
-+};
-+
-+&mipi_dphy {
-+ status = "disabled";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-i2s-ac108.dts
-@@ -0,0 +1,72 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+
-+ /* i2s + ac108 */
-+ sound0: snd-card0 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-AC108-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "i2s";
-+ bitclock-master = <&sndcodec1>;
-+ frame-master = <&sndcodec1>;
-+
-+ widgets = "Microphone", "Mic Jack",
-+ "Line", "Line In",
-+ "Line", "Line Out",
-+ "Speaker", "Speaker",
-+ "Headphone", "Headphone Jack";
-+ routing = "Headphone Jack", "HP_L",
-+ "Headphone Jack", "HP_R",
-+ "Speaker", "SPK_LP",
-+ "Speaker", "SPK_LN",
-+ "LINPUT1", "Mic Jack",
-+ "LINPUT3", "Mic Jack",
-+ "RINPUT1", "Mic Jack",
-+ "RINPUT2", "Mic Jack";
-+
-+ cpu {
-+ sound-dai = <&i2srx>;
-+ };
-+
-+ sndcodec1: codec {
-+ sound-dai = <&ac108>;
-+ clocks = <&ac108_mclk>;
-+ clock-names = "mclk";
-+ };
-+ };
-+ };
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&i2c0 {
-+ status = "okay";
-+};
-+
-+&i2srx {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-pcie-i2s-sd.dts
-@@ -0,0 +1,111 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+
-+ /* i2s + wm8960 */
-+ sound6: snd-card6 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-WM8960-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ status = "okay";
-+ format = "i2s";
-+ bitclock-master = <&sndcodec1>;
-+ frame-master = <&sndcodec1>;
-+
-+ widgets = "Microphone", "Mic Jack",
-+ "Line", "Line In",
-+ "Line", "Line Out",
-+ "Speaker", "Speaker",
-+ "Headphone", "Headphone Jack";
-+ routing = "Headphone Jack", "HP_L",
-+ "Headphone Jack", "HP_R",
-+ "Speaker", "SPK_LP",
-+ "Speaker", "SPK_LN",
-+ "LINPUT1", "Mic Jack",
-+ "LINPUT3", "Mic Jack",
-+ "RINPUT1", "Mic Jack",
-+ "RINPUT2", "Mic Jack";
-+ cpu0 {
-+ sound-dai = <&i2srx>;
-+ };
-+ cpu1 {
-+ sound-dai = <&i2stx1>;
-+ };
-+
-+ sndcodec1:codec {
-+ sound-dai = <&wm8960>;
-+ clocks = <&wm8960_mclk>;
-+ clock-names = "mclk";
-+ };
-+ };
-+ };
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
-+
-+&pcie0 {
-+ status = "okay";
-+};
-+
-+&uart3 {
-+ status = "okay";
-+};
-+
-+&i2c0 {
-+ status = "okay";
-+};
-+
-+&usb0 {
-+ clocks = <&stgcrg JH7110_STGCLK_USB0_LPM>,
-+ <&stgcrg JH7110_STGCLK_USB0_STB>,
-+ <&stgcrg JH7110_STGCLK_USB0_APB>,
-+ <&stgcrg JH7110_STGCLK_USB0_AXI>,
-+ <&stgcrg JH7110_STGCLK_USB0_UTMI_APB>;
-+ clock-names = "lpm", "stb", "apb", "axi", "utmi_apb";
-+ resets = <&stgcrg JH7110_STGRST_USB0_PWRUP>,
-+ <&stgcrg JH7110_STGRST_USB0_APB>,
-+ <&stgcrg JH7110_STGRST_USB0_AXI>,
-+ <&stgcrg JH7110_STGRST_USB0_UTMI_APB>;
-+ reset-names = "pwrup", "apb", "axi", "utmi_apb";
-+ dr_mode = "host"; /*host or peripheral*/
-+ starfive,usb2-only;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&usb_pins>;
-+ status = "okay";
-+};
-+
-+&i2srx {
-+ status = "okay";
-+};
-+
-+&i2stx1 {
-+ status = "okay";
-+};
-+
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-spi-uart2.dts
-@@ -0,0 +1,65 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&usb0 {
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
-+
-+&uart2 {
-+ status = "okay";
-+};
-+
-+&spi0 {
-+ status = "okay";
-+};
-+
-+&spi1 {
-+ status = "okay";
-+};
-+
-+&spi2 {
-+ status = "okay";
-+};
-+
-+&spi3 {
-+ status = "okay";
-+};
-+
-+&spi4 {
-+ status = "okay";
-+};
-+
-+&spi5 {
-+ status = "okay";
-+};
-+
-+&spi6 {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-uart1-rgb2hdmi.dts
-@@ -0,0 +1,57 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&usb0 {
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
-+
-+&uart1 {
-+ status = "okay";
-+};
-+
-+&rgb_output {
-+ status = "okay";
-+};
-+
-+&tda988x_pin {
-+ status = "okay";
-+};
-+
-+&dsi_output {
-+ status = "disabled";
-+};
-+
-+&mipi_dsi {
-+ status = "disabled";
-+};
-+
-+&mipi_dphy {
-+ status = "disabled";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-uart4-emmc-spdif.dts
-@@ -0,0 +1,78 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+
-+ spdif_transmitter: spdif_transmitter {
-+ compatible = "linux,spdif-dit";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ sound4: snd-card4 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-SPDIF-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "left_j";
-+ bitclock-master = <&sndcpu0>;
-+ frame-master = <&sndcpu0>;
-+
-+ sndcpu0: cpu {
-+ sound-dai = <&spdif>;
-+ };
-+
-+ codec {
-+ sound-dai = <&spdif_transmitter>;
-+ };
-+ };
-+ };
-+};
-+
-+&usb0 {
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
-+
-+&uart4 {
-+ status = "okay";
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&emmc0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <8>;
-+ cap-mmc-highspeed;
-+ mmc-hs200-1_8v;
-+ non-removable;
-+ cap-mmc-hw-reset;
-+ board-is-evb;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&pwm {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm_ch6to7_pins>;
-+ status = "okay";
-+};
-+
-+&spdif {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-uart5-pwm-i2c-tdm.dts
-@@ -0,0 +1,95 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+
-+ sound5: snd-card5 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-TDM-Sound-Card";
-+ simple-audio-card,widgets = "Microphone", "Mic Jack",
-+ "Line", "Line In",
-+ "Line", "Line Out",
-+ "Speaker", "Speaker",
-+ "Headphone", "Headphone Jack";
-+ simple-audio-card,routing = "Headphone Jack", "HP_L",
-+ "Headphone Jack", "HP_R",
-+ "Speaker", "SPK_LP",
-+ "Speaker", "SPK_LN",
-+ "LINPUT1", "Mic Jack",
-+ "LINPUT3", "Mic Jack",
-+ "RINPUT1", "Mic Jack",
-+ "RINPUT2", "Mic Jack";
-+
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "dsp_a";
-+ bitclock-master = <&dailink_master>;
-+ frame-master = <&dailink_master>;
-+
-+ cpu {
-+ sound-dai = <&tdm>;
-+ };
-+ dailink_master: codec {
-+ sound-dai = <&wm8960>;
-+ clocks = <&wm8960_mclk>;
-+ };
-+ };
-+ };
-+};
-+
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&usb0 {
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
-+
-+&uart5 {
-+ status = "okay";
-+};
-+
-+&pwm {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm_ch0to3_pins &pwm_ch4to5_pins>;
-+ status = "okay";
-+};
-+
-+&tdm {
-+ status = "okay";
-+};
-+
-+&i2c0 {
-+ status = "okay";
-+};
-+
-+&i2c1 {
-+ status = "okay";
-+};
-+
-+&i2c3 {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb-usbdevice.dts
-@@ -0,0 +1,35 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-evb.dtsi"
-+
-+/ {
-+ model = "StarFive JH7110 EVB";
-+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
-+};
-+
-+/* default sd card */
-+&mmc0 {
-+ assigned-clocks = <&syscrg JH7110_SYSCLK_SDIO0_SDCARD>;
-+ assigned-clock-rates = <50000000>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdcard0_pins>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ broken-cd;
-+ post-power-on-delay-ms = <200>;
-+ status = "okay";
-+};
-+
-+&usb0 {
-+ dr_mode = "peripheral"; /*host or peripheral*/
-+ status = "okay";
-+};
-+
-+&pcie1 {
-+ status = "okay";
-+};
+++ /dev/null
-From e9122ceaf2d8767753e2a126c14b29b78280446d Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Tue, 19 Sep 2023 21:35:39 +0800
-Subject: [PATCH 058/116] riscv: dts: starfive: Add evb-overlay dtso subdir
-
-Create subdir evb-overlay/ and add overlay .dtso for JH7110 EVB.
-The code is ported from tag JH7110_SDK_6.1_v5.11.3
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/Makefile | 1 +
- .../boot/dts/starfive/evb-overlay/Makefile | 7 +
- .../evb-overlay/jh7110-evb-overlay-can.dtso | 24 ++++
- .../jh7110-evb-overlay-rgb2hdmi.dtso | 24 ++++
- .../evb-overlay/jh7110-evb-overlay-sdio.dtso | 78 +++++++++++
- .../evb-overlay/jh7110-evb-overlay-spi.dtso | 72 ++++++++++
- .../jh7110-evb-overlay-uart4-emmc.dtso | 130 ++++++++++++++++++
- .../jh7110-evb-overlay-uart5-pwm.dtso | 92 +++++++++++++
- 8 files changed, 428 insertions(+)
- create mode 100644 arch/riscv/boot/dts/starfive/evb-overlay/Makefile
- create mode 100644 arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-can.dtso
- create mode 100644 arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-rgb2hdmi.dtso
- create mode 100644 arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-sdio.dtso
- create mode 100644 arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-spi.dtso
- create mode 100644 arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-uart4-emmc.dtso
- create mode 100644 arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-uart5-pwm.dtso
-
---- a/arch/riscv/boot/dts/starfive/Makefile
-+++ b/arch/riscv/boot/dts/starfive/Makefile
-@@ -12,6 +12,7 @@ dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-st
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb
-
-+subdir-y += evb-overlay
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-evb.dtb \
- jh7110-evb-pcie-i2s-sd.dtb \
- jh7110-evb-spi-uart2.dtb \
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/Makefile
-@@ -0,0 +1,7 @@
-+# SPDX-License-Identifier: GPL-2.0
-+dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-evb-overlay-can.dtbo \
-+ jh7110-evb-overlay-sdio.dtbo \
-+ jh7110-evb-overlay-spi.dtbo \
-+ jh7110-evb-overlay-uart4-emmc.dtbo \
-+ jh7110-evb-overlay-uart5-pwm.dtbo \
-+ jh7110-evb-overlay-rgb2hdmi.dtbo
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-can.dtso
-@@ -0,0 +1,24 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //can0
-+ fragment@0 {
-+ target-path = "/soc/can@130d0000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //can1
-+ fragment@1 {
-+ target-path = "/soc/can@130e0000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+};
-+
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-rgb2hdmi.dtso
-@@ -0,0 +1,24 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //hdmi_output
-+ fragment@0 {
-+ target-path = "/tda988x_pin";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //uart1
-+ fragment@1 {
-+ target-path = "/soc/serial@10010000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+};
-+
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-sdio.dtso
-@@ -0,0 +1,78 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //sysgpio
-+ fragment@0 {
-+ target-path = "/soc/pinctrl@13040000";
-+ __overlay__ {
-+ dt_sdcard1_pins: dt-sdcard1-0 {
-+ sdcard-pins {
-+ pinmux = <GPIOMUX(56, GPOUT_SYS_SDIO1_CLK,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(50, GPOUT_SYS_SDIO1_CMD,
-+ GPOEN_SYS_SDIO1_CMD,
-+ GPI_SYS_SDIO1_CMD)>,
-+ <GPIOMUX(49, GPOUT_SYS_SDIO1_DATA0,
-+ GPOEN_SYS_SDIO1_DATA0,
-+ GPI_SYS_SDIO1_DATA0)>,
-+ <GPIOMUX(45, GPOUT_SYS_SDIO1_DATA1,
-+ GPOEN_SYS_SDIO1_DATA1,
-+ GPI_SYS_SDIO1_DATA1)>,
-+ <GPIOMUX(62, GPOUT_SYS_SDIO1_DATA2,
-+ GPOEN_SYS_SDIO1_DATA2,
-+ GPI_SYS_SDIO1_DATA2)>,
-+ <GPIOMUX(40, GPOUT_SYS_SDIO1_DATA3,
-+ GPOEN_SYS_SDIO1_DATA3,
-+ GPI_SYS_SDIO1_DATA3)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+ };
-+ };
-+ };
-+
-+ //uart3
-+ fragment@1 {
-+ target-path = "/soc/serial@12000000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //i2c0
-+ fragment@2 {
-+ target-path = "/soc/i2c@10030000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //mmc1
-+ fragment@3 {
-+ target-path = "/soc/mmc@16020000";
-+ __overlay__ {
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <4>;
-+ no-sdio;
-+ no-mmc;
-+ broken-cd;
-+ sd-uhs-sdr12;
-+ sd-uhs-sdr25;
-+ sd-uhs-sdr50;
-+ sd-uhs-sdr104;
-+ sd-uhs-ddr50;
-+ cap-sd-highspeed;
-+ post-power-on-delay-ms = <200>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dt_sdcard1_pins>;
-+ status = "okay";
-+ };
-+ };
-+};
-+
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-spi.dtso
-@@ -0,0 +1,72 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //spi0
-+ fragment@0 {
-+ target-path = "/soc/spi@10060000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //spi1
-+ fragment@1 {
-+ target-path = "/soc/spi@10070000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //spi2
-+ fragment@2 {
-+ target-path = "/soc/spi@10080000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //spi3
-+ fragment@3 {
-+ target-path = "/soc/spi@12070000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //spi4
-+ fragment@4 {
-+ target-path = "/soc/spi@12080000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //spi5
-+ fragment@5 {
-+ target-path = "/soc/spi@12090000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //spi6
-+ fragment@6 {
-+ target-path = "/soc/spi@120a0000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //uart2
-+ fragment@7 {
-+ target-path = "/soc/serial@10020000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+};
-+
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-uart4-emmc.dtso
-@@ -0,0 +1,130 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //sysgpio
-+ fragment@0 {
-+ target-path = "/soc/pinctrl@13040000";
-+ __overlay__ {
-+ dt_emmc0_pins: dt-emmc0-0 {
-+ emmc-pins {
-+ pinmux = <GPIOMUX(22, GPOUT_SYS_SDIO0_RST,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <PINMUX(64, 0)>,
-+ <PINMUX(65, 0)>,
-+ <PINMUX(66, 0)>,
-+ <PINMUX(67, 0)>,
-+ <PINMUX(68, 0)>,
-+ <PINMUX(69, 0)>,
-+ <PINMUX(70, 0)>,
-+ <PINMUX(71, 0)>,
-+ <PINMUX(72, 0)>,
-+ <PINMUX(73, 0)>;
-+ bias-pull-up;
-+ drive-strength = <12>;
-+ input-enable;
-+ slew-rate = <1>;
-+ };
-+ };
-+
-+ dt_emmc1_pins: dt-emmc1-0 {
-+ emmc-pins {
-+ pinmux = <GPIOMUX(51, GPOUT_SYS_SDIO1_RST,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(38, GPOUT_SYS_SDIO1_CLK,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>,
-+ <GPIOMUX(36, GPOUT_SYS_SDIO1_CMD,
-+ GPOEN_SYS_SDIO1_CMD,
-+ GPI_SYS_SDIO1_CMD)>,
-+ <GPIOMUX(43, GPOUT_SYS_SDIO1_DATA0,
-+ GPOEN_SYS_SDIO1_DATA0,
-+ GPI_SYS_SDIO1_DATA0)>,
-+ <GPIOMUX(48, GPOUT_SYS_SDIO1_DATA1,
-+ GPOEN_SYS_SDIO1_DATA1,
-+ GPI_SYS_SDIO1_DATA1)>,
-+ <GPIOMUX(53, GPOUT_SYS_SDIO1_DATA2,
-+ GPOEN_SYS_SDIO1_DATA2,
-+ GPI_SYS_SDIO1_DATA2)>,
-+ <GPIOMUX(63, GPOUT_SYS_SDIO1_DATA3,
-+ GPOEN_SYS_SDIO1_DATA3,
-+ GPI_SYS_SDIO1_DATA3)>,
-+ <GPIOMUX(52, GPOUT_SYS_SDIO1_DATA4,
-+ GPOEN_SYS_SDIO1_DATA4,
-+ GPI_SYS_SDIO1_DATA4)>,
-+ <GPIOMUX(39, GPOUT_SYS_SDIO1_DATA5,
-+ GPOEN_SYS_SDIO1_DATA5,
-+ GPI_SYS_SDIO1_DATA5)>,
-+ <GPIOMUX(46, GPOUT_SYS_SDIO1_DATA6,
-+ GPOEN_SYS_SDIO1_DATA6,
-+ GPI_SYS_SDIO1_DATA6)>,
-+ <GPIOMUX(47, GPOUT_SYS_SDIO1_DATA7,
-+ GPOEN_SYS_SDIO1_DATA7,
-+ GPI_SYS_SDIO1_DATA7)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+ };
-+ };
-+ };
-+
-+ //aongpio
-+ fragment@1 {
-+ target-path = "/soc/pinctrl@17020000";
-+ __overlay__ {
-+ dt_pwm_ch6to7_pins: dt-pwm-ch6to7-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(1, GPOUT_AON_PTC0_PWM6, /* PAD_RGPIO0 */
-+ GPOEN_AON_PTC0_OE_N_6,
-+ GPI_NONE)>,
-+ <GPIOMUX(2, GPOUT_AON_PTC0_PWM7, /* PAD_RGPIO1 */
-+ GPOEN_AON_PTC0_OE_N_7,
-+ GPI_NONE)>;
-+ drive-strength = <12>;
-+ };
-+ };
-+ };
-+ };
-+
-+ //uart4
-+ fragment@2 {
-+ target-path = "/soc/serial@12010000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //mmc1
-+ fragment@3 {
-+ target-path = "/soc/mmc@16020000";
-+ __overlay__ {
-+ clock-frequency = <102400000>;
-+ max-frequency = <100000000>;
-+ card-detect-delay = <300>;
-+ bus-width = <8>;
-+ cap-mmc-hw-reset;
-+ non-removable;
-+ cap-mmc-highspeed;
-+ post-power-on-delay-ms = <200>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dt_emmc1_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ //ptc
-+ fragment@4 {
-+ target-path = "/soc/pwm@120d0000";
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dt_pwm_ch6to7_pins>;
-+ status = "okay";
-+ };
-+ };
-+};
-+
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-uart5-pwm.dtso
-@@ -0,0 +1,92 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //sysgpio
-+ fragment@0 {
-+ target-path = "/soc/pinctrl@13040000";
-+ __overlay__ {
-+ dt_pwm_ch0to3_pins: dt-pwm-ch0to3-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(45, GPOUT_SYS_PWM_CHANNEL0,
-+ GPOEN_SYS_PWM0_CHANNEL0,
-+ GPI_NONE)>,
-+ <GPIOMUX(46, GPOUT_SYS_PWM_CHANNEL1,
-+ GPOEN_SYS_PWM0_CHANNEL1,
-+ GPI_NONE)>,
-+ <GPIOMUX(47, GPOUT_SYS_PWM_CHANNEL2,
-+ GPOEN_SYS_PWM0_CHANNEL2,
-+ GPI_NONE)>,
-+ <GPIOMUX(48, GPOUT_SYS_PWM_CHANNEL3,
-+ GPOEN_SYS_PWM0_CHANNEL3,
-+ GPI_NONE)>;
-+ drive-strength = <12>;
-+ };
-+ };
-+ };
-+ };
-+
-+ //aongpio
-+ fragment@1 {
-+ target-path = "/soc/pinctrl@17020000";
-+ __overlay__ {
-+ dt_pwm_ch4to5_pins: dt-pwm-ch4to5-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(1, GPOUT_AON_PTC0_PWM4, /* PAD_RGPIO0 */
-+ GPOEN_AON_PTC0_OE_N_4,
-+ GPI_NONE)>,
-+ <GPIOMUX(2, GPOUT_AON_PTC0_PWM5, /* PAD_RGPIO1 */
-+ GPOEN_AON_PTC0_OE_N_5,
-+ GPI_NONE)>;
-+ drive-strength = <12>;
-+ };
-+ };
-+ };
-+ };
-+
-+ //uart5
-+ fragment@2 {
-+ target-path = "/soc/serial@12020000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //ptc
-+ fragment@3 {
-+ target-path = "/soc/pwm@120d0000";
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dt_pwm_ch0to3_pins &dt_pwm_ch4to5_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ //i2c0
-+ fragment@4 {
-+ target-path = "/soc/i2c@10030000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //i2c1
-+ fragment@5 {
-+ target-path = "/soc/i2c@10040000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //i2c3
-+ fragment@6 {
-+ target-path = "/soc/i2c@12030000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+};
-+
+++ /dev/null
-From 5c888fa081caf5d9473e733931d1c7b3d4b61e61 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Fri, 28 Jul 2023 18:42:55 +0800
-Subject: [PATCH 059/116] riscv: configs: Add starfive_jh7110_defconfig
-
-Add starfive_jh7110_defconfig for JH7110 EVB.
-The code is ported from tag JH7110_SDK_6.1_v5.11.3
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/configs/starfive_jh7110_defconfig | 368 +++++++++++++++++++
- 1 file changed, 368 insertions(+)
- create mode 100644 arch/riscv/configs/starfive_jh7110_defconfig
-
---- /dev/null
-+++ b/arch/riscv/configs/starfive_jh7110_defconfig
-@@ -0,0 +1,368 @@
-+CONFIG_COMPILE_TEST=y
-+# CONFIG_WERROR is not set
-+CONFIG_DEFAULT_HOSTNAME="StarFive"
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_USELIB=y
-+CONFIG_NO_HZ_IDLE=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_BPF_SYSCALL=y
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_CGROUPS=y
-+CONFIG_MEMCG=y
-+CONFIG_CGROUP_SCHED=y
-+CONFIG_CFS_BANDWIDTH=y
-+CONFIG_RT_GROUP_SCHED=y
-+CONFIG_CGROUP_PIDS=y
-+CONFIG_CGROUP_FREEZER=y
-+CONFIG_CGROUP_HUGETLB=y
-+CONFIG_CPUSETS=y
-+CONFIG_CGROUP_DEVICE=y
-+CONFIG_CGROUP_CPUACCT=y
-+CONFIG_CGROUP_PERF=y
-+CONFIG_CGROUP_BPF=y
-+CONFIG_NAMESPACES=y
-+CONFIG_USER_NS=y
-+CONFIG_CHECKPOINT_RESTORE=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_EXPERT=y
-+# CONFIG_SYSFS_SYSCALL is not set
-+CONFIG_PROFILING=y
-+CONFIG_SOC_MICROCHIP_POLARFIRE=y
-+CONFIG_SOC_STARFIVE=y
-+CONFIG_SOC_VIRT=y
-+CONFIG_ERRATA_SIFIVE=y
-+CONFIG_NONPORTABLE=y
-+CONFIG_SMP=y
-+CONFIG_RISCV_SBI_V01=y
-+# CONFIG_RISCV_BOOT_SPINWAIT is not set
-+CONFIG_HIBERNATION=y
-+CONFIG_PM_STD_PARTITION="PARTLABEL=hibernation"
-+CONFIG_PM_DEBUG=y
-+CONFIG_PM_ADVANCED_DEBUG=y
-+CONFIG_PM_TEST_SUSPEND=y
-+CONFIG_ENERGY_MODEL=y
-+CONFIG_CPU_IDLE=y
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_STAT=y
-+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
-+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
-+CONFIG_CPUFREQ_DT=y
-+CONFIG_VIRTUALIZATION=y
-+CONFIG_KVM=m
-+CONFIG_JUMP_LABEL=y
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_BINFMT_MISC=y
-+CONFIG_CMA=y
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_XFRM_USER=m
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_ADVANCED_ROUTER=y
-+CONFIG_IP_MULTIPLE_TABLES=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_BOOTP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_INET_ESP=m
-+CONFIG_NETFILTER=y
-+CONFIG_BRIDGE_NETFILTER=m
-+CONFIG_NF_CONNTRACK=m
-+CONFIG_NF_CONNTRACK_FTP=m
-+CONFIG_NF_CONNTRACK_TFTP=m
-+CONFIG_NETFILTER_XT_MARK=m
-+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
-+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-+CONFIG_NETFILTER_XT_MATCH_IPVS=m
-+CONFIG_IP_VS=m
-+CONFIG_IP_VS_PROTO_TCP=y
-+CONFIG_IP_VS_PROTO_UDP=y
-+CONFIG_IP_VS_RR=m
-+CONFIG_IP_VS_NFCT=y
-+CONFIG_NF_LOG_ARP=m
-+CONFIG_NF_LOG_IPV4=m
-+CONFIG_IP_NF_IPTABLES=m
-+CONFIG_IP_NF_FILTER=m
-+CONFIG_IP_NF_TARGET_REJECT=m
-+CONFIG_IP_NF_NAT=m
-+CONFIG_IP_NF_TARGET_MASQUERADE=m
-+CONFIG_IP_NF_TARGET_REDIRECT=m
-+CONFIG_IP_NF_MANGLE=m
-+CONFIG_NF_LOG_IPV6=m
-+CONFIG_IP6_NF_IPTABLES=m
-+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-+CONFIG_IP6_NF_FILTER=m
-+CONFIG_IP6_NF_TARGET_REJECT=m
-+CONFIG_IP6_NF_MANGLE=m
-+CONFIG_BRIDGE=m
-+CONFIG_BRIDGE_VLAN_FILTERING=y
-+CONFIG_VLAN_8021Q=m
-+CONFIG_NET_SCHED=y
-+CONFIG_NET_CLS_CGROUP=m
-+CONFIG_NETLINK_DIAG=y
-+CONFIG_CGROUP_NET_PRIO=y
-+CONFIG_CAN=y
-+CONFIG_BT=y
-+CONFIG_BT_RFCOMM=y
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=y
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HCIUART=y
-+CONFIG_BT_HCIUART_H4=y
-+CONFIG_CFG80211=y
-+CONFIG_MAC80211=y
-+CONFIG_RFKILL=y
-+CONFIG_NET_9P=y
-+CONFIG_NET_9P_VIRTIO=y
-+CONFIG_PCI=y
-+CONFIG_PCIEPORTBUS=y
-+# CONFIG_PCIEASPM is not set
-+CONFIG_PCI_HOST_GENERIC=y
-+CONFIG_PCIE_FU740=y
-+CONFIG_PCIE_STARFIVE_HOST=y
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_MTD=y
-+CONFIG_MTD_BLOCK=y
-+CONFIG_MTD_SPI_NOR=y
-+CONFIG_OF_CONFIGFS=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_VIRTIO_BLK=y
-+CONFIG_BLK_DEV_NVME=y
-+CONFIG_BLK_DEV_SD=y
-+CONFIG_BLK_DEV_SR=y
-+CONFIG_SCSI_VIRTIO=y
-+CONFIG_ATA=y
-+CONFIG_SATA_AHCI=y
-+CONFIG_SATA_AHCI_PLATFORM=y
-+CONFIG_MD=y
-+CONFIG_BLK_DEV_DM=m
-+CONFIG_DM_THIN_PROVISIONING=m
-+CONFIG_NETDEVICES=y
-+CONFIG_DUMMY=m
-+CONFIG_MACVLAN=m
-+CONFIG_IPVLAN=m
-+CONFIG_VXLAN=m
-+CONFIG_VETH=m
-+CONFIG_VIRTIO_NET=y
-+CONFIG_MACB=y
-+CONFIG_E1000E=y
-+CONFIG_R8169=y
-+CONFIG_STMMAC_ETH=y
-+CONFIG_DWMAC_DWC_QOS_ETH=y
-+# CONFIG_DWMAC_GENERIC is not set
-+CONFIG_DWMAC_STARFIVE=y
-+CONFIG_MARVELL_PHY=y
-+CONFIG_MICREL_PHY=y
-+CONFIG_MICROCHIP_PHY=y
-+CONFIG_MICROSEMI_PHY=y
-+CONFIG_MOTORCOMM_PHY=y
-+CONFIG_IPMS_CAN=y
-+CONFIG_IWLWIFI=y
-+CONFIG_IWLDVM=y
-+CONFIG_IWLMVM=y
-+CONFIG_INPUT_MOUSEDEV=y
-+CONFIG_INPUT_EVDEV=y
-+CONFIG_INPUT_TOUCHSCREEN=y
-+CONFIG_TOUCHSCREEN_TINKER_FT5406=y
-+CONFIG_SERIAL_8250=y
-+CONFIG_SERIAL_8250_CONSOLE=y
-+CONFIG_SERIAL_8250_NR_UARTS=6
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=6
-+CONFIG_SERIAL_8250_EXTENDED=y
-+CONFIG_SERIAL_8250_MANY_PORTS=y
-+CONFIG_SERIAL_8250_DW=y
-+CONFIG_SERIAL_OF_PLATFORM=y
-+CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
-+CONFIG_TTY_PRINTK=y
-+CONFIG_VIRTIO_CONSOLE=y
-+CONFIG_HW_RANDOM=y
-+CONFIG_HW_RANDOM_VIRTIO=y
-+CONFIG_HW_RANDOM_JH7110=y
-+CONFIG_I2C_CHARDEV=y
-+CONFIG_I2C_DESIGNWARE_PLATFORM=y
-+CONFIG_SPI=y
-+CONFIG_SPI_CADENCE_QUADSPI=y
-+CONFIG_SPI_PL022=y
-+CONFIG_SPI_SIFIVE=y
-+CONFIG_SPI_SPIDEV=y
-+# CONFIG_PTP_1588_CLOCK is not set
-+CONFIG_GPIO_SYSFS=y
-+CONFIG_GPIO_SIFIVE=y
-+CONFIG_SENSORS_SFCTEMP=y
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_WRITABLE_TRIPS=y
-+CONFIG_CPU_THERMAL=y
-+CONFIG_THERMAL_EMULATION=y
-+CONFIG_WATCHDOG=y
-+CONFIG_WATCHDOG_SYSFS=y
-+CONFIG_MFD_AXP20X_I2C=y
-+CONFIG_REGULATOR=y
-+CONFIG_REGULATOR_AXP20X=y
-+CONFIG_REGULATOR_STARFIVE_JH7110=y
-+# CONFIG_MEDIA_CEC_SUPPORT is not set
-+CONFIG_MEDIA_SUPPORT=y
-+CONFIG_MEDIA_USB_SUPPORT=y
-+CONFIG_USB_VIDEO_CLASS=y
-+CONFIG_V4L_PLATFORM_DRIVERS=y
-+CONFIG_V4L_MEM2MEM_DRIVERS=y
-+CONFIG_VIDEO_WAVE_VPU=m
-+CONFIG_VIN_SENSOR_SC2235=y
-+CONFIG_VIN_SENSOR_OV4689=y
-+CONFIG_VIN_SENSOR_IMX219=y
-+CONFIG_VIDEO_STF_VIN=y
-+CONFIG_VIDEO_IMX708=y
-+CONFIG_DRM_I2C_NXP_TDA998X=y
-+CONFIG_DRM_I2C_NXP_TDA9950=y
-+CONFIG_DRM_RADEON=m
-+CONFIG_DRM_VIRTIO_GPU=m
-+CONFIG_DRM_VERISILICON=y
-+CONFIG_STARFIVE_INNO_HDMI=y
-+CONFIG_STARFIVE_DSI=y
-+CONFIG_DRM_IMG_ROGUE=y
-+CONFIG_DRM_LEGACY=y
-+CONFIG_FB=y
-+CONFIG_SOUND=y
-+CONFIG_SND=y
-+CONFIG_SND_USB_AUDIO=y
-+CONFIG_SND_SOC=y
-+CONFIG_SND_DESIGNWARE_I2S=y
-+# CONFIG_SND_SOC_INTEL_SST_TOPLEVEL is not set
-+CONFIG_SND_SOC_STARFIVE=y
-+CONFIG_SND_SOC_JH7110_PDM=y
-+CONFIG_SND_SOC_JH7110_PWMDAC=y
-+CONFIG_SND_SOC_JH7110_SPDIF=y
-+CONFIG_SND_SOC_JH7110_TDM=y
-+CONFIG_SND_SOC_AC108=y
-+CONFIG_SND_SOC_WM8960=y
-+CONFIG_SND_SIMPLE_CARD=y
-+CONFIG_USB=y
-+CONFIG_USB_XHCI_HCD=y
-+CONFIG_USB_EHCI_HCD=y
-+CONFIG_USB_EHCI_HCD_PLATFORM=y
-+CONFIG_USB_OHCI_HCD=y
-+CONFIG_USB_OHCI_HCD_PLATFORM=y
-+CONFIG_USB_STORAGE=y
-+CONFIG_USB_UAS=y
-+CONFIG_USB_CDNS_SUPPORT=y
-+CONFIG_USB_CDNS3=y
-+CONFIG_USB_CDNS3_GADGET=y
-+CONFIG_USB_CDNS3_HOST=y
-+CONFIG_USB_CDNS3_STARFIVE=y
-+CONFIG_USB_GADGET=y
-+CONFIG_USB_CONFIGFS=y
-+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
-+CONFIG_USB_CONFIGFS_F_FS=y
-+CONFIG_MMC=y
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SDHCI_CADENCE=y
-+CONFIG_MMC_SPI=y
-+CONFIG_MMC_DW=y
-+CONFIG_MMC_DW_STARFIVE=y
-+CONFIG_RTC_CLASS=y
-+# CONFIG_RTC_DRV_SPEAR is not set
-+CONFIG_RTC_DRV_STARFIVE=y
-+CONFIG_DMADEVICES=y
-+CONFIG_AMBA_PL08X=y
-+CONFIG_DW_AXI_DMAC=y
-+# CONFIG_SH_DMAE_BASE is not set
-+# CONFIG_TI_EDMA is not set
-+# CONFIG_DMA_OMAP is not set
-+CONFIG_DMATEST=y
-+CONFIG_VIRTIO_PCI=y
-+CONFIG_VIRTIO_BALLOON=y
-+CONFIG_VIRTIO_INPUT=y
-+CONFIG_VIRTIO_MMIO=y
-+CONFIG_STAGING=y
-+CONFIG_STAGING_MEDIA=y
-+CONFIG_CLK_STARFIVE_JH7110_AON=y
-+CONFIG_CLK_STARFIVE_JH7110_STG=y
-+CONFIG_CLK_STARFIVE_JH7110_ISP=y
-+CONFIG_CLK_STARFIVE_JH7110_VOUT=y
-+CONFIG_MAILBOX=y
-+CONFIG_STARFIVE_MBOX=m
-+CONFIG_STARFIVE_MBOX_TEST=m
-+CONFIG_RPMSG_CHAR=y
-+CONFIG_RPMSG_CTRL=y
-+CONFIG_RPMSG_VIRTIO=y
-+CONFIG_SIFIVE_CCACHE=y
-+CONFIG_PWM=y
-+CONFIG_PWM_OCORES=y
-+CONFIG_PHY_STARFIVE_JH7110_PCIE=y
-+CONFIG_PHY_STARFIVE_JH7110_USB=y
-+CONFIG_PHY_M31_DPHY_RX0=y
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_EXT4_FS_SECURITY=y
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_AUTOFS_FS=y
-+CONFIG_FUSE_FS=y
-+CONFIG_OVERLAY_FS=y
-+CONFIG_OVERLAY_FS_INDEX=y
-+CONFIG_OVERLAY_FS_XINO_AUTO=y
-+CONFIG_OVERLAY_FS_METACOPY=y
-+CONFIG_ISO9660_FS=y
-+CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_EXFAT_FS=y
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_HUGETLBFS=y
-+CONFIG_JFFS2_FS=y
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V4=y
-+CONFIG_NFS_V4_1=y
-+CONFIG_NFS_V4_2=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_9P_FS=y
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_SECURITY=y
-+CONFIG_SECURITY_SELINUX=y
-+CONFIG_SECURITY_APPARMOR=y
-+CONFIG_DEFAULT_SECURITY_DAC=y
-+CONFIG_LSM=""
-+CONFIG_INIT_STACK_NONE=y
-+CONFIG_CRYPTO_USER=y
-+CONFIG_CRYPTO_ZSTD=y
-+CONFIG_CRYPTO_USER_API_HASH=y
-+CONFIG_CRYPTO_USER_API_SKCIPHER=y
-+CONFIG_CRYPTO_USER_API_AEAD=y
-+CONFIG_CRYPTO_STATS=y
-+CONFIG_CRYPTO_DEV_VIRTIO=y
-+CONFIG_CRYPTO_DEV_JH7110=y
-+CONFIG_DMA_CMA=y
-+CONFIG_PRINTK_TIME=y
-+CONFIG_DEBUG_FS=y
-+CONFIG_DEBUG_PAGEALLOC=y
-+CONFIG_SCHED_STACK_END_CHECK=y
-+CONFIG_DEBUG_VM=y
-+CONFIG_DEBUG_VM_PGFLAGS=y
-+CONFIG_DEBUG_MEMORY_INIT=y
-+CONFIG_DEBUG_PER_CPU_MAPS=y
-+CONFIG_SOFTLOCKUP_DETECTOR=y
-+CONFIG_WQ_WATCHDOG=y
-+CONFIG_DEBUG_TIMEKEEPING=y
-+CONFIG_DEBUG_RT_MUTEXES=y
-+CONFIG_DEBUG_SPINLOCK=y
-+CONFIG_DEBUG_MUTEXES=y
-+CONFIG_DEBUG_RWSEMS=y
-+CONFIG_DEBUG_LIST=y
-+CONFIG_DEBUG_PLIST=y
-+CONFIG_DEBUG_SG=y
-+CONFIG_RCU_CPU_STALL_TIMEOUT=60
-+# CONFIG_RCU_TRACE is not set
-+CONFIG_RCU_EQS_DEBUG=y
-+# CONFIG_FTRACE is not set
-+# CONFIG_RUNTIME_TESTING_MENU is not set
-+CONFIG_MEMTEST=y
+++ /dev/null
-From 95c702022f5e4cb786719fcf90170334b1e562cc Mon Sep 17 00:00:00 2001
-From: Jianlong Huang <jianlong.huang@starfivetech.com>
-Date: Thu, 16 Jun 2022 17:13:57 +0800
-Subject: [PATCH 060/116] of: configfs: Add configfs function
-
-Signed-off-by: Jianlong Huang <jianlong.huang@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/of/Kconfig | 7 ++
- drivers/of/Makefile | 1 +
- drivers/of/configfs.c | 277 ++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 285 insertions(+)
- create mode 100644 drivers/of/configfs.c
-
---- a/drivers/of/Kconfig
-+++ b/drivers/of/Kconfig
-@@ -102,4 +102,11 @@ config OF_OVERLAY
- config OF_NUMA
- bool
-
-+config OF_CONFIGFS
-+ bool "Device Tree Overlay ConfigFS interface"
-+ select CONFIGFS_FS
-+ select OF_OVERLAY
-+ help
-+ Enable a simple user-space driven DT overlay interface.
-+
- endif # OF
---- a/drivers/of/Makefile
-+++ b/drivers/of/Makefile
-@@ -11,6 +11,7 @@ obj-$(CONFIG_OF_UNITTEST) += unittest.o
- obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
- obj-$(CONFIG_OF_RESOLVE) += resolver.o
- obj-$(CONFIG_OF_OVERLAY) += overlay.o
-+obj-$(CONFIG_OF_CONFIGFS) += configfs.o
- obj-$(CONFIG_OF_NUMA) += of_numa.o
-
- ifdef CONFIG_KEXEC_FILE
---- /dev/null
-+++ b/drivers/of/configfs.c
-@@ -0,0 +1,277 @@
-+/*
-+ * Configfs entries for device-tree
-+ *
-+ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version
-+ * 2 of the License, or (at your option) any later version.
-+ */
-+#include <linux/ctype.h>
-+#include <linux/cpu.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_fdt.h>
-+#include <linux/spinlock.h>
-+#include <linux/slab.h>
-+#include <linux/proc_fs.h>
-+#include <linux/configfs.h>
-+#include <linux/types.h>
-+#include <linux/stat.h>
-+#include <linux/limits.h>
-+#include <linux/file.h>
-+#include <linux/vmalloc.h>
-+#include <linux/firmware.h>
-+#include <linux/sizes.h>
-+
-+#include "of_private.h"
-+
-+struct cfs_overlay_item {
-+ struct config_item item;
-+
-+ char path[PATH_MAX];
-+
-+ const struct firmware *fw;
-+ struct device_node *overlay;
-+ int ov_id;
-+
-+ void *dtbo;
-+ int dtbo_size;
-+};
-+
-+static inline struct cfs_overlay_item *to_cfs_overlay_item(
-+ struct config_item *item)
-+{
-+ return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
-+}
-+
-+static ssize_t cfs_overlay_item_path_show(struct config_item *item,
-+ char *page)
-+{
-+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
-+ return sprintf(page, "%s\n", overlay->path);
-+}
-+
-+static ssize_t cfs_overlay_item_path_store(struct config_item *item,
-+ const char *page, size_t count)
-+{
-+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
-+ const char *p = page;
-+ char *s;
-+ int err;
-+
-+ /* if it's set do not allow changes */
-+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
-+ return -EPERM;
-+
-+ /* copy to path buffer (and make sure it's always zero terminated */
-+ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
-+ overlay->path[sizeof(overlay->path) - 1] = '\0';
-+
-+ /* strip trailing newlines */
-+ s = overlay->path + strlen(overlay->path);
-+ while (s > overlay->path && *--s == '\n')
-+ *s = '\0';
-+
-+ pr_debug("%s: path is '%s'\n", __func__, overlay->path);
-+
-+ err = request_firmware(&overlay->fw, overlay->path, NULL);
-+ if (err != 0)
-+ return err;
-+
-+ err = of_overlay_fdt_apply((void *)overlay->fw->data,
-+ (u32)overlay->fw->size, &overlay->ov_id, NULL);
-+ if (err != 0)
-+ goto out_err;
-+
-+ return count;
-+
-+out_err:
-+
-+ release_firmware(overlay->fw);
-+ overlay->fw = NULL;
-+
-+ overlay->path[0] = '\0';
-+ return err;
-+}
-+
-+static ssize_t cfs_overlay_item_status_show(struct config_item *item,
-+ char *page)
-+{
-+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
-+
-+ return sprintf(page, "%s\n",
-+ overlay->ov_id > 0 ? "applied" : "unapplied");
-+}
-+
-+CONFIGFS_ATTR(cfs_overlay_item_, path);
-+CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
-+
-+static struct configfs_attribute *cfs_overlay_attrs[] = {
-+ &cfs_overlay_item_attr_path,
-+ &cfs_overlay_item_attr_status,
-+ NULL,
-+};
-+
-+ssize_t cfs_overlay_item_dtbo_read(struct config_item *item,
-+ void *buf, size_t max_count)
-+{
-+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
-+
-+ pr_debug("%s: buf=%p max_count=%zu\n", __func__,
-+ buf, max_count);
-+
-+ if (overlay->dtbo == NULL)
-+ return 0;
-+
-+ /* copy if buffer provided */
-+ if (buf != NULL) {
-+ /* the buffer must be large enough */
-+ if (overlay->dtbo_size > max_count)
-+ return -ENOSPC;
-+
-+ memcpy(buf, overlay->dtbo, overlay->dtbo_size);
-+ }
-+
-+ return overlay->dtbo_size;
-+}
-+
-+ssize_t cfs_overlay_item_dtbo_write(struct config_item *item,
-+ const void *buf, size_t count)
-+{
-+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
-+ int err;
-+
-+ /* if it's set do not allow changes */
-+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
-+ return -EPERM;
-+
-+ /* copy the contents */
-+ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
-+ if (overlay->dtbo == NULL)
-+ return -ENOMEM;
-+
-+ overlay->dtbo_size = count;
-+
-+ err = of_overlay_fdt_apply(overlay->dtbo, overlay->dtbo_size,
-+ &overlay->ov_id, NULL);
-+ if (err != 0)
-+ goto out_err;
-+
-+ return count;
-+
-+out_err:
-+ kfree(overlay->dtbo);
-+ overlay->dtbo = NULL;
-+ overlay->dtbo_size = 0;
-+ overlay->ov_id = 0;
-+
-+ return err;
-+}
-+
-+CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
-+
-+static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
-+ &cfs_overlay_item_attr_dtbo,
-+ NULL,
-+};
-+
-+static void cfs_overlay_release(struct config_item *item)
-+{
-+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
-+
-+ if (overlay->ov_id > 0)
-+ of_overlay_remove(&overlay->ov_id);
-+ if (overlay->fw)
-+ release_firmware(overlay->fw);
-+ /* kfree with NULL is safe */
-+ kfree(overlay->dtbo);
-+ kfree(overlay);
-+}
-+
-+static struct configfs_item_operations cfs_overlay_item_ops = {
-+ .release = cfs_overlay_release,
-+};
-+
-+static struct config_item_type cfs_overlay_type = {
-+ .ct_item_ops = &cfs_overlay_item_ops,
-+ .ct_attrs = cfs_overlay_attrs,
-+ .ct_bin_attrs = cfs_overlay_bin_attrs,
-+ .ct_owner = THIS_MODULE,
-+};
-+
-+static struct config_item *cfs_overlay_group_make_item(
-+ struct config_group *group, const char *name)
-+{
-+ struct cfs_overlay_item *overlay;
-+
-+ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
-+ if (!overlay)
-+ return ERR_PTR(-ENOMEM);
-+
-+ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
-+ return &overlay->item;
-+}
-+
-+static void cfs_overlay_group_drop_item(struct config_group *group,
-+ struct config_item *item)
-+{
-+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
-+
-+ config_item_put(&overlay->item);
-+}
-+
-+static struct configfs_group_operations overlays_ops = {
-+ .make_item = cfs_overlay_group_make_item,
-+ .drop_item = cfs_overlay_group_drop_item,
-+};
-+
-+static struct config_item_type overlays_type = {
-+ .ct_group_ops = &overlays_ops,
-+ .ct_owner = THIS_MODULE,
-+};
-+
-+static struct configfs_group_operations of_cfs_ops = {
-+ /* empty - we don't allow anything to be created */
-+};
-+
-+static struct config_item_type of_cfs_type = {
-+ .ct_group_ops = &of_cfs_ops,
-+ .ct_owner = THIS_MODULE,
-+};
-+
-+struct config_group of_cfs_overlay_group;
-+
-+static struct configfs_subsystem of_cfs_subsys = {
-+ .su_group = {
-+ .cg_item = {
-+ .ci_namebuf = "device-tree",
-+ .ci_type = &of_cfs_type,
-+ },
-+ },
-+ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
-+};
-+
-+static int __init of_cfs_init(void)
-+{
-+ int ret;
-+
-+ pr_info("%s\n", __func__);
-+
-+ config_group_init(&of_cfs_subsys.su_group);
-+ config_group_init_type_name(&of_cfs_overlay_group, "overlays",
-+ &overlays_type);
-+ configfs_add_default_group(&of_cfs_overlay_group,
-+ &of_cfs_subsys.su_group);
-+
-+ ret = configfs_register_subsystem(&of_cfs_subsys);
-+ if (ret != 0) {
-+ pr_err("%s: failed to register subsys\n", __func__);
-+ goto out;
-+ }
-+ pr_info("%s: OK\n", __func__);
-+out:
-+ return ret;
-+}
-+late_initcall(of_cfs_init);
+++ /dev/null
-From 7891826f8c2de9ee0f6459cf969f7b082e29b154 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Thu, 1 Jun 2023 23:10:09 -0700
-Subject: [PATCH 061/116] usr: Add gen_initramfs_list.sh
-
-Add gen_initramfs_list.sh
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- usr/gen_initramfs_list.sh | 328 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 328 insertions(+)
- create mode 100644 usr/gen_initramfs_list.sh
-
---- /dev/null
-+++ b/usr/gen_initramfs_list.sh
-@@ -0,0 +1,328 @@
-+#!/bin/sh
-+# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
-+# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
-+#
-+# Released under the terms of the GNU GPL
-+#
-+# Generate a cpio packed initramfs. It uses gen_init_cpio to generate
-+# the cpio archive, and then compresses it.
-+# The script may also be used to generate the inputfile used for gen_init_cpio
-+# This script assumes that gen_init_cpio is located in usr/ directory
-+
-+# error out on errors
-+set -e
-+
-+usage() {
-+cat << EOF
-+Usage:
-+$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
-+ -o <file> Create compressed initramfs file named <file> using
-+ gen_init_cpio and compressor depending on the extension
-+ -u <uid> User ID to map to user ID 0 (root).
-+ <uid> is only meaningful if <cpio_source> is a
-+ directory. "squash" forces all files to uid 0.
-+ -g <gid> Group ID to map to group ID 0 (root).
-+ <gid> is only meaningful if <cpio_source> is a
-+ directory. "squash" forces all files to gid 0.
-+ <cpio_source> File list or directory for cpio archive.
-+ If <cpio_source> is a .cpio file it will be used
-+ as direct input to initramfs.
-+ -d Output the default cpio list.
-+
-+All options except -o and -l may be repeated and are interpreted
-+sequentially and immediately. -u and -g states are preserved across
-+<cpio_source> options so an explicit "-u 0 -g 0" is required
-+to reset the root/group mapping.
-+EOF
-+}
-+
-+# awk style field access
-+# $1 - field number; rest is argument string
-+field() {
-+ shift $1 ; echo $1
-+}
-+
-+list_default_initramfs() {
-+ # echo usr/kinit/kinit
-+ :
-+}
-+
-+default_initramfs() {
-+ cat <<-EOF >> ${output}
-+ # This is a very simple, default initramfs
-+
-+ dir /dev 0755 0 0
-+ nod /dev/console 0600 0 0 c 5 1
-+ dir /root 0700 0 0
-+ # file /kinit usr/kinit/kinit 0755 0 0
-+ # slink /init kinit 0755 0 0
-+ EOF
-+}
-+
-+filetype() {
-+ local argv1="$1"
-+
-+ # symlink test must come before file test
-+ if [ -L "${argv1}" ]; then
-+ echo "slink"
-+ elif [ -f "${argv1}" ]; then
-+ echo "file"
-+ elif [ -d "${argv1}" ]; then
-+ echo "dir"
-+ elif [ -b "${argv1}" -o -c "${argv1}" ]; then
-+ echo "nod"
-+ elif [ -p "${argv1}" ]; then
-+ echo "pipe"
-+ elif [ -S "${argv1}" ]; then
-+ echo "sock"
-+ else
-+ echo "invalid"
-+ fi
-+ return 0
-+}
-+
-+list_print_mtime() {
-+ :
-+}
-+
-+print_mtime() {
-+ local my_mtime="0"
-+
-+ if [ -e "$1" ]; then
-+ my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1)
-+ fi
-+
-+ echo "# Last modified: ${my_mtime}" >> ${output}
-+ echo "" >> ${output}
-+}
-+
-+list_parse() {
-+ if [ -L "$1" ]; then
-+ return
-+ fi
-+ echo "$1" | sed 's/:/\\:/g; s/$/ \\/'
-+}
-+
-+# for each file print a line in following format
-+# <filetype> <name> <path to file> <octal mode> <uid> <gid>
-+# for links, devices etc the format differs. See gen_init_cpio for details
-+parse() {
-+ local location="$1"
-+ local name="/${location#${srcdir}}"
-+ # change '//' into '/'
-+ name=$(echo "$name" | sed -e 's://*:/:g')
-+ local mode="$2"
-+ local uid="$3"
-+ local gid="$4"
-+ local ftype=$(filetype "${location}")
-+ # remap uid/gid to 0 if necessary
-+ [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
-+ [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
-+ local str="${mode} ${uid} ${gid}"
-+
-+ [ "${ftype}" = "invalid" ] && return 0
-+ [ "${location}" = "${srcdir}" ] && return 0
-+
-+ case "${ftype}" in
-+ "file")
-+ str="${ftype} ${name} ${location} ${str}"
-+ ;;
-+ "nod")
-+ local dev=`LC_ALL=C ls -l "${location}"`
-+ local maj=`field 5 ${dev}`
-+ local min=`field 6 ${dev}`
-+ maj=${maj%,}
-+
-+ [ -b "${location}" ] && dev="b" || dev="c"
-+
-+ str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
-+ ;;
-+ "slink")
-+ local target=`readlink "${location}"`
-+ str="${ftype} ${name} ${target} ${str}"
-+ ;;
-+ *)
-+ str="${ftype} ${name} ${str}"
-+ ;;
-+ esac
-+
-+ echo "${str}" >> ${output}
-+
-+ return 0
-+}
-+
-+unknown_option() {
-+ printf "ERROR: unknown option \"$arg\"\n" >&2
-+ printf "If the filename validly begins with '-', " >&2
-+ printf "then it must be prefixed\n" >&2
-+ printf "by './' so that it won't be interpreted as an option." >&2
-+ printf "\n" >&2
-+ usage >&2
-+ exit 1
-+}
-+
-+list_header() {
-+ :
-+}
-+
-+header() {
-+ printf "\n#####################\n# $1\n" >> ${output}
-+}
-+
-+# process one directory (incl sub-directories)
-+dir_filelist() {
-+ ${dep_list}header "$1"
-+
-+ srcdir=$(echo "$1" | sed -e 's://*:/:g')
-+ dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" | LANG=C sort)
-+
-+ # If $dirlist is only one line, then the directory is empty
-+ if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
-+ ${dep_list}print_mtime "$1"
-+
-+ echo "${dirlist}" | \
-+ while read x; do
-+ ${dep_list}parse ${x}
-+ done
-+ fi
-+}
-+
-+# if only one file is specified and it is .cpio file then use it direct as fs
-+# if a directory is specified then add all files in given direcotry to fs
-+# if a regular file is specified assume it is in gen_initramfs format
-+input_file() {
-+ source="$1"
-+ if [ -f "$1" ]; then
-+ ${dep_list}header "$1"
-+ is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\{0,1\}/cpio/')"
-+ if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then
-+ cpio_file=$1
-+ echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
-+ [ ! -z ${dep_list} ] && echo "$1"
-+ return 0
-+ fi
-+ if [ -z ${dep_list} ]; then
-+ print_mtime "$1" >> ${output}
-+ cat "$1" >> ${output}
-+ else
-+ echo "$1 \\"
-+ cat "$1" | while read type dir file perm ; do
-+ if [ "$type" = "file" ]; then
-+ echo "$file \\";
-+ fi
-+ done
-+ fi
-+ elif [ -d "$1" ]; then
-+ dir_filelist "$1"
-+ else
-+ echo " ${prog}: Cannot open '$1'" >&2
-+ exit 1
-+ fi
-+}
-+
-+prog=$0
-+root_uid=0
-+root_gid=0
-+dep_list=
-+cpio_file=
-+cpio_list=
-+output="/dev/stdout"
-+output_file=""
-+is_cpio_compressed=
-+compr="gzip -n -9 -f"
-+
-+arg="$1"
-+case "$arg" in
-+ "-l") # files included in initramfs - used by kbuild
-+ dep_list="list_"
-+ echo "deps_initramfs := $0 \\"
-+ shift
-+ ;;
-+ "-o") # generate compressed cpio image named $1
-+ shift
-+ output_file="$1"
-+ cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
-+ output=${cpio_list}
-+ echo "$output_file" | grep -q "\.gz$" \
-+ && [ -x "`which gzip 2> /dev/null`" ] \
-+ && compr="gzip -n -9 -f"
-+ echo "$output_file" | grep -q "\.bz2$" \
-+ && [ -x "`which bzip2 2> /dev/null`" ] \
-+ && compr="bzip2 -9 -f"
-+ echo "$output_file" | grep -q "\.lzma$" \
-+ && [ -x "`which lzma 2> /dev/null`" ] \
-+ && compr="lzma -9 -f"
-+ echo "$output_file" | grep -q "\.xz$" \
-+ && [ -x "`which xz 2> /dev/null`" ] \
-+ && compr="xz --check=crc32 --lzma2=dict=1MiB"
-+ echo "$output_file" | grep -q "\.lzo$" \
-+ && [ -x "`which lzop 2> /dev/null`" ] \
-+ && compr="lzop -9 -f"
-+ echo "$output_file" | grep -q "\.lz4$" \
-+ && [ -x "`which lz4 2> /dev/null`" ] \
-+ && compr="lz4 -l -9 -f"
-+ echo "$output_file" | grep -q "\.cpio$" && compr="cat"
-+ shift
-+ ;;
-+esac
-+while [ $# -gt 0 ]; do
-+ arg="$1"
-+ shift
-+ case "$arg" in
-+ "-u") # map $1 to uid=0 (root)
-+ root_uid="$1"
-+ [ "$root_uid" = "-1" ] && root_uid=$(id -u || echo 0)
-+ shift
-+ ;;
-+ "-g") # map $1 to gid=0 (root)
-+ root_gid="$1"
-+ [ "$root_gid" = "-1" ] && root_gid=$(id -g || echo 0)
-+ shift
-+ ;;
-+ "-d") # display default initramfs list
-+ default_list="$arg"
-+ ${dep_list}default_initramfs
-+ ;;
-+ "-h")
-+ usage
-+ exit 0
-+ ;;
-+ *)
-+ case "$arg" in
-+ "-"*)
-+ unknown_option
-+ ;;
-+ *) # input file/dir - process it
-+ input_file "$arg" "$#"
-+ ;;
-+ esac
-+ ;;
-+ esac
-+done
-+
-+# If output_file is set we will generate cpio archive and compress it
-+# we are careful to delete tmp files
-+if [ ! -z ${output_file} ]; then
-+ if [ -z ${cpio_file} ]; then
-+ timestamp=
-+ if test -n "$KBUILD_BUILD_TIMESTAMP"; then
-+ timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)"
-+ if test -n "$timestamp"; then
-+ timestamp="-t $timestamp"
-+ fi
-+ fi
-+ cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)"
-+ usr/gen_init_cpio $timestamp ${cpio_list} > ${cpio_tfile}
-+ else
-+ cpio_tfile=${cpio_file}
-+ fi
-+ rm ${cpio_list}
-+ if [ "${is_cpio_compressed}" = "compressed" ]; then
-+ cat ${cpio_tfile} > ${output_file}
-+ else
-+ (cat ${cpio_tfile} | ${compr} - > ${output_file}) \
-+ || (rm -f ${output_file} ; false)
-+ fi
-+ [ -z ${cpio_file} ] && rm ${cpio_tfile}
-+fi
-+exit 0
+++ /dev/null
-From dcc2827ed6e701a65731c05b0297745559837217 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Fri, 12 May 2023 17:33:20 +0800
-Subject: [PATCH 062/116] i2c: designware: Delete SMBus functionalities
-
-The driver didn't implement the smbus interface,
-so replace the SMBus functionalities with
-I2C_FUNC_SMBUS_EMUL.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/i2c/busses/i2c-designware-core.h | 10 ++++------
- 1 file changed, 4 insertions(+), 6 deletions(-)
-
---- a/drivers/i2c/busses/i2c-designware-core.h
-+++ b/drivers/i2c/busses/i2c-designware-core.h
-@@ -18,12 +18,10 @@
- #include <linux/regmap.h>
- #include <linux/types.h>
-
--#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
-- I2C_FUNC_SMBUS_BYTE | \
-- I2C_FUNC_SMBUS_BYTE_DATA | \
-- I2C_FUNC_SMBUS_WORD_DATA | \
-- I2C_FUNC_SMBUS_BLOCK_DATA | \
-- I2C_FUNC_SMBUS_I2C_BLOCK)
-+#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL \
-+ & ~I2C_FUNC_SMBUS_QUICK \
-+ & ~I2C_FUNC_SMBUS_PROC_CALL \
-+ & ~I2C_FUNC_SMBUS_PEC))
-
- #define DW_IC_CON_MASTER BIT(0)
- #define DW_IC_CON_SPEED_STD (1 << 1)
+++ /dev/null
-From b61cefc6c785aa8a7177a0b535db746fd0047bd8 Mon Sep 17 00:00:00 2001
-From: Ziv Xu <ziv.xu@starfivetech.com>
-Date: Fri, 19 Jan 2024 15:22:55 +0800
-Subject: [PATCH 063/116] drivers: mtd: gigadevice: add gd25lq256d 32M flash
- support
-
-add gd25lq256d 32M flash support
-
-Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com>
----
- drivers/mtd/spi-nor/gigadevice.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/mtd/spi-nor/gigadevice.c
-+++ b/drivers/mtd/spi-nor/gigadevice.c
-@@ -66,6 +66,10 @@ static const struct flash_info gigadevic
- FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
-+ { "gd25lq256d", INFO(0xc86019, 0, 64 * 1024, 512)
-+ 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) },
- { "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512)
- PARSE_SFDP
- FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6)
+++ /dev/null
-From 76bc13aa12bd111f5da01e107f8d487b20b5a40c Mon Sep 17 00:00:00 2001
-From: "shanlong.li" <shanlong.li@starfivetech.com>
-Date: Thu, 8 Jun 2023 00:07:15 -0700
-Subject: [PATCH 064/116] driver: mailbox: Add mailbox driver
-
-Add mailbox driver.
-
-Signed-off-by: shanlong.li <shanlong.li@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/mailbox/Kconfig | 13 +
- drivers/mailbox/Makefile | 4 +
- drivers/mailbox/starfive_mailbox-test.c | 407 ++++++++++++++++++++++++
- drivers/mailbox/starfive_mailbox.c | 347 ++++++++++++++++++++
- 4 files changed, 771 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
-@@ -62,3 +62,7 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox
- obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o
-
- obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o
-+
-+obj-$(CONFIG_STARFIVE_MBOX) += starfive_mailbox.o
-+
-+obj-$(CONFIG_STARFIVE_MBOX_TEST) += starfive_mailbox-test.o
---- /dev/null
-+++ b/drivers/mailbox/starfive_mailbox-test.c
-@@ -0,0 +1,407 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2015 ST Microelectronics
-+ *
-+ * Author: Lee Jones <lee.jones@linaro.org>
-+ */
-+
-+#include <linux/debugfs.h>
-+#include <linux/err.h>
-+#include <linux/fs.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/mailbox_client.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/poll.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+#include <linux/sched/signal.h>
-+
-+#include <linux/mailbox_controller.h>
-+
-+#define MBOX_MAX_SIG_LEN 8
-+#define MBOX_MAX_MSG_LEN 16
-+#define MBOX_BYTES_PER_LINE 16
-+#define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2)
-+#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
-+
-+static bool mbox_data_ready;
-+
-+struct mbox_test_device {
-+ struct device *dev;
-+ void __iomem *tx_mmio;
-+ void __iomem *rx_mmio;
-+ struct mbox_chan *tx_channel;
-+ struct mbox_chan *rx_channel;
-+ char *rx_buffer;
-+ char *signal;
-+ char *message;
-+ spinlock_t lock;
-+ wait_queue_head_t waitq;
-+ struct fasync_struct *async_queue;
-+ struct dentry *root_debugfs_dir;
-+};
-+
-+static ssize_t mbox_test_signal_write(struct file *filp,
-+ const char __user *userbuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct mbox_test_device *tdev = filp->private_data;
-+
-+ if (!tdev->tx_channel) {
-+ dev_err(tdev->dev, "Channel cannot do Tx\n");
-+ return -EINVAL;
-+ }
-+
-+ if (count > MBOX_MAX_SIG_LEN) {
-+ dev_err(tdev->dev,
-+ "Signal length %zd greater than max allowed %d\n",
-+ count, MBOX_MAX_SIG_LEN);
-+ return -EINVAL;
-+ }
-+
-+ /* Only allocate memory if we need to */
-+ if (!tdev->signal) {
-+ tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL);
-+ if (!tdev->signal)
-+ return -ENOMEM;
-+ }
-+
-+ if (copy_from_user(tdev->signal, userbuf, count)) {
-+ kfree(tdev->signal);
-+ tdev->signal = NULL;
-+ return -EFAULT;
-+ }
-+
-+ return count;
-+}
-+
-+static const struct file_operations mbox_test_signal_ops = {
-+ .write = mbox_test_signal_write,
-+ .open = simple_open,
-+ .llseek = generic_file_llseek,
-+};
-+
-+static int mbox_test_message_fasync(int fd, struct file *filp, int on)
-+{
-+ struct mbox_test_device *tdev = filp->private_data;
-+
-+ return fasync_helper(fd, filp, on, &tdev->async_queue);
-+}
-+
-+static ssize_t mbox_test_message_write(struct file *filp,
-+ const char __user *userbuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct mbox_test_device *tdev = filp->private_data;
-+ void *data;
-+ int ret;
-+
-+ if (!tdev->tx_channel) {
-+ dev_err(tdev->dev, "Channel cannot do Tx\n");
-+ return -EINVAL;
-+ }
-+
-+ if (count > MBOX_MAX_MSG_LEN) {
-+ dev_err(tdev->dev,
-+ "Message length %zd greater than max allowed %d\n",
-+ count, MBOX_MAX_MSG_LEN);
-+ return -EINVAL;
-+ }
-+
-+ tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
-+ if (!tdev->message)
-+ return -ENOMEM;
-+
-+ ret = copy_from_user(tdev->message, userbuf, count);
-+ if (ret) {
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+
-+ if (tdev->tx_mmio && tdev->signal) {
-+ print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS,
-+ tdev->signal, MBOX_MAX_SIG_LEN);
-+
-+ data = tdev->signal;
-+ } else
-+ data = tdev->message;
-+
-+ print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
-+ tdev->message, MBOX_MAX_MSG_LEN);
-+
-+ ret = mbox_send_message(tdev->tx_channel, data);
-+ mbox_chan_txdone(tdev->tx_channel, ret);
-+ if (ret < 0)
-+ dev_err(tdev->dev, "Failed to send message via mailbox\n");
-+
-+out:
-+ kfree(tdev->signal);
-+ kfree(tdev->message);
-+ tdev->signal = NULL;
-+
-+ return ret < 0 ? ret : count;
-+}
-+
-+static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
-+{
-+ bool data_ready;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&tdev->lock, flags);
-+ data_ready = mbox_data_ready;
-+ spin_unlock_irqrestore(&tdev->lock, flags);
-+
-+ return data_ready;
-+}
-+
-+static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct mbox_test_device *tdev = filp->private_data;
-+ unsigned long flags;
-+ char *touser, *ptr;
-+ int ret;
-+
-+ touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
-+ if (!touser)
-+ return -ENOMEM;
-+
-+ if (!tdev->rx_channel) {
-+ ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
-+ ret = simple_read_from_buffer(userbuf, count, ppos,
-+ touser, ret);
-+ goto kfree_err;
-+ }
-+
-+ do {
-+ if (mbox_test_message_data_ready(tdev))
-+ break;
-+
-+ if (filp->f_flags & O_NONBLOCK) {
-+ ret = -EAGAIN;
-+ goto waitq_err;
-+ }
-+
-+ if (signal_pending(current)) {
-+ ret = -ERESTARTSYS;
-+ goto waitq_err;
-+ }
-+ schedule();
-+
-+ } while (1);
-+
-+ spin_lock_irqsave(&tdev->lock, flags);
-+
-+ ptr = tdev->rx_buffer;
-+
-+ mbox_data_ready = false;
-+
-+ spin_unlock_irqrestore(&tdev->lock, flags);
-+ if (copy_to_user((void __user *)userbuf, ptr, 4))
-+ ret = -EFAULT;
-+
-+waitq_err:
-+ __set_current_state(TASK_RUNNING);
-+kfree_err:
-+ kfree(touser);
-+ return ret;
-+}
-+
-+static __poll_t
-+mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
-+{
-+ struct mbox_test_device *tdev = filp->private_data;
-+
-+ poll_wait(filp, &tdev->waitq, wait);
-+
-+ if (mbox_test_message_data_ready(tdev))
-+ return EPOLLIN | EPOLLRDNORM;
-+ return 0;
-+}
-+
-+static const struct file_operations mbox_test_message_ops = {
-+ .write = mbox_test_message_write,
-+ .read = mbox_test_message_read,
-+ .fasync = mbox_test_message_fasync,
-+ .poll = mbox_test_message_poll,
-+ .open = simple_open,
-+ .llseek = generic_file_llseek,
-+};
-+
-+static int mbox_test_add_debugfs(struct platform_device *pdev,
-+ struct mbox_test_device *tdev)
-+{
-+ if (!debugfs_initialized())
-+ return 0;
-+
-+ tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
-+ if (!tdev->root_debugfs_dir) {
-+ dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
-+ return -EINVAL;
-+ }
-+
-+ debugfs_create_file("message", 0600, tdev->root_debugfs_dir,
-+ tdev, &mbox_test_message_ops);
-+
-+ debugfs_create_file("signal", 0200, tdev->root_debugfs_dir,
-+ tdev, &mbox_test_signal_ops);
-+
-+ return 0;
-+}
-+
-+static void mbox_test_receive_message(struct mbox_client *client, void *message)
-+{
-+ struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&tdev->lock, flags);
-+ if (tdev->rx_mmio) {
-+ memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN);
-+ print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS,
-+ tdev->rx_buffer, MBOX_MAX_MSG_LEN);
-+ } else if (message) {
-+ print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS,
-+ message, MBOX_MAX_MSG_LEN);
-+ memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
-+ }
-+ mbox_data_ready = true;
-+ spin_unlock_irqrestore(&tdev->lock, flags);
-+}
-+
-+static void mbox_test_prepare_message(struct mbox_client *client, void *message)
-+{
-+ struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
-+
-+ if (tdev->tx_mmio) {
-+ if (tdev->signal)
-+ memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN);
-+ else
-+ memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN);
-+ }
-+}
-+
-+static struct mbox_chan *
-+mbox_test_request_channel(struct platform_device *pdev, const char *name)
-+{
-+ struct mbox_client *client;
-+ struct mbox_chan *channel;
-+
-+ client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
-+ if (!client)
-+ return ERR_PTR(-ENOMEM);
-+
-+ client->dev = &pdev->dev;
-+ client->rx_callback = mbox_test_receive_message;
-+ client->tx_prepare = mbox_test_prepare_message;
-+ client->tx_block = false;
-+ client->knows_txdone = false;
-+ client->tx_tout = 500;
-+
-+ channel = mbox_request_channel_byname(client, name);
-+ if (IS_ERR(channel)) {
-+ dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
-+ return NULL;
-+ }
-+
-+ return channel;
-+}
-+
-+static int mbox_test_probe(struct platform_device *pdev)
-+{
-+ struct mbox_test_device *tdev;
-+ struct resource *res;
-+ resource_size_t size;
-+ int ret;
-+
-+ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
-+ if (!tdev)
-+ return -ENOMEM;
-+
-+ /* It's okay for MMIO to be NULL */
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
-+ if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
-+ /* if reserved area in SRAM, try just ioremap */
-+ size = resource_size(res);
-+ tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
-+ } else if (IS_ERR(tdev->tx_mmio)) {
-+ tdev->tx_mmio = NULL;
-+ }
-+
-+ /* If specified, second reg entry is Rx MMIO */
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
-+ if (PTR_ERR(tdev->rx_mmio) == -EBUSY) {
-+ size = resource_size(res);
-+ tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
-+ } else if (IS_ERR(tdev->rx_mmio)) {
-+ tdev->rx_mmio = tdev->tx_mmio;
-+ }
-+
-+ tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
-+ tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
-+
-+ if (!tdev->tx_channel && !tdev->rx_channel)
-+ return -EPROBE_DEFER;
-+
-+ /* If Rx is not specified but has Rx MMIO, then Rx = Tx */
-+ if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio))
-+ tdev->rx_channel = tdev->tx_channel;
-+
-+ tdev->dev = &pdev->dev;
-+ platform_set_drvdata(pdev, tdev);
-+
-+ spin_lock_init(&tdev->lock);
-+
-+ if (tdev->rx_channel) {
-+ tdev->rx_buffer = devm_kzalloc(&pdev->dev,
-+ MBOX_MAX_MSG_LEN, GFP_KERNEL);
-+ if (!tdev->rx_buffer)
-+ return -ENOMEM;
-+ }
-+
-+ ret = mbox_test_add_debugfs(pdev, tdev);
-+ if (ret)
-+ return ret;
-+
-+ dev_info(&pdev->dev, "Successfully registered\n");
-+
-+ return 0;
-+}
-+
-+static int 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);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id mbox_test_match[] = {
-+ { .compatible = "starfive,mailbox-test" },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, mbox_test_match);
-+
-+static struct platform_driver mbox_test_driver = {
-+ .driver = {
-+ .name = "mailbox_test",
-+ .of_match_table = mbox_test_match,
-+ },
-+ .probe = mbox_test_probe,
-+ .remove = mbox_test_remove,
-+};
-+module_platform_driver(mbox_test_driver);
-+
-+MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
-+MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/drivers/mailbox/starfive_mailbox.c
-@@ -0,0 +1,347 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * mailbox driver for StarFive JH7110 SoC
-+ *
-+ * Copyright (c) 2021 StarFive Technology Co., Ltd.
-+ * Author: Shanlong Li <shanlong.li@starfivetech.com>
-+ */
-+
-+#include <linux/bitops.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/err.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/iopoll.h>
-+#include <linux/mailbox_controller.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/clk.h>
-+#include <linux/reset.h>
-+#include <linux/pm_runtime.h>
-+
-+#include "mailbox.h"
-+
-+#define MBOX_CHAN_MAX 4
-+
-+#define MBOX_BASE(mbox, ch) ((mbox)->base + ((ch) * 0x10))
-+#define MBOX_IRQ_REG 0x00
-+#define MBOX_SET_REG 0x04
-+#define MBOX_CLR_REG 0x08
-+#define MBOX_CMD_REG 0x0c
-+#define MBC_PEND_SMRY 0x100
-+
-+typedef enum {
-+ MAILBOX_CORE_U7 = 0,
-+ MAILBOX_CORE_HIFI4,
-+ MAILBOX_CORE_E2,
-+ MAILBOX_CORE_RSVD0,
-+ MAILBOX_CORE_NUM,
-+} mailbox_core_t;
-+
-+struct mailbox_irq_name_c{
-+ int id;
-+ char name[16];
-+};
-+
-+static const struct mailbox_irq_name_c irq_peer_name[MBOX_CHAN_MAX] = {
-+ {MAILBOX_CORE_U7, "u74_core"},
-+ {MAILBOX_CORE_HIFI4, "hifi4_core"},
-+ {MAILBOX_CORE_E2, "e24_core"},
-+ {MAILBOX_CORE_RSVD0, "" },
-+};
-+
-+/**
-+ * starfive mailbox channel information
-+ *
-+ * A channel can be used for TX or RX, it can trigger remote
-+ * processor interrupt to notify remote processor and can receive
-+ * interrupt if has incoming message.
-+ *
-+ * @dst_irq: Interrupt vector for remote processor
-+ * @core_id: id for remote processor
-+ */
-+struct starfive_chan_info {
-+ unsigned int dst_irq;
-+ mailbox_core_t core_id;
-+};
-+
-+/**
-+ * starfive mailbox controller data
-+ *
-+ * Mailbox controller includes 4 channels and can allocate
-+ * channel for message transferring.
-+ *
-+ * @dev: Device to which it is attached
-+ * @base: Base address of the register mapping region
-+ * @chan: Representation of channels in mailbox controller
-+ * @mchan: Representation of channel info
-+ * @controller: Representation of a communication channel controller
-+ */
-+struct starfive_mbox {
-+ struct device *dev;
-+ void __iomem *base;
-+ struct mbox_chan chan[MBOX_CHAN_MAX];
-+ struct starfive_chan_info mchan[MBOX_CHAN_MAX];
-+ struct mbox_controller controller;
-+ struct clk *clk;
-+ struct reset_control *rst_rresetn;
-+};
-+
-+static struct starfive_mbox *to_starfive_mbox(struct mbox_controller *mbox)
-+{
-+ return container_of(mbox, struct starfive_mbox, controller);
-+}
-+
-+static struct mbox_chan *
-+starfive_of_mbox_index_xlate(struct mbox_controller *mbox,
-+ const struct of_phandle_args *sp)
-+{
-+ struct starfive_mbox *sbox;
-+
-+ int ind = sp->args[0];
-+ int core_id = sp->args[1];
-+
-+ if (ind >= mbox->num_chans || core_id >= MAILBOX_CORE_NUM)
-+ return ERR_PTR(-EINVAL);
-+
-+ sbox = to_starfive_mbox(mbox);
-+
-+ sbox->mchan[ind].core_id = core_id;
-+
-+ return &mbox->chans[ind];
-+}
-+
-+static irqreturn_t starfive_rx_irq_handler(int irq, void *p)
-+{
-+ struct mbox_chan *chan = p;
-+ unsigned long ch = (unsigned long)chan->con_priv;
-+ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
-+ void __iomem *base = MBOX_BASE(mbox, ch);
-+ u32 val;
-+
-+ val = readl(base + MBOX_CMD_REG);
-+ if (!val)
-+ return IRQ_NONE;
-+
-+ mbox_chan_received_data(chan, (void *)&val);
-+ writel(val, base + MBOX_CLR_REG);
-+ return IRQ_HANDLED;
-+}
-+
-+static int starfive_mbox_check_state(struct mbox_chan *chan)
-+{
-+ unsigned long ch = (unsigned long)chan->con_priv;
-+ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
-+ unsigned long irq_flag = IRQF_SHARED;
-+ long ret = 0;
-+
-+ pm_runtime_get_sync(mbox->dev);
-+ /* MAILBOX should be with IRQF_NO_SUSPEND set */
-+ if (!mbox->dev->pm_domain)
-+ irq_flag |= IRQF_NO_SUSPEND;
-+
-+ /* Mailbox is idle so directly bail out */
-+ if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch))
-+ return -EBUSY;
-+
-+ if (mbox->mchan[ch].dst_irq > 0) {
-+ dev_dbg(mbox->dev, "%s: host IRQ = %d, ch:%ld", __func__, mbox->mchan[ch].dst_irq, ch);
-+ ret = devm_request_irq(mbox->dev, mbox->mchan[ch].dst_irq, starfive_rx_irq_handler,
-+ irq_flag, irq_peer_name[ch].name, chan);
-+ if (ret < 0)
-+ dev_err(mbox->dev, "request_irq %d failed\n", mbox->mchan[ch].dst_irq);
-+ }
-+
-+ return ret;
-+}
-+
-+static int starfive_mbox_startup(struct mbox_chan *chan)
-+{
-+ return starfive_mbox_check_state(chan);
-+}
-+
-+static void starfive_mbox_shutdown(struct mbox_chan *chan)
-+{
-+ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
-+ unsigned long ch = (unsigned long)chan->con_priv;
-+ void __iomem *base = MBOX_BASE(mbox, ch);
-+
-+ writel(0x0, base + MBOX_IRQ_REG);
-+ writel(0x0, base + MBOX_CLR_REG);
-+
-+ if (mbox->mchan[ch].dst_irq > 0)
-+ devm_free_irq(mbox->dev, mbox->mchan[ch].dst_irq, chan);
-+ pm_runtime_put_sync(mbox->dev);
-+}
-+
-+static int starfive_mbox_send_data(struct mbox_chan *chan, void *msg)
-+{
-+ unsigned long ch = (unsigned long)chan->con_priv;
-+ struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
-+ struct starfive_chan_info *mchan = &mbox->mchan[ch];
-+ void __iomem *base = MBOX_BASE(mbox, ch);
-+ u32 *buf = msg;
-+
-+ /* Ensure channel is released */
-+ if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch)) {
-+ pr_debug("%s:%d. busy\n", __func__, __LINE__);
-+ return -EBUSY;
-+ }
-+
-+ /* Clear mask for destination interrupt */
-+ writel(BIT(mchan->core_id), base + MBOX_IRQ_REG);
-+
-+ /* Fill message data */
-+ writel(*buf, base + MBOX_SET_REG);
-+ return 0;
-+}
-+
-+static struct mbox_chan_ops starfive_mbox_ops = {
-+ .startup = starfive_mbox_startup,
-+ .send_data = starfive_mbox_send_data,
-+ .shutdown = starfive_mbox_shutdown,
-+};
-+
-+static const struct of_device_id starfive_mbox_of_match[] = {
-+ { .compatible = "starfive,mail_box",},
-+ {},
-+};
-+
-+MODULE_DEVICE_TABLE(of, starfive_mbox_of_match);
-+
-+void starfive_mailbox_init(struct starfive_mbox *mbox)
-+{
-+ mbox->clk = devm_clk_get_optional(mbox->dev, "clk_apb");
-+ if (IS_ERR(mbox->clk)) {
-+ dev_err(mbox->dev, "failed to get mailbox\n");
-+ return;
-+ }
-+
-+ mbox->rst_rresetn = devm_reset_control_get_exclusive(mbox->dev, "mbx_rre");
-+ if (IS_ERR(mbox->rst_rresetn)) {
-+ dev_err(mbox->dev, "failed to get mailbox reset\n");
-+ return;
-+ }
-+
-+ clk_prepare_enable(mbox->clk);
-+ reset_control_deassert(mbox->rst_rresetn);
-+}
-+
-+static int starfive_mbox_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct starfive_mbox *mbox;
-+ struct mbox_chan *chan;
-+ struct resource *res;
-+ unsigned long ch;
-+ int err;
-+
-+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
-+ if (!mbox)
-+ return -ENOMEM;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ mbox->base = devm_ioremap_resource(dev, res);
-+ mbox->dev = dev;
-+
-+ if (IS_ERR(mbox->base))
-+ return PTR_ERR(mbox->base);
-+
-+ starfive_mailbox_init(mbox);
-+
-+ mbox->controller.dev = dev;
-+ mbox->controller.chans = mbox->chan;
-+ mbox->controller.num_chans = MBOX_CHAN_MAX;
-+ mbox->controller.ops = &starfive_mbox_ops;
-+ mbox->controller.of_xlate = starfive_of_mbox_index_xlate;
-+ mbox->controller.txdone_irq = true;
-+ mbox->controller.txdone_poll = false;
-+
-+ /* Initialize mailbox channel data */
-+ chan = mbox->chan;
-+ for (ch = 0; ch < MBOX_CHAN_MAX; ch++) {
-+ mbox->mchan[ch].dst_irq = 0;
-+ mbox->mchan[ch].core_id = (mailbox_core_t)ch;
-+ chan[ch].con_priv = (void *)ch;
-+ }
-+ mbox->mchan[MAILBOX_CORE_HIFI4].dst_irq = platform_get_irq(pdev, 0);
-+ mbox->mchan[MAILBOX_CORE_E2].dst_irq = platform_get_irq(pdev, 1);
-+
-+ err = mbox_controller_register(&mbox->controller);
-+ if (err) {
-+ dev_err(dev, "Failed to register mailbox %d\n", err);
-+ return err;
-+ }
-+
-+ platform_set_drvdata(pdev, mbox);
-+ dev_info(dev, "Mailbox enabled\n");
-+ pm_runtime_set_active(dev);
-+ pm_runtime_enable(dev);
-+
-+ return 0;
-+}
-+
-+static int 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);
-+
-+ return 0;
-+}
-+
-+static int __maybe_unused starfive_mbox_suspend(struct device *dev)
-+{
-+ struct starfive_mbox *mbox = dev_get_drvdata(dev);
-+
-+ clk_disable_unprepare(mbox->clk);
-+
-+ return 0;
-+}
-+
-+static int __maybe_unused starfive_mbox_resume(struct device *dev)
-+{
-+ struct starfive_mbox *mbox = dev_get_drvdata(dev);
-+ int ret;
-+
-+ ret = clk_prepare_enable(mbox->clk);
-+ if (ret)
-+ dev_err(dev, "failed to enable clock\n");
-+
-+ return ret;
-+}
-+
-+static const struct dev_pm_ops starfive_mbox_pm_ops = {
-+ .suspend = starfive_mbox_suspend,
-+ .resume = starfive_mbox_resume,
-+ SET_RUNTIME_PM_OPS(starfive_mbox_suspend, starfive_mbox_resume, NULL)
-+};
-+static struct platform_driver starfive_mbox_driver = {
-+ .probe = starfive_mbox_probe,
-+ .remove = starfive_mbox_remove,
-+ .driver = {
-+ .name = "mailbox",
-+ .of_match_table = starfive_mbox_of_match,
-+ .pm = &starfive_mbox_pm_ops,
-+ },
-+};
-+
-+static int __init starfive_mbox_init(void)
-+{
-+ return platform_driver_register(&starfive_mbox_driver);
-+}
-+core_initcall(starfive_mbox_init);
-+
-+static void __exit starfive_mbox_exit(void)
-+{
-+ platform_driver_unregister(&starfive_mbox_driver);
-+}
-+module_exit(starfive_mbox_exit);
-+
-+MODULE_DESCRIPTION("StarFive Mailbox Controller driver");
-+MODULE_AUTHOR("Shanlong Li <shanlong.li@starfivetech.com>");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From 0f44bd6bec708782f38bba4d03deecf927d1c83d Mon Sep 17 00:00:00 2001
-From: "ziv.xu" <ziv.xu@starfivetech.com>
-Date: Fri, 9 Jun 2023 15:31:53 +0800
-Subject: [PATCH 065/116] driver: rtc: Add StarFive JH7110 rtc driver
-
-Add RTC driver and support for StarFive JH7110 SoC.
-
-Signed-off-by: ziv.xu <ziv.xu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/rtc/Kconfig | 8 +
- drivers/rtc/Makefile | 1 +
- drivers/rtc/rtc-starfive.c | 743 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 752 insertions(+)
- create mode 100644 drivers/rtc/rtc-starfive.c
-
---- a/drivers/rtc/Kconfig
-+++ b/drivers/rtc/Kconfig
-@@ -1327,6 +1327,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
-@@ -163,6 +163,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,743 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * RTC driver for the StarFive JH7110 SoC
-+ *
-+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
-+ */
-+
-+#include <asm/delay.h>
-+#include <linux/bcd.h>
-+#include <linux/bitfield.h>
-+#include <linux/clk.h>
-+#include <linux/reset.h>
-+#include <linux/completion.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_irq.h>
-+#include <linux/iopoll.h>
-+#include <linux/platform_device.h>
-+#include <linux/rtc.h>
-+
-+/* Registers */
-+#define SFT_RTC_CFG 0x00
-+#define SFT_RTC_SW_CAL_VALUE 0x04
-+#define SFT_RTC_HW_CAL_CFG 0x08
-+#define SFT_RTC_CMP_CFG 0x0C
-+#define SFT_RTC_IRQ_EN 0x10
-+#define SFT_RTC_IRQ_EVEVT 0x14
-+#define SFT_RTC_IRQ_STATUS 0x18
-+#define SFT_RTC_CAL_VALUE 0x24
-+#define SFT_RTC_CFG_TIME 0x28
-+#define SFT_RTC_CFG_DATE 0x2C
-+#define SFT_RTC_ACT_TIME 0x34
-+#define SFT_RTC_ACT_DATE 0x38
-+#define SFT_RTC_TIME 0x3C
-+#define SFT_RTC_DATE 0x40
-+#define SFT_RTC_TIME_LATCH 0x44
-+#define SFT_RTC_DATE_LATCH 0x48
-+
-+/* RTC_CFG */
-+#define RTC_CFG_ENABLE_SHIFT 0 /* RW: RTC Enable. */
-+#define RTC_CFG_CAL_EN_HW_SHIFT 1 /* RW: Enable of hardware calibretion. */
-+#define RTC_CFG_CAL_SEL_SHIFT 2 /* RW: select the hw/sw calibretion mode.*/
-+#define RTC_CFG_HOUR_MODE_SHIFT 3 /* RW: time hour mode. 24h|12h */
-+
-+/* RTC_SW_CAL_VALUE */
-+#define RTC_SW_CAL_VALUE_MASK GENMASK(15, 0)
-+#define RTC_SW_CAL_MAX RTC_SW_CAL_VALUE_MASK
-+#define RTC_SW_CAL_MIN 0
-+#define RTC_TICKS_PER_SEC 32768 /* Number of ticks per second */
-+#define RTC_PPB_MULT 1000000000LL /* Multiplier for ppb conversions */
-+
-+/* RTC_HW_CAL_CFG */
-+#define RTC_HW_CAL_REF_SEL_SHIFT 0
-+#define RTC_HW_CAL_FRQ_SEL_SHIFT 1
-+
-+/* IRQ_EN/IRQ_EVEVT/IRQ_STATUS */
-+#define RTC_IRQ_CAL_START BIT(0)
-+#define RTC_IRQ_CAL_FINISH BIT(1)
-+#define RTC_IRQ_CMP BIT(2)
-+#define RTC_IRQ_1SEC BIT(3)
-+#define RTC_IRQ_ALAEM BIT(4)
-+#define RTC_IRQ_EVT_UPDATE_PSE BIT(31) /* WO: Enable of update time&&date, IRQ_EVEVT only */
-+#define RTC_IRQ_ALL (RTC_IRQ_CAL_START \
-+ | RTC_IRQ_CAL_FINISH \
-+ | RTC_IRQ_CMP \
-+ | RTC_IRQ_1SEC \
-+ | RTC_IRQ_ALAEM)
-+
-+/* CAL_VALUE */
-+#define RTC_CAL_VALUE_MASK GENMASK(15, 0)
-+
-+/* CFG_TIME/ACT_TIME/RTC_TIME */
-+#define TIME_SEC_MASK GENMASK(6, 0)
-+#define TIME_MIN_MASK GENMASK(13, 7)
-+#define TIME_HOUR_MASK GENMASK(20, 14)
-+
-+/* CFG_DATE/ACT_DATE/RTC_DATE */
-+#define DATE_DAY_MASK GENMASK(5, 0)
-+#define DATE_MON_MASK GENMASK(10, 6)
-+#define DATE_YEAR_MASK GENMASK(18, 11)
-+
-+#define INT_TIMEOUT_US 180
-+
-+enum RTC_HOUR_MODE {
-+ RTC_HOUR_MODE_12H = 0,
-+ RTC_HOUR_MODE_24H = 1
-+};
-+
-+enum RTC_CAL_MODE {
-+ RTC_CAL_MODE_SW = 0,
-+ RTC_CAL_MODE_HW = 1
-+};
-+
-+enum RTC_HW_CAL_REF_MODE {
-+ RTC_CAL_CLK_REF = 0,
-+ RTC_CAL_CLK_MARK = 1
-+};
-+
-+static const unsigned long refclk_list[] = {
-+ 1000000,
-+ 2000000,
-+ 4000000,
-+ 5927000,
-+ 6000000,
-+ 7200000,
-+ 8000000,
-+ 10250000,
-+ 11059200,
-+ 12000000,
-+ 12288000,
-+ 13560000,
-+ 16000000,
-+ 19200000,
-+ 20000000,
-+ 22118000,
-+ 24000000,
-+ 24567000,
-+ 25000000,
-+ 26000000,
-+ 27000000,
-+ 30000000,
-+ 32000000,
-+ 33868800,
-+ 36000000,
-+ 36860000,
-+ 40000000,
-+ 44000000,
-+ 50000000,
-+ 54000000,
-+ 28224000,
-+ 28000000,
-+};
-+
-+struct sft_rtc {
-+ struct rtc_device *rtc_dev;
-+ struct completion cal_done;
-+ struct completion onesec_done;
-+ struct clk *pclk;
-+ struct clk *cal_clk;
-+ struct reset_control *rst_array;
-+ int hw_cal_map;
-+ void __iomem *regs;
-+ int rtc_irq;
-+ int ms_pulse_irq;
-+ int one_sec_pulse_irq;
-+};
-+
-+static inline void sft_rtc_set_enabled(struct sft_rtc *srtc, bool enabled)
-+{
-+ u32 val;
-+
-+ if (enabled) {
-+ val = readl(srtc->regs + SFT_RTC_CFG);
-+ val |= BIT(RTC_CFG_ENABLE_SHIFT);
-+ writel(val, srtc->regs + SFT_RTC_CFG);
-+ } else {
-+ val = readl(srtc->regs + SFT_RTC_CFG);
-+ val &= ~BIT(RTC_CFG_ENABLE_SHIFT);
-+ writel(val, srtc->regs + SFT_RTC_CFG);
-+ }
-+}
-+
-+static inline bool sft_rtc_get_enabled(struct sft_rtc *srtc)
-+{
-+ return !!(readl(srtc->regs + SFT_RTC_CFG) & BIT(RTC_CFG_ENABLE_SHIFT));
-+}
-+
-+static inline void sft_rtc_set_mode(struct sft_rtc *srtc, enum RTC_HOUR_MODE mode)
-+{
-+ u32 val;
-+
-+ val = readl(srtc->regs + SFT_RTC_CFG);
-+ val |= mode << RTC_CFG_HOUR_MODE_SHIFT;
-+ writel(val, srtc->regs + SFT_RTC_CFG);
-+}
-+
-+static inline int sft_rtc_irq_enable(struct sft_rtc *srtc, u32 irq, bool enable)
-+{
-+ u32 val;
-+
-+ if (!(irq & RTC_IRQ_ALL))
-+ return -EINVAL;
-+
-+ if (enable) {
-+ val = readl(srtc->regs + SFT_RTC_IRQ_EN);
-+ val |= irq;
-+ writel(val, srtc->regs + SFT_RTC_IRQ_EN);
-+ } else {
-+ val = readl(srtc->regs + SFT_RTC_IRQ_EN);
-+ val &= ~irq;
-+ writel(val, srtc->regs + SFT_RTC_IRQ_EN);
-+ }
-+ return 0;
-+}
-+
-+static inline void
-+sft_rtc_set_cal_hw_enable(struct sft_rtc *srtc, bool enable)
-+{
-+ u32 val;
-+
-+ if (enable) {
-+ val = readl(srtc->regs + SFT_RTC_CFG);
-+ val |= BIT(RTC_CFG_CAL_EN_HW_SHIFT);
-+ writel(val, srtc->regs + SFT_RTC_CFG);
-+ } else {
-+ val = readl(srtc->regs + SFT_RTC_CFG);
-+ val &= ~BIT(RTC_CFG_CAL_EN_HW_SHIFT);
-+ writel(val, srtc->regs + SFT_RTC_CFG);
-+ }
-+}
-+
-+static inline void
-+sft_rtc_set_cal_mode(struct sft_rtc *srtc, enum RTC_CAL_MODE mode)
-+{
-+ u32 val;
-+
-+ val = readl(srtc->regs + SFT_RTC_CFG);
-+ val |= mode << RTC_CFG_CAL_SEL_SHIFT;
-+ writel(val, srtc->regs + SFT_RTC_CFG);
-+}
-+
-+static int sft_rtc_get_hw_calclk(struct device *dev, unsigned long freq)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(refclk_list); i++)
-+ if (refclk_list[i] == freq)
-+ return i;
-+
-+ dev_err(dev, "refclk: %ldHz do not support.\n", freq);
-+ return -EINVAL;
-+}
-+
-+static inline void sft_rtc_reg2time(struct rtc_time *tm, u32 reg)
-+{
-+ tm->tm_hour = bcd2bin(FIELD_GET(TIME_HOUR_MASK, reg));
-+ tm->tm_min = bcd2bin(FIELD_GET(TIME_MIN_MASK, reg));
-+ tm->tm_sec = bcd2bin(FIELD_GET(TIME_SEC_MASK, reg));
-+}
-+
-+static inline void sft_rtc_reg2date(struct rtc_time *tm, u32 reg)
-+{
-+ tm->tm_year = bcd2bin(FIELD_GET(DATE_YEAR_MASK, reg)) + 100;
-+ tm->tm_mon = bcd2bin(FIELD_GET(DATE_MON_MASK, reg)) - 1;
-+ tm->tm_mday = bcd2bin(FIELD_GET(DATE_DAY_MASK, reg));
-+}
-+
-+static inline u32 sft_rtc_time2reg(struct rtc_time *tm)
-+{
-+ return FIELD_PREP(TIME_HOUR_MASK, bin2bcd(tm->tm_hour)) |
-+ FIELD_PREP(TIME_MIN_MASK, bin2bcd(tm->tm_min)) |
-+ FIELD_PREP(TIME_SEC_MASK, bin2bcd(tm->tm_sec));
-+}
-+
-+static inline u32 sft_rtc_date2reg(struct rtc_time *tm)
-+{
-+ return FIELD_PREP(DATE_YEAR_MASK, bin2bcd(tm->tm_year - 100)) |
-+ FIELD_PREP(DATE_MON_MASK, bin2bcd(tm->tm_mon + 1)) |
-+ FIELD_PREP(DATE_DAY_MASK, bin2bcd(tm->tm_mday));
-+}
-+
-+static inline void sft_rtc_update_pulse(struct sft_rtc *srtc)
-+{
-+ u32 val;
-+
-+ val = readl(srtc->regs + SFT_RTC_IRQ_EVEVT);
-+ val |= RTC_IRQ_EVT_UPDATE_PSE;
-+ writel(val, srtc->regs + SFT_RTC_IRQ_EVEVT);
-+}
-+
-+static irqreturn_t sft_rtc_irq_handler(int irq, void *data)
-+{
-+ struct sft_rtc *srtc = data;
-+ struct timerqueue_node *next;
-+ u32 irq_flags = 0;
-+ u32 irq_mask = 0;
-+ u32 val;
-+ int ret = 0;
-+
-+ val = readl(srtc->regs + SFT_RTC_IRQ_EVEVT);
-+ if (val & RTC_IRQ_CAL_START)
-+ irq_mask |= RTC_IRQ_CAL_START;
-+
-+ if (val & RTC_IRQ_CAL_FINISH) {
-+ irq_mask |= RTC_IRQ_CAL_FINISH;
-+ complete(&srtc->cal_done);
-+ }
-+
-+ if (val & RTC_IRQ_CMP)
-+ irq_mask |= RTC_IRQ_CMP;
-+
-+ if (val & RTC_IRQ_1SEC) {
-+ irq_flags |= RTC_PF;
-+ irq_mask |= RTC_IRQ_1SEC;
-+ complete(&srtc->onesec_done);
-+ }
-+
-+ if (val & RTC_IRQ_ALAEM) {
-+ irq_flags |= RTC_AF;
-+ irq_mask |= RTC_IRQ_ALAEM;
-+
-+ next = timerqueue_getnext(&srtc->rtc_dev->timerqueue);
-+ if (next == &srtc->rtc_dev->aie_timer.node)
-+ dev_info(&srtc->rtc_dev->dev, "alarm expires");
-+ }
-+
-+ writel(irq_mask, srtc->regs + SFT_RTC_IRQ_EVEVT);
-+
-+ /* Wait interrupt flag clear */
-+ ret = readl_poll_timeout_atomic(srtc->regs + SFT_RTC_IRQ_EVEVT, val,
-+ (val & irq_mask) == 0, 0, INT_TIMEOUT_US);
-+ if (ret)
-+ dev_warn(&srtc->rtc_dev->dev, "fail to clear rtc interrupt flag\n");
-+
-+ if (irq_flags)
-+ rtc_update_irq(srtc->rtc_dev, 1, irq_flags | RTC_IRQF);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int sft_rtc_read_time(struct device *dev, struct rtc_time *tm)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+ u32 val;
-+ int irq_1sec_state_start, irq_1sec_state_end;
-+
-+ /* If the RTC is disabled, assume the values are invalid */
-+ if (!sft_rtc_get_enabled(srtc))
-+ return -EINVAL;
-+
-+ irq_1sec_state_start =
-+ (readl(srtc->regs + SFT_RTC_IRQ_STATUS) & RTC_IRQ_1SEC) == 0 ? 0 : 1;
-+
-+read_again:
-+ val = readl(srtc->regs + SFT_RTC_TIME);
-+ sft_rtc_reg2time(tm, val);
-+
-+ val = readl(srtc->regs + SFT_RTC_DATE);
-+ sft_rtc_reg2date(tm, val);
-+
-+ if (irq_1sec_state_start == 0) {
-+ irq_1sec_state_end =
-+ (readl(srtc->regs + SFT_RTC_IRQ_STATUS) & RTC_IRQ_1SEC) == 0 ? 0 : 1;
-+ if (irq_1sec_state_end == 1) {
-+ irq_1sec_state_start = 1;
-+ goto read_again;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int sft_rtc_set_time(struct device *dev, struct rtc_time *tm)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+ u32 val;
-+ int ret;
-+
-+ val = sft_rtc_time2reg(tm);
-+ writel(val, srtc->regs + SFT_RTC_CFG_TIME);
-+
-+ val = sft_rtc_date2reg(tm);
-+ writel(val, srtc->regs + SFT_RTC_CFG_DATE);
-+
-+ /* Update pulse */
-+ sft_rtc_update_pulse(srtc);
-+
-+ /* Ensure that data is fully written */
-+ ret = wait_for_completion_interruptible_timeout(&srtc->onesec_done,
-+ usecs_to_jiffies(120));
-+ if (ret) {
-+ dev_warn(dev,
-+ "rtc wait for completion interruptible timeout.\n");
-+ }
-+ return 0;
-+}
-+
-+static int sft_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+
-+ return sft_rtc_irq_enable(srtc, RTC_IRQ_ALAEM, enabled);
-+}
-+
-+static int sft_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+ u32 val;
-+
-+ val = readl(srtc->regs + SFT_RTC_ACT_TIME);
-+ sft_rtc_reg2time(&alarm->time, val);
-+
-+ val = readl(srtc->regs + SFT_RTC_ACT_DATE);
-+ sft_rtc_reg2date(&alarm->time, val);
-+
-+ return 0;
-+}
-+
-+static int sft_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+ u32 val;
-+
-+ sft_rtc_alarm_irq_enable(dev, 0);
-+
-+ val = sft_rtc_time2reg(&alarm->time);
-+ writel(val, srtc->regs + SFT_RTC_ACT_TIME);
-+
-+ val = sft_rtc_date2reg(&alarm->time);
-+ writel(val, srtc->regs + SFT_RTC_ACT_DATE);
-+
-+ sft_rtc_alarm_irq_enable(dev, alarm->enabled);
-+
-+ return 0;
-+}
-+
-+static int sft_rtc_get_offset(struct device *dev, long *offset)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+ s64 tmp;
-+ u32 val;
-+
-+ val = readl(srtc->regs + SFT_RTC_CAL_VALUE)
-+ & RTC_SW_CAL_VALUE_MASK;
-+ val += 1;
-+ /*
-+ * the adjust val range is [0x0000-0xffff],
-+ * the default val is 0x7fff (32768-1),mapping offset=0 ;
-+ */
-+ tmp = (s64)val - RTC_TICKS_PER_SEC;
-+ tmp *= RTC_PPB_MULT;
-+ tmp = div_s64(tmp, RTC_TICKS_PER_SEC);
-+
-+ /* Offset value operates in negative way, so swap sign */
-+ *offset = -tmp;
-+
-+ return 0;
-+}
-+
-+static int sft_rtc_set_offset(struct device *dev, long offset)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+ s64 tmp;
-+ u32 val;
-+
-+ tmp = offset * RTC_TICKS_PER_SEC;
-+ tmp = div_s64(tmp, RTC_PPB_MULT);
-+
-+ tmp = RTC_TICKS_PER_SEC - tmp;
-+ tmp -= 1;
-+ if (tmp > RTC_SW_CAL_MAX || tmp < RTC_SW_CAL_MIN) {
-+ dev_err(dev, "offset is out of range.\n");
-+ return -EINVAL;
-+ }
-+
-+ val = tmp & RTC_SW_CAL_VALUE_MASK;
-+ /* set software calibration value */
-+ writel(val, srtc->regs + SFT_RTC_SW_CAL_VALUE);
-+
-+ /* set CFG_RTC-cal_sel to select calibretion by software. */
-+ sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_SW);
-+
-+ return 0;
-+}
-+
-+static __maybe_unused int
-+sft_rtc_hw_adjustment(struct device *dev, unsigned int enable)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+ u32 val;
-+
-+ if (srtc->hw_cal_map <= 0) {
-+ dev_err(dev, "fail to get cal-clock-freq.\n");
-+ return -EFAULT;
-+ }
-+
-+ if (enable) {
-+ sft_rtc_irq_enable(srtc, RTC_IRQ_CAL_FINISH, true);
-+
-+ /* Set reference clock frequency value */
-+ val = readl(srtc->regs + SFT_RTC_HW_CAL_CFG);
-+ val |= (srtc->hw_cal_map << RTC_HW_CAL_FRQ_SEL_SHIFT);
-+ writel(val, srtc->regs + SFT_RTC_HW_CAL_CFG);
-+
-+ /* Set CFG_RTC-cal_sel to select calibretion by hardware. */
-+ sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_HW);
-+
-+ /* Set CFG_RTC-cal_en_hw to launch hardware calibretion.*/
-+ sft_rtc_set_cal_hw_enable(srtc, true);
-+
-+ wait_for_completion_interruptible_timeout(&srtc->cal_done,
-+ usecs_to_jiffies(100));
-+
-+ sft_rtc_irq_enable(srtc, RTC_IRQ_CAL_FINISH, false);
-+ } else {
-+ sft_rtc_set_cal_mode(srtc, RTC_CAL_MODE_SW);
-+ sft_rtc_set_cal_hw_enable(srtc, false);
-+ }
-+
-+ return 0;
-+}
-+
-+static int sft_rtc_get_cal_clk(struct device *dev, struct sft_rtc *srtc)
-+{
-+ struct device_node *np = dev->of_node;
-+ unsigned long cal_clk_freq;
-+ u32 freq;
-+ int ret;
-+
-+ srtc->cal_clk = devm_clk_get(dev, "cal_clk");
-+ if (IS_ERR(srtc->cal_clk))
-+ return PTR_ERR(srtc->cal_clk);
-+
-+ clk_prepare_enable(srtc->cal_clk);
-+
-+ cal_clk_freq = clk_get_rate(srtc->cal_clk);
-+ if (!cal_clk_freq) {
-+ dev_warn(dev,
-+ "get rate failed, next try to get from dts.\n");
-+ ret = of_property_read_u32(np, "rtc,cal-clock-freq", &freq);
-+ if (!ret) {
-+ cal_clk_freq = (u64)freq;
-+ } else {
-+ dev_err(dev,
-+ "Need rtc,cal-clock-freq define in dts.\n");
-+ goto err_disable_cal_clk;
-+ }
-+ }
-+
-+ srtc->hw_cal_map = sft_rtc_get_hw_calclk(dev, cal_clk_freq);
-+ if (srtc->hw_cal_map < 0) {
-+ ret = srtc->hw_cal_map;
-+ goto err_disable_cal_clk;
-+ }
-+
-+ return 0;
-+
-+err_disable_cal_clk:
-+ clk_disable_unprepare(srtc->cal_clk);
-+
-+ return ret;
-+}
-+
-+static int sft_rtc_get_irq(struct platform_device *pdev, struct sft_rtc *srtc)
-+{
-+ int ret;
-+
-+ srtc->rtc_irq = platform_get_irq_byname(pdev, "rtc");
-+ if (srtc->rtc_irq < 0)
-+ return -EINVAL;
-+
-+ ret = devm_request_irq(&pdev->dev, srtc->rtc_irq,
-+ sft_rtc_irq_handler, 0,
-+ KBUILD_MODNAME, srtc);
-+ if (ret)
-+ dev_err(&pdev->dev, "Failed to request interrupt, %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static const struct rtc_class_ops starfive_rtc_ops = {
-+ .read_time = sft_rtc_read_time,
-+ .set_time = sft_rtc_set_time,
-+ .read_alarm = sft_rtc_read_alarm,
-+ .set_alarm = sft_rtc_set_alarm,
-+ .alarm_irq_enable = sft_rtc_alarm_irq_enable,
-+ .set_offset = sft_rtc_set_offset,
-+ .read_offset = sft_rtc_get_offset,
-+};
-+
-+static int sft_rtc_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct sft_rtc *srtc;
-+ struct rtc_time tm;
-+ struct irq_desc *desc;
-+ int ret;
-+
-+ srtc = devm_kzalloc(dev, sizeof(*srtc), GFP_KERNEL);
-+ if (!srtc)
-+ return -ENOMEM;
-+
-+ srtc->regs = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(srtc->regs))
-+ return PTR_ERR(srtc->regs);
-+
-+ srtc->pclk = devm_clk_get(dev, "pclk");
-+ if (IS_ERR(srtc->pclk)) {
-+ ret = PTR_ERR(srtc->pclk);
-+ dev_err(dev,
-+ "Failed to retrieve the peripheral clock, %d\n", ret);
-+ return ret;
-+ }
-+
-+ srtc->rst_array = devm_reset_control_array_get_exclusive(dev);
-+ if (IS_ERR(srtc->rst_array)) {
-+ ret = PTR_ERR(srtc->rst_array);
-+ dev_err(dev,
-+ "Failed to retrieve the rtc reset, %d\n", ret);
-+ return ret;
-+ }
-+
-+ init_completion(&srtc->cal_done);
-+ init_completion(&srtc->onesec_done);
-+
-+ ret = clk_prepare_enable(srtc->pclk);
-+ if (ret) {
-+ dev_err(dev,
-+ "Failed to enable the peripheral clock, %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = sft_rtc_get_cal_clk(dev, srtc);
-+ if (ret)
-+ goto err_disable_pclk;
-+
-+ ret = reset_control_deassert(srtc->rst_array);
-+ if (ret) {
-+ dev_err(dev,
-+ "Failed to deassert rtc resets, %d\n", ret);
-+ goto err_disable_cal_clk;
-+ }
-+
-+ ret = sft_rtc_get_irq(pdev, srtc);
-+ if (ret)
-+ goto err_disable_cal_clk;
-+
-+ srtc->rtc_dev = devm_rtc_allocate_device(dev);
-+ if (IS_ERR(srtc->rtc_dev))
-+ return PTR_ERR(srtc->rtc_dev);
-+
-+ platform_set_drvdata(pdev, srtc);
-+
-+ /* The RTC supports 01.01.2001 - 31.12.2099 */
-+ srtc->rtc_dev->range_min = mktime64(2001, 1, 1, 0, 0, 0);
-+ srtc->rtc_dev->range_max = mktime64(2099, 12, 31, 23, 59, 59);
-+
-+ srtc->rtc_dev->ops = &starfive_rtc_ops;
-+ device_init_wakeup(dev, true);
-+
-+ desc = irq_to_desc(srtc->rtc_irq);
-+ irq_desc_get_chip(desc)->flags = IRQCHIP_SKIP_SET_WAKE;
-+
-+ /* Always use 24-hour mode and keep the RTC values */
-+ sft_rtc_set_mode(srtc, RTC_HOUR_MODE_24H);
-+
-+ sft_rtc_set_enabled(srtc, true);
-+
-+ if (device_property_read_bool(dev, "rtc,hw-adjustment"))
-+ sft_rtc_hw_adjustment(dev, true);
-+
-+ /*
-+ * If rtc time is out of supported range, reset it to the minimum time.
-+ * notice that, actual year = 1900 + tm.tm_year
-+ * actual month = 1 + tm.tm_mon
-+ */
-+ sft_rtc_read_time(dev, &tm);
-+ if (tm.tm_year < 101 || tm.tm_year > 199 || tm.tm_mon < 0 || tm.tm_mon > 11 ||
-+ tm.tm_mday < 1 || tm.tm_mday > 31 || tm.tm_hour < 0 || tm.tm_hour > 23 ||
-+ tm.tm_min < 0 || tm.tm_min > 59 || tm.tm_sec < 0 || tm.tm_sec > 59) {
-+ rtc_time64_to_tm(srtc->rtc_dev->range_min, &tm);
-+ sft_rtc_set_time(dev, &tm);
-+ }
-+
-+ ret = devm_rtc_register_device(srtc->rtc_dev);
-+ if (ret)
-+ goto err_disable_wakeup;
-+
-+ return 0;
-+
-+err_disable_wakeup:
-+ device_init_wakeup(dev, false);
-+
-+err_disable_cal_clk:
-+ clk_disable_unprepare(srtc->cal_clk);
-+
-+err_disable_pclk:
-+ clk_disable_unprepare(srtc->pclk);
-+
-+ return ret;
-+}
-+
-+static int 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);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM_SLEEP
-+static int sft_rtc_suspend(struct device *dev)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+
-+ if (device_may_wakeup(dev))
-+ enable_irq_wake(srtc->rtc_irq);
-+
-+ return 0;
-+}
-+
-+static int sft_rtc_resume(struct device *dev)
-+{
-+ struct sft_rtc *srtc = dev_get_drvdata(dev);
-+
-+ if (device_may_wakeup(dev))
-+ disable_irq_wake(srtc->rtc_irq);
-+
-+ return 0;
-+}
-+#endif
-+
-+static SIMPLE_DEV_PM_OPS(sft_rtc_pm_ops, sft_rtc_suspend, sft_rtc_resume);
-+
-+static const struct of_device_id sft_rtc_of_match[] = {
-+ { .compatible = "starfive,jh7110-rtc" },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(of, sft_rtc_of_match);
-+
-+static struct platform_driver starfive_rtc_driver = {
-+ .driver = {
-+ .name = "starfive-rtc",
-+ .of_match_table = sft_rtc_of_match,
-+ .pm = &sft_rtc_pm_ops,
-+ },
-+ .probe = sft_rtc_probe,
-+ .remove = sft_rtc_remove,
-+};
-+module_platform_driver(starfive_rtc_driver);
-+
-+MODULE_AUTHOR("Samin Guo <samin.guo@starfivetech.com>");
-+MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
-+MODULE_DESCRIPTION("StarFive RTC driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:starfive-rtc");
+++ /dev/null
-From 552114b8cbbd956ad8466261b5f11b059eba82ca Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Sun, 25 Jun 2023 09:40:29 +0800
-Subject: [PATCH 066/116] uart: 8250: Add dw auto flow ctrl support
-
-Add designeware 8250 auto flow ctrl support. Enable
-it by add auto-flow-control in dts.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
----
- drivers/tty/serial/8250/8250_core.c | 2 ++
- drivers/tty/serial/8250/8250_dw.c | 3 +++
- drivers/tty/serial/8250/8250_port.c | 14 +++++++++++++-
- include/linux/serial_8250.h | 1 +
- include/uapi/linux/serial_core.h | 2 ++
- 5 files changed, 21 insertions(+), 1 deletion(-)
-
---- a/drivers/tty/serial/8250/8250_core.c
-+++ b/drivers/tty/serial/8250/8250_core.c
-@@ -1129,6 +1129,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
-@@ -612,6 +612,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(dev, "baudclk");
- if (data->clk == NULL)
---- a/drivers/tty/serial/8250/8250_port.c
-+++ b/drivers/tty/serial/8250/8250_port.c
-@@ -330,6 +330,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 */
-@@ -1143,6 +1151,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;
-+ }
- }
-
- /*
-@@ -2822,7 +2835,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
-@@ -245,4 +245,6 @@
- /* Sunplus UART */
- #define PORT_SUNPLUS 123
-
-+#define PORT_16550A_AFE 124
-+
- #endif /* _UAPILINUX_SERIAL_CORE_H */
+++ /dev/null
-From 6edee93a89254f30c3387c88231e7ecec06ba84a Mon Sep 17 00:00:00 2001
-From: "shanlong.li" <shanlong.li@starfivetech.com>
-Date: Mon, 10 Jul 2023 03:07:57 -0700
-Subject: [PATCH 067/116] driver:uart: fix up uart communicate fail
-
-fix up uart communicate fail
-
-Signed-off-by: shanlong.li <shanlong.li@starfivetech.com>
----
- drivers/tty/serial/8250/8250_dw.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
---- a/drivers/tty/serial/8250/8250_dw.c
-+++ b/drivers/tty/serial/8250/8250_dw.c
-@@ -652,10 +652,10 @@ static int dw8250_probe(struct platform_
- if (err)
- return err;
-
-- data->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
-- if (IS_ERR(data->rst))
-- return PTR_ERR(data->rst);
--
-+ data->rst = devm_reset_control_array_get_exclusive(dev);
-+ if (IS_ERR(data->rst)) {
-+ err = PTR_ERR(data->rst);
-+ }
- reset_control_deassert(data->rst);
-
- err = devm_add_action_or_reset(dev, dw8250_reset_control_assert, data->rst);
+++ /dev/null
-From 777d288f03a0b350f6c2d4367b01a80d9f25cd6e Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Wed, 20 Sep 2023 17:19:59 +0800
-Subject: [PATCH 068/116] uart: 8250: add reset operation in runtime PM
-
-add reset operation in runtime PM
-
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
----
- drivers/tty/serial/8250/8250_dw.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/tty/serial/8250/8250_dw.c
-+++ b/drivers/tty/serial/8250/8250_dw.c
-@@ -745,6 +745,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);
-@@ -760,6 +762,8 @@ static int dw8250_runtime_resume(struct
-
- clk_prepare_enable(data->clk);
-
-+ reset_control_deassert(data->rst);
-+
- return 0;
- }
-
+++ /dev/null
-From 5eda2331a252436756fb40861f01a7a38b1502c7 Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Thu, 15 Jun 2023 20:14:22 +0800
-Subject: [PATCH 069/116] dt-bindings: CAN: Add StarFive CAN module
-
-Add documentation to describe StarFive CAN engine.
-
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
----
- .../devicetree/bindings/net/can/ipms-can.yaml | 97 +++++++++++++++++++
- 1 file changed, 97 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/net/can/ipms-can.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/can/ipms-can.yaml
-@@ -0,0 +1,97 @@
-+# SPDX-License-Identifier: GPL-2.0
-+%YAML 1.2
-+---
-+#$id: http://devicetree.org/schemas/net/can/ipms-can.yaml#
-+#$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: IPMS CAN/CANFD controller Device Tree Bindings
-+
-+properties:
-+ compatible:
-+ const:ipms,can
-+
-+ reg:
-+ maxItems: 1
-+ items:
-+ - description:CAN controller registers
-+
-+ interrupts:
-+ maxItems: 1
-+
-+ clocks:
-+ minItems: 1
-+ items:
-+ - description:apb_clk clock
-+ - description:core_clk clock
-+ - description:timer_clk clock
-+
-+ clock-names:
-+ minItems: 1
-+ items:
-+ - const:apb_clk
-+ - const:core_clk
-+ - const:timer_clk
-+ resets:
-+ minItems: 1
-+ items:
-+ - description:apb_clk reset
-+ - description:core_clk reset
-+ - description:timer_clk reset
-+ reset-names:
-+ minItems: 1
-+ items:
-+ - const:rst_apb
-+ - const:rst_core
-+ - const:rst_timer
-+ starfive,sys-syscon:
-+ format:
-+ starfive,sys-syscon = <&arg0 arg1 arg2 arg3>
-+ description:
-+ arg0:arg0 is sys_syscon.
-+ arg1:arg1 is syscon register offset, used to enable can2.0/canfd function, can0 is 0x10, can1 is 0x88.
-+ arg2:arg2 is used to enable the register shift of the can2.0/canfd function, can0 is 0x3, can1 is 0x12.
-+ arg3:arg3 is used to enable the register mask of the can2.0/canfd function, can0 is 0x8, can1 is 0x40000
-+
-+ syscon,can_or_canfd:
-+ description:
-+ IPMS CAN-CTRL core is a serial communications controller that performs serial communication according to the CAN protocol.
-+ This CAN bus interface uses the basic CAN principle and meets all constraints of the CAN-specification 2.0B active.
-+ Furthermore this CAN core can be configured to meet the specification of CAN with flexible data rate CAN FD.
-+ When syscon,can_or_canfd is set to 0, use CAN2.0B.
-+ when syscon,can_or_canfd is set to 1, use CAN FD.
-+required:
-+ - compatible
-+ - reg
-+ - interrupts
-+ - clocks
-+ - clock-names
-+ - resets
-+ - reset-names
-+ - starfive,sys-syscon
-+ - syscon,can_or_canfd
-+additionalProperties:false
-+
-+examples:
-+ - |
-+ can0: can@130d0000{
-+ compatible = "ipms,can";
-+ reg = <0x0 0x130d0000 0x0 0x1000>;
-+ interrupts = <112>;
-+ interrupt-parent = <&plic>;
-+ clocks = <&clkgen JH7110_CAN0_CTRL_CLK_APB>,
-+ <&clkgen JH7110_CAN0_CTRL_CLK_CAN>,
-+ <&clkgen JH7110_CAN0_CTRL_CLK_TIMER>;
-+ clock-names = "apb_clk",
-+ "core_clk",
-+ "timer_clk";
-+ resets = <&rstgen RSTN_U0_CAN_CTRL_APB>,
-+ <&rstgen RSTN_U0_CAN_CTRL_CORE>,
-+ <&rstgen RSTN_U0_CAN_CTRL_TIMER>;
-+ reset-names = "rst_apb",
-+ "rst_core",
-+ "rst_timer";
-+ starfive,sys-syscon = <&sys_syscon, 0x10 0x3 0x8>;
-+ syscon,can_or_canfd = <0>;
-+ };
-+
-+...
+++ /dev/null
-From b1fbe15b87be654b1b280a76ec1470917d79f720 Mon Sep 17 00:00:00 2001
-From: William Qiu <william.qiu@starfivetech.com>
-Date: Thu, 15 Jun 2023 20:15:25 +0800
-Subject: [PATCH 070/116] CAN: starfive - Add CAN engine support
-
-Adding device probe StarFive CAN module.
-
-Signed-off-by: William Qiu <william.qiu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/net/can/Kconfig | 5 +
- drivers/net/can/Makefile | 1 +
- drivers/net/can/ipms_canfd.c | 1275 ++++++++++++++++++++++++++++++++++
- 3 files changed, 1281 insertions(+)
- create mode 100644 drivers/net/can/ipms_canfd.c
-
---- a/drivers/net/can/Kconfig
-+++ b/drivers/net/can/Kconfig
-@@ -214,6 +214,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
-@@ -31,5 +31,6 @@ 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
-
- subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
---- /dev/null
-+++ b/drivers/net/can/ipms_canfd.c
-@@ -0,0 +1,1275 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * StarFive Controller Area Network Host Controller Driver
-+ *
-+ * Copyright (c) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/reset.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/can/dev.h>
-+#include <linux/can/error.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/of_device.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/regmap.h>
-+
-+#define DRIVER_NAME "ipms_canfd"
-+
-+/* CAN registers set */
-+enum canfd_device_reg {
-+ CANFD_RUBF_OFFSET = 0x00, /* Receive Buffer Registers 0x00-0x4f */
-+ CANFD_RUBF_ID_OFFSET = 0x00,
-+ CANFD_RBUF_CTL_OFFSET = 0x04,
-+ CANFD_RBUF_DATA_OFFSET = 0x08,
-+ CANFD_TBUF_OFFSET = 0x50, /* Transmit Buffer Registers 0x50-0x97 */
-+ CANFD_TBUF_ID_OFFSET = 0x50,
-+ CANFD_TBUF_CTL_OFFSET = 0x54,
-+ CANFD_TBUF_DATA_OFFSET = 0x58,
-+ CANFD_TTS_OFFSET = 0x98, /* Transmission Time Stamp 0x98-0x9f */
-+ CANFD_CFG_STAT_OFFSET = 0xa0,
-+ CANFD_TCMD_OFFSET = 0xa1,
-+ CANFD_TCTRL_OFFSET = 0xa2,
-+ CANFD_RCTRL_OFFSET = 0xa3,
-+ CANFD_RTIE_OFFSET = 0xa4,
-+ CANFD_RTIF_OFFSET = 0xa5,
-+ CANFD_ERRINT_OFFSET = 0xa6,
-+ CANFD_LIMIT_OFFSET = 0xa7,
-+ CANFD_S_SEG_1_OFFSET = 0xa8,
-+ CANFD_S_SEG_2_OFFSET = 0xa9,
-+ CANFD_S_SJW_OFFSET = 0xaa,
-+ CANFD_S_PRESC_OFFSET = 0xab,
-+ CANFD_F_SEG_1_OFFSET = 0xac,
-+ CANFD_F_SEG_2_OFFSET = 0xad,
-+ CANFD_F_SJW_OFFSET = 0xae,
-+ CANFD_F_PRESC_OFFSET = 0xaf,
-+ CANFD_EALCAP_OFFSET = 0xb0,
-+ CANFD_RECNT_OFFSET = 0xb2,
-+ CANFD_TECNT_OFFSET = 0xb3,
-+};
-+
-+enum canfd_reg_bitchange {
-+ CAN_FD_SET_RST_MASK = 0x80, /* Set Reset Bit */
-+ CAN_FD_OFF_RST_MASK = 0x7f, /* Reset Off Bit */
-+ CAN_FD_SET_FULLCAN_MASK = 0x10, /* set TTTBM as 1->full TTCAN mode */
-+ CAN_FD_OFF_FULLCAN_MASK = 0xef, /* set TTTBM as 0->separate PTB and STB mode */
-+ CAN_FD_SET_FIFO_MASK = 0x20, /* set TSMODE as 1->FIFO mode */
-+ CAN_FD_OFF_FIFO_MASK = 0xdf, /* set TSMODE as 0->Priority mode */
-+ CAN_FD_SET_TSONE_MASK = 0x04,
-+ CAN_FD_OFF_TSONE_MASK = 0xfb,
-+ CAN_FD_SET_TSALL_MASK = 0x02,
-+ CAN_FD_OFF_TSALL_MASK = 0xfd,
-+ CAN_FD_LBMEMOD_MASK = 0x40, /* set loop back mode, external */
-+ CAN_FD_LBMIMOD_MASK = 0x20, /* set loopback internal mode */
-+ CAN_FD_SET_BUSOFF_MASK = 0x01,
-+ CAN_FD_OFF_BUSOFF_MASK = 0xfe,
-+ CAN_FD_SET_TTSEN_MASK = 0x80, /* set ttsen, tts update enable */
-+ CAN_FD_SET_BRS_MASK = 0x10, /* can fd Bit Rate Switch mask */
-+ CAN_FD_OFF_BRS_MASK = 0xef,
-+ CAN_FD_SET_EDL_MASK = 0x20, /* Extended Data Length */
-+ CAN_FD_OFF_EDL_MASK = 0xdf,
-+ CAN_FD_SET_DLC_MASK = 0x0f,
-+ CAN_FD_SET_TENEXT_MASK = 0x40,
-+ CAN_FD_SET_IDE_MASK = 0x80,
-+ CAN_FD_OFF_IDE_MASK = 0x7f,
-+ CAN_FD_SET_RTR_MASK = 0x40,
-+ CAN_FD_OFF_RTR_MASK = 0xbf,
-+ CAN_FD_INTR_ALL_MASK = 0xff, /* all interrupts enable mask */
-+ CAN_FD_SET_RIE_MASK = 0x80,
-+ CAN_FD_OFF_RIE_MASK = 0x7f,
-+ CAN_FD_SET_RFIE_MASK = 0x20,
-+ CAN_FD_OFF_RFIE_MASK = 0xdf,
-+ CAN_FD_SET_RAFIE_MASK = 0x10,
-+ CAN_FD_OFF_RAFIE_MASK = 0xef,
-+ CAN_FD_SET_EIE_MASK = 0x02,
-+ CAN_FD_OFF_EIE_MASK = 0xfd,
-+ CAN_FD_TASCTIVE_MASK = 0x02,
-+ CAN_FD_RASCTIVE_MASK = 0x04,
-+ CAN_FD_SET_TBSEL_MASK = 0x80, /* message writen in STB */
-+ CAN_FD_OFF_TBSEL_MASK = 0x7f, /* message writen in PTB */
-+ CAN_FD_SET_STBY_MASK = 0x20,
-+ CAN_FD_OFF_STBY_MASK = 0xdf,
-+ CAN_FD_SET_TPE_MASK = 0x10, /* Transmit primary enable */
-+ CAN_FD_SET_TPA_MASK = 0x08,
-+ CAN_FD_SET_SACK_MASK = 0x80,
-+ CAN_FD_SET_RREL_MASK = 0x10,
-+ CAN_FD_RSTAT_NOT_EMPTY_MASK = 0x03,
-+ CAN_FD_SET_RIF_MASK = 0x80,
-+ CAN_FD_OFF_RIF_MASK = 0x7f,
-+ CAN_FD_SET_RAFIF_MASK = 0x10,
-+ CAN_FD_SET_RFIF_MASK = 0x20,
-+ CAN_FD_SET_TPIF_MASK = 0x08, /* Transmission Primary Interrupt Flag */
-+ CAN_FD_SET_TSIF_MASK = 0x04,
-+ CAN_FD_SET_EIF_MASK = 0x02,
-+ CAN_FD_SET_AIF_MASK = 0x01,
-+ CAN_FD_SET_EWARN_MASK = 0x80,
-+ CAN_FD_SET_EPASS_MASK = 0x40,
-+ CAN_FD_SET_EPIE_MASK = 0x20,
-+ CAN_FD_SET_EPIF_MASK = 0x10,
-+ CAN_FD_SET_ALIE_MASK = 0x08,
-+ CAN_FD_SET_ALIF_MASK = 0x04,
-+ CAN_FD_SET_BEIE_MASK = 0x02,
-+ CAN_FD_SET_BEIF_MASK = 0x01,
-+ CAN_FD_OFF_EPIE_MASK = 0xdf,
-+ CAN_FD_OFF_BEIE_MASK = 0xfd,
-+ CAN_FD_SET_AFWL_MASK = 0x40,
-+ CAN_FD_SET_EWL_MASK = 0x0b,
-+ CAN_FD_SET_KOER_MASK = 0xe0,
-+ CAN_FD_SET_BIT_ERROR_MASK = 0x20,
-+ CAN_FD_SET_FORM_ERROR_MASK = 0x40,
-+ CAN_FD_SET_STUFF_ERROR_MASK = 0x60,
-+ CAN_FD_SET_ACK_ERROR_MASK = 0x80,
-+ CAN_FD_SET_CRC_ERROR_MASK = 0xa0,
-+ CAN_FD_SET_OTH_ERROR_MASK = 0xc0,
-+};
-+
-+/* seg1,seg2,sjw,prescaler all have 8 bits */
-+#define BITS_OF_BITTIMING_REG 8
-+
-+/* in can_bittiming strucure every field has 32 bits---->u32 */
-+#define FBITS_IN_BITTIMING_STR 32
-+#define SEG_1_SHIFT 0
-+#define SEG_2_SHIFT 8
-+#define SJW_SHIFT 16
-+#define PRESC_SHIFT 24
-+
-+/* TTSEN bit used for 32 bit register read or write */
-+#define TTSEN_8_32_SHIFT 24
-+#define RTR_32_8_SHIFT 24
-+
-+/* transmit mode */
-+#define XMIT_FULL 0
-+#define XMIT_SEP_FIFO 1
-+#define XMIT_SEP_PRIO 2
-+#define XMIT_PTB_MODE 3
-+
-+enum IPMS_CAN_TYPE {
-+ IPMS_CAN_TYPY_CAN = 0,
-+ IPMS_CAN_TYPE_CANFD,
-+};
-+
-+struct ipms_canfd_priv {
-+ struct can_priv can;
-+ struct napi_struct napi;
-+ struct device *dev;
-+ struct regmap *reg_syscon;
-+ void __iomem *reg_base;
-+ u32 (*read_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg);
-+ void (*write_reg)(const struct ipms_canfd_priv *priv, enum canfd_device_reg reg, u32 val);
-+ struct clk *can_clk;
-+ u32 tx_mode;
-+ struct reset_control *resets;
-+ struct clk_bulk_data *clks;
-+ int nr_clks;
-+ u32 can_or_canfd;
-+};
-+
-+static struct can_bittiming_const canfd_bittiming_const = {
-+ .name = DRIVER_NAME,
-+ .tseg1_min = 2,
-+ .tseg1_max = 16,
-+ .tseg2_min = 2,
-+ .tseg2_max = 8,
-+ .sjw_max = 4,
-+ .brp_min = 1,
-+ .brp_max = 512,
-+ .brp_inc = 1,
-+
-+};
-+
-+static struct can_bittiming_const canfd_data_bittiming_const = {
-+ .name = DRIVER_NAME,
-+ .tseg1_min = 1,
-+ .tseg1_max = 16,
-+ .tseg2_min = 2,
-+ .tseg2_max = 8,
-+ .sjw_max = 8,
-+ .brp_min = 1,
-+ .brp_max = 512,
-+ .brp_inc = 1,
-+};
-+
-+static void canfd_write_reg_le(const struct ipms_canfd_priv *priv,
-+ enum canfd_device_reg reg, u32 val)
-+{
-+ iowrite32(val, priv->reg_base + reg);
-+}
-+
-+static u32 canfd_read_reg_le(const struct ipms_canfd_priv *priv,
-+ enum canfd_device_reg reg)
-+{
-+ return ioread32(priv->reg_base + reg);
-+}
-+
-+static inline unsigned char can_ioread8(const void *addr)
-+{
-+ void *addr_down;
-+ union val {
-+ u8 val_8[4];
-+ u32 val_32;
-+ } val;
-+ u32 offset = 0;
-+
-+ addr_down = (void *)ALIGN_DOWN((unsigned long)addr, 4);
-+ offset = addr - addr_down;
-+ val.val_32 = ioread32(addr_down);
-+ return val.val_8[offset];
-+}
-+
-+static inline void can_iowrite8(unsigned char value, void *addr)
-+{
-+ void *addr_down;
-+ union val {
-+ u8 val_8[4];
-+ u32 val_32;
-+ } val;
-+ u8 offset = 0;
-+
-+ addr_down = (void *)ALIGN_DOWN((unsigned long)addr, 4);
-+ offset = addr - addr_down;
-+ val.val_32 = ioread32(addr_down);
-+ val.val_8[offset] = value;
-+ iowrite32(val.val_32, addr_down);
-+}
-+
-+static void canfd_reigister_set_bit(const struct ipms_canfd_priv *priv,
-+ enum canfd_device_reg reg,
-+ enum canfd_reg_bitchange set_mask)
-+{
-+ void *addr_down;
-+ union val {
-+ u8 val_8[4];
-+ u32 val_32;
-+ } val;
-+ u8 offset = 0;
-+
-+ addr_down = (void *)ALIGN_DOWN((unsigned long)(priv->reg_base + reg), 4);
-+ offset = (priv->reg_base + reg) - addr_down;
-+ val.val_32 = ioread32(addr_down);
-+ val.val_8[offset] |= set_mask;
-+ iowrite32(val.val_32, addr_down);
-+}
-+
-+static void canfd_reigister_off_bit(const struct ipms_canfd_priv *priv,
-+ enum canfd_device_reg reg,
-+ enum canfd_reg_bitchange set_mask)
-+{
-+ void *addr_down;
-+ union val {
-+ u8 val_8[4];
-+ u32 val_32;
-+ } val;
-+ u8 offset = 0;
-+
-+ addr_down = (void *)ALIGN_DOWN((unsigned long)(priv->reg_base + reg), 4);
-+ offset = (priv->reg_base + reg) - addr_down;
-+ val.val_32 = ioread32(addr_down);
-+ val.val_8[offset] &= set_mask;
-+ iowrite32(val.val_32, addr_down);
-+}
-+
-+static int canfd_device_driver_bittime_configuration(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ struct can_bittiming *bt = &priv->can.bittiming;
-+ struct can_bittiming *dbt = &priv->can.data_bittiming;
-+ u32 reset_test, bittiming_temp, dat_bittiming;
-+
-+ reset_test = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
-+
-+ if (!(reset_test & CAN_FD_SET_RST_MASK)) {
-+ netdev_alert(ndev, "Not in reset mode, cannot set bit timing\n");
-+ return -EPERM;
-+ }
-+
-+ bittiming_temp = ((bt->phase_seg1 + bt->prop_seg + 1 - 2) << SEG_1_SHIFT) |
-+ ((bt->phase_seg2 - 1) << SEG_2_SHIFT) |
-+ ((bt->sjw - 1) << SJW_SHIFT) |
-+ ((bt->brp - 1) << PRESC_SHIFT);
-+
-+ /* Check the bittime parameter */
-+ if ((((int)(bt->phase_seg1 + bt->prop_seg + 1) - 2) < 0) ||
-+ (((int)(bt->phase_seg2) - 1) < 0) ||
-+ (((int)(bt->sjw) - 1) < 0) ||
-+ (((int)(bt->brp) - 1) < 0))
-+ return -EINVAL;
-+
-+ priv->write_reg(priv, CANFD_S_SEG_1_OFFSET, bittiming_temp);
-+
-+ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) {
-+ dat_bittiming = ((dbt->phase_seg1 + dbt->prop_seg + 1 - 2) << SEG_1_SHIFT) |
-+ ((dbt->phase_seg2 - 1) << SEG_2_SHIFT) |
-+ ((dbt->sjw - 1) << SJW_SHIFT) |
-+ ((dbt->brp - 1) << PRESC_SHIFT);
-+
-+ if ((((int)(dbt->phase_seg1 + dbt->prop_seg + 1) - 2) < 0) ||
-+ (((int)(dbt->phase_seg2) - 1) < 0) ||
-+ (((int)(dbt->sjw) - 1) < 0) ||
-+ (((int)(dbt->brp) - 1) < 0))
-+ return -EINVAL;
-+
-+ priv->write_reg(priv, CANFD_F_SEG_1_OFFSET, dat_bittiming);
-+ }
-+
-+ canfd_reigister_off_bit(priv, CANFD_CFG_STAT_OFFSET, CAN_FD_OFF_RST_MASK);
-+
-+ netdev_dbg(ndev, "Slow bit rate: %08x\n", priv->read_reg(priv, CANFD_S_SEG_1_OFFSET));
-+ netdev_dbg(ndev, "Fast bit rate: %08x\n", priv->read_reg(priv, CANFD_F_SEG_1_OFFSET));
-+
-+ return 0;
-+}
-+
-+int canfd_get_freebuffer(struct ipms_canfd_priv *priv)
-+{
-+ /* Get next transmit buffer */
-+ canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_TENEXT_MASK);
-+
-+ if (can_ioread8(priv->reg_base + CANFD_TCTRL_OFFSET) & CAN_FD_SET_TENEXT_MASK)
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static void canfd_tx_interrupt(struct net_device *ndev, u8 isr)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+
-+ /* wait till transmission of the PTB or STB finished */
-+ while (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
-+ if (isr & CAN_FD_SET_TPIF_MASK)
-+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_TPIF_MASK);
-+
-+ if (isr & CAN_FD_SET_TSIF_MASK)
-+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_TSIF_MASK);
-+
-+ isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
-+ }
-+ netif_wake_queue(ndev);
-+}
-+
-+static int can_rx(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ struct net_device_stats *stats = &ndev->stats;
-+ struct can_frame *cf;
-+ struct sk_buff *skb;
-+ u32 can_id;
-+ u8 dlc, control, rx_status;
-+
-+ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
-+
-+ if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
-+ return 0;
-+ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
-+ can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
-+ dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
-+
-+ skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
-+ if (!skb) {
-+ stats->rx_dropped++;
-+ return 0;
-+ }
-+ cf->can_dlc = can_cc_dlc2len(dlc);
-+
-+ /* change the CANFD id into socketcan id format */
-+ if (control & CAN_FD_SET_IDE_MASK) {
-+ cf->can_id = can_id;
-+ cf->can_id |= CAN_EFF_FLAG;
-+ } else {
-+ cf->can_id = can_id;
-+ cf->can_id &= (~CAN_EFF_FLAG);
-+ }
-+
-+ if (control & CAN_FD_SET_RTR_MASK)
-+ cf->can_id |= CAN_RTR_FLAG;
-+
-+ if (!(control & CAN_FD_SET_RTR_MASK)) {
-+ *((u32 *)(cf->data + 0)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET);
-+ *((u32 *)(cf->data + 4)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + 4);
-+ }
-+
-+ canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK);
-+ stats->rx_bytes += can_fd_dlc2len(cf->can_dlc);
-+ stats->rx_packets++;
-+ netif_receive_skb(skb);
-+
-+ return 1;
-+}
-+
-+static int canfd_rx(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ struct net_device_stats *stats = &ndev->stats;
-+ struct canfd_frame *cf;
-+ struct sk_buff *skb;
-+ u32 can_id;
-+ u8 dlc, control, rx_status;
-+ int i;
-+
-+ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
-+
-+ if (!(rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK))
-+ return 0;
-+ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
-+ can_id = priv->read_reg(priv, CANFD_RUBF_ID_OFFSET);
-+ dlc = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET) & CAN_FD_SET_DLC_MASK;
-+
-+ if (control & CAN_FD_SET_EDL_MASK)
-+ /* allocate sk_buffer for canfd frame */
-+ skb = alloc_canfd_skb(ndev, &cf);
-+ else
-+ /* allocate sk_buffer for can frame */
-+ skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
-+
-+ if (!skb) {
-+ stats->rx_dropped++;
-+ return 0;
-+ }
-+
-+ /* change the CANFD or CAN2.0 data into socketcan data format */
-+ if (control & CAN_FD_SET_EDL_MASK)
-+ cf->len = can_fd_dlc2len(dlc);
-+ else
-+ cf->len = can_cc_dlc2len(dlc);
-+
-+ /* change the CANFD id into socketcan id format */
-+ if (control & CAN_FD_SET_EDL_MASK) {
-+ cf->can_id = can_id;
-+ if (control & CAN_FD_SET_IDE_MASK)
-+ cf->can_id |= CAN_EFF_FLAG;
-+ else
-+ cf->can_id &= (~CAN_EFF_FLAG);
-+ } else {
-+ cf->can_id = can_id;
-+ if (control & CAN_FD_SET_IDE_MASK)
-+ cf->can_id |= CAN_EFF_FLAG;
-+ else
-+ cf->can_id &= (~CAN_EFF_FLAG);
-+
-+ if (control & CAN_FD_SET_RTR_MASK)
-+ cf->can_id |= CAN_RTR_FLAG;
-+ }
-+
-+ /* CANFD frames handed over to SKB */
-+ if (control & CAN_FD_SET_EDL_MASK) {
-+ for (i = 0; i < cf->len; i += 4)
-+ *((u32 *)(cf->data + i)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + i);
-+ } else {
-+ /* skb reads the received datas, if the RTR bit not set */
-+ if (!(control & CAN_FD_SET_RTR_MASK)) {
-+ *((u32 *)(cf->data + 0)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET);
-+ *((u32 *)(cf->data + 4)) = priv->read_reg(priv, CANFD_RBUF_DATA_OFFSET + 4);
-+ }
-+ }
-+
-+ canfd_reigister_set_bit(priv, CANFD_RCTRL_OFFSET, CAN_FD_SET_RREL_MASK);
-+
-+ stats->rx_bytes += cf->len;
-+ stats->rx_packets++;
-+ netif_receive_skb(skb);
-+
-+ return 1;
-+}
-+
-+static int canfd_rx_poll(struct napi_struct *napi, int quota)
-+{
-+ struct net_device *ndev = napi->dev;
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ int work_done = 0;
-+ u8 rx_status = 0, control = 0;
-+
-+ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
-+ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
-+
-+ /* clear receive interrupt and deal with all the received frames */
-+ while ((rx_status & CAN_FD_RSTAT_NOT_EMPTY_MASK) && (work_done < quota)) {
-+ (control & CAN_FD_SET_EDL_MASK) ? (work_done += canfd_rx(ndev)) : (work_done += can_rx(ndev));
-+
-+ control = can_ioread8(priv->reg_base + CANFD_RBUF_CTL_OFFSET);
-+ rx_status = can_ioread8(priv->reg_base + CANFD_RCTRL_OFFSET);
-+ }
-+ napi_complete(napi);
-+ canfd_reigister_set_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_SET_RIE_MASK);
-+ return work_done;
-+}
-+
-+static void canfd_rxfull_interrupt(struct net_device *ndev, u8 isr)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+
-+ if (isr & CAN_FD_SET_RAFIF_MASK)
-+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RAFIF_MASK);
-+
-+ if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK))
-+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
-+ (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK));
-+}
-+
-+static int set_canfd_xmit_mode(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+
-+ switch (priv->tx_mode) {
-+ case XMIT_FULL:
-+ canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_FULLCAN_MASK);
-+ break;
-+ case XMIT_SEP_FIFO:
-+ canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FULLCAN_MASK);
-+ canfd_reigister_set_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_SET_FIFO_MASK);
-+ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TBSEL_MASK);
-+ break;
-+ case XMIT_SEP_PRIO:
-+ canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FULLCAN_MASK);
-+ canfd_reigister_off_bit(priv, CANFD_TCTRL_OFFSET, CAN_FD_OFF_FIFO_MASK);
-+ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TBSEL_MASK);
-+ break;
-+ case XMIT_PTB_MODE:
-+ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_OFF_TBSEL_MASK);
-+ break;
-+ default:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static netdev_tx_t canfd_driver_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
-+ struct net_device_stats *stats = &ndev->stats;
-+ u32 ttsen, id, ctl, addr_off;
-+ int i;
-+
-+ priv->tx_mode = XMIT_PTB_MODE;
-+
-+ if (can_dropped_invalid_skb(ndev, skb))
-+ return NETDEV_TX_OK;
-+
-+ switch (priv->tx_mode) {
-+ case XMIT_FULL:
-+ return NETDEV_TX_BUSY;
-+ case XMIT_PTB_MODE:
-+ set_canfd_xmit_mode(ndev);
-+ canfd_reigister_off_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_OFF_STBY_MASK);
-+
-+ if (cf->can_id & CAN_EFF_FLAG) {
-+ id = (cf->can_id & CAN_EFF_MASK);
-+ ttsen = 0 << TTSEN_8_32_SHIFT;
-+ id |= ttsen;
-+ } else {
-+ id = (cf->can_id & CAN_SFF_MASK);
-+ ttsen = 0 << TTSEN_8_32_SHIFT;
-+ id |= ttsen;
-+ }
-+
-+ ctl = can_fd_len2dlc(cf->len);
-+
-+ /* transmit can fd frame */
-+ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD) {
-+ if (can_is_canfd_skb(skb)) {
-+ if (cf->can_id & CAN_EFF_FLAG)
-+ ctl |= CAN_FD_SET_IDE_MASK;
-+ else
-+ ctl &= CAN_FD_OFF_IDE_MASK;
-+
-+ if (cf->flags & CANFD_BRS)
-+ ctl |= CAN_FD_SET_BRS_MASK;
-+
-+ ctl |= CAN_FD_SET_EDL_MASK;
-+
-+ addr_off = CANFD_TBUF_DATA_OFFSET;
-+
-+ for (i = 0; i < cf->len; i += 4) {
-+ priv->write_reg(priv, addr_off,
-+ *((u32 *)(cf->data + i)));
-+ addr_off += 4;
-+ }
-+ } else {
-+ ctl &= CAN_FD_OFF_EDL_MASK;
-+ ctl &= CAN_FD_OFF_BRS_MASK;
-+
-+ if (cf->can_id & CAN_EFF_FLAG)
-+ ctl |= CAN_FD_SET_IDE_MASK;
-+ else
-+ ctl &= CAN_FD_OFF_IDE_MASK;
-+
-+ if (cf->can_id & CAN_RTR_FLAG) {
-+ ctl |= CAN_FD_SET_RTR_MASK;
-+ priv->write_reg(priv,
-+ CANFD_TBUF_ID_OFFSET, id);
-+ priv->write_reg(priv,
-+ CANFD_TBUF_CTL_OFFSET, ctl);
-+ } else {
-+ ctl &= CAN_FD_OFF_RTR_MASK;
-+ addr_off = CANFD_TBUF_DATA_OFFSET;
-+ priv->write_reg(priv, addr_off,
-+ *((u32 *)(cf->data + 0)));
-+ priv->write_reg(priv, addr_off + 4,
-+ *((u32 *)(cf->data + 4)));
-+ }
-+ }
-+ priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id);
-+ priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl);
-+ addr_off = CANFD_TBUF_DATA_OFFSET;
-+ } else {
-+ ctl &= CAN_FD_OFF_EDL_MASK;
-+ ctl &= CAN_FD_OFF_BRS_MASK;
-+
-+ if (cf->can_id & CAN_EFF_FLAG)
-+ ctl |= CAN_FD_SET_IDE_MASK;
-+ else
-+ ctl &= CAN_FD_OFF_IDE_MASK;
-+
-+ if (cf->can_id & CAN_RTR_FLAG) {
-+ ctl |= CAN_FD_SET_RTR_MASK;
-+ priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id);
-+ priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl);
-+ } else {
-+ ctl &= CAN_FD_OFF_RTR_MASK;
-+ priv->write_reg(priv, CANFD_TBUF_ID_OFFSET, id);
-+ priv->write_reg(priv, CANFD_TBUF_CTL_OFFSET, ctl);
-+ addr_off = CANFD_TBUF_DATA_OFFSET;
-+ priv->write_reg(priv, addr_off,
-+ *((u32 *)(cf->data + 0)));
-+ priv->write_reg(priv, addr_off + 4,
-+ *((u32 *)(cf->data + 4)));
-+ }
-+ }
-+ canfd_reigister_set_bit(priv, CANFD_TCMD_OFFSET, CAN_FD_SET_TPE_MASK);
-+ stats->tx_bytes += cf->len;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ /*Due to cache blocking, we need call dev_kfree_skb() here to free the socket
-+ buffer and return NETDEV_TX_OK */
-+ dev_kfree_skb(skb);
-+
-+ return NETDEV_TX_OK;
-+}
-+
-+static int set_reset_mode(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ u8 ret;
-+
-+ ret = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
-+ ret |= CAN_FD_SET_RST_MASK;
-+ can_iowrite8(ret, priv->reg_base + CANFD_CFG_STAT_OFFSET);
-+
-+ return 0;
-+}
-+
-+static void canfd_driver_stop(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ int ret;
-+
-+ ret = set_reset_mode(ndev);
-+ if (ret)
-+ netdev_err(ndev, "Mode Resetting Failed!\n");
-+
-+ priv->can.state = CAN_STATE_STOPPED;
-+}
-+
-+static int canfd_driver_close(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+
-+ netif_stop_queue(ndev);
-+ napi_disable(&priv->napi);
-+ canfd_driver_stop(ndev);
-+
-+ free_irq(ndev->irq, ndev);
-+ close_candev(ndev);
-+
-+ pm_runtime_put(priv->dev);
-+
-+ return 0;
-+}
-+
-+static enum can_state get_of_chip_status(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ u8 can_stat, eir;
-+
-+ can_stat = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
-+ eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
-+
-+ if (can_stat & CAN_FD_SET_BUSOFF_MASK)
-+ return CAN_STATE_BUS_OFF;
-+
-+ if ((eir & CAN_FD_SET_EPASS_MASK) && ~(can_stat & CAN_FD_SET_BUSOFF_MASK))
-+ return CAN_STATE_ERROR_PASSIVE;
-+
-+ if (eir & CAN_FD_SET_EWARN_MASK && ~(eir & CAN_FD_SET_EPASS_MASK))
-+ return CAN_STATE_ERROR_WARNING;
-+
-+ if (~(eir & CAN_FD_SET_EPASS_MASK))
-+ return CAN_STATE_ERROR_ACTIVE;
-+
-+ return CAN_STATE_ERROR_ACTIVE;
-+}
-+
-+static void canfd_error_interrupt(struct net_device *ndev, u8 isr, u8 eir)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ struct net_device_stats *stats = &ndev->stats;
-+ struct can_frame *cf;
-+ struct sk_buff *skb;
-+ u8 koer, recnt = 0, tecnt = 0, can_stat = 0;
-+
-+ skb = alloc_can_err_skb(ndev, &cf);
-+
-+ koer = can_ioread8(priv->reg_base + CANFD_EALCAP_OFFSET) & CAN_FD_SET_KOER_MASK;
-+ recnt = can_ioread8(priv->reg_base + CANFD_RECNT_OFFSET);
-+ tecnt = can_ioread8(priv->reg_base + CANFD_TECNT_OFFSET);
-+
-+ /*Read can status*/
-+ can_stat = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
-+
-+ /* Bus off --->active error mode */
-+ if ((isr & CAN_FD_SET_EIF_MASK) && priv->can.state == CAN_STATE_BUS_OFF)
-+ priv->can.state = get_of_chip_status(ndev);
-+
-+ /* State selection */
-+ if (can_stat & CAN_FD_SET_BUSOFF_MASK) {
-+ priv->can.state = get_of_chip_status(ndev);
-+ priv->can.can_stats.bus_off++;
-+ canfd_reigister_set_bit(priv, CANFD_CFG_STAT_OFFSET, CAN_FD_SET_BUSOFF_MASK);
-+ can_bus_off(ndev);
-+ if (skb)
-+ cf->can_id |= CAN_ERR_BUSOFF;
-+
-+ } else if ((eir & CAN_FD_SET_EPASS_MASK) && ~(can_stat & CAN_FD_SET_BUSOFF_MASK)) {
-+ priv->can.state = get_of_chip_status(ndev);
-+ priv->can.can_stats.error_passive++;
-+ if (skb) {
-+ cf->can_id |= CAN_ERR_CRTL;
-+ cf->data[1] |= (recnt > 127) ? CAN_ERR_CRTL_RX_PASSIVE : 0;
-+ cf->data[1] |= (tecnt > 127) ? CAN_ERR_CRTL_TX_PASSIVE : 0;
-+ cf->data[6] = tecnt;
-+ cf->data[7] = recnt;
-+ }
-+ } else if (eir & CAN_FD_SET_EWARN_MASK && ~(eir & CAN_FD_SET_EPASS_MASK)) {
-+ priv->can.state = get_of_chip_status(ndev);
-+ priv->can.can_stats.error_warning++;
-+ if (skb) {
-+ cf->can_id |= CAN_ERR_CRTL;
-+ cf->data[1] |= (recnt > 95) ? CAN_ERR_CRTL_RX_WARNING : 0;
-+ cf->data[1] |= (tecnt > 95) ? CAN_ERR_CRTL_TX_WARNING : 0;
-+ cf->data[6] = tecnt;
-+ cf->data[7] = recnt;
-+ }
-+ }
-+
-+ /* Check for in protocol defined error interrupt */
-+ if (eir & CAN_FD_SET_BEIF_MASK) {
-+ if (skb)
-+ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-+
-+ /* bit error interrupt */
-+ if (koer == CAN_FD_SET_BIT_ERROR_MASK) {
-+ stats->tx_errors++;
-+ if (skb) {
-+ cf->can_id |= CAN_ERR_PROT;
-+ cf->data[2] = CAN_ERR_PROT_BIT;
-+ }
-+ }
-+ /* format error interrupt */
-+ if (koer == CAN_FD_SET_FORM_ERROR_MASK) {
-+ stats->rx_errors++;
-+ if (skb) {
-+ cf->can_id |= CAN_ERR_PROT;
-+ cf->data[2] = CAN_ERR_PROT_FORM;
-+ }
-+ }
-+ /* stuffing error interrupt */
-+ if (koer == CAN_FD_SET_STUFF_ERROR_MASK) {
-+ stats->rx_errors++;
-+ if (skb) {
-+ cf->can_id |= CAN_ERR_PROT;
-+ cf->data[3] = CAN_ERR_PROT_STUFF;
-+ }
-+ }
-+ /* ack error interrupt */
-+ if (koer == CAN_FD_SET_ACK_ERROR_MASK) {
-+ stats->tx_errors++;
-+ if (skb) {
-+ cf->can_id |= CAN_ERR_PROT;
-+ cf->data[2] = CAN_ERR_PROT_LOC_ACK;
-+ }
-+ }
-+ /* crc error interrupt */
-+ if (koer == CAN_FD_SET_CRC_ERROR_MASK) {
-+ stats->rx_errors++;
-+ if (skb) {
-+ cf->can_id |= CAN_ERR_PROT;
-+ cf->data[2] = CAN_ERR_PROT_LOC_CRC_SEQ;
-+ }
-+ }
-+ priv->can.can_stats.bus_error++;
-+ }
-+ if (skb) {
-+ stats->rx_packets++;
-+ stats->rx_bytes += cf->can_dlc;
-+ netif_rx(skb);
-+ }
-+
-+ netdev_dbg(ndev, "Recnt is 0x%02x", can_ioread8(priv->reg_base + CANFD_RECNT_OFFSET));
-+ netdev_dbg(ndev, "Tecnt is 0x%02x", can_ioread8(priv->reg_base + CANFD_TECNT_OFFSET));
-+}
-+
-+static irqreturn_t canfd_interrupt(int irq, void *dev_id)
-+{
-+ struct net_device *ndev = (struct net_device *)dev_id;
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ u8 isr, eir;
-+ u8 isr_handled = 0, eir_handled = 0;
-+
-+ /* read the value of interrupt status register */
-+ isr = can_ioread8(priv->reg_base + CANFD_RTIF_OFFSET);
-+
-+ /* read the value of error interrupt register */
-+ eir = can_ioread8(priv->reg_base + CANFD_ERRINT_OFFSET);
-+
-+ /* Check for Tx interrupt and Processing it */
-+ if (isr & (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK)) {
-+ canfd_tx_interrupt(ndev, isr);
-+ isr_handled |= (CAN_FD_SET_TPIF_MASK | CAN_FD_SET_TSIF_MASK);
-+ }
-+ if (isr & (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK)) {
-+ canfd_rxfull_interrupt(ndev, isr);
-+ isr_handled |= (CAN_FD_SET_RAFIF_MASK | CAN_FD_SET_RFIF_MASK);
-+ }
-+ /* Check Rx interrupt and Processing the receive interrupt routine */
-+ if (isr & CAN_FD_SET_RIF_MASK) {
-+ canfd_reigister_off_bit(priv, CANFD_RTIE_OFFSET, CAN_FD_OFF_RIE_MASK);
-+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET, CAN_FD_SET_RIF_MASK);
-+
-+ napi_schedule(&priv->napi);
-+ isr_handled |= CAN_FD_SET_RIF_MASK;
-+ }
-+ if ((isr & CAN_FD_SET_EIF_MASK) | (eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK))) {
-+ /* reset EPIF and BEIF. Reset EIF */
-+ canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET,
-+ eir & (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK));
-+ canfd_reigister_set_bit(priv, CANFD_RTIF_OFFSET,
-+ isr & CAN_FD_SET_EIF_MASK);
-+
-+ canfd_error_interrupt(ndev, isr, eir);
-+
-+ isr_handled |= CAN_FD_SET_EIF_MASK;
-+ eir_handled |= (CAN_FD_SET_EPIF_MASK | CAN_FD_SET_BEIF_MASK);
-+ }
-+ if ((isr_handled == 0) && (eir_handled == 0)) {
-+ netdev_err(ndev, "Unhandled interrupt!\n");
-+ return IRQ_NONE;
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int canfd_chip_start(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ int err;
-+ u8 ret;
-+
-+ err = set_reset_mode(ndev);
-+ if (err) {
-+ netdev_err(ndev, "Mode Resetting Failed!\n");
-+ return err;
-+ }
-+
-+ err = canfd_device_driver_bittime_configuration(ndev);
-+ if (err) {
-+ netdev_err(ndev, "Bittime Setting Failed!\n");
-+ return err;
-+ }
-+
-+ /* Set Almost Full Warning Limit */
-+ canfd_reigister_set_bit(priv, CANFD_LIMIT_OFFSET, CAN_FD_SET_AFWL_MASK);
-+
-+ /* Programmable Error Warning Limit = (EWL+1)*8. Set EWL=11->Error Warning=96 */
-+ canfd_reigister_set_bit(priv, CANFD_LIMIT_OFFSET, CAN_FD_SET_EWL_MASK);
-+
-+ /* Interrupts enable */
-+ can_iowrite8(CAN_FD_INTR_ALL_MASK, priv->reg_base + CANFD_RTIE_OFFSET);
-+
-+ /* Error Interrupts enable(Error Passive and Bus Error) */
-+ canfd_reigister_set_bit(priv, CANFD_ERRINT_OFFSET, CAN_FD_SET_EPIE_MASK);
-+
-+ ret = can_ioread8(priv->reg_base + CANFD_CFG_STAT_OFFSET);
-+
-+ /* Check whether it is loopback mode or normal mode */
-+ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
-+ ret |= CAN_FD_LBMIMOD_MASK;
-+ } else {
-+ ret &= ~CAN_FD_LBMEMOD_MASK;
-+ ret &= ~CAN_FD_LBMIMOD_MASK;
-+ }
-+
-+ can_iowrite8(ret, priv->reg_base + CANFD_CFG_STAT_OFFSET);
-+
-+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
-+
-+ return 0;
-+}
-+
-+static int canfd_do_set_mode(struct net_device *ndev, enum can_mode mode)
-+{
-+ int ret;
-+
-+ switch (mode) {
-+ case CAN_MODE_START:
-+ ret = canfd_chip_start(ndev);
-+ if (ret) {
-+ netdev_err(ndev, "Could Not Start CAN device !!\n");
-+ return ret;
-+ }
-+ netif_wake_queue(ndev);
-+ break;
-+ default:
-+ ret = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int canfd_driver_open(struct net_device *ndev)
-+{
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ int ret;
-+
-+ ret = pm_runtime_get_sync(priv->dev);
-+ if (ret < 0) {
-+ netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n",
-+ __func__, ret);
-+ goto err;
-+ }
-+
-+ /* Set chip into reset mode */
-+ ret = set_reset_mode(ndev);
-+ if (ret) {
-+ netdev_err(ndev, "Mode Resetting Failed!\n");
-+ return ret;
-+ }
-+
-+ /* Common open */
-+ ret = open_candev(ndev);
-+ if (ret)
-+ return ret;
-+
-+ /* Register interrupt handler */
-+ ret = request_irq(ndev->irq, canfd_interrupt, IRQF_SHARED, ndev->name, ndev);
-+ if (ret) {
-+ netdev_err(ndev, "Request_irq err: %d\n", ret);
-+ goto exit_irq;
-+ }
-+
-+ ret = canfd_chip_start(ndev);
-+ if (ret) {
-+ netdev_err(ndev, "Could Not Start CAN device !\n");
-+ goto exit_can_start;
-+ }
-+
-+ napi_enable(&priv->napi);
-+ netif_start_queue(ndev);
-+
-+ return 0;
-+
-+exit_can_start:
-+ free_irq(ndev->irq, ndev);
-+err:
-+ pm_runtime_put(priv->dev);
-+exit_irq:
-+ close_candev(ndev);
-+ return ret;
-+}
-+
-+static int canfd_control_parse_dt(struct ipms_canfd_priv *priv)
-+{
-+ struct of_phandle_args args;
-+ u32 syscon_mask, syscon_shift;
-+ u32 can_or_canfd;
-+ u32 syscon_offset, regval;
-+ int ret;
-+
-+ ret = of_parse_phandle_with_fixed_args(priv->dev->of_node,
-+ "starfive,sys-syscon", 3, 0, &args);
-+ if (ret) {
-+ dev_err(priv->dev, "Failed to parse starfive,sys-syscon\n");
-+ return -EINVAL;
-+ }
-+
-+ priv->reg_syscon = syscon_node_to_regmap(args.np);
-+ of_node_put(args.np);
-+ if (IS_ERR(priv->reg_syscon))
-+ return PTR_ERR(priv->reg_syscon);
-+
-+ syscon_offset = args.args[0];
-+ syscon_shift = args.args[1];
-+ syscon_mask = args.args[2];
-+
-+ ret = device_property_read_u32(priv->dev, "syscon,can_or_canfd", &can_or_canfd);
-+ if (ret)
-+ goto exit_parse;
-+
-+ priv->can_or_canfd = can_or_canfd;
-+
-+ /* enable can2.0/canfd function */
-+ regval = can_or_canfd << syscon_shift;
-+ ret = regmap_update_bits(priv->reg_syscon, syscon_offset, syscon_mask, regval);
-+ if (ret)
-+ return ret;
-+ return 0;
-+exit_parse:
-+ return ret;
-+}
-+
-+static const struct net_device_ops canfd_netdev_ops = {
-+ .ndo_open = canfd_driver_open,
-+ .ndo_stop = canfd_driver_close,
-+ .ndo_start_xmit = canfd_driver_start_xmit,
-+ .ndo_change_mtu = can_change_mtu,
-+};
-+
-+static int canfd_driver_probe(struct platform_device *pdev)
-+{
-+ struct net_device *ndev;
-+ struct ipms_canfd_priv *priv;
-+ void __iomem *addr;
-+ int ret;
-+ u32 frq;
-+
-+ addr = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(addr)) {
-+ ret = PTR_ERR(addr);
-+ goto exit;
-+ }
-+
-+ ndev = alloc_candev(sizeof(struct ipms_canfd_priv), 1);
-+ if (!ndev) {
-+ ret = -ENOMEM;
-+ goto exit;
-+ }
-+
-+ priv = netdev_priv(ndev);
-+ priv->dev = &pdev->dev;
-+
-+ ret = canfd_control_parse_dt(priv);
-+ if (ret)
-+ goto free_exit;
-+
-+ priv->nr_clks = devm_clk_bulk_get_all(priv->dev, &priv->clks);
-+ if (priv->nr_clks < 0) {
-+ dev_err(priv->dev, "Failed to get can clocks\n");
-+ ret = -ENODEV;
-+ goto free_exit;
-+ }
-+
-+ ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks);
-+ if (ret) {
-+ dev_err(priv->dev, "Failed to enable clocks\n");
-+ goto free_exit;
-+ }
-+
-+ priv->resets = devm_reset_control_array_get_exclusive(priv->dev);
-+ if (IS_ERR(priv->resets)) {
-+ ret = PTR_ERR(priv->resets);
-+ dev_err(priv->dev, "Failed to get can resets");
-+ goto clk_exit;
-+ }
-+
-+ ret = reset_control_deassert(priv->resets);
-+ if (ret)
-+ goto clk_exit;
-+ priv->can.bittiming_const = &canfd_bittiming_const;
-+ priv->can.data_bittiming_const = &canfd_data_bittiming_const;
-+ priv->can.do_set_mode = canfd_do_set_mode;
-+
-+ /* in user space the execution mode can be chosen */
-+ if (priv->can_or_canfd == IPMS_CAN_TYPE_CANFD)
-+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_FD;
-+ else
-+ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK;
-+ priv->reg_base = addr;
-+ priv->write_reg = canfd_write_reg_le;
-+ priv->read_reg = canfd_read_reg_le;
-+
-+ pm_runtime_enable(&pdev->dev);
-+
-+ priv->can_clk = devm_clk_get(&pdev->dev, "core_clk");
-+ if (IS_ERR(priv->can_clk)) {
-+ dev_err(&pdev->dev, "Device clock not found.\n");
-+ ret = PTR_ERR(priv->can_clk);
-+ goto reset_exit;
-+ }
-+
-+ device_property_read_u32(priv->dev, "frequency", &frq);
-+ clk_set_rate(priv->can_clk, frq);
-+
-+ priv->can.clock.freq = clk_get_rate(priv->can_clk);
-+ ndev->irq = platform_get_irq(pdev, 0);
-+
-+ /* we support local echo */
-+ ndev->flags |= IFF_ECHO;
-+ ndev->netdev_ops = &canfd_netdev_ops;
-+
-+ platform_set_drvdata(pdev, ndev);
-+ SET_NETDEV_DEV(ndev, &pdev->dev);
-+
-+ netif_napi_add(ndev, &priv->napi, canfd_rx_poll);
-+ ret = register_candev(ndev);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Fail to register failed (err=%d)\n", ret);
-+ goto reset_exit;
-+ }
-+
-+ dev_dbg(&pdev->dev, "Driver registered: regs=%p, irp=%d, clock=%d\n",
-+ priv->reg_base, ndev->irq, priv->can.clock.freq);
-+
-+ return 0;
-+
-+reset_exit:
-+ reset_control_assert(priv->resets);
-+clk_exit:
-+ clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
-+free_exit:
-+ free_candev(ndev);
-+exit:
-+ return ret;
-+}
-+
-+static int 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);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM_SLEEP
-+static int __maybe_unused canfd_suspend(struct device *dev)
-+{
-+ struct net_device *ndev = dev_get_drvdata(dev);
-+
-+ if (netif_running(ndev)) {
-+ netif_stop_queue(ndev);
-+ netif_device_detach(ndev);
-+ canfd_driver_stop(ndev);
-+ }
-+
-+ return pm_runtime_force_suspend(dev);
-+}
-+
-+static int __maybe_unused canfd_resume(struct device *dev)
-+{
-+ struct net_device *ndev = dev_get_drvdata(dev);
-+ int ret;
-+
-+ ret = pm_runtime_force_resume(dev);
-+ if (ret) {
-+ dev_err(dev, "pm_runtime_force_resume failed on resume\n");
-+ return ret;
-+ }
-+
-+ if (netif_running(ndev)) {
-+ ret = canfd_chip_start(ndev);
-+ if (ret) {
-+ dev_err(dev, "canfd_chip_start failed on resume\n");
-+ return ret;
-+ }
-+
-+ netif_device_attach(ndev);
-+ netif_start_queue(ndev);
-+ }
-+
-+ return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_PM
-+static int canfd_runtime_suspend(struct device *dev)
-+{
-+ struct net_device *ndev = dev_get_drvdata(dev);
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+
-+ reset_control_assert(priv->resets);
-+ clk_bulk_disable_unprepare(priv->nr_clks, priv->clks);
-+
-+ return 0;
-+}
-+
-+static int canfd_runtime_resume(struct device *dev)
-+{
-+ struct net_device *ndev = dev_get_drvdata(dev);
-+ struct ipms_canfd_priv *priv = netdev_priv(ndev);
-+ int ret;
-+
-+ ret = clk_bulk_prepare_enable(priv->nr_clks, priv->clks);
-+ if (ret) {
-+ dev_err(dev, "Failed to prepare_enable clk\n");
-+ return ret;
-+ }
-+
-+ ret = reset_control_deassert(priv->resets);
-+ if (ret) {
-+ dev_err(dev, "Failed to deassert reset\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+#endif
-+
-+static const struct dev_pm_ops canfd_pm_ops = {
-+ SET_SYSTEM_SLEEP_PM_OPS(canfd_suspend, canfd_resume)
-+ SET_RUNTIME_PM_OPS(canfd_runtime_suspend,
-+ canfd_runtime_resume, NULL)
-+};
-+
-+static const struct of_device_id canfd_of_match[] = {
-+ { .compatible = "ipms,can" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, canfd_of_match);
-+
-+static struct platform_driver can_driver = {
-+ .probe = canfd_driver_probe,
-+ .remove = canfd_driver_remove,
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .pm = &canfd_pm_ops,
-+ .of_match_table = canfd_of_match,
-+ },
-+};
-+
-+module_platform_driver(can_driver);
-+
-+MODULE_DESCRIPTION("ipms can controller driver for StarFive jh7110 SoC");
-+MODULE_AUTHOR("William Qiu<william.qiu@starfivetech.com");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From b12213d474966fbf47e7afa36a6655b5b241cf36 Mon Sep 17 00:00:00 2001
-From: "Kevin.xie" <kevin.xie@starfivetech.com>
-Date: Fri, 9 Jun 2023 14:57:13 +0800
-Subject: [PATCH 071/116] regulator: starfive-jh7110: Add regulator support for
- JH7110 A type EVB.
-
-Add 7 regulators base on regulator framework for
-JH7110 evb HW design.
-
-Signed-off-by: Kevin.xie <kevin.xie@starfivetech.com>
----
- drivers/regulator/Kconfig | 10 ++
- drivers/regulator/Makefile | 1 +
- drivers/regulator/starfive-jh7110-regulator.c | 126 ++++++++++++++++++
- include/linux/regulator/jh7110.h | 24 ++++
- 4 files changed, 161 insertions(+)
- create mode 100644 drivers/regulator/starfive-jh7110-regulator.c
- create mode 100644 include/linux/regulator/jh7110.h
-
---- a/drivers/regulator/Kconfig
-+++ b/drivers/regulator/Kconfig
-@@ -1335,6 +1335,16 @@ config REGULATOR_SM5703
- This driver provides support for voltage regulators of SM5703
- multi-function device.
-
-+config REGULATOR_STARFIVE_JH7110
-+ tristate "Starfive JH7110 PMIC"
-+ depends on I2C
-+ select REGMAP_I2C
-+ help
-+ Say y here to select this option to enable the power regulator of
-+ Starfive JH7110 PMIC.
-+ This driver supports the control of different power rails of device
-+ through regulator interface.
-+
- config REGULATOR_STM32_BOOSTER
- tristate "STMicroelectronics STM32 BOOSTER"
- depends on ARCH_STM32 || COMPILE_TEST
---- a/drivers/regulator/Makefile
-+++ b/drivers/regulator/Makefile
-@@ -156,6 +156,7 @@ obj-$(CONFIG_REGULATOR_SC2731) += sc2731
- obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
- obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o
- obj-$(CONFIG_REGULATOR_SM5703) += sm5703-regulator.o
-+obj-$(CONFIG_REGULATOR_STARFIVE_JH7110) += starfive-jh7110-regulator.o
- obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o
- obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
- obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
---- /dev/null
-+++ b/drivers/regulator/starfive-jh7110-regulator.c
-@@ -0,0 +1,126 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (c) 2022 Starfive Technology Co., Ltd.
-+ * Author: Mason Huo <mason.huo@starfivetech.com>
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/gpio.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+#include <linux/regmap.h>
-+#include <linux/regulator/driver.h>
-+#include <linux/regulator/machine.h>
-+#include <linux/regulator/of_regulator.h>
-+#include <linux/regulator/jh7110.h>
-+#include <linux/slab.h>
-+
-+#define JH7110_PM_POWER_SW_0 0x80
-+#define JH7110_PM_POWER_SW_1 0x81
-+#define ENABLE_MASK(id) BIT(id)
-+
-+
-+static const struct regmap_config jh7110_regmap_config = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .max_register = JH7110_PM_POWER_SW_1,
-+ .cache_type = REGCACHE_FLAT,
-+};
-+
-+static const struct regulator_ops jh7110_ldo_ops = {
-+ .enable = regulator_enable_regmap,
-+ .disable = regulator_disable_regmap,
-+ .is_enabled = regulator_is_enabled_regmap,
-+};
-+
-+#define JH7110_LDO(_id, _name, en_reg, en_mask) \
-+{\
-+ .name = (_name),\
-+ .ops = &jh7110_ldo_ops,\
-+ .of_match = of_match_ptr(_name),\
-+ .regulators_node = of_match_ptr("regulators"),\
-+ .type = REGULATOR_VOLTAGE,\
-+ .id = JH7110_ID_##_id,\
-+ .owner = THIS_MODULE,\
-+ .enable_reg = JH7110_PM_POWER_SW_##en_reg,\
-+ .enable_mask = ENABLE_MASK(en_mask),\
-+}
-+
-+static const struct regulator_desc jh7110_regulators[] = {
-+ JH7110_LDO(LDO_REG1, "hdmi_1p8", 0, 0),
-+ JH7110_LDO(LDO_REG2, "mipitx_1p8", 0, 1),
-+ JH7110_LDO(LDO_REG3, "mipirx_1p8", 0, 2),
-+ JH7110_LDO(LDO_REG4, "hdmi_0p9", 0, 3),
-+ JH7110_LDO(LDO_REG5, "mipitx_0p9", 0, 4),
-+ JH7110_LDO(LDO_REG6, "mipirx_0p9", 0, 5),
-+ JH7110_LDO(LDO_REG7, "sdio_vdd", 1, 0),
-+};
-+
-+static int jh7110_i2c_probe(struct i2c_client *i2c)
-+{
-+ struct regulator_config config = { };
-+ struct regulator_dev *rdev;
-+ struct regulator_init_data *init_data;
-+ struct regmap *regmap;
-+ int i, ret;
-+
-+ regmap = devm_regmap_init_i2c(i2c, &jh7110_regmap_config);
-+ if (IS_ERR(regmap)) {
-+ ret = PTR_ERR(regmap);
-+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node, NULL);
-+ if (!init_data)
-+ return -ENOMEM;
-+ config.init_data = init_data;
-+
-+ for (i = 0; i < JH7110_MAX_REGULATORS; i++) {
-+ config.dev = &i2c->dev;
-+ config.regmap = regmap;
-+
-+ rdev = devm_regulator_register(&i2c->dev,
-+ &jh7110_regulators[i], &config);
-+ if (IS_ERR(rdev)) {
-+ dev_err(&i2c->dev,
-+ "Failed to register JH7110 regulator\n");
-+ return PTR_ERR(rdev);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct i2c_device_id jh7110_i2c_id[] = {
-+ {"jh7110_evb_reg", 0},
-+ {},
-+};
-+MODULE_DEVICE_TABLE(i2c, jh7110_i2c_id);
-+
-+#ifdef CONFIG_OF
-+static const struct of_device_id jh7110_dt_ids[] = {
-+ { .compatible = "starfive,jh7110-evb-regulator",
-+ .data = &jh7110_i2c_id[0] },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, jh7110_dt_ids);
-+#endif
-+
-+static struct i2c_driver jh7110_regulator_driver = {
-+ .driver = {
-+ .name = "jh7110-evb-regulator",
-+ .of_match_table = of_match_ptr(jh7110_dt_ids),
-+ },
-+ .probe = jh7110_i2c_probe,
-+ .id_table = jh7110_i2c_id,
-+};
-+
-+module_i2c_driver(jh7110_regulator_driver);
-+
-+MODULE_AUTHOR("Mason Huo <mason.huo@starfivetech.com>");
-+MODULE_DESCRIPTION("Regulator device driver for Starfive JH7110");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/include/linux/regulator/jh7110.h
-@@ -0,0 +1,24 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+/*
-+ * Copyright (c) 2022 Starfive Technology Co., Ltd.
-+ * Author: Mason Huo <mason.huo@starfivetech.com>
-+ */
-+
-+#ifndef __LINUX_REGULATOR_JH7110_H
-+#define __LINUX_REGULATOR_JH7110_H
-+
-+#define JH7110_MAX_REGULATORS 7
-+
-+
-+enum jh7110_reg_id {
-+ JH7110_ID_LDO_REG1 = 0,
-+ JH7110_ID_LDO_REG2,
-+ JH7110_ID_LDO_REG3,
-+ JH7110_ID_LDO_REG4,
-+ JH7110_ID_LDO_REG5,
-+ JH7110_ID_LDO_REG6,
-+ JH7110_ID_LDO_REG7,
-+};
-+
-+
-+#endif /* __LINUX_REGULATOR_JH7110_H */
+++ /dev/null
-From f0b4cffe4d1813305f783d208f260747ecc56c50 Mon Sep 17 00:00:00 2001
-From: "Kevin.xie" <kevin.xie@starfivetech.com>
-Date: Thu, 24 Nov 2022 16:59:12 +0800
-Subject: [PATCH 072/116] drivers: nvme: Add precheck and delay for CQE pending
- status.
-
-To workaroud the NVMe I/O timeout problem in bootup S10udev case
-which caused by the CQE update lantancy.
-
-Signed-off-by: Kevin.xie <kevin.xie@starfivetech.com>
----
- drivers/nvme/host/pci.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/nvme/host/pci.c
-+++ b/drivers/nvme/host/pci.c
-@@ -28,6 +28,7 @@
- #include <linux/io-64-nonatomic-hi-lo.h>
- #include <linux/sed-opal.h>
- #include <linux/pci-p2pdma.h>
-+#include <linux/delay.h>
-
- #include "trace.h"
- #include "nvme.h"
-@@ -1058,6 +1059,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++;
- /*
+++ /dev/null
-From eb294df4b9fab46bc5dbf676edf51e28e06d1968 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?=
- <joao.mario@tecnico.ulisboa.pt>
-Date: Tue, 16 Nov 2021 15:48:09 +0000
-Subject: [PATCH 073/116] RISC-V: Create unique identification for SoC PMU
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The SBI PMU platform driver did not provide any identification for
-perf events matching. This patch introduces a new sysfs file inside the
-platform device (soc:pmu/id) for pmu identification.
-
-The identification is a 64-bit value generated as:
-[63-32]: mvendorid;
-[31]: marchid[MSB];
-[30-16]: marchid[15-0];
-[15-0]: mimpid[15MSBs];
-
-The CSRs are detailed in the RISC-V privileged spec [1].
-The marchid is split in MSB + 15LSBs, due to the MSB being used for
-open-source architecture identification.
-
-[1] https://github.com/riscv/riscv-isa-manual
-
-Signed-off-by: João Mário Domingos <joao.mario@tecnico.ulisboa.pt>
----
- drivers/perf/riscv_pmu_sbi.c | 47 ++++++++++++++++++++++++++++++++++++
- 1 file changed, 47 insertions(+)
-
---- a/drivers/perf/riscv_pmu_sbi.c
-+++ b/drivers/perf/riscv_pmu_sbi.c
-@@ -1019,6 +1019,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;
-@@ -1067,6 +1107,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 = cpuhp_state_add_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
- if (ret)
- return ret;
+++ /dev/null
-From 1dc069ffadf4ce7817a716f9df2f480254e9b01d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?=
- <joao.mario@tecnico.ulisboa.pt>
-Date: Tue, 16 Nov 2021 15:48:10 +0000
-Subject: [PATCH 074/116] RISC-V: Support CPUID for risc-v in perf
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch creates the header.c file for the risc-v architecture and introduces support for
-PMU identification through sysfs.
-It is now possible to configure pmu-events in risc-v.
-
-Depends on patch [1], that introduces the id sysfs file.
-
-Signed-off-by: João Mário Domingos <joao.mario@tecnico.ulisboa.pt>
-Signed-off-by: minda.chen <minda.chen@starfivetech.com>
----
- drivers/perf/riscv_pmu.c | 18 ++++++++++++++++++
- 1 file changed, 18 insertions(+)
-
---- a/drivers/perf/riscv_pmu.c
-+++ b/drivers/perf/riscv_pmu.c
-@@ -18,6 +18,23 @@
-
- #include <asm/sbi.h>
-
-+PMU_FORMAT_ATTR(event, "config:0-63");
-+
-+static struct attribute *riscv_arch_formats_attr[] = {
-+ &format_attr_event.attr,
-+ NULL,
-+};
-+
-+static struct attribute_group riscv_pmu_format_group = {
-+ .name = "format",
-+ .attrs = riscv_arch_formats_attr,
-+};
-+
-+static const struct attribute_group *riscv_pmu_attr_groups[] = {
-+ &riscv_pmu_format_group,
-+ NULL,
-+};
-+
- static bool riscv_perf_user_access(struct perf_event *event)
- {
- return ((event->attr.type == PERF_TYPE_HARDWARE) ||
-@@ -410,6 +427,7 @@ struct riscv_pmu *riscv_pmu_alloc(void)
- cpuc->events[i] = 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,
+++ /dev/null
-From 3e6ea12dda276c01a756764fcafa315b19860c33 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jo=C3=A3o=20M=C3=A1rio=20Domingos?=
- <joao.mario@tecnico.ulisboa.pt>
-Date: Tue, 16 Nov 2021 15:48:11 +0000
-Subject: [PATCH 075/116] RISC-V: Added generic pmu-events mapfile
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The pmu-events now supports custom events for RISC-V, plus the cycle,
-time and instret events were defined.
-
-Signed-off-by: João Mário Domingos <joao.mario@tecnico.ulisboa.pt>
----
- .../pmu-events/arch/riscv/riscv-generic.json | 20 +++++++++++++++++++
- 1 file changed, 20 insertions(+)
- create mode 100644 tools/perf/pmu-events/arch/riscv/riscv-generic.json
-
---- /dev/null
-+++ b/tools/perf/pmu-events/arch/riscv/riscv-generic.json
-@@ -0,0 +1,20 @@
-+[
-+ {
-+ "PublicDescription": "CPU Cycles",
-+ "EventCode": "0x00",
-+ "EventName": "riscv_cycles",
-+ "BriefDescription": "CPU cycles RISC-V generic counter"
-+ },
-+ {
-+ "PublicDescription": "CPU Time",
-+ "EventCode": "0x01",
-+ "EventName": "riscv_time",
-+ "BriefDescription": "CPU time RISC-V generic counter"
-+ },
-+ {
-+ "PublicDescription": "CPU Instructions",
-+ "EventCode": "0x02",
-+ "EventName": "riscv_instret",
-+ "BriefDescription": "CPU retired instructions RISC-V generic counter"
-+ }
-+]
-\ No newline at end of file
+++ /dev/null
-From 30e0cdcf9e05faa65ecde4ed8b70039568fdb660 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Thu, 2 Mar 2023 17:16:01 +0800
-Subject: [PATCH 076/116] perf: sbi: disable cpu hotplug callback.
-
-register cpu hotplug callback will cause dhrystone
-and coremark benchmark reduce the scores. this CPU
-hotplug ops will do in sbi cpu/on and off. So disable
-this no side effect.
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/perf/riscv_pmu_sbi.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/perf/riscv_pmu_sbi.c
-+++ b/drivers/perf/riscv_pmu_sbi.c
-@@ -1114,9 +1114,11 @@ static int pmu_sbi_device_probe(struct p
- }
- pdev->dev.groups = pmu_sbi_groups;
-
-+#ifndef CONFIG_ARCH_STARFIVE
- ret = cpuhp_state_add_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
- if (ret)
- return ret;
-+#endif
-
- ret = riscv_pm_pmu_register(pmu);
- if (ret)
+++ /dev/null
-From fc4b5c7c27e1b56b1f848e50511c4fd081b1b6c5 Mon Sep 17 00:00:00 2001
-From: Walker Chen <walker.chen@starfivetech.com>
-Date: Mon, 12 Jun 2023 21:21:45 +0800
-Subject: [PATCH 077/116] dmaengine: dw-axi-dmac: Drop unused print message
-
-Removed printing information which is not related to StarFive
-platform.
-
-Signed-off-by: Walker Chen <walker.chen@starfivetech.com>
----
- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-@@ -523,7 +523,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;
- }
-
+++ /dev/null
-From cd2254c6be9441ebacaa35693ecb5ce116b90622 Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Fri, 16 Jun 2023 16:27:46 +0800
-Subject: [PATCH 079/116] ASoC: codecs: Add AC108 Codec driver
-
-Add AC108 Codec driver and AC101 driver for AC10x.
-
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- sound/soc/codecs/Kconfig | 5 +
- sound/soc/codecs/Makefile | 2 +
- sound/soc/codecs/ac101.c | 1716 +++++++++++++++++++++++++++++++++
- sound/soc/codecs/ac101_regs.h | 431 +++++++++
- sound/soc/codecs/ac108.c | 1622 +++++++++++++++++++++++++++++++
- sound/soc/codecs/ac108.h | 749 ++++++++++++++
- sound/soc/codecs/ac10x.h | 152 +++
- 7 files changed, 4677 insertions(+)
- create mode 100644 sound/soc/codecs/ac101.c
- create mode 100644 sound/soc/codecs/ac101_regs.h
- create mode 100644 sound/soc/codecs/ac108.c
- create mode 100644 sound/soc/codecs/ac108.h
- create mode 100644 sound/soc/codecs/ac10x.h
-
---- a/sound/soc/codecs/Kconfig
-+++ b/sound/soc/codecs/Kconfig
-@@ -16,6 +16,7 @@ config SND_SOC_ALL_CODECS
- depends on COMPILE_TEST
- imply SND_SOC_88PM860X
- imply SND_SOC_AB8500_CODEC
-+ imply SND_SOC_AC108
- imply SND_SOC_AC97_CODEC
- imply SND_SOC_AD1836
- imply SND_SOC_AD193X_SPI
-@@ -397,6 +398,10 @@ config SND_SOC_AB8500_CODEC
- tristate
- depends on ABX500_CORE
-
-+config SND_SOC_AC108
-+ tristate "AC108"
-+ depends on I2C
-+
- config SND_SOC_AC97_CODEC
- tristate "Build generic ASoC AC97 CODEC driver"
- select SND_AC97_CODEC
---- a/sound/soc/codecs/Makefile
-+++ b/sound/soc/codecs/Makefile
-@@ -2,6 +2,7 @@
- snd-soc-88pm860x-objs := 88pm860x-codec.o
- snd-soc-ab8500-codec-objs := ab8500-codec.o
- snd-soc-ac97-objs := ac97.o
-+snd-soc-ac108-objs := ac108.o ac101.o
- snd-soc-ad1836-objs := ad1836.o
- snd-soc-ad193x-objs := ad193x.o
- snd-soc-ad193x-spi-objs := ad193x-spi.o
-@@ -386,6 +387,7 @@ snd-soc-simple-mux-objs := simple-mux.o
-
- obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
- obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o
-+obj-$(CONFIG_SND_SOC_AC108) += snd-soc-ac108.o
- obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
- obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
- obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
---- /dev/null
-+++ b/sound/soc/codecs/ac101.c
-@@ -0,0 +1,1716 @@
-+/*
-+ * ac101.c
-+ *
-+ * (C) Copyright 2017-2018
-+ * Seeed Technology Co., Ltd. <www.seeedstudio.com>
-+ *
-+ * PeterYang <linsheng.yang@seeed.cc>
-+ *
-+ * (C) Copyright 2014-2017
-+ * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
-+ *
-+ * huangxin <huangxin@Reuuimllatech.com>
-+ * liushaohua <liushaohua@allwinnertech.com>
-+ *
-+ * X-Powers AC101 codec driver
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2 of
-+ * the License, or (at your option) any later version.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/input.h>
-+#include <linux/irq.h>
-+#include <linux/module.h>
-+#include <linux/regmap.h>
-+#include <sound/tlv.h>
-+#include <linux/workqueue.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/soc-dapm.h>
-+
-+#include "ac101_regs.h"
-+#include "ac10x.h"
-+
-+/* #undef AC101_DEBG
-+ * use 'make DEBUG=1' to enable debugging
-+ */
-+
-+/*
-+ * *** To sync channels ***
-+ *
-+ * 1. disable clock in codec hw_params()
-+ * 2. clear fifo in bcm2835 hw_params()
-+ * 3. clear fifo in bcm2385 prepare()
-+ * 4. enable RX in bcm2835 trigger()
-+ * 5. enable clock in machine trigger()
-+ */
-+
-+/*Default initialize configuration*/
-+static bool speaker_double_used = 1;
-+static int double_speaker_val = 0x1B;
-+static int single_speaker_val = 0x19;
-+static int headset_val = 0x3B;
-+static int mainmic_val = 0x4;
-+static int headsetmic_val = 0x4;
-+static bool dmic_used = 0;
-+static int adc_digital_val = 0xb0b0;
-+static bool drc_used = false;
-+
-+#define AC101_RATES (SNDRV_PCM_RATE_8000_96000 & \
-+ ~(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000 | \
-+ SNDRV_PCM_RATE_88200))
-+#define AC101_FORMATS (/*SNDRV_PCM_FMTBIT_S16_LE | \
-+ SNDRV_PCM_FMTBIT_S24_LE |*/ \
-+ SNDRV_PCM_FMTBIT_S32_LE | \
-+ 0)
-+
-+static struct ac10x_priv* static_ac10x;
-+
-+
-+int ac101_read(struct snd_soc_codec *codec, unsigned reg) {
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int r, v = 0;
-+
-+ if ((r = regmap_read(ac10x->regmap101, reg, &v)) < 0) {
-+ dev_err(codec->dev, "read reg %02X fail\n",
-+ reg);
-+ return r;
-+ }
-+ return v;
-+}
-+
-+int ac101_write(struct snd_soc_codec *codec, unsigned reg, unsigned val) {
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int v;
-+
-+ v = regmap_write(ac10x->regmap101, reg, val);
-+ return v;
-+}
-+
-+int ac101_update_bits(struct snd_soc_codec *codec, unsigned reg,
-+ unsigned mask, unsigned value
-+) {
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int v;
-+
-+ v = regmap_update_bits(ac10x->regmap101, reg, mask, value);
-+ return v;
-+}
-+
-+
-+
-+#ifdef CONFIG_AC101_SWITCH_DETECT
-+/******************************************************************************/
-+/********************************switch****************************************/
-+/******************************************************************************/
-+#define KEY_HEADSETHOOK 226 /* key define */
-+#define HEADSET_FILTER_CNT (10)
-+
-+/*
-+ * switch_hw_config:config the 53 codec register
-+ */
-+static void switch_hw_config(struct snd_soc_codec *codec)
-+{
-+ int r;
-+
-+ AC101_DBG();
-+
-+ /*HMIC/MMIC BIAS voltage level select:2.5v*/
-+ ac101_update_bits(codec, OMIXER_BST1_CTRL, (0xf<<BIASVOLTAGE), (0xf<<BIASVOLTAGE));
-+ /*debounce when Key down or keyup*/
-+ ac101_update_bits(codec, HMIC_CTRL1, (0xf<<HMIC_M), (0x0<<HMIC_M));
-+ /*debounce when earphone plugin or pullout*/
-+ ac101_update_bits(codec, HMIC_CTRL1, (0xf<<HMIC_N), (0x0<<HMIC_N));
-+ /*Down Sample Setting Select: Downby 4,32Hz*/
-+ ac101_update_bits(codec, HMIC_CTRL2, (0x3<<HMIC_SAMPLE_SELECT),
-+ (0x02<<HMIC_SAMPLE_SELECT));
-+ /*Hmic_th2 for detecting Keydown or Keyup.*/
-+ ac101_update_bits(codec, HMIC_CTRL2, (0x1f<<HMIC_TH2), (0x8<<HMIC_TH2));
-+ /*Hmic_th1[4:0],detecting eraphone plugin or pullout*/
-+ ac101_update_bits(codec, HMIC_CTRL2, (0x1f<<HMIC_TH1), (0x1<<HMIC_TH1));
-+ /*Headset microphone BIAS working mode: when HBIASEN = 1 */
-+ ac101_update_bits(codec, ADC_APC_CTRL, (0x1<<HBIASMOD), (0x1<<HBIASMOD));
-+ /*Headset microphone BIAS Enable*/
-+ ac101_update_bits(codec, ADC_APC_CTRL, (0x1<<HBIASEN), (0x1<<HBIASEN));
-+ /*Headset microphone BIAS Current sensor & ADC Enable*/
-+ ac101_update_bits(codec, ADC_APC_CTRL, (0x1<<HBIASADCEN), (0x1<<HBIASADCEN));
-+ /*Earphone Plugin/out Irq Enable*/
-+ ac101_update_bits(codec, HMIC_CTRL1, (0x1<<HMIC_PULLOUT_IRQ), (0x1<<HMIC_PULLOUT_IRQ));
-+ ac101_update_bits(codec, HMIC_CTRL1, (0x1<<HMIC_PLUGIN_IRQ), (0x1<<HMIC_PLUGIN_IRQ));
-+
-+ /*Hmic KeyUp/key down Irq Enable*/
-+ ac101_update_bits(codec, HMIC_CTRL1, (0x1<<HMIC_KEYDOWN_IRQ), (0x1<<HMIC_KEYDOWN_IRQ));
-+ ac101_update_bits(codec, HMIC_CTRL1, (0x1<<HMIC_KEYUP_IRQ), (0x1<<HMIC_KEYUP_IRQ));
-+
-+ /*headphone calibration clock frequency select*/
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x7<<HPCALICKS), (0x7<<HPCALICKS));
-+
-+ /*clear hmic interrupt */
-+ r = HMIC_PEND_ALL;
-+ ac101_write(codec, HMIC_STS, r);
-+
-+ return;
-+}
-+
-+/*
-+ * switch_status_update: update the switch state.
-+ */
-+static void switch_status_update(struct ac10x_priv *ac10x)
-+{
-+ AC101_DBG("ac10x->state:%d\n", ac10x->state);
-+
-+ input_report_switch(ac10x->inpdev, SW_HEADPHONE_INSERT, ac10x->state);
-+ input_sync(ac10x->inpdev);
-+ return;
-+}
-+
-+/*
-+ * work_cb_clear_irq: clear audiocodec pending and Record the interrupt.
-+ */
-+static void work_cb_clear_irq(struct work_struct *work)
-+{
-+ int reg_val = 0;
-+ struct ac10x_priv *ac10x = container_of(work, struct ac10x_priv, work_clear_irq);
-+ struct snd_soc_codec *codec = ac10x->codec;
-+
-+ ac10x->irq_cntr++;
-+
-+ reg_val = ac101_read(codec, HMIC_STS);
-+ if (BIT(HMIC_PULLOUT_PEND) & reg_val) {
-+ ac10x->pullout_cntr++;
-+ AC101_DBG("ac10x->pullout_cntr: %d\n", ac10x->pullout_cntr);
-+ }
-+
-+ reg_val |= HMIC_PEND_ALL;
-+ ac101_write(codec, HMIC_STS, reg_val);
-+
-+ reg_val = ac101_read(codec, HMIC_STS);
-+ if ((reg_val & HMIC_PEND_ALL) != 0){
-+ reg_val |= HMIC_PEND_ALL;
-+ ac101_write(codec, HMIC_STS, reg_val);
-+ }
-+
-+ if (cancel_work_sync(&ac10x->work_switch) != 0) {
-+ ac10x->irq_cntr--;
-+ }
-+
-+ if (0 == schedule_work(&ac10x->work_switch)) {
-+ ac10x->irq_cntr--;
-+ AC101_DBG("[work_cb_clear_irq] add work struct failed!\n");
-+ }
-+}
-+
-+enum {
-+ HBIAS_LEVEL_1 = 0x02,
-+ HBIAS_LEVEL_2 = 0x0B,
-+ HBIAS_LEVEL_3 = 0x13,
-+ HBIAS_LEVEL_4 = 0x17,
-+ HBIAS_LEVEL_5 = 0x19,
-+};
-+
-+static int __ac101_get_hmic_data(struct snd_soc_codec *codec) {
-+ #ifdef AC101_DEBG
-+ static long counter;
-+ #endif
-+ int r, d;
-+
-+ d = GET_HMIC_DATA(ac101_read(codec, HMIC_STS));
-+
-+ r = 0x1 << HMIC_DATA_PEND;
-+ ac101_write(codec, HMIC_STS, r);
-+
-+ /* prevent i2c accessing too frequently */
-+ usleep_range(1500, 3000);
-+
-+ AC101_DBG("HMIC_DATA(%3ld): %02X\n", counter++, d);
-+ return d;
-+}
-+
-+/*
-+ * work_cb_earphone_switch: judge the status of the headphone
-+ */
-+static void work_cb_earphone_switch(struct work_struct *work)
-+{
-+ struct ac10x_priv *ac10x = container_of(work, struct ac10x_priv, work_switch);
-+ struct snd_soc_codec *codec = ac10x->codec;
-+
-+ static int hook_flag1 = 0, hook_flag2 = 0;
-+ static int KEY_VOLUME_FLAG = 0;
-+
-+ unsigned filter_buf = 0;
-+ int filt_index = 0;
-+ int t = 0;
-+
-+ ac10x->irq_cntr--;
-+
-+ /* read HMIC_DATA */
-+ t = __ac101_get_hmic_data(codec);
-+
-+ if ((t >= HBIAS_LEVEL_2) && (ac10x->mode == FOUR_HEADPHONE_PLUGIN)) {
-+ t = __ac101_get_hmic_data(codec);
-+
-+ if (t >= HBIAS_LEVEL_5){
-+ msleep(150);
-+ t = __ac101_get_hmic_data(codec);
-+ if (((t < HBIAS_LEVEL_2 && t >= HBIAS_LEVEL_1 - 1) || t >= HBIAS_LEVEL_5)
-+ && (ac10x->pullout_cntr == 0)) {
-+ input_report_key(ac10x->inpdev, KEY_HEADSETHOOK, 1);
-+ input_sync(ac10x->inpdev);
-+
-+ AC101_DBG("KEY_HEADSETHOOK1\n");
-+
-+ if (hook_flag1 != hook_flag2)
-+ hook_flag1 = hook_flag2 = 0;
-+ hook_flag1++;
-+ }
-+ if (ac10x->pullout_cntr)
-+ ac10x->pullout_cntr--;
-+ } else if (t >= HBIAS_LEVEL_4) {
-+ msleep(80);
-+ t = __ac101_get_hmic_data(codec);
-+ if (t < HBIAS_LEVEL_5 && t >= HBIAS_LEVEL_4 && (ac10x->pullout_cntr == 0)) {
-+ KEY_VOLUME_FLAG = 1;
-+ input_report_key(ac10x->inpdev, KEY_VOLUMEUP, 1);
-+ input_sync(ac10x->inpdev);
-+ input_report_key(ac10x->inpdev, KEY_VOLUMEUP, 0);
-+ input_sync(ac10x->inpdev);
-+
-+ AC101_DBG("HMIC_DATA: %d KEY_VOLUMEUP\n", t);
-+ }
-+ if (ac10x->pullout_cntr)
-+ ac10x->pullout_cntr--;
-+ } else if (t >= HBIAS_LEVEL_3){
-+ msleep(80);
-+ t = __ac101_get_hmic_data(codec);
-+ if (t < HBIAS_LEVEL_4 && t >= HBIAS_LEVEL_3 && (ac10x->pullout_cntr == 0)) {
-+ KEY_VOLUME_FLAG = 1;
-+ input_report_key(ac10x->inpdev, KEY_VOLUMEDOWN, 1);
-+ input_sync(ac10x->inpdev);
-+ input_report_key(ac10x->inpdev, KEY_VOLUMEDOWN, 0);
-+ input_sync(ac10x->inpdev);
-+ AC101_DBG("KEY_VOLUMEDOWN\n");
-+ }
-+ if (ac10x->pullout_cntr)
-+ ac10x->pullout_cntr--;
-+ }
-+ } else if ((t < HBIAS_LEVEL_2 && t >= HBIAS_LEVEL_1) &&
-+ (ac10x->mode == FOUR_HEADPHONE_PLUGIN)) {
-+ t = __ac101_get_hmic_data(codec);
-+ if (t < HBIAS_LEVEL_2 && t >= HBIAS_LEVEL_1) {
-+ if (KEY_VOLUME_FLAG) {
-+ KEY_VOLUME_FLAG = 0;
-+ }
-+ if (hook_flag1 == (++hook_flag2)) {
-+ hook_flag1 = hook_flag2 = 0;
-+ input_report_key(ac10x->inpdev, KEY_HEADSETHOOK, 0);
-+ input_sync(ac10x->inpdev);
-+
-+ AC101_DBG("KEY_HEADSETHOOK0\n");
-+ }
-+ }
-+ } else {
-+ while (ac10x->irq_cntr == 0 && ac10x->irq != 0) {
-+ msleep(20);
-+
-+ t = __ac101_get_hmic_data(codec);
-+
-+ if (filt_index <= HEADSET_FILTER_CNT) {
-+ if (filt_index++ == 0) {
-+ filter_buf = t;
-+ } else if (filter_buf != t) {
-+ filt_index = 0;
-+ }
-+ continue;
-+ }
-+
-+ filt_index = 0;
-+ if (filter_buf >= HBIAS_LEVEL_2) {
-+ ac10x->mode = THREE_HEADPHONE_PLUGIN;
-+ ac10x->state = 2;
-+ } else if (filter_buf >= HBIAS_LEVEL_1 - 1) {
-+ ac10x->mode = FOUR_HEADPHONE_PLUGIN;
-+ ac10x->state = 1;
-+ } else {
-+ ac10x->mode = HEADPHONE_IDLE;
-+ ac10x->state = 0;
-+ }
-+ switch_status_update(ac10x);
-+ ac10x->pullout_cntr = 0;
-+ break;
-+ }
-+ }
-+}
-+
-+/*
-+ * audio_hmic_irq: the interrupt handlers
-+ */
-+static irqreturn_t audio_hmic_irq(int irq, void *para)
-+{
-+ struct ac10x_priv *ac10x = (struct ac10x_priv *)para;
-+ if (ac10x == NULL) {
-+ return -EINVAL;
-+ }
-+
-+ if (0 == schedule_work(&ac10x->work_clear_irq)){
-+ AC101_DBG("[audio_hmic_irq] work already in queue_codec_irq, adding failed!\n");
-+ }
-+ return IRQ_HANDLED;
-+}
-+
-+static int ac101_switch_probe(struct ac10x_priv *ac10x) {
-+ struct i2c_client *i2c = ac10x->i2c101;
-+ long ret;
-+
-+ ac10x->gpiod_irq = devm_gpiod_get_optional(&i2c->dev, "switch-irq", GPIOD_IN);
-+ if (IS_ERR(ac10x->gpiod_irq)) {
-+ ac10x->gpiod_irq = NULL;
-+ dev_err(&i2c->dev, "failed get switch-irq in device tree\n");
-+ goto _err_irq;
-+ }
-+
-+ gpiod_direction_input(ac10x->gpiod_irq);
-+
-+ ac10x->irq = gpiod_to_irq(ac10x->gpiod_irq);
-+ if (IS_ERR_VALUE(ac10x->irq)) {
-+ pr_info("[ac101] map gpio to irq failed, errno = %ld\n", ac10x->irq);
-+ ac10x->irq = 0;
-+ goto _err_irq;
-+ }
-+
-+ /* request irq, set irq type to falling edge trigger */
-+ ret = devm_request_irq(ac10x->codec->dev, ac10x->irq, audio_hmic_irq,
-+ IRQF_TRIGGER_FALLING, "SWTICH_EINT", ac10x);
-+ if (IS_ERR_VALUE(ret)) {
-+ pr_info("[ac101] request virq %ld failed, errno = %ld\n", ac10x->irq, ret);
-+ goto _err_irq;
-+ }
-+
-+ ac10x->mode = HEADPHONE_IDLE;
-+ ac10x->state = -1;
-+
-+ /*use for judge the state of switch*/
-+ INIT_WORK(&ac10x->work_switch, work_cb_earphone_switch);
-+ INIT_WORK(&ac10x->work_clear_irq, work_cb_clear_irq);
-+
-+ /********************create input device************************/
-+ ac10x->inpdev = devm_input_allocate_device(ac10x->codec->dev);
-+ if (!ac10x->inpdev) {
-+ AC101_DBG("input_allocate_device: not enough memory for input device\n");
-+ ret = -ENOMEM;
-+ goto _err_input_allocate_device;
-+ }
-+
-+ ac10x->inpdev->name = "seed-voicecard-headset";
-+ ac10x->inpdev->phys = dev_name(ac10x->codec->dev);
-+ ac10x->inpdev->id.bustype = BUS_I2C;
-+ ac10x->inpdev->dev.parent = ac10x->codec->dev;
-+ input_set_drvdata(ac10x->inpdev, ac10x->codec);
-+
-+ ac10x->inpdev->evbit[0] = BIT_MASK(EV_KEY) | BIT(EV_SW);
-+
-+ set_bit(KEY_HEADSETHOOK, ac10x->inpdev->keybit);
-+ set_bit(KEY_VOLUMEUP, ac10x->inpdev->keybit);
-+ set_bit(KEY_VOLUMEDOWN, ac10x->inpdev->keybit);
-+ input_set_capability(ac10x->inpdev, EV_SW, SW_HEADPHONE_INSERT);
-+
-+ ret = input_register_device(ac10x->inpdev);
-+ if (ret) {
-+ AC101_DBG("input_register_device: input_register_device failed\n");
-+ goto _err_input_register_device;
-+ }
-+
-+ /* the first headset state checking */
-+ switch_hw_config(ac10x->codec);
-+ ac10x->irq_cntr = 1;
-+ schedule_work(&ac10x->work_switch);
-+
-+ return 0;
-+
-+_err_input_register_device:
-+_err_input_allocate_device:
-+
-+ if (ac10x->irq) {
-+ devm_free_irq(&i2c->dev, ac10x->irq, ac10x);
-+ ac10x->irq = 0;
-+ }
-+_err_irq:
-+ return ret;
-+}
-+/******************************************************************************/
-+/********************************switch****************************************/
-+/******************************************************************************/
-+#endif
-+
-+
-+
-+void drc_config(struct snd_soc_codec *codec)
-+{
-+ int reg_val;
-+ reg_val = ac101_read(codec, 0xa3);
-+ reg_val &= ~(0x7ff<<0);
-+ reg_val |= 1<<0;
-+ ac101_write(codec, 0xa3, reg_val);
-+ ac101_write(codec, 0xa4, 0x2baf);
-+
-+ reg_val = ac101_read(codec, 0xa5);
-+ reg_val &= ~(0x7ff<<0);
-+ reg_val |= 1<<0;
-+ ac101_write(codec, 0xa5, reg_val);
-+ ac101_write(codec, 0xa6, 0x2baf);
-+
-+ reg_val = ac101_read(codec, 0xa7);
-+ reg_val &= ~(0x7ff<<0);
-+ ac101_write(codec, 0xa7, reg_val);
-+ ac101_write(codec, 0xa8, 0x44a);
-+
-+ reg_val = ac101_read(codec, 0xa9);
-+ reg_val &= ~(0x7ff<<0);
-+ ac101_write(codec, 0xa9, reg_val);
-+ ac101_write(codec, 0xaa, 0x1e06);
-+
-+ reg_val = ac101_read(codec, 0xab);
-+ reg_val &= ~(0x7ff<<0);
-+ reg_val |= (0x352<<0);
-+ ac101_write(codec, 0xab, reg_val);
-+ ac101_write(codec, 0xac, 0x6910);
-+
-+ reg_val = ac101_read(codec, 0xad);
-+ reg_val &= ~(0x7ff<<0);
-+ reg_val |= (0x77a<<0);
-+ ac101_write(codec, 0xad, reg_val);
-+ ac101_write(codec, 0xae, 0xaaaa);
-+
-+ reg_val = ac101_read(codec, 0xaf);
-+ reg_val &= ~(0x7ff<<0);
-+ reg_val |= (0x2de<<0);
-+ ac101_write(codec, 0xaf, reg_val);
-+ ac101_write(codec, 0xb0, 0xc982);
-+
-+ ac101_write(codec, 0x16, 0x9f9f);
-+
-+}
-+
-+void drc_enable(struct snd_soc_codec *codec,bool on)
-+{
-+ int reg_val;
-+ if (on) {
-+ ac101_write(codec, 0xb5, 0xA080);
-+ reg_val = ac101_read(codec, MOD_CLK_ENA);
-+ reg_val |= (0x1<<6);
-+ ac101_write(codec, MOD_CLK_ENA, reg_val);
-+ reg_val = ac101_read(codec, MOD_RST_CTRL);
-+ reg_val |= (0x1<<6);
-+ ac101_write(codec, MOD_RST_CTRL, reg_val);
-+
-+ reg_val = ac101_read(codec, 0xa0);
-+ reg_val |= (0x7<<0);
-+ ac101_write(codec, 0xa0, reg_val);
-+ } else {
-+ ac101_write(codec, 0xb5, 0x0);
-+ reg_val = ac101_read(codec, MOD_CLK_ENA);
-+ reg_val &= ~(0x1<<6);
-+ ac101_write(codec, MOD_CLK_ENA, reg_val);
-+ reg_val = ac101_read(codec, MOD_RST_CTRL);
-+ reg_val &= ~(0x1<<6);
-+ ac101_write(codec, MOD_RST_CTRL, reg_val);
-+
-+ reg_val = ac101_read(codec, 0xa0);
-+ reg_val &= ~(0x7<<0);
-+ ac101_write(codec, 0xa0, reg_val);
-+ }
-+}
-+
-+void set_configuration(struct snd_soc_codec *codec)
-+{
-+ if (speaker_double_used) {
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x1f<<SPK_VOL),
-+ (double_speaker_val<<SPK_VOL));
-+ } else {
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x1f<<SPK_VOL),
-+ (single_speaker_val<<SPK_VOL));
-+ }
-+ ac101_update_bits(codec, HPOUT_CTRL, (0x3f<<HP_VOL), (headset_val<<HP_VOL));
-+ ac101_update_bits(codec, ADC_SRCBST_CTRL, (0x7<<ADC_MIC1G), (mainmic_val<<ADC_MIC1G));
-+ ac101_update_bits(codec, ADC_SRCBST_CTRL, (0x7<<ADC_MIC2G), (headsetmic_val<<ADC_MIC2G));
-+ if (dmic_used) {
-+ ac101_write(codec, ADC_VOL_CTRL, adc_digital_val);
-+ }
-+ if (drc_used) {
-+ drc_config(codec);
-+ }
-+ /*headphone calibration clock frequency select*/
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x7<<HPCALICKS), (0x7<<HPCALICKS));
-+
-+ /* I2S1 DAC Timeslot 0 data <- I2S1 DAC channel 0 */
-+ // "AIF1IN0L Mux" <= "AIF1DACL"
-+ // "AIF1IN0R Mux" <= "AIF1DACR"
-+ ac101_update_bits(codec, AIF1_DACDAT_CTRL, 0x3 << AIF1_DA0L_SRC, 0x0 << AIF1_DA0L_SRC);
-+ ac101_update_bits(codec, AIF1_DACDAT_CTRL, 0x3 << AIF1_DA0R_SRC, 0x0 << AIF1_DA0R_SRC);
-+ /* Timeslot 0 Left & Right Channel enable */
-+ ac101_update_bits(codec, AIF1_DACDAT_CTRL, 0x3 << AIF1_DA0R_ENA, 0x3 << AIF1_DA0R_ENA);
-+
-+ /* DAC Digital Mixer Source Select <- I2S1 DA0 */
-+ // "DACL Mixer" += "AIF1IN0L Mux"
-+ // "DACR Mixer" += "AIF1IN0R Mux"
-+ ac101_update_bits(codec, DAC_MXR_SRC, 0xF << DACL_MXR_ADCL, 0x8 << DACL_MXR_ADCL);
-+ ac101_update_bits(codec, DAC_MXR_SRC, 0xF << DACR_MXR_ADCR, 0x8 << DACR_MXR_ADCR);
-+ /* Internal DAC Analog Left & Right Channel enable */
-+ ac101_update_bits(codec, OMIXER_DACA_CTRL, 0x3 << DACALEN, 0x3 << DACALEN);
-+
-+ /* Output Mixer Source Select */
-+ // "Left Output Mixer" += "DACL Mixer"
-+ // "Right Output Mixer" += "DACR Mixer"
-+ ac101_update_bits(codec, OMIXER_SR, 0x1 << LMIXMUTEDACL, 0x1 << LMIXMUTEDACL);
-+ ac101_update_bits(codec, OMIXER_SR, 0x1 << RMIXMUTEDACR, 0x1 << RMIXMUTEDACR);
-+ /* Left & Right Analog Output Mixer enable */
-+ ac101_update_bits(codec, OMIXER_DACA_CTRL, 0x3 << LMIXEN, 0x3 << LMIXEN);
-+
-+ /* Headphone Ouput Control */
-+ // "HP_R Mux" <= "DACR Mixer"
-+ // "HP_L Mux" <= "DACL Mixer"
-+ ac101_update_bits(codec, HPOUT_CTRL, 0x1 << LHPS, 0x0 << LHPS);
-+ ac101_update_bits(codec, HPOUT_CTRL, 0x1 << RHPS, 0x0 << RHPS);
-+
-+ /* Speaker Output Control */
-+ // "SPK_L Mux" <= "SPK_LR Adder"
-+ // "SPK_R Mux" <= "SPK_LR Adder"
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x1 << LSPKS) | (0x1 << RSPKS),
-+ (0x1 << LSPKS) | (0x1 << RSPKS));
-+ /* Enable Left & Right Speaker */
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x1 << LSPK_EN) | (0x1 << RSPK_EN),
-+ (0x1 << LSPK_EN) | (0x1 << RSPK_EN));
-+ return;
-+}
-+
-+static int late_enable_dac(struct snd_soc_codec* codec, int event) {
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ mutex_lock(&ac10x->dac_mutex);
-+ switch (event) {
-+ case SND_SOC_DAPM_PRE_PMU:
-+ AC101_DBG();
-+ if (ac10x->dac_enable == 0){
-+ /*enable dac module clk*/
-+ ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_DAC_DIG),
-+ (0x1<<MOD_CLK_DAC_DIG));
-+ ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_DAC_DIG),
-+ (0x1<<MOD_RESET_DAC_DIG));
-+ ac101_update_bits(codec, DAC_DIG_CTRL, (0x1<<ENDA), (0x1<<ENDA));
-+ ac101_update_bits(codec, DAC_DIG_CTRL, (0x1<<ENHPF),(0x1<<ENHPF));
-+ }
-+ ac10x->dac_enable++;
-+ break;
-+ case SND_SOC_DAPM_POST_PMD:
-+ if (ac10x->dac_enable != 0){
-+ ac10x->dac_enable = 0;
-+
-+ ac101_update_bits(codec, DAC_DIG_CTRL, (0x1<<ENHPF),(0x0<<ENHPF));
-+ ac101_update_bits(codec, DAC_DIG_CTRL, (0x1<<ENDA), (0x0<<ENDA));
-+ /*disable dac module clk*/
-+ ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_DAC_DIG),
-+ (0x0<<MOD_CLK_DAC_DIG));
-+ ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_DAC_DIG),
-+ (0x0<<MOD_RESET_DAC_DIG));
-+ }
-+ break;
-+ }
-+ mutex_unlock(&ac10x->dac_mutex);
-+ return 0;
-+}
-+
-+static int ac101_headphone_event(struct snd_soc_codec* codec, int event) {
-+ switch (event) {
-+ case SND_SOC_DAPM_POST_PMU:
-+ /*open*/
-+ AC101_DBG("post:open\n");
-+ ac101_update_bits(codec, OMIXER_DACA_CTRL, (0xf<<HPOUTPUTENABLE),
-+ (0xf<<HPOUTPUTENABLE));
-+ msleep(10);
-+ ac101_update_bits(codec, HPOUT_CTRL, (0x1<<HPPA_EN), (0x1<<HPPA_EN));
-+ ac101_update_bits(codec, HPOUT_CTRL, (0x3<<LHPPA_MUTE), (0x3<<LHPPA_MUTE));
-+ break;
-+ case SND_SOC_DAPM_PRE_PMD:
-+ /*close*/
-+ AC101_DBG("pre:close\n");
-+ ac101_update_bits(codec, HPOUT_CTRL, (0x3<<LHPPA_MUTE), (0x0<<LHPPA_MUTE));
-+ msleep(10);
-+ ac101_update_bits(codec, OMIXER_DACA_CTRL, (0xf<<HPOUTPUTENABLE),
-+ (0x0<<HPOUTPUTENABLE));
-+ ac101_update_bits(codec, HPOUT_CTRL, (0x1<<HPPA_EN), (0x0<<HPPA_EN));
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static int ac101_sysclk_started(void) {
-+ int reg_val;
-+
-+ reg_val = ac101_read(static_ac10x->codec, SYSCLK_CTRL);
-+ return (reg_val & (0x1<<SYSCLK_ENA));
-+}
-+
-+static int ac101_aif1clk(struct snd_soc_codec* codec, int event, int quick) {
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int ret = 0;
-+
-+ switch (event) {
-+ case SND_SOC_DAPM_PRE_PMU:
-+ if (ac10x->aif1_clken == 0){
-+ ret = ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<AIF1CLK_ENA),
-+ (0x1<<AIF1CLK_ENA));
-+ if(!quick || _MASTER_MULTI_CODEC != _MASTER_AC101) {
-+ /* enable aif1clk & sysclk */
-+ ret = ret || ac101_update_bits(codec, MOD_CLK_ENA,
-+ (0x1<<MOD_CLK_AIF1),
-+ (0x1<<MOD_CLK_AIF1));
-+ ret = ret || ac101_update_bits(codec, MOD_RST_CTRL,
-+ (0x1<<MOD_RESET_AIF1),
-+ (0x1<<MOD_RESET_AIF1));
-+ }
-+ ret = ret || ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<SYSCLK_ENA),
-+ (0x1<<SYSCLK_ENA));
-+
-+ if (ret) {
-+ AC101_DBG("start sysclk failed\n");
-+ } else {
-+ AC101_DBG("hw sysclk enable\n");
-+ ac10x->aif1_clken++;
-+ }
-+ }
-+ break;
-+ case SND_SOC_DAPM_POST_PMD:
-+ if (ac10x->aif1_clken != 0) {
-+ /* disable aif1clk & sysclk */
-+ ret = ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<AIF1CLK_ENA),
-+ (0x0<<AIF1CLK_ENA));
-+ ret = ret || ac101_update_bits(codec, MOD_CLK_ENA, (0x1<<MOD_CLK_AIF1),
-+ (0x0<<MOD_CLK_AIF1));
-+ ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1),
-+ (0x0<<MOD_RESET_AIF1));
-+ ret = ret || ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<SYSCLK_ENA),
-+ (0x0<<SYSCLK_ENA));
-+
-+ if (ret) {
-+ AC101_DBG("stop sysclk failed\n");
-+ } else {
-+ AC101_DBG("hw sysclk disable\n");
-+ ac10x->aif1_clken = 0;
-+ }
-+ break;
-+ }
-+ }
-+
-+ AC101_DBG("event=%d pre_up/%d post_down/%d\n", event, SND_SOC_DAPM_PRE_PMU,
-+ SND_SOC_DAPM_POST_PMD);
-+
-+ return ret;
-+}
-+
-+/**
-+ * snd_ac101_get_volsw - single mixer get callback
-+ * @kcontrol: mixer control
-+ * @ucontrol: control element information
-+ *
-+ * Callback to get the value of a single mixer control, or a double mixer
-+ * control that spans 2 registers.
-+ *
-+ * Returns 0 for success.
-+ */
-+static int snd_ac101_get_volsw(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol
-+){
-+ struct soc_mixer_control *mc =
-+ (struct soc_mixer_control *)kcontrol->private_value;
-+ unsigned int val, mask = (1 << fls(mc->max)) - 1;
-+ unsigned int invert = mc->invert;
-+ int ret;
-+
-+ if ((ret = ac101_read(static_ac10x->codec, mc->reg)) < 0)
-+ return ret;
-+
-+ val = (ret >> mc->shift) & mask;
-+ ucontrol->value.integer.value[0] = val - mc->min;
-+ if (invert) {
-+ ucontrol->value.integer.value[0] =
-+ mc->max - ucontrol->value.integer.value[0];
-+ }
-+
-+ if (snd_soc_volsw_is_stereo(mc)) {
-+ val = (ret >> mc->rshift) & mask;
-+ ucontrol->value.integer.value[1] = val - mc->min;
-+ if (invert) {
-+ ucontrol->value.integer.value[1] =
-+ mc->max - ucontrol->value.integer.value[1];
-+ }
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * snd_ac101_put_volsw - single mixer put callback
-+ * @kcontrol: mixer control
-+ * @ucontrol: control element information
-+ *
-+ * Callback to set the value of a single mixer control, or a double mixer
-+ * control that spans 2 registers.
-+ *
-+ * Returns 0 for success.
-+ */
-+static int snd_ac101_put_volsw(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol
-+){
-+ struct soc_mixer_control *mc =
-+ (struct soc_mixer_control *)kcontrol->private_value;
-+ unsigned int sign_bit = mc->sign_bit;
-+ unsigned int val, mask = (1 << fls(mc->max)) - 1;
-+ unsigned int invert = mc->invert;
-+ int ret;
-+
-+ if (sign_bit)
-+ mask = BIT(sign_bit + 1) - 1;
-+
-+ val = ((ucontrol->value.integer.value[0] + mc->min) & mask);
-+ if (invert) {
-+ val = mc->max - val;
-+ }
-+
-+ ret = ac101_update_bits(static_ac10x->codec, mc->reg, mask << mc->shift, val << mc->shift);
-+
-+ if (! snd_soc_volsw_is_stereo(mc)) {
-+ return ret;
-+ }
-+ val = ((ucontrol->value.integer.value[1] + mc->min) & mask);
-+ if (invert) {
-+ val = mc->max - val;
-+ }
-+
-+ ret = ac101_update_bits(static_ac10x->codec, mc->reg, mask << mc->rshift,
-+ val << mc->rshift);
-+ return ret;
-+}
-+
-+
-+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -11925, 75, 0);
-+static const DECLARE_TLV_DB_SCALE(dac_mix_vol_tlv, -600, 600, 0);
-+static const DECLARE_TLV_DB_SCALE(dig_vol_tlv, -7308, 116, 0);
-+static const DECLARE_TLV_DB_SCALE(speaker_vol_tlv, -4800, 150, 0);
-+static const DECLARE_TLV_DB_SCALE(headphone_vol_tlv, -6300, 100, 0);
-+
-+static struct snd_kcontrol_new ac101_controls[] = {
-+ /*DAC*/
-+ SOC_DOUBLE_TLV("DAC volume", DAC_VOL_CTRL, DAC_VOL_L, DAC_VOL_R, 0xff, 0, dac_vol_tlv),
-+ SOC_DOUBLE_TLV("DAC mixer gain", DAC_MXR_GAIN, DACL_MXR_GAIN, DACR_MXR_GAIN,
-+ 0xf, 0, dac_mix_vol_tlv),
-+ SOC_SINGLE_TLV("digital volume", DAC_DBG_CTRL, DVC, 0x3f, 1, dig_vol_tlv),
-+ SOC_SINGLE_TLV("speaker volume", SPKOUT_CTRL, SPK_VOL, 0x1f, 0, speaker_vol_tlv),
-+ SOC_SINGLE_TLV("headphone volume", HPOUT_CTRL, HP_VOL, 0x3f, 0, headphone_vol_tlv),
-+};
-+
-+/* PLL divisors */
-+struct pll_div {
-+ unsigned int pll_in;
-+ unsigned int pll_out;
-+ int m;
-+ int n_i;
-+ int n_f;
-+};
-+
-+struct aif1_fs {
-+ unsigned samp_rate;
-+ int bclk_div;
-+ int srbit;
-+ #define _SERIES_24_576K 0
-+ #define _SERIES_22_579K 1
-+ int series;
-+};
-+
-+struct kv_map {
-+ int val;
-+ int bit;
-+};
-+
-+/*
-+ * Note : pll code from original tdm/i2s driver.
-+ * freq_out = freq_in * N/(M*(2k+1)) , k=1,N=N_i+N_f,N_f=factor*0.2;
-+ * N_i[0,1023], N_f_factor[0,7], m[1,64]=REG_VAL[1-63,0]
-+ */
-+static const struct pll_div codec_pll_div[] = {
-+ {128000, _FREQ_22_579K, 1, 529, 1},
-+ {192000, _FREQ_22_579K, 1, 352, 4},
-+ {256000, _FREQ_22_579K, 1, 264, 3},
-+ {384000, _FREQ_22_579K, 1, 176, 2}, /*((176+2*0.2)*6000000)/(38*(2*1+1))*/
-+ {1411200, _FREQ_22_579K, 1, 48, 0},
-+ {2822400, _FREQ_22_579K, 1, 24, 0}, /* accurate, 11025 * 256 */
-+ {5644800, _FREQ_22_579K, 1, 12, 0}, /* accurate, 22050 * 256 */
-+ {6000000, _FREQ_22_579K, 38, 429, 0}, /*((429+0*0.2)*6000000)/(38*(2*1+1))*/
-+ {11289600, _FREQ_22_579K, 1, 6, 0}, /* accurate, 44100 * 256 */
-+ {13000000, _FREQ_22_579K, 19, 99, 0},
-+ {19200000, _FREQ_22_579K, 25, 88, 1},
-+ {24000000, _FREQ_22_579K, 63, 177, 4}, /* 22577778 Hz */
-+
-+ {128000, _FREQ_24_576K, 1, 576, 0},
-+ {192000, _FREQ_24_576K, 1, 384, 0},
-+ {256000, _FREQ_24_576K, 1, 288, 0},
-+ {384000, _FREQ_24_576K, 1, 192, 0},
-+ {2048000, _FREQ_24_576K, 1, 36, 0}, /* accurate, 8000 * 256 */
-+ {3072000, _FREQ_24_576K, 1, 24, 0}, /* accurate, 12000 * 256 */
-+ {4096000, _FREQ_24_576K, 1, 18, 0}, /* accurate, 16000 * 256 */
-+ {6000000, _FREQ_24_576K, 25, 307, 1},
-+ {6144000, _FREQ_24_576K, 4, 48, 0}, /* accurate, 24000 * 256 */
-+ {12288000, _FREQ_24_576K, 8, 48, 0}, /* accurate, 48000 * 256 */
-+ {13000000, _FREQ_24_576K, 42, 238, 1},
-+ {19200000, _FREQ_24_576K, 25, 96, 0},
-+ {24000000, _FREQ_24_576K, 25, 76, 4}, /* accurate */
-+
-+ {_FREQ_22_579K, _FREQ_22_579K, 8, 24, 0}, /* accurate, 88200 * 256 */
-+ {_FREQ_24_576K, _FREQ_24_576K, 8, 24, 0}, /* accurate, 96000 * 256 */
-+};
-+
-+static const struct aif1_fs codec_aif1_fs[] = {
-+ {8000, 12, 0},
-+ {11025, 8, 1, _SERIES_22_579K},
-+ {12000, 8, 2},
-+ {16000, 6, 3},
-+ {22050, 4, 4, _SERIES_22_579K},
-+ {24000, 4, 5},
-+ /* {32000, 3, 6}, dividing by 3 is not support */
-+ {44100, 2, 7, _SERIES_22_579K},
-+ {48000, 2, 8},
-+ {96000, 1, 9},
-+};
-+
-+static const struct kv_map codec_aif1_lrck[] = {
-+ {16, 0},
-+ {32, 1},
-+ {64, 2},
-+ {128, 3},
-+ {256, 4},
-+};
-+
-+static const struct kv_map codec_aif1_wsize[] = {
-+ {8, 0},
-+ {16, 1},
-+ {20, 2},
-+ {24, 3},
-+ {32, 3},
-+};
-+
-+static const unsigned ac101_bclkdivs[] = {
-+ 1, 2, 4, 6,
-+ 8, 12, 16, 24,
-+ 32, 48, 64, 96,
-+ 128, 192, 0, 0,
-+};
-+
-+static int ac101_aif_play(struct ac10x_priv* ac10x) {
-+ struct snd_soc_codec * codec = ac10x->codec;
-+
-+ late_enable_dac(codec, SND_SOC_DAPM_PRE_PMU);
-+ ac101_headphone_event(codec, SND_SOC_DAPM_POST_PMU);
-+ if (drc_used) {
-+ drc_enable(codec, 1);
-+ }
-+
-+ /* Enable Left & Right Speaker */
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x1 << LSPK_EN) | (0x1 << RSPK_EN),
-+ (0x1 << LSPK_EN) | (0x1 << RSPK_EN));
-+ if (ac10x->gpiod_spk_amp_gate) {
-+ gpiod_set_value(ac10x->gpiod_spk_amp_gate, 1);
-+ }
-+ return 0;
-+}
-+
-+static void ac10x_work_aif_play(struct work_struct *work) {
-+ struct ac10x_priv *ac10x = container_of(work, struct ac10x_priv, dlywork.work);
-+
-+ ac101_aif_play(ac10x);
-+ return;
-+}
-+
-+int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute)
-+{
-+ struct snd_soc_codec *codec = codec_dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ AC101_DBG("mute=%d\n", mute);
-+
-+ ac101_write(codec, DAC_VOL_CTRL, mute? 0: 0xA0A0);
-+
-+ if (!mute) {
-+ #if _MASTER_MULTI_CODEC != _MASTER_AC101
-+ /* enable global clock */
-+ ac10x->aif1_clken = 0;
-+ ac101_aif1clk(codec, SND_SOC_DAPM_PRE_PMU, 0);
-+ ac101_aif_play(ac10x);
-+ #else
-+ schedule_delayed_work(&ac10x->dlywork, msecs_to_jiffies(50));
-+ #endif
-+ } else {
-+ #if _MASTER_MULTI_CODEC == _MASTER_AC101
-+ cancel_delayed_work_sync(&ac10x->dlywork);
-+ #endif
-+
-+ if (ac10x->gpiod_spk_amp_gate) {
-+ gpiod_set_value(ac10x->gpiod_spk_amp_gate, 0);
-+ }
-+ /* Disable Left & Right Speaker */
-+ ac101_update_bits(codec, SPKOUT_CTRL, (0x1 << LSPK_EN) | (0x1 << RSPK_EN),
-+ (0x0 << LSPK_EN) | (0x0 << RSPK_EN));
-+ if (drc_used) {
-+ drc_enable(codec, 0);
-+ }
-+ ac101_headphone_event(codec, SND_SOC_DAPM_PRE_PMD);
-+ late_enable_dac(codec, SND_SOC_DAPM_POST_PMD);
-+
-+ #if _MASTER_MULTI_CODEC != _MASTER_AC101
-+ ac10x->aif1_clken = 1;
-+ ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
-+ #endif
-+ }
-+ return 0;
-+}
-+
-+void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai)
-+{
-+ struct snd_soc_codec *codec = codec_dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ AC101_DBG("stream = %s, play: %d, capt: %d, active: %d\n",
-+ snd_pcm_stream_str(substream),
-+ codec_dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active,
-+ codec_dai->stream[SNDRV_PCM_STREAM_CAPTURE].active,
-+ snd_soc_dai_active(codec_dai));
-+
-+ if (!snd_soc_dai_active(codec_dai)) {
-+ ac10x->aif1_clken = 1;
-+ ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
-+ } else {
-+ ac101_aif1clk(codec, SND_SOC_DAPM_PRE_PMU, 0);
-+ }
-+}
-+
-+static int ac101_set_pll(struct snd_soc_dai *codec_dai, int pll_id, int source,
-+ unsigned int freq_in, unsigned int freq_out)
-+{
-+ struct snd_soc_codec *codec = codec_dai->codec;
-+ int i, m, n_i, n_f;
-+
-+ AC101_DBG("pll_id:%d\n", pll_id);
-+
-+ /* clear volatile reserved bits*/
-+ ac101_update_bits(codec, SYSCLK_CTRL, 0xFF & ~(0x1 << SYSCLK_ENA), 0x0);
-+
-+ /* select aif1 clk srouce from mclk1 */
-+ ac101_update_bits(codec, SYSCLK_CTRL, (0x3<<AIF1CLK_SRC), (0x0<<AIF1CLK_SRC));
-+ /* disable pll */
-+ ac101_update_bits(codec, PLL_CTRL2, (0x1<<PLL_EN), (0<<PLL_EN));
-+
-+ if (!freq_out)
-+ return 0;
-+ if ((freq_in < 128000) || (freq_in > _FREQ_24_576K)) {
-+ return -EINVAL;
-+ } else if ((freq_in == _FREQ_24_576K) || (freq_in == _FREQ_22_579K)) {
-+ if (pll_id == AC101_MCLK1) {
-+ /*select aif1 clk source from mclk1*/
-+ ac101_update_bits(codec, SYSCLK_CTRL, (0x3<<AIF1CLK_SRC),
-+ (0x0<<AIF1CLK_SRC));
-+ return 0;
-+ }
-+ }
-+
-+ switch (pll_id) {
-+ case AC101_MCLK1:
-+ /*pll source from MCLK1*/
-+ ac101_update_bits(codec, SYSCLK_CTRL, (0x3<<PLLCLK_SRC), (0x0<<PLLCLK_SRC));
-+ break;
-+ case AC101_BCLK1:
-+ /*pll source from BCLK1*/
-+ ac101_update_bits(codec, SYSCLK_CTRL, (0x3<<PLLCLK_SRC), (0x2<<PLLCLK_SRC));
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ /* freq_out = freq_in * n/(m*(2k+1)) , k=1,N=N_i+N_f */
-+ for (i = m = n_i = n_f = 0; i < ARRAY_SIZE(codec_pll_div); i++) {
-+ if ((codec_pll_div[i].pll_in == freq_in) &&
-+ (codec_pll_div[i].pll_out == freq_out)) {
-+ m = codec_pll_div[i].m;
-+ n_i = codec_pll_div[i].n_i;
-+ n_f = codec_pll_div[i].n_f;
-+ break;
-+ }
-+ }
-+ /* config pll m */
-+ if (m == 64) m = 0;
-+ ac101_update_bits(codec, PLL_CTRL1, (0x3f<<PLL_POSTDIV_M), (m<<PLL_POSTDIV_M));
-+ /* config pll n */
-+ ac101_update_bits(codec, PLL_CTRL2, (0x3ff<<PLL_PREDIV_NI), (n_i<<PLL_PREDIV_NI));
-+ ac101_update_bits(codec, PLL_CTRL2, (0x7<<PLL_POSTDIV_NF), (n_f<<PLL_POSTDIV_NF));
-+ /* enable pll */
-+ ac101_update_bits(codec, PLL_CTRL2, (0x1<<PLL_EN), (1<<PLL_EN));
-+ ac101_update_bits(codec, SYSCLK_CTRL, (0x1<<PLLCLK_ENA), (0x1<<PLLCLK_ENA));
-+ ac101_update_bits(codec, SYSCLK_CTRL, (0x3<<AIF1CLK_SRC), (0x3<<AIF1CLK_SRC));
-+
-+ return 0;
-+}
-+
-+int ac101_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *codec_dai)
-+{
-+ int i = 0;
-+ int AIF_CLK_CTRL = AIF1_CLK_CTRL;
-+ int aif1_word_size = 24;
-+ int aif1_slot_size = 32;
-+ int aif1_lrck_div;
-+ struct snd_soc_codec *codec = codec_dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int reg_val, freq_out;
-+ unsigned channels;
-+
-+ AC101_DBG("+++\n");
-+
-+ if (_MASTER_MULTI_CODEC == _MASTER_AC101 && ac101_sysclk_started()) {
-+ /* not configure hw_param twice if stream is playback, tell the caller it's started */
-+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-+ return 1;
-+ }
-+ }
-+
-+ /* get channels count & slot size */
-+ channels = params_channels(params);
-+
-+ switch (params_format(params)) {
-+ case SNDRV_PCM_FORMAT_S24_LE:
-+ case SNDRV_PCM_FORMAT_S32_LE:
-+ aif1_slot_size = 32;
-+ break;
-+ case SNDRV_PCM_FORMAT_S16_LE:
-+ default:
-+ aif1_slot_size = 16;
-+ break;
-+ }
-+
-+ /* set LRCK/BCLK ratio */
-+ aif1_lrck_div = aif1_slot_size * channels;
-+ for (i = 0; i < ARRAY_SIZE(codec_aif1_lrck); i++) {
-+ if (codec_aif1_lrck[i].val == aif1_lrck_div) {
-+ break;
-+ }
-+ }
-+ ac101_update_bits(codec, AIF_CLK_CTRL, (0x7 << AIF1_LRCK_DIV),
-+ codec_aif1_lrck[i].bit << AIF1_LRCK_DIV);
-+
-+ /* set PLL output freq */
-+ freq_out = _FREQ_24_576K;
-+ for (i = 0; i < ARRAY_SIZE(codec_aif1_fs); i++) {
-+ if (codec_aif1_fs[i].samp_rate == params_rate(params)) {
-+ if (codec_dai->stream[SNDRV_PCM_STREAM_CAPTURE].active && dmic_used &&
-+ codec_aif1_fs[i].samp_rate == 44100) {
-+ ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS),
-+ (0x4<<AIF1_FS));
-+ } else {
-+ ac101_update_bits(codec, AIF_SR_CTRL, (0xf<<AIF1_FS),
-+ ((codec_aif1_fs[i].srbit)<<AIF1_FS));
-+ }
-+ if (codec_aif1_fs[i].series == _SERIES_22_579K)
-+ freq_out = _FREQ_22_579K;
-+ break;
-+ }
-+ }
-+
-+ /* set I2S word size */
-+ for (i = 0; i < ARRAY_SIZE(codec_aif1_wsize); i++) {
-+ if (codec_aif1_wsize[i].val == aif1_word_size) {
-+ break;
-+ }
-+ }
-+ ac101_update_bits(codec, AIF_CLK_CTRL, (0x3<<AIF1_WORK_SIZ),
-+ ((codec_aif1_wsize[i].bit)<<AIF1_WORK_SIZ));
-+
-+ /* set TDM slot size */
-+ if ((reg_val = codec_aif1_wsize[i].bit) > 2) reg_val = 2;
-+ ac101_update_bits(codec, AIF1_ADCDAT_CTRL, 0x3 << AIF1_SLOT_SIZ, reg_val << AIF1_SLOT_SIZ);
-+
-+ /* setting pll if it's master mode */
-+ reg_val = ac101_read(codec, AIF_CLK_CTRL);
-+ if ((reg_val & (0x1 << AIF1_MSTR_MOD)) == 0) {
-+ unsigned bclkdiv;
-+
-+ ac101_set_pll(codec_dai, AC101_MCLK1, 0, ac10x->sysclk, freq_out);
-+
-+ bclkdiv = freq_out / (aif1_lrck_div * params_rate(params));
-+ for (i = 0; i < ARRAY_SIZE(ac101_bclkdivs) - 1; i++) {
-+ if (ac101_bclkdivs[i] >= bclkdiv) {
-+ break;
-+ }
-+ }
-+ ac101_update_bits(codec, AIF_CLK_CTRL, (0xf<<AIF1_BCLK_DIV), i<<AIF1_BCLK_DIV);
-+ } else {
-+ /* set pll clock source to BCLK if slave mode */
-+ ac101_set_pll(codec_dai, AC101_BCLK1, 0, aif1_lrck_div * params_rate(params),
-+ freq_out);
-+ }
-+
-+ #if _MASTER_MULTI_CODEC == _MASTER_AC101
-+ /* Master mode, to clear cpu_dai fifos, disable output bclk & lrck */
-+ ac101_aif1clk(codec, SND_SOC_DAPM_POST_PMD, 0);
-+ #endif
-+
-+ AC101_DBG("rate: %d , channels: %d , samp_res: %d",
-+ params_rate(params), channels, aif1_slot_size);
-+
-+ AC101_DBG("---\n");
-+ return 0;
-+}
-+
-+int ac101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
-+{
-+ int reg_val;
-+ int AIF_CLK_CTRL = AIF1_CLK_CTRL;
-+ struct snd_soc_codec *codec = codec_dai->codec;
-+
-+ AC101_DBG();
-+
-+ /*
-+ * master or slave selection
-+ * 0 = Master mode
-+ * 1 = Slave mode
-+ */
-+ reg_val = ac101_read(codec, AIF_CLK_CTRL);
-+ reg_val &= ~(0x1<<AIF1_MSTR_MOD);
-+ switch(fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-+ case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master, ap is slave*/
-+ #if _MASTER_MULTI_CODEC == _MASTER_AC101
-+ pr_warn("AC101 as Master\n");
-+ reg_val |= (0x0<<AIF1_MSTR_MOD);
-+ break;
-+ #else
-+ pr_warn("AC108 as Master\n");
-+ #endif
-+ case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave, ap is master*/
-+ pr_warn("AC101 as Slave\n");
-+ reg_val |= (0x1<<AIF1_MSTR_MOD);
-+ break;
-+ default:
-+ pr_err("unknwon master/slave format\n");
-+ return -EINVAL;
-+ }
-+
-+ /*
-+ * Enable TDM mode
-+ */
-+ reg_val |= (0x1 << AIF1_TDMM_ENA);
-+ ac101_write(codec, AIF_CLK_CTRL, reg_val);
-+
-+ /* i2s mode selection */
-+ reg_val = ac101_read(codec, AIF_CLK_CTRL);
-+ reg_val&=~(3<<AIF1_DATA_FMT);
-+ switch(fmt & SND_SOC_DAIFMT_FORMAT_MASK){
-+ case SND_SOC_DAIFMT_I2S: /* I2S1 mode */
-+ reg_val |= (0x0<<AIF1_DATA_FMT);
-+ break;
-+ case SND_SOC_DAIFMT_RIGHT_J: /* Right Justified mode */
-+ reg_val |= (0x2<<AIF1_DATA_FMT);
-+ break;
-+ case SND_SOC_DAIFMT_LEFT_J: /* Left Justified mode */
-+ reg_val |= (0x1<<AIF1_DATA_FMT);
-+ break;
-+ case SND_SOC_DAIFMT_DSP_A: /* L reg_val msb after FRM LRC */
-+ reg_val |= (0x3<<AIF1_DATA_FMT);
-+ break;
-+ case SND_SOC_DAIFMT_DSP_B:
-+ /* TODO: data offset set to 0 */
-+ reg_val |= (0x3<<AIF1_DATA_FMT);
-+ break;
-+ default:
-+ pr_err("%s, line:%d\n", __func__, __LINE__);
-+ return -EINVAL;
-+ }
-+ ac101_write(codec, AIF_CLK_CTRL, reg_val);
-+
-+ /* DAI signal inversions */
-+ reg_val = ac101_read(codec, AIF_CLK_CTRL);
-+ switch(fmt & SND_SOC_DAIFMT_INV_MASK){
-+ case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + nor frame */
-+ reg_val &= ~(0x1<<AIF1_LRCK_INV);
-+ reg_val &= ~(0x1<<AIF1_BCLK_INV);
-+ break;
-+ case SND_SOC_DAIFMT_NB_IF: /* normal bclk + inv frm */
-+ reg_val |= (0x1<<AIF1_LRCK_INV);
-+ reg_val &= ~(0x1<<AIF1_BCLK_INV);
-+ break;
-+ case SND_SOC_DAIFMT_IB_NF: /* invert bclk + nor frm */
-+ reg_val &= ~(0x1<<AIF1_LRCK_INV);
-+ reg_val |= (0x1<<AIF1_BCLK_INV);
-+ break;
-+ case SND_SOC_DAIFMT_IB_IF: /* invert bclk + inv frm */
-+ reg_val |= (0x1<<AIF1_LRCK_INV);
-+ reg_val |= (0x1<<AIF1_BCLK_INV);
-+ break;
-+ }
-+ ac101_write(codec, AIF_CLK_CTRL, reg_val);
-+
-+ return 0;
-+}
-+
-+int ac101_audio_startup(struct snd_pcm_substream *substream,
-+ struct snd_soc_dai *codec_dai)
-+{
-+ // struct snd_soc_codec *codec = codec_dai->codec;
-+
-+ AC101_DBG("\n\n\n");
-+
-+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-+ }
-+ return 0;
-+}
-+
-+int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
-+ struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_codec *codec = dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int ret = 0;
-+
-+ AC101_DBG("stream=%s cmd=%d\n",
-+ snd_pcm_stream_str(substream),
-+ cmd);
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ case SNDRV_PCM_TRIGGER_RESUME:
-+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+ #if _MASTER_MULTI_CODEC == _MASTER_AC101
-+ if (ac10x->aif1_clken == 0){
-+ /*
-+ * enable aif1clk, it' here due to reduce time between 'AC108 Sysclk Enable' and 'AC101 Sysclk Enable'
-+ * Or else the two AC108 chips lost the sync.
-+ */
-+ ret = 0;
-+ ret = ret || ac101_update_bits(codec, MOD_CLK_ENA,
-+ (0x1<<MOD_CLK_AIF1), (0x1<<MOD_CLK_AIF1));
-+ ret = ret || ac101_update_bits(codec, MOD_RST_CTRL, (0x1<<MOD_RESET_AIF1),
-+ (0x1<<MOD_RESET_AIF1));
-+ }
-+ #endif
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ case SNDRV_PCM_TRIGGER_SUSPEND:
-+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ }
-+ return ret;
-+}
-+
-+#if 0
-+static int ac101_set_dai_sysclk(struct snd_soc_dai *codec_dai,
-+ int clk_id, unsigned int freq, int dir)
-+{
-+ struct snd_soc_codec *codec = codec_dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ AC101_DBG("id=%d freq=%d, dir=%d\n",
-+ clk_id, freq, dir);
-+
-+ ac10x->sysclk = freq;
-+
-+ return 0;
-+}
-+
-+static const struct snd_soc_dai_ops ac101_aif1_dai_ops = {
-+ //.startup = ac101_audio_startup,
-+ //.shutdown = ac101_aif_shutdown,
-+ //.set_sysclk = ac101_set_dai_sysclk,
-+ //.set_pll = ac101_set_pll,
-+ //.set_fmt = ac101_set_dai_fmt,
-+ //.hw_params = ac101_hw_params,
-+ //.trigger = ac101_trigger,
-+ //.digital_mute = ac101_aif_mute,
-+};
-+
-+static struct snd_soc_dai_driver ac101_dai[] = {
-+ {
-+ .name = "ac10x-aif1",
-+ .id = AIF1_CLK,
-+ .playback = {
-+ .stream_name = "Playback",
-+ .channels_min = 1,
-+ .channels_max = 8,
-+ .rates = AC101_RATES,
-+ .formats = AC101_FORMATS,
-+ },
-+ #if 0
-+ .capture = {
-+ .stream_name = "Capture",
-+ .channels_min = 1,
-+ .channels_max = 8,
-+ .rates = AC101_RATES,
-+ .formats = AC101_FORMATS,
-+ },
-+ #endif
-+ .ops = &ac101_aif1_dai_ops,
-+ }
-+};
-+#endif
-+
-+static void codec_resume_work(struct work_struct *work)
-+{
-+ struct ac10x_priv *ac10x = container_of(work, struct ac10x_priv, codec_resume);
-+ struct snd_soc_codec *codec = ac10x->codec;
-+
-+ AC101_DBG("+++\n");
-+
-+ set_configuration(codec);
-+ if (drc_used) {
-+ drc_config(codec);
-+ }
-+ /*enable this bit to prevent leakage from ldoin*/
-+ ac101_update_bits(codec, ADDA_TUNE3, (0x1<<OSCEN), (0x1<<OSCEN));
-+
-+ AC101_DBG("---\n");
-+ return;
-+}
-+
-+int ac101_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
-+{
-+ switch (level) {
-+ case SND_SOC_BIAS_ON:
-+ AC101_DBG("SND_SOC_BIAS_ON\n");
-+ break;
-+ case SND_SOC_BIAS_PREPARE:
-+ AC101_DBG("SND_SOC_BIAS_PREPARE\n");
-+ break;
-+ case SND_SOC_BIAS_STANDBY:
-+ AC101_DBG("SND_SOC_BIAS_STANDBY\n");
-+ #ifdef CONFIG_AC101_SWITCH_DETECT
-+ switch_hw_config(codec);
-+ #endif
-+ break;
-+ case SND_SOC_BIAS_OFF:
-+ #ifdef CONFIG_AC101_SWITCH_DETECT
-+ ac101_update_bits(codec, ADC_APC_CTRL, (0x1<<HBIASEN), (0<<HBIASEN));
-+ ac101_update_bits(codec, ADC_APC_CTRL, (0x1<<HBIASADCEN), (0<<HBIASADCEN));
-+ #endif
-+ ac101_update_bits(codec, OMIXER_DACA_CTRL, (0xf<<HPOUTPUTENABLE),
-+ (0<<HPOUTPUTENABLE));
-+ ac101_update_bits(codec, ADDA_TUNE3, (0x1<<OSCEN), (0<<OSCEN));
-+ AC101_DBG("SND_SOC_BIAS_OFF\n");
-+ break;
-+ }
-+ snd_soc_codec_get_dapm(codec)->bias_level = level;
-+ return 0;
-+}
-+
-+int ac101_codec_probe(struct snd_soc_codec *codec)
-+{
-+ int ret = 0;
-+ struct ac10x_priv *ac10x;
-+
-+ ac10x = dev_get_drvdata(codec->dev);
-+ if (ac10x == NULL) {
-+ AC101_DBG("not set client data!\n");
-+ return -ENOMEM;
-+ }
-+ ac10x->codec = codec;
-+
-+ INIT_DELAYED_WORK(&ac10x->dlywork, ac10x_work_aif_play);
-+ INIT_WORK(&ac10x->codec_resume, codec_resume_work);
-+ ac10x->dac_enable = 0;
-+ ac10x->aif1_clken = 0;
-+ mutex_init(&ac10x->dac_mutex);
-+
-+ set_configuration(ac10x->codec);
-+
-+ /*enable this bit to prevent leakage from ldoin*/
-+ ac101_update_bits(codec, ADDA_TUNE3, (0x1<<OSCEN), (0x1<<OSCEN));
-+ ac101_write(codec, DAC_VOL_CTRL, 0);
-+
-+ /* customized get/put inteface */
-+ for (ret = 0; ret < ARRAY_SIZE(ac101_controls); ret++) {
-+ struct snd_kcontrol_new* skn = &ac101_controls[ret];
-+
-+ skn->get = snd_ac101_get_volsw;
-+ skn->put = snd_ac101_put_volsw;
-+ }
-+ ret = snd_soc_add_codec_controls(codec, ac101_controls, ARRAY_SIZE(ac101_controls));
-+ if (ret) {
-+ pr_err("[ac10x] Failed to register audio mode control, "
-+ "will continue without it.\n");
-+ }
-+
-+ #ifdef CONFIG_AC101_SWITCH_DETECT
-+ ret = ac101_switch_probe(ac10x);
-+ if (ret) {
-+ // not care the switch return value
-+ }
-+ #endif
-+
-+ return 0;
-+}
-+
-+/* power down chip */
-+int ac101_codec_remove(struct snd_soc_codec *codec)
-+{
-+ #ifdef CONFIG_AC101_SWITCH_DETECT
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ if (ac10x->irq) {
-+ devm_free_irq(codec->dev, ac10x->irq, ac10x);
-+ ac10x->irq = 0;
-+ }
-+
-+ if (cancel_work_sync(&ac10x->work_switch) != 0) {
-+ }
-+
-+ if (cancel_work_sync(&ac10x->work_clear_irq) != 0) {
-+ }
-+
-+ if (ac10x->inpdev) {
-+ input_unregister_device(ac10x->inpdev);
-+ ac10x->inpdev = NULL;
-+ }
-+ #endif
-+
-+ return 0;
-+}
-+
-+int ac101_codec_suspend(struct snd_soc_codec *codec)
-+{
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ AC101_DBG("[codec]:suspend\n");
-+ regcache_cache_only(ac10x->regmap101, true);
-+ return 0;
-+}
-+
-+int ac101_codec_resume(struct snd_soc_codec *codec)
-+{
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int ret;
-+
-+ AC101_DBG("[codec]:resume");
-+
-+ /* Sync reg_cache with the hardware */
-+ regcache_cache_only(ac10x->regmap101, false);
-+ ret = regcache_sync(ac10x->regmap101);
-+ if (ret != 0) {
-+ dev_err(codec->dev, "Failed to sync register cache: %d\n", ret);
-+ regcache_cache_only(ac10x->regmap101, true);
-+ return ret;
-+ }
-+
-+ #ifdef CONFIG_AC101_SWITCH_DETECT
-+ ac10x->mode = HEADPHONE_IDLE;
-+ ac10x->state = -1;
-+ #endif
-+
-+ ac101_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-+ schedule_work(&ac10x->codec_resume);
-+ return 0;
-+}
-+
-+/***************************************************************************/
-+static ssize_t ac101_debug_store(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t count)
-+{
-+ struct ac10x_priv *ac10x = dev_get_drvdata(dev);
-+ int val = 0, flag = 0;
-+ u16 value_w, value_r;
-+ u8 reg, num, i=0;
-+
-+ val = simple_strtol(buf, NULL, 16);
-+ flag = (val >> 24) & 0xF;
-+ if (flag) {
-+ reg = (val >> 16) & 0xFF;
-+ value_w = val & 0xFFFF;
-+ ac101_write(ac10x->codec, reg, value_w);
-+ printk("write 0x%x to reg:0x%x\n", value_w, reg);
-+ } else {
-+ reg = (val >> 8) & 0xFF;
-+ num = val & 0xff;
-+ printk("\n");
-+ printk("read:start add:0x%x,count:0x%x\n", reg, num);
-+
-+ regcache_cache_bypass(ac10x->regmap101, true);
-+ do {
-+ value_r = ac101_read(ac10x->codec, reg);
-+ printk("0x%x: 0x%04x ", reg++, value_r);
-+ if (++i % 4 == 0 || i == num)
-+ printk("\n");
-+ } while (i < num);
-+ regcache_cache_bypass(ac10x->regmap101, false);
-+ }
-+ return count;
-+}
-+static ssize_t ac101_debug_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ printk("echo flag|reg|val > ac10x\n");
-+ printk("eg read star addres=0x06,count 0x10:echo 0610 >ac10x\n");
-+ printk("eg write value:0x13fe to address:0x06 :echo 10613fe > ac10x\n");
-+ return 0;
-+}
-+static DEVICE_ATTR(ac10x, 0644, ac101_debug_show, ac101_debug_store);
-+
-+static struct attribute *audio_debug_attrs[] = {
-+ &dev_attr_ac10x.attr,
-+ NULL,
-+};
-+
-+static struct attribute_group audio_debug_attr_group = {
-+ .name = "ac101_debug",
-+ .attrs = audio_debug_attrs,
-+};
-+/***************************************************************************/
-+
-+/************************************************************/
-+static bool ac101_volatile_reg(struct device *dev, unsigned int reg)
-+{
-+ switch (reg) {
-+ case PLL_CTRL2:
-+ case HMIC_STS:
-+ return true;
-+ }
-+ return false;
-+}
-+
-+static const struct regmap_config ac101_regmap = {
-+ .reg_bits = 8,
-+ .val_bits = 16,
-+ .reg_stride = 1,
-+ .max_register = 0xB5,
-+ .cache_type = REGCACHE_FLAT,
-+ .volatile_reg = ac101_volatile_reg,
-+};
-+
-+/* Sync reg_cache from the hardware */
-+int ac10x_fill_regcache(struct device* dev, struct regmap* map) {
-+ int r, i, n;
-+ int v;
-+
-+ n = regmap_get_max_register(map);
-+ for (i = 0; i < n; i++) {
-+ regcache_cache_bypass(map, true);
-+ r = regmap_read(map, i, &v);
-+ if (r) {
-+ dev_dbg(dev, "failed to read register %d\n", i);
-+ continue;
-+ }
-+ regcache_cache_bypass(map, false);
-+
-+ regcache_cache_only(map, true);
-+ r = regmap_write(map, i, v);
-+ regcache_cache_only(map, false);
-+ }
-+ regcache_cache_bypass(map, false);
-+ regcache_cache_only(map, false);
-+
-+ return 0;
-+}
-+
-+int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
-+{
-+ struct ac10x_priv *ac10x = i2c_get_clientdata(i2c);
-+ int ret = 0;
-+ unsigned v = 0;
-+
-+ AC101_DBG();
-+
-+ static_ac10x = ac10x;
-+
-+ ac10x->regmap101 = devm_regmap_init_i2c(i2c, &ac101_regmap);
-+ if (IS_ERR(ac10x->regmap101)) {
-+ ret = PTR_ERR(ac10x->regmap101);
-+ dev_err(&i2c->dev, "Fail to initialize I/O: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Chip reset */
-+ regcache_cache_only(ac10x->regmap101, false);
-+ ret = regmap_write(ac10x->regmap101, CHIP_AUDIO_RST, 0);
-+ msleep(50);
-+
-+ /* sync regcache for FLAT type */
-+ ac10x_fill_regcache(&i2c->dev, ac10x->regmap101);
-+
-+ ret = regmap_read(ac10x->regmap101, CHIP_AUDIO_RST, &v);
-+ if (ret < 0) {
-+ dev_err(&i2c->dev, "failed to read vendor ID: %d\n", ret);
-+ return ret;
-+ }
-+
-+ if (v != AC101_CHIP_ID) {
-+ dev_err(&i2c->dev, "chip is not AC101 (%X)\n", v);
-+ dev_err(&i2c->dev, "Expected %X\n", AC101_CHIP_ID);
-+ return -ENODEV;
-+ }
-+
-+ ret = sysfs_create_group(&i2c->dev.kobj, &audio_debug_attr_group);
-+ if (ret) {
-+ pr_err("failed to create attr group\n");
-+ }
-+
-+ ac10x->gpiod_spk_amp_gate = devm_gpiod_get_optional(&i2c->dev, "spk-amp-switch",
-+ GPIOD_OUT_LOW);
-+ if (IS_ERR(ac10x->gpiod_spk_amp_gate)) {
-+ ac10x->gpiod_spk_amp_gate = NULL;
-+ dev_err(&i2c->dev, "failed get spk-amp-switch in device tree\n");
-+ }
-+
-+ return 0;
-+}
-+
-+void ac101_shutdown(struct i2c_client *i2c)
-+{
-+ struct ac10x_priv *ac10x = i2c_get_clientdata(i2c);
-+ struct snd_soc_codec *codec = ac10x->codec;
-+ int reg_val;
-+
-+ if (codec == NULL) {
-+ pr_err(": no sound card.\n");
-+ return;
-+ }
-+
-+ /*set headphone volume to 0*/
-+ reg_val = ac101_read(codec, HPOUT_CTRL);
-+ reg_val &= ~(0x3f<<HP_VOL);
-+ ac101_write(codec, HPOUT_CTRL, reg_val);
-+
-+ /*disable pa*/
-+ reg_val = ac101_read(codec, HPOUT_CTRL);
-+ reg_val &= ~(0x1<<HPPA_EN);
-+ ac101_write(codec, HPOUT_CTRL, reg_val);
-+
-+ /*hardware xzh support*/
-+ reg_val = ac101_read(codec, OMIXER_DACA_CTRL);
-+ reg_val &= ~(0xf<<HPOUTPUTENABLE);
-+ ac101_write(codec, OMIXER_DACA_CTRL, reg_val);
-+
-+ /*unmute l/r headphone pa*/
-+ reg_val = ac101_read(codec, HPOUT_CTRL);
-+ reg_val &= ~((0x1<<RHPPA_MUTE)|(0x1<<LHPPA_MUTE));
-+ ac101_write(codec, HPOUT_CTRL, reg_val);
-+ return;
-+}
-+
-+int ac101_remove(struct i2c_client *i2c)
-+{
-+ sysfs_remove_group(&i2c->dev.kobj, &audio_debug_attr_group);
-+ return 0;
-+}
-+
-+MODULE_DESCRIPTION("ASoC ac10x driver");
-+MODULE_AUTHOR("huangxin,liushaohua");
-+MODULE_AUTHOR("PeterYang<linsheng.yang@seeed.cc>");
---- /dev/null
-+++ b/sound/soc/codecs/ac101_regs.h
-@@ -0,0 +1,431 @@
-+/*
-+ * ac101_regs.h
-+ *
-+ * (C) Copyright 2017-2018
-+ * Seeed Technology Co., Ltd. <www.seeedstudio.com>
-+ *
-+ * PeterYang <linsheng.yang@seeed.cc>
-+ *
-+ * (C) Copyright 2010-2017
-+ * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
-+ * huangxin <huangxin@reuuimllatech.com>
-+ *
-+ * some simple description for this code
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2 of
-+ * the License, or (at your option) any later version.
-+ *
-+ */
-+#ifndef __AC101_REGS_H__
-+#define __AC101_REGS_H__
-+
-+/*pll source*/
-+#define AC101_MCLK1 1
-+#define AC101_MCLK2 2
-+#define AC101_BCLK1 3
-+#define AC101_BCLK2 4
-+
-+#define AIF1_CLK 1
-+#define AIF2_CLK 2
-+
-+#define CHIP_AUDIO_RST 0x0
-+#define PLL_CTRL1 0x1
-+#define PLL_CTRL2 0x2
-+#define SYSCLK_CTRL 0x3
-+#define MOD_CLK_ENA 0x4
-+#define MOD_RST_CTRL 0x5
-+#define AIF_SR_CTRL 0x6
-+
-+#define AIF1_CLK_CTRL 0x10
-+#define AIF1_ADCDAT_CTRL 0x11
-+#define AIF1_DACDAT_CTRL 0x12
-+#define AIF1_MXR_SRC 0x13
-+#define AIF1_VOL_CTRL1 0x14
-+#define AIF1_VOL_CTRL2 0x15
-+#define AIF1_VOL_CTRL3 0x16
-+#define AIF1_VOL_CTRL4 0x17
-+#define AIF1_MXR_GAIN 0x18
-+#define AIF1_RXD_CTRL 0x19
-+#define ADC_DIG_CTRL 0x40
-+#define ADC_VOL_CTRL 0x41
-+#define ADC_DBG_CTRL 0x42
-+
-+#define HMIC_CTRL1 0x44
-+#define HMIC_CTRL2 0x45
-+#define HMIC_STS 0x46
-+
-+#define DAC_DIG_CTRL 0x48
-+#define DAC_VOL_CTRL 0x49
-+#define DAC_DBG_CTRL 0x4a
-+#define DAC_MXR_SRC 0x4c
-+#define DAC_MXR_GAIN 0x4d
-+
-+#define ADC_APC_CTRL 0x50
-+#define ADC_SRC 0x51
-+#define ADC_SRCBST_CTRL 0x52
-+#define OMIXER_DACA_CTRL 0x53
-+#define OMIXER_SR 0x54
-+#define OMIXER_BST1_CTRL 0x55
-+#define HPOUT_CTRL 0x56
-+#define ESPKOUT_CTRL 0x57
-+#define SPKOUT_CTRL 0x58
-+#define LOUT_CTRL 0x59
-+#define ADDA_TUNE1 0x5a
-+#define ADDA_TUNE2 0x5b
-+#define ADDA_TUNE3 0x5c
-+#define HPOUT_STR 0x5d
-+
-+/*CHIP_AUDIO_RST*/
-+#define AC101_CHIP_ID 0x0101
-+
-+/*PLL_CTRL1*/
-+#define DPLL_DAC_BIAS 14
-+#define PLL_POSTDIV_M 8
-+#define CLOSE_LOOP 6
-+#define INT 0
-+
-+/*PLL_CTRL2*/
-+#define PLL_EN 15
-+#define PLL_LOCK_STATUS 14
-+#define PLL_PREDIV_NI 4
-+#define PLL_POSTDIV_NF 0
-+
-+/*SYSCLK_CTRL*/
-+#define PLLCLK_ENA 15
-+#define PLLCLK_SRC 12
-+#define AIF1CLK_ENA 11
-+#define AIF1CLK_SRC 8
-+#define AIF2CLK_ENA 7
-+#define AIF2CLK_SRC 4
-+#define SYSCLK_ENA 3
-+#define SYSCLK_SRC 0
-+
-+/*MOD_CLK_ENA*/
-+#define MOD_CLK_AIF1 15
-+#define MOD_CLK_AIF2 14
-+#define MOD_CLK_AIF3 13
-+#define MOD_CLK_SRC1 11
-+#define MOD_CLK_SRC2 10
-+#define MOD_CLK_HPF_AGC 7
-+#define MOD_CLK_HPF_DRC 6
-+#define MOD_CLK_ADC_DIG 3
-+#define MOD_CLK_DAC_DIG 2
-+
-+/*MOD_RST_CTRL*/
-+#define MOD_RESET_CTL 0
-+#define MOD_RESET_AIF1 15
-+#define MOD_RESET_AIF2 14
-+#define MOD_RESET_AIF3 13
-+#define MOD_RESET_SRC1 11
-+#define MOD_RESET_SRC2 10
-+#define MOD_RESET_HPF_AGC 7
-+#define MOD_RESET_HPF_DRC 6
-+#define MOD_RESET_ADC_DIG 3
-+#define MOD_RESET_DAC_DIG 2
-+
-+/*AIF_SR_CTRL*/
-+#define AIF1_FS 12 //AIF1 Sample Rate
-+#define AIF2_FS 8 //AIF2 Sample Rate
-+#define SRC1_ENA 3
-+#define SRC1_SRC 2
-+#define SRC2_ENA 1
-+#define SRC2_SRC 0
-+
-+/*AIF1LCK_CTRL*/
-+#define AIF1_MSTR_MOD 15
-+#define AIF1_BCLK_INV 14
-+#define AIF1_LRCK_INV 13
-+#define AIF1_BCLK_DIV 9
-+#define AIF1_LRCK_DIV 6
-+#define AIF1_WORK_SIZ 4
-+#define AIF1_DATA_FMT 2
-+#define DSP_MONO_PCM 1
-+#define AIF1_TDMM_ENA 0
-+
-+/*AIF1_ADCDAT_CTRL*/
-+#define AIF1_AD0L_ENA 15
-+#define AIF1_AD0R_ENA 14
-+#define AIF1_AD1L_ENA 13
-+#define AIF1_AD1R_ENA 12
-+#define AIF1_AD0L_SRC 10
-+#define AIF1_AD0R_SRC 8
-+#define AIF1_AD1L_SRC 6
-+#define AIF1_AD1R_SRC 4
-+#define AIF1_ADCP_ENA 3
-+#define AIF1_ADUL_ENA 2
-+#define AIF1_SLOT_SIZ 0
-+
-+/*AIF1_DACDAT_CTRL*/
-+#define AIF1_DA0L_ENA 15
-+#define AIF1_DA0R_ENA 14
-+#define AIF1_DA1L_ENA 13
-+#define AIF1_DA1R_ENA 12
-+#define AIF1_DA0L_SRC 10
-+#define AIF1_DA0R_SRC 8
-+#define AIF1_DA1L_SRC 6
-+#define AIF1_DA1R_SRC 4
-+#define AIF1_DACP_ENA 3
-+#define AIF1_DAUL_ENA 2
-+#define AIF1_SLOT_SIZ 0
-+
-+/*AIF1_MXR_SRC*/
-+#define AIF1_AD0L_AIF1_DA0L_MXR 15
-+#define AIF1_AD0L_AIF2_DACL_MXR 14
-+#define AIF1_AD0L_ADCL_MXR 13
-+#define AIF1_AD0L_AIF2_DACR_MXR 12
-+#define AIF1_AD0R_AIF1_DA0R_MXR 11
-+#define AIF1_AD0R_AIF2_DACR_MXR 10
-+#define AIF1_AD0R_ADCR_MXR 9
-+#define AIF1_AD0R_AIF2_DACL_MXR 8
-+#define AIF1_AD1L_AIF2_DACL_MXR 7
-+#define AIF1_AD1L_ADCL_MXR 6
-+#define AIF1_AD1L_MXR_SRC 6
-+#define AIF1_AD1R_AIF2_DACR_MXR 3
-+#define AIF1_AD1R_ADCR_MXR 2
-+#define AIF1_AD1R_MXR_SRC 2
-+
-+/*AIF1_VOL_CTRL1*/
-+#define AIF1_AD0L_VOL 8
-+#define AIF1_AD0R_VOL 0
-+
-+/*AIF1_VOL_CTRL2*/
-+#define AIF1_AD1L_VOL 8
-+#define AIF1_AD1R_VOL 0
-+
-+/*AIF1_VOL_CTRL3*/
-+#define AIF1_DA0L_VOL 8
-+#define AIF1_DA0R_VOL 0
-+
-+/*AIF1_VOL_CTRL4*/
-+#define AIF1_DA1L_VOL 8
-+#define AIF1_DA1R_VOL 0
-+
-+/*AIF1_MXR_GAIN*/
-+#define AIF1_AD0L_MXR_GAIN 12
-+#define AIF1_AD0R_MXR_GAIN 8
-+#define AIF1_AD1L_MXR_GAIN 6
-+#define AIF1_AD1R_MXR_GAIN 2
-+
-+/*AIF1_RXD_CTRL*/
-+#define AIF1_N_DATA_DISCARD 8
-+
-+/*ADC_DIG_CTRL*/
-+#define ENAD 15
-+#define ENDM 14
-+#define ADFIR32 13
-+#define ADOUT_DTS 2
-+#define ADOUT_DLY 1
-+
-+/*ADC_VOL_CTRL*/
-+#define ADC_VOL_L 8
-+#define ADC_VOL_R 0
-+
-+/*ADC_DBG_CTRL*/
-+#define ADSW 15
-+#define DMIC_CLK_PIN_CTRL 12
-+
-+/*HMIC_CTRL1*/
-+#define HMIC_M 12
-+#define HMIC_N 8
-+#define HMIC_DATA_IRQ_MODE 7
-+#define HMIC_TH1_HYSTERESIS 5
-+#define HMIC_PULLOUT_IRQ 4
-+#define HMIC_PLUGIN_IRQ 3
-+#define HMIC_KEYUP_IRQ 2
-+#define HMIC_KEYDOWN_IRQ 1
-+#define HMIC_DATA_IRQ_EN 0
-+
-+/*HMIC_CTRL2*/
-+#define HMIC_SAMPLE_SELECT 14
-+#define HMIC_TH2_HYSTERESIS 13
-+#define HMIC_TH2 8
-+#define HMIC_SF 6
-+#define KEYUP_CLEAR 5
-+#define HMIC_TH1 0
-+
-+/*HMIC_STS*/
-+#define HMIC_DATA 8
-+#define GET_HMIC_DATA(r) (((r) >> HMIC_DATA) & 0x1F)
-+#define HMIC_PULLOUT_PEND 4
-+#define HMIC_PLUGIN_PEND 3
-+#define HMIC_KEYUP_PEND 2
-+#define HMKC_KEYDOWN_PEND 1
-+#define HMIC_DATA_PEND 0
-+#define HMIC_PEND_ALL (0x1F)
-+
-+/*DAC_DIG_CTRL*/
-+#define ENDA 15
-+#define ENHPF 14
-+#define DAFIR32 13
-+#define MODQU 8
-+
-+/*DAC_VOL_CTRL*/
-+#define DAC_VOL_L 8
-+#define DAC_VOL_R 0
-+
-+/*DAC_DBG_CTRL*/
-+#define DASW 15
-+#define ENDWA_N 14
-+#define DAC_MOD_DBG 13
-+#define DAC_PTN_SEL 6
-+#define DVC 0
-+
-+/*DAC_MXR_SRC*/
-+#define DACL_MXR_AIF1_DA0L 15
-+#define DACL_MXR_AIF1_DA1L 14
-+#define DACL_MXR_AIF2_DACL 13
-+#define DACL_MXR_ADCL 12
-+#define DACL_MXR_SRC 12
-+#define DACR_MXR_AIF1_DA0R 11
-+#define DACR_MXR_AIF1_DA1R 10
-+#define DACR_MXR_AIF2_DACR 9
-+#define DACR_MXR_ADCR 8
-+#define DACR_MXR_SRC 8
-+
-+/*DAC_MXR_GAIN*/
-+#define DACL_MXR_GAIN 12
-+#define DACR_MXR_GAIN 8
-+
-+/*ADC_APC_CTRL*/
-+#define ADCREN 15
-+#define ADCRG 12
-+#define ADCLEN 11
-+#define ADCLG 8
-+#define MBIASEN 7
-+#define MMIC_BIAS_CHOP_EN 6
-+#define MMIC_BIAS_CHOP_CKS 4
-+#define HBIASMOD 2
-+#define HBIASEN 1
-+#define HBIASADCEN 0
-+
-+/*ADC_SRC*/
-+#define RADCMIXMUTEMIC1BOOST (13)
-+#define RADCMIXMUTEMIC2BOOST (12)
-+#define RADCMIXMUTELINEINLR (11)
-+#define RADCMIXMUTELINEINR (10)
-+#define RADCMIXMUTEAUXINR (9)
-+#define RADCMIXMUTEROUTPUT (8)
-+#define RADCMIXMUTELOUTPUT (7)
-+#define LADCMIXMUTEMIC1BOOST (6)
-+#define LADCMIXMUTEMIC2BOOST (5)
-+#define LADCMIXMUTELINEINLR (4)
-+#define LADCMIXMUTELINEINL (3)
-+#define LADCMIXMUTEAUXINL (2)
-+#define LADCMIXMUTELOUTPUT (1)
-+#define LADCMIXMUTEROUTPUT (0)
-+
-+/*ADC_SRCBST_CTRL*/
-+#define MIC1AMPEN 15
-+#define ADC_MIC1G 12
-+#define MIC2AMPEN 11
-+#define ADC_MIC2G 8
-+#define MIC2SLT 7
-+#define LINEIN_PREG 4
-+#define AUXI_PREG 0
-+
-+/*OMIXER_DACA_CTRL*/
-+#define DACAREN 15
-+#define DACALEN 14
-+#define RMIXEN 13
-+#define LMIXEN 12
-+#define HPOUTPUTENABLE 8
-+
-+/*OMIXER_SR*/
-+#define RMIXMUTEMIC1BOOST (13)
-+#define RMIXMUTEMIC2BOOST (12)
-+#define RMIXMUTELINEINLR (11)
-+#define RMIXMUTELINEINR (10)
-+#define RMIXMUTEAUXINR (9)
-+#define RMIXMUTEDACR (8)
-+#define RMIXMUTEDACL (7)
-+#define LMIXMUTEMIC1BOOST (6)
-+#define LMIXMUTEMIC2BOOST (5)
-+#define LMIXMUTELINEINLR (4)
-+#define LMIXMUTELINEINL (3)
-+#define LMIXMUTEAUXINL (2)
-+#define LMIXMUTEDACL (1)
-+#define LMIXMUTEDACR (0)
-+
-+/*OMIXER_BST1_CTRL*/
-+#define BIASVOLTAGE 12
-+#define AXG 9
-+#define OMIXER_MIC1G 6
-+#define OMIXER_MIC2G 3
-+#define LINEING 0
-+
-+/*HPOUT_CTRL*/
-+#define RHPS 15
-+#define LHPS 14
-+#define RHPPA_MUTE 13
-+#define LHPPA_MUTE 12
-+#define HPPA_EN 11
-+#define HP_VOL 4
-+#define HPPA_DEL 2
-+#define HPPA_IS 0
-+
-+/*ESPKOUT_CTRL*/
-+#define EAR_RAMP_TIME 11
-+#define ESPA_OUT_CURRENT 9
-+#define ESPSR 7
-+#define ESPPA_MUTE 6
-+#define ESPPA_EN 5
-+#define ESP_VOL 0
-+
-+/*SPKOUT_CTRL*/
-+#define HPCALICKS 13
-+#define RSPKS 12
-+#define RSPKINVEN 11
-+#define RSPK_EN 9
-+#define LSPKS 8
-+#define LSPKINVEN 7
-+#define LSPK_EN 5
-+#define SPK_VOL 0
-+
-+/*LOUT_CTRL*/
-+#define LINEOUTG 5
-+#define LINEOUTEN 4
-+#define LINEOUTS0 3
-+#define LINEOUTS1 2
-+#define LINEOUTS2 1
-+#define LINEOUTS3 0
-+
-+/*ADDA_TUNE1*/
-+#define CURRENT_TEST_SELECT 14
-+#define BIHE_CTRL 12
-+#define DITHER 11
-+#define DITHER_CLK 9
-+#define ZERO_CROSSOVER_EN 8
-+#define ZERO_CROSSOVER_TIME 7
-+#define EAR_SPEED_SELECT 6
-+#define REF_CHOPPEN_CKS 4
-+#define OPMIC_BIAS_CUR 0
-+
-+/*ADDA_TUNE2*/
-+#define OPDAC_BIAS_CUR 14
-+#define OPDRV_BIAS_CUR 12
-+#define OPMIX_BIAS_CUR 10
-+#define OPEAR_BIAS_CUR 8
-+#define OPVR_BIAS_CUR 6
-+#define OPAAF_BIAS_CUR 4
-+#define OPADC1_BIAS_CUR 2
-+#define OPADC2_BIAS_CUR 0
-+
-+/*ADDA_TUNE3*/
-+#define LDOEN 15
-+#define LDO_SEL 12
-+#define BIASCALIVERIFY 11
-+#define BIASMODE 10
-+#define BIASCALIDATA 9
-+#define OSCS 1
-+#define OSCEN 0
-+
-+/*HPOUT_STR*/
-+#define HPVL_SOFT_MOD 14
-+#define HPVL_STEP_CTRL 8
-+#define DACA_CHND_ENA 7
-+#define HPPA_MXRD_ENA 6
-+#define HPVL_CTRL_OUT 0
-+
-+#endif//__AC101_REGS_H__
---- /dev/null
-+++ b/sound/soc/codecs/ac108.c
-@@ -0,0 +1,1622 @@
-+/*
-+ * ac10x.c -- ac10x ALSA SoC Audio driver
-+ *
-+ *
-+ * Author: Baozhu Zuo<zuobaozhu@gmail.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/pm.h>
-+#include <linux/regmap.h>
-+#include <linux/slab.h>
-+#include <linux/workqueue.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/tlv.h>
-+
-+#include "ac108.h"
-+#include "ac10x.h"
-+
-+#define _USE_CAPTURE 1
-+#define _MASTER_INDEX 0
-+
-+/* #undef DEBUG
-+ * use 'make DEBUG=1' to enable debugging
-+ */
-+
-+/**
-+ * TODO:
-+ * 1, add PM API: ac108_suspend,ac108_resume
-+ * 2,0x65-0x6a
-+ * 3,0x76-0x79 high 4bit
-+ */
-+struct pll_div {
-+ unsigned int freq_in;
-+ unsigned int freq_out;
-+ unsigned int m1;
-+ unsigned int m2;
-+ unsigned int n;
-+ unsigned int k1;
-+ unsigned int k2;
-+};
-+
-+static struct ac10x_priv *ac10x;
-+
-+struct real_val_to_reg_val {
-+ unsigned int real_val;
-+ unsigned int reg_val;
-+};
-+
-+static const struct real_val_to_reg_val ac108_sample_rate[] = {
-+ { 8000, 0 },
-+ { 11025, 1 },
-+ { 12000, 2 },
-+ { 16000, 3 },
-+ { 22050, 4 },
-+ { 24000, 5 },
-+ { 32000, 6 },
-+ { 44100, 7 },
-+ { 48000, 8 },
-+ { 96000, 9 },
-+};
-+
-+/* Sample resolution */
-+static const struct real_val_to_reg_val ac108_samp_res[] = {
-+ { 8, 1 },
-+ { 12, 2 },
-+ { 16, 3 },
-+ { 20, 4 },
-+ { 24, 5 },
-+ { 28, 6 },
-+ { 32, 7 },
-+};
-+
-+static const unsigned int ac108_bclkdivs[] = {
-+ 0, 1, 2, 4,
-+ 6, 8, 12, 16,
-+ 24, 32, 48, 64,
-+ 96, 128, 176, 192,
-+};
-+
-+/* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] ; M1[0,31], M2[0,1], N[0,1023], K1[0,31], K2[0,1] */
-+static const struct pll_div ac108_pll_div_list[] = {
-+ { 400000, _FREQ_24_576K, 0, 0, 614, 4, 1 },
-+ { 512000, _FREQ_24_576K, 0, 0, 960, 9, 1 }, /* _FREQ_24_576K/48 */
-+ { 768000, _FREQ_24_576K, 0, 0, 640, 9, 1 }, /* _FREQ_24_576K/32 */
-+ { 800000, _FREQ_24_576K, 0, 0, 614, 9, 1 },
-+ { 1024000, _FREQ_24_576K, 0, 0, 480, 9, 1 }, /* _FREQ_24_576K/24 */
-+ { 1600000, _FREQ_24_576K, 0, 0, 307, 9, 1 },
-+ { 2048000, _FREQ_24_576K, 0, 0, 240, 9, 1 }, /* accurate, 8000 * 256 */
-+ { 3072000, _FREQ_24_576K, 0, 0, 160, 9, 1 }, /* accurate, 12000 * 256 */
-+ { 4096000, _FREQ_24_576K, 2, 0, 360, 9, 1 }, /* accurate, 16000 * 256 */
-+ { 6000000, _FREQ_24_576K, 4, 0, 410, 9, 1 },
-+ { 12000000, _FREQ_24_576K, 9, 0, 410, 9, 1 },
-+ { 13000000, _FREQ_24_576K, 8, 0, 340, 9, 1 },
-+ { 15360000, _FREQ_24_576K, 12, 0, 415, 9, 1 },
-+ { 16000000, _FREQ_24_576K, 12, 0, 400, 9, 1 },
-+ { 19200000, _FREQ_24_576K, 15, 0, 410, 9, 1 },
-+ { 19680000, _FREQ_24_576K, 15, 0, 400, 9, 1 },
-+ { 24000000, _FREQ_24_576K, 9, 0, 256,24, 0 }, /* accurate, 24M -> 24.576M */
-+
-+ { 400000, _FREQ_22_579K, 0, 0, 566, 4, 1 },
-+ { 512000, _FREQ_22_579K, 0, 0, 880, 9, 1 },
-+ { 768000, _FREQ_22_579K, 0, 0, 587, 9, 1 },
-+ { 800000, _FREQ_22_579K, 0, 0, 567, 9, 1 },
-+ { 1024000, _FREQ_22_579K, 0, 0, 440, 9, 1 },
-+ { 1600000, _FREQ_22_579K, 1, 0, 567, 9, 1 },
-+ { 2048000, _FREQ_22_579K, 0, 0, 220, 9, 1 },
-+ { 3072000, _FREQ_22_579K, 0, 0, 148, 9, 1 },
-+ { 4096000, _FREQ_22_579K, 2, 0, 330, 9, 1 },
-+ { 6000000, _FREQ_22_579K, 2, 0, 227, 9, 1 },
-+ { 12000000, _FREQ_22_579K, 8, 0, 340, 9, 1 },
-+ { 13000000, _FREQ_22_579K, 9, 0, 350, 9, 1 },
-+ { 15360000, _FREQ_22_579K, 10, 0, 325, 9, 1 },
-+ { 16000000, _FREQ_22_579K, 11, 0, 340, 9, 1 },
-+ { 19200000, _FREQ_22_579K, 13, 0, 330, 9, 1 },
-+ { 19680000, _FREQ_22_579K, 14, 0, 345, 9, 1 },
-+ { 24000000, _FREQ_22_579K, 24, 0, 588,24, 0 }, /* accurate, 24M -> 22.5792M */
-+
-+
-+ { _FREQ_24_576K / 1, _FREQ_24_576K, 9, 0, 200, 9, 1 }, /* _FREQ_24_576K */
-+ { _FREQ_24_576K / 2, _FREQ_24_576K, 9, 0, 400, 9, 1 }, /* 12288000,accurate, 48000 * 256 */
-+ { _FREQ_24_576K / 4, _FREQ_24_576K, 4, 0, 400, 9, 1 }, /* 6144000, accurate, 24000 * 256 */
-+ { _FREQ_24_576K / 16, _FREQ_24_576K, 0, 0, 320, 9, 1 }, /* 1536000 */
-+ { _FREQ_24_576K / 64, _FREQ_24_576K, 0, 0, 640, 4, 1 }, /* 384000 */
-+ { _FREQ_24_576K / 96, _FREQ_24_576K, 0, 0, 960, 4, 1 }, /* 256000 */
-+ { _FREQ_24_576K / 128, _FREQ_24_576K, 0, 0, 512, 1, 1 }, /* 192000 */
-+ { _FREQ_24_576K / 176, _FREQ_24_576K, 0, 0, 880, 4, 0 }, /* 140000 */
-+ { _FREQ_24_576K / 192, _FREQ_24_576K, 0, 0, 960, 4, 0 }, /* 128000 */
-+
-+ { _FREQ_22_579K / 1, _FREQ_22_579K, 9, 0, 200, 9, 1 }, /* _FREQ_22_579K */
-+ { _FREQ_22_579K / 2, _FREQ_22_579K, 9, 0, 400, 9, 1 }, /* 11289600,accurate, 44100 * 256 */
-+ { _FREQ_22_579K / 4, _FREQ_22_579K, 4, 0, 400, 9, 1 }, /* 5644800, accurate, 22050 * 256 */
-+ { _FREQ_22_579K / 16, _FREQ_22_579K, 0, 0, 320, 9, 1 }, /* 1411200 */
-+ { _FREQ_22_579K / 64, _FREQ_22_579K, 0, 0, 640, 4, 1 }, /* 352800 */
-+ { _FREQ_22_579K / 96, _FREQ_22_579K, 0, 0, 960, 4, 1 }, /* 235200 */
-+ { _FREQ_22_579K / 128, _FREQ_22_579K, 0, 0, 512, 1, 1 }, /* 176400 */
-+ { _FREQ_22_579K / 176, _FREQ_22_579K, 0, 0, 880, 4, 0 }, /* 128290 */
-+ { _FREQ_22_579K / 192, _FREQ_22_579K, 0, 0, 960, 4, 0 }, /* 117600 */
-+
-+ { _FREQ_22_579K / 6, _FREQ_22_579K, 2, 0, 360, 9, 1 }, /* 3763200 */
-+ { _FREQ_22_579K / 8, _FREQ_22_579K, 0, 0, 160, 9, 1 }, /* 2822400, accurate, 11025 * 256 */
-+ { _FREQ_22_579K / 12, _FREQ_22_579K, 0, 0, 240, 9, 1 }, /* 1881600 */
-+ { _FREQ_22_579K / 24, _FREQ_22_579K, 0, 0, 480, 9, 1 }, /* 940800 */
-+ { _FREQ_22_579K / 32, _FREQ_22_579K, 0, 0, 640, 9, 1 }, /* 705600 */
-+ { _FREQ_22_579K / 48, _FREQ_22_579K, 0, 0, 960, 9, 1 }, /* 470400 */
-+};
-+
-+
-+/* AC108 definition */
-+#define AC108_CHANNELS_MAX 8 /* range[1, 16] */
-+#define AC108_RATES (SNDRV_PCM_RATE_8000_96000 & \
-+ ~(SNDRV_PCM_RATE_64000 | \
-+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000))
-+#define AC108_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
-+ /*SNDRV_PCM_FMTBIT_S20_3LE | \
-+ SNDRV_PCM_FMTBIT_S24_LE |*/ \
-+ SNDRV_PCM_FMTBIT_S32_LE)
-+
-+static const DECLARE_TLV_DB_SCALE(tlv_adc_pga_gain, 0, 100, 0);
-+static const DECLARE_TLV_DB_SCALE(tlv_ch_digital_vol, -11925, 75, 0);
-+
-+int ac10x_read(u8 reg, u8* rt_val, struct regmap* i2cm)
-+{
-+ int r, v = 0;
-+
-+ if ((r = regmap_read(i2cm, reg, &v)) < 0)
-+ pr_info("ac10x_read info->[REG-0x%02x]\n", reg);
-+ else
-+ *rt_val = v;
-+ return r;
-+}
-+
-+int ac10x_write(u8 reg, u8 val, struct regmap* i2cm)
-+{
-+ int r;
-+
-+ if ((r = regmap_write(i2cm, reg, val)) < 0)
-+ pr_info("ac10x_write info->[REG-0x%02x,val-0x%02x]\n", reg, val);
-+ return r;
-+}
-+
-+int ac10x_update_bits(u8 reg, u8 mask, u8 val, struct regmap* i2cm)
-+{
-+ int r;
-+
-+ if ((r = regmap_update_bits(i2cm, reg, mask, val)) < 0)
-+ pr_info("%s() info->[REG-0x%02x,val-0x%02x]\n", __func__, reg, val);
-+ return r;
-+}
-+
-+/**
-+ * snd_ac108_get_volsw - single mixer get callback
-+ * @kcontrol: mixer control
-+ * @ucontrol: control element information
-+ *
-+ * Callback to get the value of a single mixer control, or a double mixer
-+ * control that spans 2 registers.
-+ *
-+ * Returns 0 for success.
-+ */
-+static int snd_ac108_get_volsw(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct soc_mixer_control *mc =
-+ (struct soc_mixer_control *)kcontrol->private_value;
-+ unsigned int mask = (1 << fls(mc->max)) - 1;
-+ unsigned int invert = mc->invert;
-+ int ret, chip = mc->autodisable;
-+ u8 val;
-+
-+ if ((ret = ac10x_read(mc->reg, &val, ac10x->i2cmap[chip])) < 0)
-+ return ret;
-+
-+ val = ((val >> mc->shift) & mask) - mc->min;
-+ if (invert) {
-+ val = mc->max - val;
-+ }
-+ ucontrol->value.integer.value[0] = val;
-+ return 0;
-+}
-+
-+/**
-+ * snd_ac108_put_volsw - single mixer put callback
-+ * @kcontrol: mixer control
-+ * @ucontrol: control element information
-+ *
-+ * Callback to set the value of a single mixer control, or a double mixer
-+ * control that spans 2 registers.
-+ *
-+ * Returns 0 for success.
-+ */
-+static int snd_ac108_put_volsw(struct snd_kcontrol *kcontrol,
-+ struct snd_ctl_elem_value *ucontrol)
-+{
-+ struct soc_mixer_control *mc =
-+ (struct soc_mixer_control *)kcontrol->private_value;
-+ unsigned int sign_bit = mc->sign_bit;
-+ unsigned int val, mask = (1 << fls(mc->max)) - 1;
-+ unsigned int invert = mc->invert;
-+ int ret, chip = mc->autodisable;
-+
-+ if (sign_bit)
-+ mask = BIT(sign_bit + 1) - 1;
-+
-+ val = ((ucontrol->value.integer.value[0] + mc->min) & mask);
-+ if (invert) {
-+ val = mc->max - val;
-+ }
-+
-+ mask = mask << mc->shift;
-+ val = val << mc->shift;
-+
-+ ret = ac10x_update_bits(mc->reg, mask, val, ac10x->i2cmap[chip]);
-+ return ret;
-+}
-+
-+#define SOC_AC108_SINGLE_TLV(xname, reg, shift, max, invert, chip, tlv_array) \
-+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
-+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-+ .tlv.p = (tlv_array), \
-+ .info = snd_soc_info_volsw, .get = snd_ac108_get_volsw,\
-+ .put = snd_ac108_put_volsw, \
-+ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, chip) }
-+
-+/* single ac108 */
-+static const struct snd_kcontrol_new ac108_snd_controls[] = {
-+ /* ### chip 0 ### */
-+ /*0x70: ADC1 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH1 digital volume", ADC1_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+ /*0x71: ADC2 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH2 digital volume", ADC2_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+ /*0x72: ADC3 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH3 digital volume", ADC3_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+ /*0x73: ADC4 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH4 digital volume", ADC4_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+
-+ /*0x90: Analog PGA1 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC1 PGA gain", ANA_PGA1_CTRL,
-+ ADC1_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+ /*0x91: Analog PGA2 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC2 PGA gain", ANA_PGA2_CTRL,
-+ ADC2_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+ /*0x92: Analog PGA3 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC3 PGA gain", ANA_PGA3_CTRL,
-+ ADC3_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+ /*0x93: Analog PGA4 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC4 PGA gain", ANA_PGA4_CTRL,
-+ ADC4_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+};
-+/* multiple ac108s */
-+static const struct snd_kcontrol_new ac108tdm_snd_controls[] = {
-+ /* ### chip 1 ### */
-+ /*0x70: ADC1 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH1 digital volume", ADC1_DVOL_CTRL,
-+ 0, 0xff, 0, 1, tlv_ch_digital_vol),
-+ /*0x71: ADC2 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH2 digital volume", ADC2_DVOL_CTRL,
-+ 0, 0xff, 0, 1, tlv_ch_digital_vol),
-+ /*0x72: ADC3 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH3 digital volume", ADC3_DVOL_CTRL,
-+ 0, 0xff, 0, 1, tlv_ch_digital_vol),
-+ /*0x73: ADC4 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH4 digital volume", ADC4_DVOL_CTRL,
-+ 0, 0xff, 0, 1, tlv_ch_digital_vol),
-+
-+ /*0x90: Analog PGA1 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC1 PGA gain", ANA_PGA1_CTRL,
-+ ADC1_ANALOG_PGA, 0x1f, 0, 1, tlv_adc_pga_gain),
-+ /*0x91: Analog PGA2 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC2 PGA gain", ANA_PGA2_CTRL,
-+ ADC2_ANALOG_PGA, 0x1f, 0, 1, tlv_adc_pga_gain),
-+ /*0x92: Analog PGA3 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC3 PGA gain", ANA_PGA3_CTRL,
-+ ADC3_ANALOG_PGA, 0x1f, 0, 1, tlv_adc_pga_gain),
-+ /*0x93: Analog PGA4 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC4 PGA gain", ANA_PGA4_CTRL,
-+ ADC4_ANALOG_PGA, 0x1f, 0, 1, tlv_adc_pga_gain),
-+
-+ /* ### chip 0 ### */
-+ /*0x70: ADC1 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH5 digital volume", ADC1_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+ /*0x71: ADC2 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH6 digital volume", ADC2_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+ /*0x72: ADC3 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH7 digital volume", ADC3_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+ /*0x73: ADC4 Digital Channel Volume Control Register*/
-+ SOC_AC108_SINGLE_TLV("CH8 digital volume", ADC4_DVOL_CTRL,
-+ 0, 0xff, 0, 0, tlv_ch_digital_vol),
-+
-+ /*0x90: Analog PGA1 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC5 PGA gain", ANA_PGA1_CTRL,
-+ ADC1_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+ /*0x91: Analog PGA2 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC6 PGA gain", ANA_PGA2_CTRL,
-+ ADC2_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+ /*0x92: Analog PGA3 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC7 PGA gain", ANA_PGA3_CTRL,
-+ ADC3_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+ /*0x93: Analog PGA4 Control Register*/
-+ SOC_AC108_SINGLE_TLV("ADC8 PGA gain", ANA_PGA4_CTRL,
-+ ADC4_ANALOG_PGA, 0x1f, 0, 0, tlv_adc_pga_gain),
-+};
-+
-+
-+static const struct snd_soc_dapm_widget ac108_dapm_widgets[] = {
-+ /* input widgets */
-+ SND_SOC_DAPM_INPUT("MIC1P"),
-+ SND_SOC_DAPM_INPUT("MIC1N"),
-+
-+ SND_SOC_DAPM_INPUT("MIC2P"),
-+ SND_SOC_DAPM_INPUT("MIC2N"),
-+
-+ SND_SOC_DAPM_INPUT("MIC3P"),
-+ SND_SOC_DAPM_INPUT("MIC3N"),
-+
-+ SND_SOC_DAPM_INPUT("MIC4P"),
-+ SND_SOC_DAPM_INPUT("MIC4N"),
-+
-+ SND_SOC_DAPM_INPUT("DMIC1"),
-+ SND_SOC_DAPM_INPUT("DMIC2"),
-+
-+ /*0xa0: ADC1 Analog Control 1 Register*/
-+ /*0xa1-0xa6:use the defualt value*/
-+ SND_SOC_DAPM_AIF_IN("Channel 1 AAF", "Capture", 0, ANA_ADC1_CTRL1, ADC1_DSM_ENABLE, 1),
-+ SND_SOC_DAPM_SUPPLY("Channel 1 EN", ANA_ADC1_CTRL1, ADC1_PGA_ENABLE, 1, NULL, 0),
-+ SND_SOC_DAPM_MICBIAS("MIC1BIAS", ANA_ADC1_CTRL1, ADC1_MICBIAS_EN, 1),
-+
-+ /*0xa7: ADC2 Analog Control 1 Register*/
-+ /*0xa8-0xad:use the defualt value*/
-+ SND_SOC_DAPM_AIF_IN("Channel 2 AAF", "Capture", 0, ANA_ADC2_CTRL1, ADC2_DSM_ENABLE, 1),
-+ SND_SOC_DAPM_SUPPLY("Channel 2 EN", ANA_ADC2_CTRL1, ADC2_PGA_ENABLE, 1, NULL, 0),
-+ SND_SOC_DAPM_MICBIAS("MIC2BIAS", ANA_ADC2_CTRL1, ADC2_MICBIAS_EN, 1),
-+
-+ /*0xae: ADC3 Analog Control 1 Register*/
-+ /*0xaf-0xb4:use the defualt value*/
-+ SND_SOC_DAPM_AIF_IN("Channel 3 AAF", "Capture", 0, ANA_ADC3_CTRL1, ADC3_DSM_ENABLE, 1),
-+ SND_SOC_DAPM_SUPPLY("Channel 3 EN", ANA_ADC3_CTRL1, ADC3_PGA_ENABLE, 1, NULL, 0),
-+ SND_SOC_DAPM_MICBIAS("MIC3BIAS", ANA_ADC3_CTRL1, ADC3_MICBIAS_EN, 1),
-+
-+ /*0xb5: ADC4 Analog Control 1 Register*/
-+ /*0xb6-0xbb:use the defualt value*/
-+ SND_SOC_DAPM_AIF_IN("Channel 4 AAF", "Capture", 0, ANA_ADC4_CTRL1, ADC4_DSM_ENABLE, 1),
-+ SND_SOC_DAPM_SUPPLY("Channel 4 EN", ANA_ADC4_CTRL1, ADC4_PGA_ENABLE, 1, NULL, 0),
-+ SND_SOC_DAPM_MICBIAS("MIC4BIAS", ANA_ADC4_CTRL1, ADC4_MICBIAS_EN, 1),
-+
-+
-+ /*0x61: ADC Digital Part Enable Register*/
-+ SND_SOC_DAPM_SUPPLY("ADC EN", ADC_DIG_EN, 4, 1, NULL, 0),
-+ SND_SOC_DAPM_ADC("ADC1", "Capture", ADC_DIG_EN, 0, 1),
-+ SND_SOC_DAPM_ADC("ADC2", "Capture", ADC_DIG_EN, 1, 1),
-+ SND_SOC_DAPM_ADC("ADC3", "Capture", ADC_DIG_EN, 2, 1),
-+ SND_SOC_DAPM_ADC("ADC4", "Capture", ADC_DIG_EN, 3, 1),
-+
-+ SND_SOC_DAPM_SUPPLY("ADC1 CLK", ANA_ADC4_CTRL7, ADC1_CLK_GATING, 1, NULL, 0),
-+ SND_SOC_DAPM_SUPPLY("ADC2 CLK", ANA_ADC4_CTRL7, ADC2_CLK_GATING, 1, NULL, 0),
-+ SND_SOC_DAPM_SUPPLY("ADC3 CLK", ANA_ADC4_CTRL7, ADC3_CLK_GATING, 1, NULL, 0),
-+ SND_SOC_DAPM_SUPPLY("ADC4 CLK", ANA_ADC4_CTRL7, ADC4_CLK_GATING, 1, NULL, 0),
-+
-+ SND_SOC_DAPM_SUPPLY("DSM EN", ANA_ADC4_CTRL6, DSM_DEMOFF, 1, NULL, 0),
-+
-+ /*0x62:Digital MIC Enable Register*/
-+ SND_SOC_DAPM_MICBIAS("DMIC1 enable", DMIC_EN, 0, 0),
-+ SND_SOC_DAPM_MICBIAS("DMIC2 enable", DMIC_EN, 1, 0),
-+};
-+
-+static const struct snd_soc_dapm_route ac108_dapm_routes[] = {
-+
-+ { "ADC1", NULL, "Channel 1 AAF" },
-+ { "ADC2", NULL, "Channel 2 AAF" },
-+ { "ADC3", NULL, "Channel 3 AAF" },
-+ { "ADC4", NULL, "Channel 4 AAF" },
-+
-+ { "Channel 1 AAF", NULL, "MIC1BIAS" },
-+ { "Channel 2 AAF", NULL, "MIC2BIAS" },
-+ { "Channel 3 AAF", NULL, "MIC3BIAS" },
-+ { "Channel 4 AAF", NULL, "MIC4BIAS" },
-+
-+ { "MIC1BIAS", NULL, "ADC1 CLK" },
-+ { "MIC2BIAS", NULL, "ADC2 CLK" },
-+ { "MIC3BIAS", NULL, "ADC3 CLK" },
-+ { "MIC4BIAS", NULL, "ADC4 CLK" },
-+
-+
-+ { "ADC1 CLK", NULL, "DSM EN" },
-+ { "ADC2 CLK", NULL, "DSM EN" },
-+ { "ADC3 CLK", NULL, "DSM EN" },
-+ { "ADC4 CLK", NULL, "DSM EN" },
-+
-+
-+ { "DSM EN", NULL, "ADC EN" },
-+
-+ { "Channel 1 EN", NULL, "DSM EN" },
-+ { "Channel 2 EN", NULL, "DSM EN" },
-+ { "Channel 3 EN", NULL, "DSM EN" },
-+ { "Channel 4 EN", NULL, "DSM EN" },
-+
-+
-+ { "MIC1P", NULL, "Channel 1 EN" },
-+ { "MIC1N", NULL, "Channel 1 EN" },
-+
-+ { "MIC2P", NULL, "Channel 2 EN" },
-+ { "MIC2N", NULL, "Channel 2 EN" },
-+
-+ { "MIC3P", NULL, "Channel 3 EN" },
-+ { "MIC3N", NULL, "Channel 3 EN" },
-+
-+ { "MIC4P", NULL, "Channel 4 EN" },
-+ { "MIC4N", NULL, "Channel 4 EN" },
-+
-+};
-+
-+static int ac108_multi_write(u8 reg, u8 val, struct ac10x_priv *ac10x)
-+{
-+ u8 i;
-+ for (i = 0; i < ac10x->codec_cnt; i++)
-+ ac10x_write(reg, val, ac10x->i2cmap[i]);
-+ return 0;
-+}
-+
-+static int ac108_multi_update_bits(u8 reg, u8 mask, u8 val, struct ac10x_priv *ac10x)
-+{
-+ int r = 0;
-+ u8 i;
-+ for (i = 0; i < ac10x->codec_cnt; i++)
-+ r |= ac10x_update_bits(reg, mask, val, ac10x->i2cmap[i]);
-+ return r;
-+}
-+
-+static unsigned int ac108_codec_read(struct snd_soc_codec *codec, unsigned int reg)
-+{
-+ unsigned char val_r;
-+ struct ac10x_priv *ac10x = dev_get_drvdata(codec->dev);
-+ /*read one chip is fine*/
-+ ac10x_read(reg, &val_r, ac10x->i2cmap[_MASTER_INDEX]);
-+ return val_r;
-+}
-+
-+static int ac108_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val)
-+{
-+ struct ac10x_priv *ac10x = dev_get_drvdata(codec->dev);
-+ ac108_multi_write(reg, val, ac10x);
-+ return 0;
-+}
-+
-+/**
-+ * The Power management related registers are Reg01h~Reg09h
-+ * 0x01-0x05,0x08,use the default value
-+ * @author baozhu (17-6-21)
-+ *
-+ * @param ac10x
-+ */
-+static void ac108_configure_power(struct ac10x_priv *ac10x)
-+{
-+ /**
-+ * 0x06:Enable Analog LDO
-+ */
-+ ac108_multi_update_bits(PWR_CTRL6, 0x01 << LDO33ANA_ENABLE, 0x01 << LDO33ANA_ENABLE, ac10x);
-+ /**
-+ * 0x07:
-+ * Control VREF output and micbias voltage ?
-+ * REF faststart disable, enable Enable VREF (needed for Analog
-+ * LDO and MICBIAS)
-+ */
-+ ac108_multi_update_bits(PWR_CTRL7,
-+ 0x1f << VREF_SEL | 0x01 << VREF_FASTSTART_ENABLE |
-+ 0x01 << VREF_ENABLE,
-+ 0x13 << VREF_SEL | 0x00 << VREF_FASTSTART_ENABLE |
-+ 0x01 << VREF_ENABLE,
-+ ac10x);
-+ /**
-+ * 0x09:
-+ * Disable fast-start circuit on VREFP
-+ * VREFP_RESCTRL=00=1 MOhm
-+ * IGEN_TRIM=100=+25%
-+ * Enable VREFP (needed by all audio input channels)
-+ */
-+ ac108_multi_update_bits(PWR_CTRL9,
-+ 0x01 << VREFP_FASTSTART_ENABLE | 0x03 << VREFP_RESCTRL |
-+ 0x07 << IGEN_TRIM | 0x01 << VREFP_ENABLE,
-+ 0x00 << VREFP_FASTSTART_ENABLE | 0x00 << VREFP_RESCTRL |
-+ 0x04 << IGEN_TRIM | 0x01 << VREFP_ENABLE,
-+ ac10x);
-+}
-+
-+/**
-+ * The clock management related registers are Reg20h~Reg25h
-+ * The PLL management related registers are Reg10h~Reg18h.
-+ * @author baozhu (17-6-20)
-+ *
-+ * @param ac10x
-+ * @param rate : sample rate
-+ *
-+ * @return int : fail or success
-+ */
-+static int ac108_config_pll(struct ac10x_priv *ac10x, unsigned rate, unsigned lrck_ratio)
-+{
-+ unsigned int i = 0;
-+ struct pll_div ac108_pll_div = { 0 };
-+
-+ if (ac10x->clk_id == SYSCLK_SRC_PLL) {
-+ unsigned pll_src, pll_freq_in;
-+
-+ if (lrck_ratio == 0) {
-+ /* PLL clock source from MCLK */
-+ pll_freq_in = ac10x->sysclk;
-+ pll_src = 0x0;
-+ } else {
-+ /* PLL clock source from BCLK */
-+ pll_freq_in = rate * lrck_ratio;
-+ pll_src = 0x1;
-+ }
-+
-+ /* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] */
-+ for (i = 0; i < ARRAY_SIZE(ac108_pll_div_list); i++) {
-+ if (ac108_pll_div_list[i].freq_in == pll_freq_in &&
-+ ac108_pll_div_list[i].freq_out % rate == 0) {
-+ ac108_pll_div = ac108_pll_div_list[i];
-+ dev_info(&ac10x->i2c[_MASTER_INDEX]->dev,
-+ "AC108 PLL freq_in match:%u, freq_out:%u\n\n",
-+ ac108_pll_div.freq_in, ac108_pll_div.freq_out);
-+ break;
-+ }
-+ }
-+ /* 0x11,0x12,0x13,0x14: Config PLL DIV param M1/M2/N/K1/K2 */
-+ ac108_multi_update_bits(PLL_CTRL5,
-+ 0x1f << PLL_POSTDIV1 | 0x01 << PLL_POSTDIV2,
-+ ac108_pll_div.k1 << PLL_POSTDIV1 |
-+ ac108_pll_div.k2 << PLL_POSTDIV2, ac10x);
-+ ac108_multi_update_bits(PLL_CTRL4, 0xff << PLL_LOOPDIV_LSB,
-+ (unsigned char)ac108_pll_div.n << PLL_LOOPDIV_LSB, ac10x);
-+ ac108_multi_update_bits(PLL_CTRL3, 0x03 << PLL_LOOPDIV_MSB,
-+ (ac108_pll_div.n >> 8) << PLL_LOOPDIV_MSB, ac10x);
-+ ac108_multi_update_bits(PLL_CTRL2, 0x1f << PLL_PREDIV1 | 0x01 << PLL_PREDIV2,
-+ ac108_pll_div.m1 << PLL_PREDIV1 |
-+ ac108_pll_div.m2 << PLL_PREDIV2, ac10x);
-+
-+ /*0x18: PLL clk lock enable*/
-+ ac108_multi_update_bits(PLL_LOCK_CTRL, 0x1 << PLL_LOCK_EN,
-+ 0x1 << PLL_LOCK_EN, ac10x);
-+
-+ /**
-+ * 0x20: enable pll, pll source from mclk/bclk, sysclk source from pll, enable sysclk
-+ */
-+ ac108_multi_update_bits(SYSCLK_CTRL,
-+ 0x01 << PLLCLK_EN | 0x03 << PLLCLK_SRC |
-+ 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN,
-+ 0x01 << PLLCLK_EN | pll_src << PLLCLK_SRC |
-+ 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac10x);
-+ ac10x->mclk = ac108_pll_div.freq_out;
-+ }
-+ if (ac10x->clk_id == SYSCLK_SRC_MCLK) {
-+ /**
-+ *0x20: sysclk source from mclk, enable sysclk
-+ */
-+ ac108_multi_update_bits(SYSCLK_CTRL,
-+ 0x01 << PLLCLK_EN | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN,
-+ 0x00 << PLLCLK_EN | 0x00 << SYSCLK_SRC | 0x01 << SYSCLK_EN,
-+ ac10x);
-+ ac10x->mclk = ac10x->sysclk;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * support no more than 16 slots.
-+ */
-+static int ac108_multi_chips_slots(struct ac10x_priv *ac, int slots)
-+{
-+ int i;
-+
-+ /*
-+ * codec0 enable slots 2,3,0,1 when 1 codec
-+ *
-+ * codec0 enable slots 6,7,0,1 when 2 codec
-+ * codec1 enable slots 2,3,4,5
-+ *
-+ * ...
-+ */
-+ for (i = 0; i < ac->codec_cnt; i++) {
-+ /* rotate map, due to channels rotated by CPU_DAI */
-+ const unsigned vec_mask[] = {
-+ 0x3 << 6 | 0x3, // slots 6,7,0,1
-+ 0xF << 2, // slots 2,3,4,5
-+ 0,
-+ 0,
-+ };
-+ const unsigned vec_maps[] = {
-+ /*
-+ * chip 0,
-+ * mic 0 sample -> slot 6
-+ * mic 1 sample -> slot 7
-+ * mic 2 sample -> slot 0
-+ * mic 3 sample -> slot 1
-+ */
-+ 0x0 << 12 | 0x1 << 14 | 0x2 << 0 | 0x3 << 2,
-+ /*
-+ * chip 1,
-+ * mic 0 sample -> slot 2
-+ * mic 1 sample -> slot 3
-+ * mic 2 sample -> slot 4
-+ * mic 3 sample -> slot 5
-+ */
-+ 0x0 << 4 | 0x1 << 6 | 0x2 << 8 | 0x3 << 10,
-+ 0,
-+ 0,
-+ };
-+ unsigned vec;
-+
-+ /* 0x38-0x3A I2S_TX1_CTRLx */
-+ if (ac->codec_cnt == 1) {
-+ vec = 0xFUL;
-+ } else {
-+ vec = vec_mask[i];
-+ }
-+ ac10x_write(I2S_TX1_CTRL1, slots - 1, ac->i2cmap[i]);
-+ ac10x_write(I2S_TX1_CTRL2, (vec >> 0) & 0xFF, ac->i2cmap[i]);
-+ ac10x_write(I2S_TX1_CTRL3, (vec >> 8) & 0xFF, ac->i2cmap[i]);
-+
-+ /* 0x3C-0x3F I2S_TX1_CHMP_CTRLx */
-+ if (ac->codec_cnt == 1) {
-+ vec = (0x2 << 0 | 0x3 << 2 | 0x0 << 4 | 0x1 << 6);
-+ } else if (ac->codec_cnt == 2) {
-+ vec = vec_maps[i];
-+ }
-+
-+ ac10x_write(I2S_TX1_CHMP_CTRL1, (vec >> 0) & 0xFF, ac->i2cmap[i]);
-+ ac10x_write(I2S_TX1_CHMP_CTRL2, (vec >> 8) & 0xFF, ac->i2cmap[i]);
-+ ac10x_write(I2S_TX1_CHMP_CTRL3, (vec >> 16) & 0xFF, ac->i2cmap[i]);
-+ ac10x_write(I2S_TX1_CHMP_CTRL4, (vec >> 24) & 0xFF, ac->i2cmap[i]);
-+ }
-+ return 0;
-+}
-+
-+static int ac108_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-+{
-+ unsigned int i, channels, samp_res, rate;
-+ struct snd_soc_codec *codec = dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ unsigned bclkdiv;
-+ int ret = 0;
-+ u8 v;
-+
-+ dev_dbg(dai->dev, "%s() stream=%s play:%d capt:%d +++\n", __func__,
-+ snd_pcm_stream_str(substream),
-+ dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active,
-+ dai->stream[SNDRV_PCM_STREAM_CAPTURE].active);
-+
-+ if (ac10x->i2c101) {
-+ ret = ac101_hw_params(substream, params, dai);
-+ if (ret > 0) {
-+ dev_dbg(dai->dev, "%s() L%d returned\n", __func__, __LINE__);
-+ /* not configure hw_param twice */
-+ return 0;
-+ }
-+ }
-+
-+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
-+ dai->stream[SNDRV_PCM_STREAM_PLAYBACK].active)
-+ || (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-+ dai->stream[SNDRV_PCM_STREAM_CAPTURE].active)) {
-+ /* not configure hw_param twice */
-+ /* return 0; */
-+ }
-+
-+ channels = params_channels(params);
-+
-+ /* Master mode, to clear cpu_dai fifos, output bclk without lrck */
-+ ac10x_read(I2S_CTRL, &v, ac10x->i2cmap[_MASTER_INDEX]);
-+ if (v & (0x01 << BCLK_IOEN)) {
-+ ac10x_update_bits(I2S_CTRL, 0x1 << LRCK_IOEN,
-+ 0x0 << LRCK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
-+ }
-+
-+ switch (params_format(params)) {
-+ case SNDRV_PCM_FORMAT_S8:
-+ samp_res = 0;
-+ break;
-+ case SNDRV_PCM_FORMAT_S16_LE:
-+ samp_res = 2;
-+ break;
-+ case SNDRV_PCM_FORMAT_S20_3LE:
-+ samp_res = 3;
-+ break;
-+ case SNDRV_PCM_FORMAT_S24_LE:
-+ samp_res = 4;
-+ break;
-+ case SNDRV_PCM_FORMAT_S32_LE:
-+ samp_res = 6;
-+ break;
-+ default:
-+ dev_err(dai->dev, "AC108 don't supported the sample resolution: %u\n",
-+ params_format(params));
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < ARRAY_SIZE(ac108_sample_rate); i++) {
-+ if (ac108_sample_rate[i].real_val == params_rate(params) /
-+ (ac10x->data_protocol + 1UL)) {
-+ rate = i;
-+ break;
-+ }
-+ }
-+ if (i >= ARRAY_SIZE(ac108_sample_rate)) {
-+ return -EINVAL;
-+ }
-+
-+ if (channels == 8 && ac108_sample_rate[rate].real_val == 96000) {
-+ /* 24.576M bit clock is not support by ac108 */
-+ return -EINVAL;
-+ }
-+
-+ dev_dbg(dai->dev, "rate: %d , channels: %d , samp_res: %d",
-+ ac108_sample_rate[rate].real_val,
-+ channels,
-+ ac108_samp_res[samp_res].real_val);
-+
-+ /**
-+ * 0x33:
-+ * The 8-Low bit of LRCK period value. It is used to program
-+ * the number of BCLKs per channel of sample frame. This value
-+ * is interpreted as follow:
-+ * The 8-Low bit of LRCK period value. It is used to program
-+ * the number of BCLKs per channel of sample frame. This value
-+ * is interpreted as follow: PCM mode: Number of BCLKs within
-+ * (Left + Right) channel width I2S / Left-Justified /
-+ * Right-Justified mode: Number of BCLKs within each individual
-+ * channel width (Left or Right) N+1
-+ * For example:
-+ * n = 7: 8 BCLK width
-+ * …
-+ * n = 1023: 1024 BCLKs width
-+ * 0X32[0:1]:
-+ * The 2-High bit of LRCK period value.
-+ */
-+ if (ac10x->i2s_mode != PCM_FORMAT) {
-+ if (ac10x->data_protocol) {
-+ ac108_multi_write(I2S_LRCK_CTRL2, ac108_samp_res[samp_res].real_val - 1,
-+ ac10x);
-+ /*encoding mode, the max LRCK period value < 32,so the 2-High bit is zero*/
-+ ac108_multi_update_bits(I2S_LRCK_CTRL1, 0x03 << 0, 0x00, ac10x);
-+ } else {
-+ /*TDM mode or normal mode*/
-+ //ac108_multi_update_bits(I2S_LRCK_CTRL1, 0x03 << 0, 0x00, ac10x);
-+ ac108_multi_write(I2S_LRCK_CTRL2, ac108_samp_res[samp_res].real_val - 1,
-+ ac10x);
-+ ac108_multi_update_bits(I2S_LRCK_CTRL1, 0x03 << 0, 0x00, ac10x);
-+ }
-+ } else {
-+ unsigned div;
-+
-+ /*TDM mode or normal mode*/
-+ div = ac108_samp_res[samp_res].real_val * channels - 1;
-+ ac108_multi_write(I2S_LRCK_CTRL2, (div & 0xFF), ac10x);
-+ ac108_multi_update_bits(I2S_LRCK_CTRL1, 0x03 << 0, (div >> 8) << 0, ac10x);
-+ }
-+
-+ /**
-+ * 0x35:
-+ * TX Encoding mode will add 4bits to mark channel number
-+ * TODO: need a chat to explain this
-+ */
-+ ac108_multi_update_bits(I2S_FMT_CTRL2, 0x07 << SAMPLE_RESOLUTION | 0x07 << SLOT_WIDTH_SEL,
-+ ac108_samp_res[samp_res].reg_val << SAMPLE_RESOLUTION |
-+ ac108_samp_res[samp_res].reg_val << SLOT_WIDTH_SEL, ac10x);
-+
-+ /**
-+ * 0x60:
-+ * ADC Sample Rate synchronised with I2S1 clock zone
-+ */
-+ ac108_multi_update_bits(ADC_SPRC, 0x0f << ADC_FS_I2S1,
-+ ac108_sample_rate[rate].reg_val << ADC_FS_I2S1, ac10x);
-+ ac108_multi_write(HPF_EN, 0x0F, ac10x);
-+
-+ if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
-+ ac108_config_pll(ac10x, ac108_sample_rate[rate].real_val,
-+ ac108_samp_res[samp_res].real_val * channels);
-+ } else {
-+ ac108_config_pll(ac10x, ac108_sample_rate[rate].real_val, 0);
-+ }
-+
-+ /*
-+ * master mode only
-+ */
-+ bclkdiv = ac10x->mclk / (ac108_sample_rate[rate].real_val * channels *
-+ ac108_samp_res[samp_res].real_val);
-+ for (i = 0; i < ARRAY_SIZE(ac108_bclkdivs) - 1; i++) {
-+ if (ac108_bclkdivs[i] >= bclkdiv) {
-+ break;
-+ }
-+ }
-+ ac108_multi_update_bits(I2S_BCLK_CTRL, 0x0F << BCLKDIV, i << BCLKDIV, ac10x);
-+
-+ /*
-+ * slots allocation for each chip
-+ */
-+ ac108_multi_chips_slots(ac10x, channels);
-+
-+ /*0x21: Module clock enable<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
-+ ac108_multi_write(MOD_CLK_EN, 1 << I2S | 1 << ADC_DIGITAL |
-+ 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x);
-+ /*0x22: Module reset de-asserted<I2S, ADC digital, MIC offset Calibration, ADC analog>*/
-+ ac108_multi_write(MOD_RST_CTRL, 1 << I2S | 1 << ADC_DIGITAL |
-+ 1 << MIC_OFFSET_CALIBRATION | 1 << ADC_ANALOG, ac10x);
-+
-+ ac108_multi_write(I2S_TX1_CHMP_CTRL1, 0xE4, ac10x);
-+ ac108_multi_write(I2S_TX1_CHMP_CTRL2, 0xE4, ac10x);
-+ ac108_multi_write(I2S_TX1_CHMP_CTRL3, 0xE4, ac10x);
-+ ac108_multi_write(I2S_TX1_CHMP_CTRL4, 0xE4, ac10x);
-+
-+ ac108_multi_write(I2S_TX2_CHMP_CTRL1, 0xE4, ac10x);
-+ ac108_multi_write(I2S_TX2_CHMP_CTRL2, 0xE4, ac10x);
-+ ac108_multi_write(I2S_TX2_CHMP_CTRL3, 0xE4, ac10x);
-+ ac108_multi_write(I2S_TX2_CHMP_CTRL4, 0xE4, ac10x);
-+
-+ dev_dbg(dai->dev, "%s() stream=%s ---\n", __func__,
-+ snd_pcm_stream_str(substream));
-+
-+ return 0;
-+}
-+
-+static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir)
-+{
-+
-+ struct ac10x_priv *ac10x = snd_soc_dai_get_drvdata(dai);
-+
-+ freq = 24000000;
-+ clk_id = SYSCLK_SRC_PLL;
-+
-+ switch (clk_id) {
-+ case SYSCLK_SRC_MCLK:
-+ ac108_multi_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC,
-+ SYSCLK_SRC_MCLK << SYSCLK_SRC, ac10x);
-+ break;
-+ case SYSCLK_SRC_PLL:
-+ ac108_multi_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC,
-+ SYSCLK_SRC_PLL << SYSCLK_SRC, ac10x);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ ac10x->sysclk = freq;
-+ ac10x->clk_id = clk_id;
-+
-+ return 0;
-+}
-+
-+/**
-+ * The i2s format management related registers are Reg
-+ * 30h~Reg36h
-+ * 33h,35h will be set in ac108_hw_params, It's BCLK width and
-+ * Sample Resolution.
-+ * @author baozhu (17-6-20)
-+ *
-+ * @param dai
-+ * @param fmt
-+ *
-+ * @return int
-+ */
-+static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-+{
-+ unsigned char tx_offset, lrck_polarity, brck_polarity;
-+ struct ac10x_priv *ac10x = dev_get_drvdata(dai->dev);
-+
-+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-+ case SND_SOC_DAIFMT_CBM_CFM: /* AC108 Master */
-+ if (! ac10x->i2c101 || _MASTER_MULTI_CODEC == _MASTER_AC108) {
-+ /**
-+ * 0x30:chip is master mode ,BCLK & LRCK output
-+ */
-+ ac108_multi_update_bits(I2S_CTRL,
-+ 0x03 << LRCK_IOEN | 0x03 << SDO1_EN |
-+ 0x1 << TXEN | 0x1 << GEN,
-+ 0x03 << LRCK_IOEN | 0x01 << SDO1_EN |
-+ 0x1 << TXEN | 0x1 << GEN, ac10x);
-+ /* multi_chips: only one chip set as Master, and the others also need to set as Slave */
-+ ac10x_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x01 << BCLK_IOEN,
-+ ac10x->i2cmap[_MASTER_INDEX]);
-+ } else {
-+ /* TODO: Both cpu_dai and codec_dai(AC108) be set as slave in DTS */
-+ dev_err(dai->dev, "used as slave when AC101 is master\n");
-+ }
-+ break;
-+ case SND_SOC_DAIFMT_CBS_CFS: /* AC108 Slave */
-+ /**
-+ * 0x30:chip is slave mode, BCLK & LRCK input,enable SDO1_EN and
-+ * SDO2_EN, Transmitter Block Enable, Globe Enable
-+ */
-+ ac108_multi_update_bits(I2S_CTRL,
-+ 0x03 << LRCK_IOEN | 0x03 << SDO1_EN |
-+ 0x1 << TXEN | 0x1 << GEN,
-+ 0x00 << LRCK_IOEN | 0x03 << SDO1_EN |
-+ 0x0 << TXEN | 0x0 << GEN, ac10x);
-+ break;
-+ default:
-+ dev_err(dai->dev, "AC108 Master/Slave mode config error:%u\n\n",
-+ (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12);
-+ return -EINVAL;
-+ }
-+
-+ /*AC108 config I2S/LJ/RJ/PCM format*/
-+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-+ case SND_SOC_DAIFMT_I2S:
-+ ac10x->i2s_mode = LEFT_JUSTIFIED_FORMAT;
-+ tx_offset = 1;
-+ break;
-+ case SND_SOC_DAIFMT_RIGHT_J:
-+ ac10x->i2s_mode = RIGHT_JUSTIFIED_FORMAT;
-+ tx_offset = 0;
-+ break;
-+ case SND_SOC_DAIFMT_LEFT_J:
-+ ac10x->i2s_mode = LEFT_JUSTIFIED_FORMAT;
-+ tx_offset = 0;
-+ break;
-+ case SND_SOC_DAIFMT_DSP_A:
-+ ac10x->i2s_mode = PCM_FORMAT;
-+ tx_offset = 1;
-+ break;
-+ case SND_SOC_DAIFMT_DSP_B:
-+ ac10x->i2s_mode = PCM_FORMAT;
-+ tx_offset = 0;
-+ break;
-+ default:
-+ dev_err(dai->dev, "AC108 I2S format config error:%u\n\n",
-+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
-+ return -EINVAL;
-+ }
-+
-+ /*AC108 config BCLK&LRCK polarity*/
-+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-+ case SND_SOC_DAIFMT_NB_NF:
-+ brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P;
-+ lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW;
-+ break;
-+ case SND_SOC_DAIFMT_NB_IF:
-+ brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P;
-+ lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH;
-+ break;
-+ case SND_SOC_DAIFMT_IB_NF:
-+ brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N;
-+ lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW;
-+ break;
-+ case SND_SOC_DAIFMT_IB_IF:
-+ brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N;
-+ lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH;
-+ break;
-+ default:
-+ dev_err(dai->dev, "AC108 config BCLK/LRCLK polarity error:%u\n\n",
-+ (fmt & SND_SOC_DAIFMT_INV_MASK) >> 8);
-+ return -EINVAL;
-+ }
-+
-+ ac108_configure_power(ac10x);
-+
-+ /**
-+ *0x31: 0: normal mode, negative edge drive and positive edge sample
-+ 1: invert mode, positive edge drive and negative edge sample
-+ */
-+ ac108_multi_update_bits(I2S_BCLK_CTRL, 0x01 << BCLK_POLARITY,
-+ brck_polarity << BCLK_POLARITY, ac10x);
-+ /**
-+ * 0x32: same as 0x31
-+ */
-+ ac108_multi_update_bits(I2S_LRCK_CTRL1, 0x01 << LRCK_POLARITY,
-+ lrck_polarity << LRCK_POLARITY, ac10x);
-+ /**
-+ * 0x34:Encoding Mode Selection,Mode
-+ * Selection,data is offset by 1 BCLKs to LRCK
-+ * normal mode for the last half cycle of BCLK in the slot ?
-+ * turn to hi-z state (TDM) when not transferring slot ?
-+ */
-+ ac108_multi_update_bits(I2S_FMT_CTRL1,
-+ 0x01 << ENCD_SEL | 0x03 << MODE_SEL | 0x01 << TX2_OFFSET |
-+ 0x01 << TX1_OFFSET | 0x01 << TX_SLOT_HIZ | 0x01 << TX_STATE,
-+ ac10x->data_protocol << ENCD_SEL | ac10x->i2s_mode << MODE_SEL |
-+ tx_offset << TX2_OFFSET | tx_offset << TX1_OFFSET |
-+ 0x00 << TX_SLOT_HIZ | 0x01 << TX_STATE, ac10x);
-+
-+ /**
-+ * 0x60:
-+ * MSB / LSB First Select: This driver only support MSB First Select .
-+ * OUT2_MUTE,OUT1_MUTE shoule be set in widget.
-+ * LRCK = 1 BCLK width
-+ * Linear PCM
-+ *
-+ * TODO:pcm mode, bit[0:1] and bit[2] is special
-+ */
-+ ac108_multi_update_bits(I2S_FMT_CTRL3,
-+ 0x01 << TX_MLS | 0x03 << SEXT |
-+ 0x01 << LRCK_WIDTH | 0x03 << TX_PDM,
-+ 0x00 << TX_MLS | 0x03 << SEXT |
-+ 0x00 << LRCK_WIDTH | 0x00 << TX_PDM, ac10x);
-+
-+ ac108_multi_write(HPF_EN, 0x00, ac10x);
-+
-+ if (ac10x->i2c101) {
-+ return ac101_set_dai_fmt(dai, fmt);
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * due to miss channels order in cpu_dai, we meed defer the clock starting.
-+ */
-+static int ac108_set_clock(int y_start_n_stop)
-+{
-+ u8 reg;
-+ int ret = 0;
-+
-+ dev_dbg(ac10x->codec->dev, "%s() L%d cmd:%d\n", __func__, __LINE__, y_start_n_stop);
-+
-+ /* spin_lock move to machine trigger */
-+
-+ if (y_start_n_stop && ac10x->sysclk_en == 0) {
-+ /* enable lrck clock */
-+ ac10x_read(I2S_CTRL, ®, ac10x->i2cmap[_MASTER_INDEX]);
-+ if (reg & (0x01 << BCLK_IOEN)) {
-+ ret = ret || ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN,
-+ 0x03 << LRCK_IOEN,
-+ ac10x->i2cmap[_MASTER_INDEX]);
-+ }
-+
-+ /*0x10: PLL Common voltage enable, PLL enable */
-+ ret = ret || ac108_multi_update_bits(PLL_CTRL1,
-+ 0x01 << PLL_EN | 0x01 << PLL_COM_EN,
-+ 0x01 << PLL_EN | 0x01 << PLL_COM_EN, ac10x);
-+ /* enable global clock */
-+ ret = ret || ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN,
-+ 0x1 << TXEN | 0x1 << GEN, ac10x);
-+
-+ ac10x->sysclk_en = 1UL;
-+ } else if (!y_start_n_stop && ac10x->sysclk_en != 0) {
-+ /* disable global clock */
-+ ret = ret || ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN,
-+ 0x0 << TXEN | 0x0 << GEN, ac10x);
-+
-+ /*0x10: PLL Common voltage disable, PLL disable */
-+ ret = ret || ac108_multi_update_bits(PLL_CTRL1, 0x01 << PLL_EN | 0x01 << PLL_COM_EN,
-+ 0x00 << PLL_EN | 0x00 << PLL_COM_EN, ac10x);
-+
-+ /* disable lrck clock if it's enabled */
-+ ac10x_read(I2S_CTRL, ®, ac10x->i2cmap[_MASTER_INDEX]);
-+ if (reg & (0x01 << LRCK_IOEN)) {
-+ ret = ret || ac10x_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN,
-+ 0x01 << BCLK_IOEN,
-+ ac10x->i2cmap[_MASTER_INDEX]);
-+ }
-+ if (!ret) {
-+ ac10x->sysclk_en = 0UL;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static int ac108_prepare(struct snd_pcm_substream *substream,
-+ struct snd_soc_dai *dai)
-+{
-+ u8 r;
-+
-+ dev_dbg(dai->dev, "%s() stream=%s\n",
-+ __func__,
-+ snd_pcm_stream_str(substream));
-+
-+ if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
-+ ac101_trigger(substream, SNDRV_PCM_TRIGGER_START, dai);
-+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-+ return 0;
-+ }
-+ }
-+
-+ ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
-+ if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
-+ /* disable global clock */
-+ ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN,
-+ 0x0 << TXEN | 0x0 << GEN, ac10x);
-+ }
-+
-+ /* delayed clock starting, move to machine trigger() */
-+ ac108_set_clock(1);
-+
-+ return 0;
-+}
-+
-+int ac108_audio_startup(struct snd_pcm_substream *substream,
-+ struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_codec *codec = dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ if (ac10x->i2c101) {
-+ return ac101_audio_startup(substream, dai);
-+ }
-+ return 0;
-+}
-+
-+void ac108_aif_shutdown(struct snd_pcm_substream *substream,
-+ struct snd_soc_dai *dai)
-+{
-+ struct snd_soc_codec *codec = dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ ac108_set_clock(0);
-+
-+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-+ /*0x21: Module clock disable <I2S, ADC digital, MIC offset Calibration, ADC analog>*/
-+ ac108_multi_write(MOD_CLK_EN, 0x0, ac10x);
-+ /*0x22: Module reset asserted <I2S, ADC digital, MIC offset Calibration, ADC analog>*/
-+ ac108_multi_write(MOD_RST_CTRL, 0x0, ac10x);
-+ }
-+
-+ if (ac10x->i2c101) {
-+ ac101_aif_shutdown(substream, dai);
-+ }
-+}
-+
-+int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int stream)
-+{
-+ struct snd_soc_codec *codec = dai->codec;
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ if (ac10x->i2c101) {
-+ return ac101_aif_mute(dai, mute);
-+ }
-+ return 0;
-+}
-+
-+static const struct snd_soc_dai_ops ac108_dai_ops = {
-+ .startup = ac108_audio_startup,
-+ .shutdown = ac108_aif_shutdown,
-+
-+ /*DAI clocking configuration*/
-+ .set_sysclk = ac108_set_sysclk,
-+
-+ /*ALSA PCM audio operations*/
-+ .hw_params = ac108_hw_params,
-+ .prepare = ac108_prepare,
-+ .mute_stream = ac108_aif_mute,
-+
-+ /*DAI format configuration*/
-+ .set_fmt = ac108_set_fmt,
-+};
-+
-+static struct snd_soc_dai_driver ac108_dai0 = {
-+ .name = "ac10x-codec0",
-+ #if _USE_CAPTURE
-+ .playback = {
-+ .stream_name = "Playback",
-+ .channels_min = 1,
-+ .channels_max = AC108_CHANNELS_MAX,
-+ .rates = AC108_RATES,
-+ .formats = AC108_FORMATS,
-+ },
-+ #endif
-+ .capture = {
-+ .stream_name = "Capture",
-+ .channels_min = 1,
-+ .channels_max = AC108_CHANNELS_MAX,
-+ .rates = AC108_RATES,
-+ .formats = AC108_FORMATS,
-+ },
-+ .ops = &ac108_dai_ops,
-+};
-+
-+static struct snd_soc_dai_driver ac108_dai1 = {
-+ .name = "ac10x-codec1",
-+ #if _USE_CAPTURE
-+ .playback = {
-+ .stream_name = "Playback",
-+ .channels_min = 1,
-+ .channels_max = AC108_CHANNELS_MAX,
-+ .rates = AC108_RATES,
-+ .formats = AC108_FORMATS,
-+ },
-+ #endif
-+ .capture = {
-+ .stream_name = "Capture",
-+ .channels_min = 1,
-+ .channels_max = AC108_CHANNELS_MAX,
-+ .rates = AC108_RATES,
-+ .formats = AC108_FORMATS,
-+ },
-+ .ops = &ac108_dai_ops,
-+};
-+
-+static struct snd_soc_dai_driver *ac108_dai[] = {
-+ &ac108_dai0,
-+ &ac108_dai1,
-+};
-+
-+static int ac108_add_widgets(struct snd_soc_codec *codec)
-+{
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-+ const struct snd_kcontrol_new* snd_kcntl = ac108_snd_controls;
-+ int ctrl_cnt = ARRAY_SIZE(ac108_snd_controls);
-+
-+ /* only register controls correspond to exist chips */
-+ if (ac10x->tdm_chips_cnt >= 2) {
-+ snd_kcntl = ac108tdm_snd_controls;
-+ ctrl_cnt = ARRAY_SIZE(ac108tdm_snd_controls);
-+ }
-+ snd_soc_add_codec_controls(codec, snd_kcntl, ctrl_cnt);
-+
-+ snd_soc_dapm_new_controls(dapm, ac108_dapm_widgets,ARRAY_SIZE(ac108_dapm_widgets));
-+ snd_soc_dapm_add_routes(dapm, ac108_dapm_routes, ARRAY_SIZE(ac108_dapm_routes));
-+
-+ return 0;
-+}
-+
-+static int ac108_codec_probe(struct snd_soc_codec *codec)
-+{
-+ spin_lock_init(&ac10x->lock);
-+
-+ ac10x->codec = codec;
-+ dev_set_drvdata(codec->dev, ac10x);
-+ ac108_add_widgets(codec);
-+
-+ if (ac10x->i2c101) {
-+ ac101_codec_probe(codec);
-+ }
-+
-+ /* change default volume */
-+ ac108_multi_update_bits(ADC1_DVOL_CTRL, 0xff, 0xc8, ac10x);
-+ ac108_multi_update_bits(ADC2_DVOL_CTRL, 0xff, 0xc8, ac10x);
-+ ac108_multi_update_bits(ADC3_DVOL_CTRL, 0xff, 0xc8, ac10x);
-+ ac108_multi_update_bits(ADC4_DVOL_CTRL, 0xff, 0xc8, ac10x);
-+
-+ return 0;
-+}
-+
-+static int ac108_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
-+{
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ dev_dbg(codec->dev, "AC108 level:%d\n", level);
-+
-+ switch (level) {
-+ case SND_SOC_BIAS_ON:
-+ ac108_multi_update_bits(ANA_ADC1_CTRL1, 0x01 << ADC1_MICBIAS_EN,
-+ 0x01 << ADC1_MICBIAS_EN, ac10x);
-+ ac108_multi_update_bits(ANA_ADC2_CTRL1, 0x01 << ADC2_MICBIAS_EN,
-+ 0x01 << ADC2_MICBIAS_EN, ac10x);
-+ ac108_multi_update_bits(ANA_ADC3_CTRL1, 0x01 << ADC3_MICBIAS_EN,
-+ 0x01 << ADC3_MICBIAS_EN, ac10x);
-+ ac108_multi_update_bits(ANA_ADC4_CTRL1, 0x01 << ADC4_MICBIAS_EN,
-+ 0x01 << ADC4_MICBIAS_EN, ac10x);
-+ break;
-+
-+ case SND_SOC_BIAS_PREPARE:
-+ /* Put the MICBIASes into regulating mode */
-+ break;
-+
-+ case SND_SOC_BIAS_STANDBY:
-+ break;
-+
-+ case SND_SOC_BIAS_OFF:
-+ ac108_multi_update_bits(ANA_ADC1_CTRL1, 0x01 << ADC1_MICBIAS_EN,
-+ 0x00 << ADC1_MICBIAS_EN, ac10x);
-+ ac108_multi_update_bits(ANA_ADC2_CTRL1, 0x01 << ADC2_MICBIAS_EN,
-+ 0x00 << ADC2_MICBIAS_EN, ac10x);
-+ ac108_multi_update_bits(ANA_ADC3_CTRL1, 0x01 << ADC3_MICBIAS_EN,
-+ 0x00 << ADC3_MICBIAS_EN, ac10x);
-+ ac108_multi_update_bits(ANA_ADC4_CTRL1, 0x01 << ADC4_MICBIAS_EN,
-+ 0x00 << ADC4_MICBIAS_EN, ac10x);
-+ break;
-+ }
-+
-+ if (ac10x->i2c101) {
-+ ac101_set_bias_level(codec, level);
-+ }
-+ return 0;
-+}
-+
-+int ac108_codec_remove(struct snd_soc_codec *codec) {
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+
-+ if (! ac10x->i2c101) {
-+ return 0;
-+ }
-+ return ac101_codec_remove(codec);
-+}
-+#if __NO_SND_SOC_CODEC_DRV
-+void ac108_codec_remove_void(struct snd_soc_codec *codec)
-+{
-+ ac108_codec_remove(codec);
-+}
-+#define ac108_codec_remove ac108_codec_remove_void
-+#endif
-+
-+int ac108_codec_suspend(struct snd_soc_codec *codec)
-+{
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int i;
-+
-+ for (i = 0; i < ac10x->codec_cnt; i++) {
-+ regcache_cache_only(ac10x->i2cmap[i], true);
-+ }
-+
-+ if (! ac10x->i2c101) {
-+ return 0;
-+ }
-+ return ac101_codec_suspend(codec);
-+}
-+
-+int ac108_codec_resume(struct snd_soc_codec *codec)
-+{
-+ struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-+ int i, ret;
-+
-+ /* Sync reg_cache with the hardware */
-+ for (i = 0; i < ac10x->codec_cnt; i++) {
-+ regcache_cache_only(ac10x->i2cmap[i], false);
-+ ret = regcache_sync(ac10x->i2cmap[i]);
-+ if (ret != 0) {
-+ dev_err(codec->dev, "Failed to sync i2cmap%d register cache: %d\n",
-+ i, ret);
-+ regcache_cache_only(ac10x->i2cmap[i], true);
-+ }
-+ }
-+
-+ if (! ac10x->i2c101) {
-+ return 0;
-+ }
-+ return ac101_codec_resume(codec);
-+}
-+
-+static struct snd_soc_codec_driver ac10x_soc_codec_driver = {
-+ .probe = ac108_codec_probe,
-+ .remove = ac108_codec_remove,
-+ .suspend = ac108_codec_suspend,
-+ .resume = ac108_codec_resume,
-+ .set_bias_level = ac108_set_bias_level,
-+ .read = ac108_codec_read,
-+ .write = ac108_codec_write,
-+};
-+
-+static ssize_t ac108_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int val = 0, flag = 0;
-+ u8 i = 0, reg, num, value_w, value_r[4];
-+
-+ val = simple_strtol(buf, NULL, 16);
-+ flag = (val >> 16) & 0xF;
-+
-+ if (flag) {
-+ reg = (val >> 8) & 0xFF;
-+ value_w = val & 0xFF;
-+ ac108_multi_write(reg, value_w, ac10x);
-+ dev_info(dev, "Write 0x%02x to REG:0x%02x\n", value_w, reg);
-+ } else {
-+ int k;
-+
-+ reg = (val >> 8) & 0xFF;
-+ num = val & 0xff;
-+ dev_info(dev, "\nRead: start REG:0x%02x,count:0x%02x\n", reg, num);
-+
-+ for (k = 0; k < ac10x->codec_cnt; k++)
-+ regcache_cache_bypass(ac10x->i2cmap[k], true);
-+
-+ do {
-+ memset(value_r, 0, sizeof value_r);
-+
-+ for (k = 0; k < ac10x->codec_cnt; k++)
-+ ac10x_read(reg, &value_r[k], ac10x->i2cmap[k]);
-+
-+ if (ac10x->codec_cnt >= 2)
-+ dev_info(dev, "REG[0x%02x]: 0x%02x 0x%02x", reg,
-+ value_r[0], value_r[1]);
-+ else
-+ dev_info(dev, "REG[0x%02x]: 0x%02x", reg, value_r[0]);
-+ reg++;
-+
-+ if ((++i == num) || (i % 4 == 0))
-+ dev_info(dev, "\n");
-+ } while (i < num);
-+
-+ for (k = 0; k < ac10x->codec_cnt; k++)
-+ regcache_cache_bypass(ac10x->i2cmap[k], false);
-+ }
-+
-+ return count;
-+}
-+
-+static ssize_t ac108_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ dev_info(dev, "echo flag|reg|val > ac108\n");
-+ dev_info(dev, "eg read star addres=0x06,count 0x10:echo 0610 >ac108\n");
-+ dev_info(dev, "eg write value:0xfe to address:0x06 :echo 106fe > ac108\n");
-+ return 0;
-+}
-+
-+static DEVICE_ATTR(ac108, 0644, ac108_show, ac108_store);
-+static struct attribute *ac108_debug_attrs[] = {
-+ &dev_attr_ac108.attr,
-+ NULL,
-+};
-+static struct attribute_group ac108_debug_attr_group = {
-+ .name = "ac108_debug",
-+ .attrs = ac108_debug_attrs,
-+};
-+
-+static const struct i2c_device_id ac108_i2c_id[] = {
-+ { "ac108_0", 0 },
-+ { "ac108_1", 1 },
-+ { "ac108_2", 2 },
-+ { "ac108_3", 3 },
-+ { "ac101", AC101_I2C_ID },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(i2c, ac108_i2c_id);
-+
-+static const struct regmap_config ac108_regmap = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .reg_stride = 1,
-+ .max_register = 0xDF,
-+ .cache_type = REGCACHE_FLAT,
-+};
-+static int ac108_i2c_probe(struct i2c_client *i2c)
-+{
-+ struct device_node *np = i2c->dev.of_node;
-+ const struct i2c_device_id *i2c_id;
-+ unsigned int val = 0;
-+ int ret = 0, index;
-+
-+ if (ac10x == NULL) {
-+ ac10x = kzalloc(sizeof(struct ac10x_priv), GFP_KERNEL);
-+ if (ac10x == NULL) {
-+ dev_err(&i2c->dev, "Unable to allocate ac10x private data\n");
-+ return -ENOMEM;
-+ }
-+ }
-+
-+ i2c_id = i2c_match_id(ac108_i2c_id, i2c);
-+ index = (int)i2c_id->driver_data;
-+ if (index == AC101_I2C_ID) {
-+ ac10x->i2c101 = i2c;
-+ i2c_set_clientdata(i2c, ac10x);
-+ ret = ac101_probe(i2c, i2c_id);
-+ if (ret) {
-+ ac10x->i2c101 = NULL;
-+ return ret;
-+ }
-+ goto __ret;
-+ }
-+
-+ ret = of_property_read_u32(np, "data-protocol", &val);
-+ if (ret) {
-+ dev_err(&i2c->dev, "Please set data-protocol.\n");
-+ return -EINVAL;
-+ }
-+ ac10x->data_protocol = val;
-+
-+ if (of_property_read_u32(np, "tdm-chips-count", &val)) val = 1;
-+ ac10x->tdm_chips_cnt = val;
-+
-+ dev_info(&i2c->dev, " ac10x i2c_id number: %d\n", index);
-+ dev_info(&i2c->dev, " ac10x data protocol: %d\n", ac10x->data_protocol);
-+
-+ ac10x->i2c[index] = i2c;
-+ ac10x->i2cmap[index] = devm_regmap_init_i2c(i2c, &ac108_regmap);
-+ if (IS_ERR(ac10x->i2cmap[index])) {
-+ ret = PTR_ERR(ac10x->i2cmap[index]);
-+ dev_err(&i2c->dev, "Fail to initialize i2cmap%d I/O: %d\n", index, ret);
-+ return ret;
-+ }
-+
-+ /*
-+ * Writing this register with 0x12
-+ * will resets all register to their default state.
-+ */
-+ regcache_cache_only(ac10x->i2cmap[index], false);
-+
-+ ret = regmap_write(ac10x->i2cmap[index], CHIP_RST, CHIP_RST_VAL);
-+ msleep(1);
-+
-+ /* sync regcache for FLAT type */
-+ ac10x_fill_regcache(&i2c->dev, ac10x->i2cmap[index]);
-+
-+ ac10x->codec_cnt++;
-+ dev_info(&i2c->dev, " ac10x codec count : %d\n", ac10x->codec_cnt);
-+
-+ ret = sysfs_create_group(&i2c->dev.kobj, &ac108_debug_attr_group);
-+ if (ret) {
-+ dev_err(&i2c->dev, "failed to create attr group\n");
-+ }
-+
-+__ret:
-+ /* It's time to bind codec to i2c[_MASTER_INDEX] when all i2c are ready */
-+ if ((ac10x->codec_cnt != 0 && ac10x->tdm_chips_cnt < 2)
-+ || (ac10x->i2c[0] && ac10x->i2c[1] && ac10x->i2c101)) {
-+ /* no playback stream */
-+ if (! ac10x->i2c101) {
-+ memset(&ac108_dai[_MASTER_INDEX]->playback, '\0',
-+ sizeof ac108_dai[_MASTER_INDEX]->playback);
-+ }
-+ ret = snd_soc_register_codec(&ac10x->i2c[_MASTER_INDEX]->dev,
-+ &ac10x_soc_codec_driver,
-+ ac108_dai[_MASTER_INDEX], 1);
-+ if (ret < 0) {
-+ dev_err(&i2c->dev, "Failed to register ac10x codec: %d\n", ret);
-+ }
-+ }
-+ return ret;
-+}
-+
-+static void ac108_i2c_remove(struct i2c_client *i2c)
-+{
-+ if (ac10x->codec != NULL) {
-+ snd_soc_unregister_codec(&ac10x->i2c[_MASTER_INDEX]->dev);
-+ ac10x->codec = NULL;
-+ }
-+ if (i2c == ac10x->i2c101) {
-+ ac101_remove(ac10x->i2c101);
-+ ac10x->i2c101 = NULL;
-+ goto __ret;
-+ }
-+
-+ if (i2c == ac10x->i2c[0]) {
-+ ac10x->i2c[0] = NULL;
-+ }
-+ if (i2c == ac10x->i2c[1]) {
-+ ac10x->i2c[1] = NULL;
-+ }
-+
-+ sysfs_remove_group(&i2c->dev.kobj, &ac108_debug_attr_group);
-+
-+__ret:
-+ if (!ac10x->i2c[0] && !ac10x->i2c[1] && !ac10x->i2c101) {
-+ kfree(ac10x);
-+ ac10x = NULL;
-+ }
-+}
-+
-+static const struct of_device_id ac108_of_match[] = {
-+ { .compatible = "x-power,ac108_0", },
-+ { .compatible = "x-power,ac108_1", },
-+ { .compatible = "x-power,ac108_2", },
-+ { .compatible = "x-power,ac108_3", },
-+ { .compatible = "x-power,ac101", },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, ac108_of_match);
-+
-+static struct i2c_driver ac108_i2c_driver = {
-+ .driver = {
-+ .name = "ac10x-codec",
-+ .of_match_table = ac108_of_match,
-+ },
-+ .probe = ac108_i2c_probe,
-+ .remove = ac108_i2c_remove,
-+ .id_table = ac108_i2c_id,
-+};
-+
-+module_i2c_driver(ac108_i2c_driver);
-+
-+MODULE_DESCRIPTION("ASoC AC108 driver");
-+MODULE_AUTHOR("Baozhu Zuo<zuobaozhu@gmail.com>");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/sound/soc/codecs/ac108.h
-@@ -0,0 +1,749 @@
-+/*
-+ * ac108.h -- ac108 ALSA Soc Audio driver
-+ *
-+ * Author: panjunwen
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#ifndef _AC108_H
-+#define _AC108_H
-+
-+/*** AC108 Codec Register Define***/
-+
-+//Chip Reset
-+#define CHIP_RST 0x00
-+#define CHIP_RST_VAL 0x12
-+
-+//Power Control
-+#define PWR_CTRL1 0x01
-+#define PWR_CTRL2 0x02
-+#define PWR_CTRL3 0x03
-+#define PWR_CTRL4 0x04
-+#define PWR_CTRL5 0x05
-+#define PWR_CTRL6 0x06
-+#define PWR_CTRL7 0x07
-+#define PWR_CTRL8 0x08
-+#define PWR_CTRL9 0x09
-+
-+//PLL Configure Control
-+#define PLL_CTRL1 0x10
-+#define PLL_CTRL2 0x11
-+#define PLL_CTRL3 0x12
-+#define PLL_CTRL4 0x13
-+#define PLL_CTRL5 0x14
-+#define PLL_CTRL6 0x16
-+#define PLL_CTRL7 0x17
-+#define PLL_LOCK_CTRL 0x18
-+
-+//System Clock Control
-+#define SYSCLK_CTRL 0x20
-+#define MOD_CLK_EN 0x21
-+#define MOD_RST_CTRL 0x22
-+#define DSM_CLK_CTRL 0x25
-+
-+//I2S Common Control
-+#define I2S_CTRL 0x30
-+#define I2S_BCLK_CTRL 0x31
-+#define I2S_LRCK_CTRL1 0x32
-+#define I2S_LRCK_CTRL2 0x33
-+#define I2S_FMT_CTRL1 0x34
-+#define I2S_FMT_CTRL2 0x35
-+#define I2S_FMT_CTRL3 0x36
-+
-+//I2S TX1 Control
-+#define I2S_TX1_CTRL1 0x38
-+#define I2S_TX1_CTRL2 0x39
-+#define I2S_TX1_CTRL3 0x3A
-+#define I2S_TX1_CHMP_CTRL1 0x3C
-+#define I2S_TX1_CHMP_CTRL2 0x3D
-+#define I2S_TX1_CHMP_CTRL3 0x3E
-+#define I2S_TX1_CHMP_CTRL4 0x3F
-+
-+//I2S TX2 Control
-+#define I2S_TX2_CTRL1 0x40
-+#define I2S_TX2_CTRL2 0x41
-+#define I2S_TX2_CTRL3 0x42
-+#define I2S_TX2_CHMP_CTRL1 0x44
-+#define I2S_TX2_CHMP_CTRL2 0x45
-+#define I2S_TX2_CHMP_CTRL3 0x46
-+#define I2S_TX2_CHMP_CTRL4 0x47
-+
-+//I2S RX1 Control
-+#define I2S_RX1_CTRL1 0x50
-+#define I2S_RX1_CHMP_CTRL1 0x54
-+#define I2S_RX1_CHMP_CTRL2 0x55
-+#define I2S_RX1_CHMP_CTRL3 0x56
-+#define I2S_RX1_CHMP_CTRL4 0x57
-+
-+//I2S Loopback Debug
-+#define I2S_LPB_DEBUG 0x58
-+
-+//ADC Common Control
-+#define ADC_SPRC 0x60
-+#define ADC_DIG_EN 0x61
-+#define DMIC_EN 0x62
-+#define ADC_DSR 0x63
-+#define ADC_FIR 0x64
-+#define ADC_DDT_CTRL 0x65
-+
-+//HPF Control
-+#define HPF_EN 0x66
-+#define HPF_COEF_REGH1 0x67
-+#define HPF_COEF_REGH2 0x68
-+#define HPF_COEF_REGL1 0x69
-+#define HPF_COEF_REGL2 0x6A
-+#define HPF_GAIN_REGH1 0x6B
-+#define HPF_GAIN_REGH2 0x6C
-+#define HPF_GAIN_REGL1 0x6D
-+#define HPF_GAIN_REGL2 0x6E
-+
-+//ADC Digital Channel Volume Control
-+#define ADC1_DVOL_CTRL 0x70
-+#define ADC2_DVOL_CTRL 0x71
-+#define ADC3_DVOL_CTRL 0x72
-+#define ADC4_DVOL_CTRL 0x73
-+
-+//ADC Digital Mixer Source and Gain Control
-+#define ADC1_DMIX_SRC 0x76
-+#define ADC2_DMIX_SRC 0x77
-+#define ADC3_DMIX_SRC 0x78
-+#define ADC4_DMIX_SRC 0x79
-+
-+//ADC Digital Debug Control
-+#define ADC_DIG_DEBUG 0x7F
-+
-+//I2S Pad Drive Control
-+#define I2S_DAT_PADDRV_CTRL 0x80
-+#define I2S_CLK_PADDRV_CTRL 0x81
-+
-+//Analog PGA Control
-+#define ANA_PGA1_CTRL 0x90
-+#define ANA_PGA2_CTRL 0x91
-+#define ANA_PGA3_CTRL 0x92
-+#define ANA_PGA4_CTRL 0x93
-+
-+//MIC Offset Control
-+#define MIC_OFFSET_CTRL1 0x96
-+#define MIC_OFFSET_CTRL2 0x97
-+#define MIC1_OFFSET_STATU1 0x98
-+#define MIC1_OFFSET_STATU2 0x99
-+#define MIC2_OFFSET_STATU1 0x9A
-+#define MIC2_OFFSET_STATU2 0x9B
-+#define MIC3_OFFSET_STATU1 0x9C
-+#define MIC3_OFFSET_STATU2 0x9D
-+#define MIC4_OFFSET_STATU1 0x9E
-+#define MIC4_OFFSET_STATU2 0x9F
-+
-+//ADC1 Analog Control
-+#define ANA_ADC1_CTRL1 0xA0
-+#define ANA_ADC1_CTRL2 0xA1
-+#define ANA_ADC1_CTRL3 0xA2
-+#define ANA_ADC1_CTRL4 0xA3
-+#define ANA_ADC1_CTRL5 0xA4
-+#define ANA_ADC1_CTRL6 0xA5
-+#define ANA_ADC1_CTRL7 0xA6
-+
-+//ADC2 Analog Control
-+#define ANA_ADC2_CTRL1 0xA7
-+#define ANA_ADC2_CTRL2 0xA8
-+#define ANA_ADC2_CTRL3 0xA9
-+#define ANA_ADC2_CTRL4 0xAA
-+#define ANA_ADC2_CTRL5 0xAB
-+#define ANA_ADC2_CTRL6 0xAC
-+#define ANA_ADC2_CTRL7 0xAD
-+
-+//ADC3 Analog Control
-+#define ANA_ADC3_CTRL1 0xAE
-+#define ANA_ADC3_CTRL2 0xAF
-+#define ANA_ADC3_CTRL3 0xB0
-+#define ANA_ADC3_CTRL4 0xB1
-+#define ANA_ADC3_CTRL5 0xB2
-+#define ANA_ADC3_CTRL6 0xB3
-+#define ANA_ADC3_CTRL7 0xB4
-+
-+//ADC4 Analog Control
-+#define ANA_ADC4_CTRL1 0xB5
-+#define ANA_ADC4_CTRL2 0xB6
-+#define ANA_ADC4_CTRL3 0xB7
-+#define ANA_ADC4_CTRL4 0xB8
-+#define ANA_ADC4_CTRL5 0xB9
-+#define ANA_ADC4_CTRL6 0xBA
-+#define ANA_ADC4_CTRL7 0xBB
-+
-+//GPIO Configure
-+#define GPIO_CFG1 0xC0
-+#define GPIO_CFG2 0xC1
-+#define GPIO_DAT 0xC2
-+#define GPIO_DRV 0xC3
-+#define GPIO_PULL 0xC4
-+#define GPIO_INT_CFG 0xC5
-+#define GPIO_INT_EN 0xC6
-+#define GPIO_INT_STATUS 0xC7
-+
-+//Misc
-+#define BGTC_DAT 0xD1
-+#define BGVC_DAT 0xD2
-+#define PRNG_CLK_CTRL 0xDF
-+
-+/*** AC108 Codec Register Bit Define***/
-+
-+/*PWR_CTRL1*/
-+#define CP12_CTRL 4
-+#define CP12_SENSE_SELECT 3
-+
-+/*PWR_CTRL2*/
-+#define CP12_SENSE_FILT 6
-+#define CP12_COMP_FF_EN 3
-+#define CP12_FORCE_ENABLE 2
-+#define CP12_FORCE_RSTB 1
-+
-+/*PWR_CTRL3*/
-+#define LDO33DIG_CTRL 0
-+
-+/*PWR_CTRL6*/
-+#define LDO33ANA_2XHDRM 2
-+#define LDO33ANA_ENABLE 0
-+
-+/*PWR_CTRL7*/
-+#define VREF_SEL 3
-+#define VREF_FASTSTART_ENABLE 1
-+#define VREF_ENABLE 0
-+
-+/*PWR_CTRL9*/
-+#define VREFP_FASTSTART_ENABLE 7
-+#define VREFP_RESCTRL 5
-+#define VREFP_LPMODE 4
-+#define IGEN_TRIM 1
-+#define VREFP_ENABLE 0
-+
-+/*PLL_CTRL1*/
-+#define PLL_IBIAS 4
-+#define PLL_NDET 3
-+#define PLL_LOCKED_STATUS 2
-+#define PLL_COM_EN 1
-+#define PLL_EN 0
-+
-+/*PLL_CTRL2*/
-+#define PLL_PREDIV2 5
-+#define PLL_PREDIV1 0
-+
-+/*PLL_CTRL3*/
-+#define PLL_LOOPDIV_MSB 0
-+
-+/*PLL_CTRL4*/
-+#define PLL_LOOPDIV_LSB 0
-+
-+/*PLL_CTRL5*/
-+#define PLL_POSTDIV2 5
-+#define PLL_POSTDIV1 0
-+
-+/*PLL_CTRL6*/
-+#define PLL_LDO 6
-+#define PLL_CP 0
-+
-+/*PLL_CTRL7*/
-+#define PLL_CAP 6
-+#define PLL_RES 4
-+#define PLL_TEST_EN 0
-+
-+/*PLL_LOCK_CTRL*/
-+#define LOCK_LEVEL1 2
-+#define LOCK_LEVEL2 1
-+#define PLL_LOCK_EN 0
-+
-+/*SYSCLK_CTRL*/
-+#define PLLCLK_EN 7
-+#define PLLCLK_SRC 4
-+#define SYSCLK_SRC 3
-+#define SYSCLK_EN 0
-+
-+/*MOD_CLK_EN & MOD_RST_CTRL*/
-+#define I2S 7
-+#define ADC_DIGITAL 4
-+#define MIC_OFFSET_CALIBRATION 1
-+#define ADC_ANALOG 0
-+
-+/*DSM_CLK_CTRL*/
-+#define MIC_OFFSET_DIV 4
-+#define DSM_CLK_SEL 0
-+
-+/*I2S_CTRL*/
-+#define BCLK_IOEN 7
-+#define LRCK_IOEN 6
-+#define SDO2_EN 5
-+#define SDO1_EN 4
-+#define TXEN 2
-+#define RXEN 1
-+#define GEN 0
-+
-+/*I2S_BCLK_CTRL*/
-+#define EDGE_TRANSFER 5
-+#define BCLK_POLARITY 4
-+#define BCLKDIV 0
-+
-+/*I2S_LRCK_CTRL1*/
-+#define LRCK_POLARITY 4
-+#define LRCK_PERIODH 0
-+
-+/*I2S_LRCK_CTRL2*/
-+#define LRCK_PERIODL 0
-+
-+/*I2S_FMT_CTRL1*/
-+#define ENCD_SEL 6
-+#define MODE_SEL 4
-+#define TX2_OFFSET 3
-+#define TX1_OFFSET 2
-+#define TX_SLOT_HIZ 1
-+#define TX_STATE 0
-+
-+/*I2S_FMT_CTRL2*/
-+#define SLOT_WIDTH_SEL 4
-+#define SAMPLE_RESOLUTION 0
-+
-+/*I2S_FMT_CTRL3*/
-+#define TX_MLS 7
-+#define SEXT 5
-+#define OUT2_MUTE 4
-+#define OUT1_MUTE 3
-+#define LRCK_WIDTH 2
-+#define TX_PDM 0
-+
-+/*I2S_TX1_CTRL1*/
-+#define TX1_CHSEL 0
-+
-+/*I2S_TX1_CTRL2*/
-+#define TX1_CH8_EN 7
-+#define TX1_CH7_EN 6
-+#define TX1_CH6_EN 5
-+#define TX1_CH5_EN 4
-+#define TX1_CH4_EN 3
-+#define TX1_CH3_EN 2
-+#define TX1_CH2_EN 1
-+#define TX1_CH1_EN 0
-+
-+/*I2S_TX1_CTRL3*/
-+#define TX1_CH16_EN 7
-+#define TX1_CH15_EN 6
-+#define TX1_CH14_EN 5
-+#define TX1_CH13_EN 4
-+#define TX1_CH12_EN 3
-+#define TX1_CH11_EN 2
-+#define TX1_CH10_EN 1
-+#define TX1_CH9_EN 0
-+
-+/*I2S_TX1_CHMP_CTRL1*/
-+#define TX1_CH4_MAP 6
-+#define TX1_CH3_MAP 4
-+#define TX1_CH2_MAP 2
-+#define TX1_CH1_MAP 0
-+
-+/*I2S_TX1_CHMP_CTRL2*/
-+#define TX1_CH8_MAP 6
-+#define TX1_CH7_MAP 4
-+#define TX1_CH6_MAP 2
-+#define TX1_CH5_MAP 0
-+
-+/*I2S_TX1_CHMP_CTRL3*/
-+#define TX1_CH12_MAP 6
-+#define TX1_CH11_MAP 4
-+#define TX1_CH10_MAP 2
-+#define TX1_CH9_MAP 0
-+
-+/*I2S_TX1_CHMP_CTRL4*/
-+#define TX1_CH16_MAP 6
-+#define TX1_CH15_MAP 4
-+#define TX1_CH14_MAP 2
-+#define TX1_CH13_MAP 0
-+
-+/*I2S_TX2_CTRL1*/
-+#define TX2_CHSEL 0
-+
-+/*I2S_TX2_CHMP_CTRL1*/
-+#define TX2_CH4_MAP 6
-+#define TX2_CH3_MAP 4
-+#define TX2_CH2_MAP 2
-+#define TX2_CH1_MAP 0
-+
-+/*I2S_TX2_CHMP_CTRL2*/
-+#define TX2_CH8_MAP 6
-+#define TX2_CH7_MAP 4
-+#define TX2_CH6_MAP 2
-+#define TX2_CH5_MAP 0
-+
-+/*I2S_TX2_CHMP_CTRL3*/
-+#define TX2_CH12_MAP 6
-+#define TX2_CH11_MAP 4
-+#define TX2_CH10_MAP 2
-+#define TX2_CH9_MAP 0
-+
-+/*I2S_TX2_CHMP_CTRL4*/
-+#define TX2_CH16_MAP 6
-+#define TX2_CH15_MAP 4
-+#define TX2_CH14_MAP 2
-+#define TX2_CH13_MAP 0
-+
-+/*I2S_RX1_CTRL1*/
-+#define RX1_CHSEL 0
-+
-+/*I2S_RX1_CHMP_CTRL1*/
-+#define RX1_CH4_MAP 6
-+#define RX1_CH3_MAP 4
-+#define RX1_CH2_MAP 2
-+#define RX1_CH1_MAP 0
-+
-+/*I2S_RX1_CHMP_CTRL2*/
-+#define RX1_CH8_MAP 6
-+#define RX1_CH7_MAP 4
-+#define RX1_CH6_MAP 2
-+#define RX1_CH5_MAP 0
-+
-+/*I2S_RX1_CHMP_CTRL3*/
-+#define RX1_CH12_MAP 6
-+#define RX1_CH11_MAP 4
-+#define RX1_CH10_MAP 2
-+#define RX1_CH9_MAP 0
-+
-+/*I2S_RX1_CHMP_CTRL4*/
-+#define RX1_CH16_MAP 6
-+#define RX1_CH15_MAP 4
-+#define RX1_CH14_MAP 2
-+#define RX1_CH13_MAP 0
-+
-+/*I2S_LPB_DEBUG*/
-+#define I2S_LPB_DEBUG_EN 0
-+
-+/*ADC_SPRC*/
-+#define ADC_FS_I2S1 0
-+
-+/*ADC_DIG_EN*/
-+#define DG_EN 4
-+#define ENAD4 3
-+#define ENAD3 2
-+#define ENAD2 1
-+#define ENAD1 0
-+
-+/*DMIC_EN*/
-+#define DMIC2_EN 1
-+#define DMIC1_EN 0
-+
-+/*ADC_DSR*/
-+#define DIG_ADC4_SRS 6
-+#define DIG_ADC3_SRS 4
-+#define DIG_ADC2_SRS 2
-+#define DIG_ADC1_SRS 0
-+
-+/*ADC_DDT_CTRL*/
-+#define ADOUT_DLY_EN 2
-+#define ADOUT_DTS 0
-+
-+/*HPF_EN*/
-+#define DIG_ADC4_HPF_EN 3
-+#define DIG_ADC3_HPF_EN 2
-+#define DIG_ADC2_HPF_EN 1
-+#define DIG_ADC1_HPF_EN 0
-+
-+/*ADC1_DMIX_SRC*/
-+#define ADC1_ADC4_DMXL_GC 7
-+#define ADC1_ADC3_DMXL_GC 6
-+#define ADC1_ADC2_DMXL_GC 5
-+#define ADC1_ADC1_DMXL_GC 4
-+#define ADC1_ADC4_DMXL_SRC 3
-+#define ADC1_ADC3_DMXL_SRC 2
-+#define ADC1_ADC2_DMXL_SRC 1
-+#define ADC1_ADC1_DMXL_SRC 0
-+
-+/*ADC2_DMIX_SRC*/
-+#define ADC2_ADC4_DMXL_GC 7
-+#define ADC2_ADC3_DMXL_GC 6
-+#define ADC2_ADC2_DMXL_GC 5
-+#define ADC2_ADC1_DMXL_GC 4
-+#define ADC2_ADC4_DMXL_SRC 3
-+#define ADC2_ADC3_DMXL_SRC 2
-+#define ADC2_ADC2_DMXL_SRC 1
-+#define ADC2_ADC1_DMXL_SRC 0
-+
-+/*ADC3_DMIX_SRC*/
-+#define ADC3_ADC4_DMXL_GC 7
-+#define ADC3_ADC3_DMXL_GC 6
-+#define ADC3_ADC2_DMXL_GC 5
-+#define ADC3_ADC1_DMXL_GC 4
-+#define ADC3_ADC4_DMXL_SRC 3
-+#define ADC3_ADC3_DMXL_SRC 2
-+#define ADC3_ADC2_DMXL_SRC 1
-+#define ADC3_ADC1_DMXL_SRC 0
-+
-+/*ADC4_DMIX_SRC*/
-+#define ADC4_ADC4_DMXL_GC 7
-+#define ADC4_ADC3_DMXL_GC 6
-+#define ADC4_ADC2_DMXL_GC 5
-+#define ADC4_ADC1_DMXL_GC 4
-+#define ADC4_ADC4_DMXL_SRC 3
-+#define ADC4_ADC3_DMXL_SRC 2
-+#define ADC4_ADC2_DMXL_SRC 1
-+#define ADC4_ADC1_DMXL_SRC 0
-+
-+/*ADC_DIG_DEBUG*/
-+#define ADC_PTN_SEL 0
-+
-+/*I2S_DAT_PADDRV_CTRL*/
-+#define TX2_DAT_DRV 4
-+#define TX1_DAT_DRV 0
-+
-+/*I2S_CLK_PADDRV_CTRL*/
-+#define LRCK_DRV 4
-+#define BCLK_DRV 0
-+
-+/*ANA_PGA1_CTRL*/
-+#define ADC1_ANALOG_PGA 1
-+#define ADC1_ANALOG_PGA_STEP 0
-+
-+/*ANA_PGA2_CTRL*/
-+#define ADC2_ANALOG_PGA 1
-+#define ADC2_ANALOG_PGA_STEP 0
-+
-+/*ANA_PGA3_CTRL*/
-+#define ADC3_ANALOG_PGA 1
-+#define ADC3_ANALOG_PGA_STEP 0
-+
-+/*ANA_PGA4_CTRL*/
-+#define ADC4_ANALOG_PGA 1
-+#define ADC4_ANALOG_PGA_STEP 0
-+
-+
-+/*MIC_OFFSET_CTRL1*/
-+#define MIC_OFFSET_CAL_EN4 3
-+#define MIC_OFFSET_CAL_EN3 2
-+#define MIC_OFFSET_CAL_EN2 1
-+#define MIC_OFFSET_CAL_EN1 0
-+
-+/*MIC_OFFSET_CTRL2*/
-+#define MIC_OFFSET_CAL_GAIN 3
-+#define MIC_OFFSET_CAL_CHANNEL 1
-+#define MIC_OFFSET_CAL_EN_ONCE 0
-+
-+/*MIC1_OFFSET_STATU1*/
-+#define MIC1_OFFSET_CAL_DONE 7
-+#define MIC1_OFFSET_CAL_RUN_STA 6
-+#define MIC1_OFFSET_MSB 0
-+
-+/*MIC1_OFFSET_STATU2*/
-+#define MIC1_OFFSET_LSB 0
-+
-+/*MIC2_OFFSET_STATU1*/
-+#define MIC2_OFFSET_CAL_DONE 7
-+#define MIC2_OFFSET_CAL_RUN_STA 6
-+#define MIC2_OFFSET_MSB 0
-+
-+/*MIC2_OFFSET_STATU2*/
-+#define MIC2_OFFSET_LSB 0
-+
-+/*MIC3_OFFSET_STATU1*/
-+#define MIC3_OFFSET_CAL_DONE 7
-+#define MIC3_OFFSET_CAL_RUN_STA 6
-+#define MIC3_OFFSET_MSB 0
-+
-+/*MIC3_OFFSET_STATU2*/
-+#define MIC3_OFFSET_LSB 0
-+
-+/*MIC4_OFFSET_STATU1*/
-+#define MIC4_OFFSET_CAL_DONE 7
-+#define MIC4_OFFSET_CAL_RUN_STA 6
-+#define MIC4_OFFSET_MSB 0
-+
-+/*MIC4_OFFSET_STATU2*/
-+#define MIC4_OFFSET_LSB 0
-+
-+/*ANA_ADC1_CTRL1*/
-+#define ADC1_PGA_BYPASS 7
-+#define ADC1_PGA_BYP_RCM 6
-+#define ADC1_PGA_CTRL_RCM 4
-+#define ADC1_PGA_MUTE 3
-+#define ADC1_DSM_ENABLE 2
-+#define ADC1_PGA_ENABLE 1
-+#define ADC1_MICBIAS_EN 0
-+
-+/*ANA_ADC1_CTRL3*/
-+#define ADC1_ANA_CAL_EN 5
-+#define ADC1_SEL_OUT_EDGE 3
-+#define ADC1_DSM_DISABLE 2
-+#define ADC1_VREFP_DISABLE 1
-+#define ADC1_AAF_DISABLE 0
-+
-+/*ANA_ADC1_CTRL6*/
-+#define PGA_CTRL_TC 6
-+#define PGA_CTRL_RC 4
-+#define PGA_CTRL_I_LIN 2
-+#define PGA_CTRL_I_IN 0
-+
-+/*ANA_ADC1_CTRL7*/
-+#define PGA_CTRL_HI_Z 7
-+#define PGA_CTRL_SHORT_RF 6
-+#define PGA_CTRL_VCM_VG 4
-+#define PGA_CTRL_VCM_IN 0
-+
-+/*ANA_ADC2_CTRL1*/
-+#define ADC2_PGA_BYPASS 7
-+#define ADC2_PGA_BYP_RCM 6
-+#define ADC2_PGA_CTRL_RCM 4
-+#define ADC2_PGA_MUTE 3
-+#define ADC2_DSM_ENABLE 2
-+#define ADC2_PGA_ENABLE 1
-+#define ADC2_MICBIAS_EN 0
-+
-+/*ANA_ADC2_CTRL3*/
-+#define ADC2_ANA_CAL_EN 5
-+#define ADC2_SEL_OUT_EDGE 3
-+#define ADC2_DSM_DISABLE 2
-+#define ADC2_VREFP_DISABLE 1
-+#define ADC2_AAF_DISABLE 0
-+
-+/*ANA_ADC2_CTRL6*/
-+#define PGA_CTRL_IBOOST 7
-+#define PGA_CTRL_IQCTRL 6
-+#define PGA_CTRL_OABIAS 4
-+#define PGA_CTRL_CMLP_DIS 3
-+#define PGA_CTRL_PDB_RIN 2
-+#define PGA_CTRL_PEAKDET 0
-+
-+/*ANA_ADC2_CTRL7*/
-+#define AAF_LPMODE_EN 7
-+#define AAF_STG2_IB_SEL 4
-+#define AAFDSM_IB_DIV2 3
-+#define AAF_STG1_IB_SEL 0
-+
-+/*ANA_ADC3_CTRL1*/
-+#define ADC3_PGA_BYPASS 7
-+#define ADC3_PGA_BYP_RCM 6
-+#define ADC3_PGA_CTRL_RCM 4
-+#define ADC3_PGA_MUTE 3
-+#define ADC3_DSM_ENABLE 2
-+#define ADC3_PGA_ENABLE 1
-+#define ADC3_MICBIAS_EN 0
-+
-+/*ANA_ADC3_CTRL3*/
-+#define ADC3_ANA_CAL_EN 5
-+#define ADC3_INVERT_CLK 4
-+#define ADC3_SEL_OUT_EDGE 3
-+#define ADC3_DSM_DISABLE 2
-+#define ADC3_VREFP_DISABLE 1
-+#define ADC3_AAF_DISABLE 0
-+
-+/*ANA_ADC3_CTRL7*/
-+#define DSM_COMP_IB_SEL 6
-+#define DSM_OTA_CTRL 4
-+#define DSM_LPMODE 3
-+#define DSM_OTA_IB_SEL 0
-+
-+/*ANA_ADC4_CTRL1*/
-+#define ADC4_PGA_BYPASS 7
-+#define ADC4_PGA_BYP_RCM 6
-+#define ADC4_PGA_CTRL_RCM 4
-+#define ADC4_PGA_MUTE 3
-+#define ADC4_DSM_ENABLE 2
-+#define ADC4_PGA_ENABLE 1
-+#define ADC4_MICBIAS_EN 0
-+
-+/*ANA_ADC4_CTRL3*/
-+#define ADC4_ANA_CAL_EN 5
-+#define ADC4_SEL_OUT_EDGE 3
-+#define ADC4_DSM_DISABLE 2
-+#define ADC4_VREFP_DISABLE 1
-+#define ADC4_AAF_DISABLE 0
-+
-+/*ANA_ADC4_CTRL6*/
-+#define DSM_DEMOFF 5
-+#define DSM_EN_DITHER 4
-+#define DSM_VREFP_LPMODE 2
-+#define DSM_VREFP_OUTCTRL 0
-+
-+/*ANA_ADC4_CTRL7*/
-+#define CK8M_EN 5
-+#define OSC_EN 4
-+#define ADC4_CLK_GATING 3
-+#define ADC3_CLK_GATING 2
-+#define ADC2_CLK_GATING 1
-+#define ADC1_CLK_GATING 0
-+
-+/*GPIO_CFG1*/
-+#define GPIO2_SELECT 4
-+#define GPIO1_SELECT 0
-+
-+/*GPIO_CFG2*/
-+#define GPIO4_SELECT 4
-+#define GPIO3_SELECT 0
-+
-+/*GPIO_DAT*///order???
-+#define GPIO4_DAT 3
-+#define GPIO3_DAT 2
-+#define GPIO2_DAT 1
-+#define GPIO1_DAT 0
-+
-+/*GPIO_DRV*/
-+#define GPIO4_DRV 6
-+#define GPIO3_DRV 4
-+#define GPIO2_DRV 2
-+#define GPIO1_DRV 0
-+
-+/*GPIO_PULL*/
-+#define GPIO4_PULL 6
-+#define GPIO3_PULL 4
-+#define GPIO2_PULL 2
-+#define GPIO1_PULL 0
-+
-+/*GPIO_INT_CFG*/
-+#define GPIO4_EINT_CFG 6
-+#define GPIO3_EINT_CFG 4
-+#define GPIO2_EINT_CFG 2
-+#define GPIO1_EINT_CFG 0
-+
-+/*GPIO_INT_EN*///order???
-+#define GPIO4_EINT_EN 3
-+#define GPIO3_EINT_EN 2
-+#define GPIO2_EINT_EN 1
-+#define GPIO1_EINT_EN 0
-+
-+/*GPIO_INT_STATUS*///order???
-+#define GPIO4_EINT_STA 3
-+#define GPIO3_EINT_STA 2
-+#define GPIO2_EINT_STA 1
-+#define GPIO1_EINT_STA 0
-+
-+/*PRNG_CLK_CTRL*/
-+#define PRNG_CLK_EN 1
-+#define PRNG_CLK_POS 0
-+
-+/*** Some Config Value ***/
-+
-+//[SYSCLK_CTRL]: PLLCLK_SRC
-+#define PLLCLK_SRC_MCLK 0
-+#define PLLCLK_SRC_BCLK 1
-+#define PLLCLK_SRC_GPIO2 2
-+#define PLLCLK_SRC_GPIO3 3
-+
-+//[SYSCLK_CTRL]: SYSCLK_SRC
-+#define SYSCLK_SRC_MCLK 0
-+#define SYSCLK_SRC_PLL 1
-+
-+//I2S BCLK POLARITY Control
-+#define BCLK_NORMAL_DRIVE_N_SAMPLE_P 0
-+#define BCLK_INVERT_DRIVE_P_SAMPLE_N 1
-+
-+//I2S LRCK POLARITY Control
-+#define LRCK_LEFT_LOW_RIGHT_HIGH 0
-+#define LRCK_LEFT_HIGH_RIGHT_LOW 1
-+
-+//I2S Format Selection
-+#define PCM_FORMAT 0
-+#define LEFT_JUSTIFIED_FORMAT 1
-+#define RIGHT_JUSTIFIED_FORMAT 2
-+
-+//I2S data protocol types
-+
-+#define IS_ENCODING_MODE 0
-+
-+#endif
-+
---- /dev/null
-+++ b/sound/soc/codecs/ac10x.h
-@@ -0,0 +1,152 @@
-+/*
-+ * ac10x.h
-+ *
-+ * (C) Copyright 2017-2018
-+ * Seeed Technology Co., Ltd. <www.seeedstudio.com>
-+ *
-+ * PeterYang <linsheng.yang@seeed.cc>
-+ *
-+ * (C) Copyright 2010-2017
-+ * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
-+ * huangxin <huangxin@reuuimllatech.com>
-+ *
-+ * some simple description for this code
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2 of
-+ * the License, or (at your option) any later version.
-+ *
-+ */
-+#ifndef __AC10X_H__
-+#define __AC10X_H__
-+
-+#define AC101_I2C_ID 4
-+#define _MASTER_AC108 0
-+#define _MASTER_AC101 1
-+#define _MASTER_MULTI_CODEC _MASTER_AC101
-+
-+/* enable headset detecting & headset button pressing */
-+#define CONFIG_AC101_SWITCH_DETECT
-+
-+/* obsolete */
-+#define CONFIG_AC10X_TRIG_LOCK 0
-+
-+#ifdef AC101_DEBG
-+ #define AC101_DBG(format,args...) printk("[AC101] %s() L%d " format, __func__, __LINE__, ##args)
-+#else
-+ #define AC101_DBG(...)
-+#endif
-+
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
-+#define __NO_SND_SOC_CODEC_DRV 1
-+#else
-+#define __NO_SND_SOC_CODEC_DRV 0
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
-+#if __has_attribute(__fallthrough__)
-+# define fallthrough __attribute__((__fallthrough__))
-+#else
-+# define fallthrough do {} while (0) /* fallthrough */
-+#endif
-+#endif
-+
-+#if __NO_SND_SOC_CODEC_DRV
-+#define codec component
-+#define snd_soc_codec snd_soc_component
-+#define snd_soc_codec_driver snd_soc_component_driver
-+#define snd_soc_codec_get_drvdata snd_soc_component_get_drvdata
-+#define snd_soc_codec_get_dapm snd_soc_component_get_dapm
-+#define snd_soc_codec_get_bias_level snd_soc_component_get_bias_level
-+#define snd_soc_kcontrol_codec snd_soc_kcontrol_component
-+#define snd_soc_read snd_soc_component_read32
-+#define snd_soc_register_codec snd_soc_register_component
-+#define snd_soc_unregister_codec snd_soc_unregister_component
-+#define snd_soc_update_bits snd_soc_component_update_bits
-+#define snd_soc_write snd_soc_component_write
-+#define snd_soc_add_codec_controls snd_soc_add_component_controls
-+#endif
-+
-+
-+#ifdef CONFIG_AC101_SWITCH_DETECT
-+enum headphone_mode_u {
-+ HEADPHONE_IDLE,
-+ FOUR_HEADPHONE_PLUGIN,
-+ THREE_HEADPHONE_PLUGIN,
-+};
-+#endif
-+
-+struct ac10x_priv {
-+ struct i2c_client *i2c[4];
-+ struct regmap* i2cmap[4];
-+ int codec_cnt;
-+ unsigned sysclk;
-+#define _FREQ_24_576K 24576000
-+#define _FREQ_22_579K 22579200
-+ unsigned mclk; /* master clock or aif_clock/aclk */
-+ int clk_id;
-+ unsigned char i2s_mode;
-+ unsigned char data_protocol;
-+ struct delayed_work dlywork;
-+ int tdm_chips_cnt;
-+ int sysclk_en;
-+
-+ /* member for ac101 .begin */
-+ struct snd_soc_codec *codec;
-+ struct i2c_client *i2c101;
-+ struct regmap* regmap101;
-+
-+ struct mutex dac_mutex;
-+ u8 dac_enable;
-+ spinlock_t lock;
-+ u8 aif1_clken;
-+
-+ struct work_struct codec_resume;
-+ struct gpio_desc* gpiod_spk_amp_gate;
-+
-+ #ifdef CONFIG_AC101_SWITCH_DETECT
-+ struct gpio_desc* gpiod_irq;
-+ long irq;
-+ volatile int irq_cntr;
-+ volatile int pullout_cntr;
-+ volatile int state;
-+
-+ enum headphone_mode_u mode;
-+ struct work_struct work_switch;
-+ struct work_struct work_clear_irq;
-+
-+ struct input_dev* inpdev;
-+ #endif
-+ /* member for ac101 .end */
-+};
-+
-+
-+/* AC101 DAI operations */
-+int ac101_audio_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai);
-+void ac101_aif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai);
-+int ac101_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt);
-+int ac101_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *codec_dai);
-+int ac101_trigger(struct snd_pcm_substream *substream, int cmd,
-+ struct snd_soc_dai *dai);
-+int ac101_aif_mute(struct snd_soc_dai *codec_dai, int mute);
-+
-+/* codec driver specific */
-+int ac101_codec_probe(struct snd_soc_codec *codec);
-+int ac101_codec_remove(struct snd_soc_codec *codec);
-+int ac101_codec_suspend(struct snd_soc_codec *codec);
-+int ac101_codec_resume(struct snd_soc_codec *codec);
-+int ac101_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level);
-+
-+/* i2c device specific */
-+int ac101_probe(struct i2c_client *i2c, const struct i2c_device_id *id);
-+void ac101_shutdown(struct i2c_client *i2c);
-+int ac101_remove(struct i2c_client *i2c);
-+
-+int ac10x_fill_regcache(struct device* dev, struct regmap* map);
-+
-+#endif//__AC10X_H__
+++ /dev/null
-From f03b7c834baef87e4f740e10a8bbcbfc57bd985a Mon Sep 17 00:00:00 2001
-From: Xingyu Wu <xingyu.wu@starfivetech.com>
-Date: Thu, 15 Jun 2023 11:32:50 +0800
-Subject: [PATCH 080/116] ASoC: starfive: Add SPDIF and PCM driver
-
-Add SPDIF and SPDIF-PCM driver for StarFive JH7110.
-
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- sound/soc/starfive/Kconfig | 17 +
- sound/soc/starfive/Makefile | 5 +
- sound/soc/starfive/jh7110_spdif.c | 568 ++++++++++++++++++++++++++
- sound/soc/starfive/jh7110_spdif.h | 196 +++++++++
- sound/soc/starfive/jh7110_spdif_pcm.c | 339 +++++++++++++++
- 5 files changed, 1125 insertions(+)
- create mode 100644 sound/soc/starfive/jh7110_spdif.c
- create mode 100644 sound/soc/starfive/jh7110_spdif.h
- create mode 100644 sound/soc/starfive/jh7110_spdif_pcm.c
-
---- a/sound/soc/starfive/Kconfig
-+++ b/sound/soc/starfive/Kconfig
-@@ -16,6 +16,23 @@ config SND_SOC_JH7110_PWMDAC
- Say Y or M if you want to add support for StarFive JH7110
- PWM-DAC driver.
-
-+config SND_SOC_JH7110_SPDIF
-+ tristate "JH7110 SPDIF module"
-+ depends on HAVE_CLK && SND_SOC_STARFIVE
-+ select SND_SOC_GENERIC_DMAENGINE_PCM
-+ select REGMAP_MMIO
-+ help
-+ Say Y or M if you want to add support for SPDIF driver of StarFive
-+ JH7110 SoC.
-+
-+config SND_SOC_JH7110_SPDIF_PCM
-+ bool "PCM PIO extension for JH7110 SPDIF"
-+ depends on SND_SOC_JH7110_SPDIF
-+ default y if SND_SOC_JH7110_SPDIF
-+ help
-+ Say Y or N if you want to add a custom ALSA extension that registers
-+ a PCM and uses PIO to transfer data.
-+
- config SND_SOC_JH7110_TDM
- tristate "JH7110 TDM device driver"
- depends on HAVE_CLK && SND_SOC_STARFIVE
---- a/sound/soc/starfive/Makefile
-+++ b/sound/soc/starfive/Makefile
-@@ -1,3 +1,8 @@
- # StarFive Platform Support
- obj-$(CONFIG_SND_SOC_JH7110_PWMDAC) += jh7110_pwmdac.o
-+
-+obj-$(CONFIG_SND_SOC_JH7110_SPDIF) += spdif.o
-+spdif-y := jh7110_spdif.o
-+spdif-$(CONFIG_SND_SOC_JH7110_SPDIF_PCM) += jh7110_spdif_pcm.o
-+
- obj-$(CONFIG_SND_SOC_JH7110_TDM) += jh7110_tdm.o
---- /dev/null
-+++ b/sound/soc/starfive/jh7110_spdif.c
-@@ -0,0 +1,568 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * SPDIF driver for the StarFive JH7110 SoC
-+ *
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+#include <linux/slab.h>
-+#include <sound/core.h>
-+#include <sound/dmaengine_pcm.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+
-+#include "jh7110_spdif.h"
-+
-+static irqreturn_t spdif_irq_handler(int irq, void *dev_id)
-+{
-+ struct sf_spdif_dev *dev = dev_id;
-+ bool irq_valid = false;
-+ unsigned int intr;
-+ unsigned int stat;
-+
-+ regmap_read(dev->regmap, SPDIF_INT_REG, &intr);
-+ regmap_read(dev->regmap, SPDIF_STAT_REG, &stat);
-+ regmap_update_bits(dev->regmap, SPDIF_CTRL, SPDIF_MASK_ENABLE, 0);
-+ regmap_update_bits(dev->regmap, SPDIF_INT_REG, SPDIF_INT_REG_BIT, 0);
-+
-+ if ((stat & SPDIF_EMPTY_FLAG) || (stat & SPDIF_AEMPTY_FLAG)) {
-+ sf_spdif_pcm_push_tx(dev);
-+ irq_valid = true;
-+ }
-+
-+ if ((stat & SPDIF_FULL_FLAG) || (stat & SPDIF_AFULL_FLAG)) {
-+ sf_spdif_pcm_pop_rx(dev);
-+ irq_valid = true;
-+ }
-+
-+ if (stat & SPDIF_PARITY_FLAG)
-+ irq_valid = true;
-+
-+ if (stat & SPDIF_UNDERR_FLAG)
-+ irq_valid = true;
-+
-+ if (stat & SPDIF_OVRERR_FLAG)
-+ irq_valid = true;
-+
-+ if (stat & SPDIF_SYNCERR_FLAG)
-+ irq_valid = true;
-+
-+ if (stat & SPDIF_LOCK_FLAG)
-+ irq_valid = true;
-+
-+ if (stat & SPDIF_BEGIN_FLAG)
-+ irq_valid = true;
-+
-+ if (stat & SPDIF_RIGHT_LEFT)
-+ irq_valid = true;
-+
-+ regmap_update_bits(dev->regmap, SPDIF_CTRL,
-+ SPDIF_MASK_ENABLE, SPDIF_MASK_ENABLE);
-+
-+ if (irq_valid)
-+ return IRQ_HANDLED;
-+ else
-+ return IRQ_NONE;
-+}
-+
-+static int sf_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
-+ struct snd_soc_dai *dai)
-+{
-+ struct sf_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
-+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-+
-+ if (tx) {
-+ /* tx mode */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_TR_MODE, SPDIF_TR_MODE);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_MASK_FIFO, SPDIF_EMPTY_MASK | SPDIF_AEMPTY_MASK);
-+ } else {
-+ /* rx mode */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_TR_MODE, 0);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_MASK_FIFO, SPDIF_FULL_MASK | SPDIF_AFULL_MASK);
-+ }
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ case SNDRV_PCM_TRIGGER_RESUME:
-+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+ /* clock recovery form the SPDIF data stream 0:clk_enable */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_CLK_ENABLE, 0);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_ENABLE, SPDIF_ENABLE);
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ case SNDRV_PCM_TRIGGER_SUSPEND:
-+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+ /* clock recovery form the SPDIF data stream 1:power save mode */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_CLK_ENABLE, SPDIF_CLK_ENABLE);
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_ENABLE, 0);
-+ break;
-+ default:
-+ dev_err(dai->dev, "%s L.%d cmd:%d\n", __func__, __LINE__, cmd);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-+{
-+ struct sf_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
-+ unsigned int channels = params_channels(params);
-+ unsigned int rate = params_rate(params);
-+ unsigned int format = params_format(params);
-+ unsigned int tsamplerate;
-+ unsigned int mclk;
-+ unsigned int audio_root;
-+ int ret;
-+
-+ switch (channels) {
-+ case 1:
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_CHANNEL_MODE, SPDIF_CHANNEL_MODE);
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_DUPLICATE, SPDIF_DUPLICATE);
-+ spdif->channels = false;
-+ break;
-+ case 2:
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_CHANNEL_MODE, 0);
-+ spdif->channels = true;
-+ break;
-+ default:
-+ dev_err(dai->dev, "invalid channels number\n");
-+ return -EINVAL;
-+ }
-+
-+ switch (format) {
-+ case SNDRV_PCM_FORMAT_S16_LE:
-+ case SNDRV_PCM_FORMAT_S24_LE:
-+ case SNDRV_PCM_FORMAT_S24_3LE:
-+ case SNDRV_PCM_FORMAT_S32_LE:
-+ break;
-+ default:
-+ dev_err(dai->dev, "invalid format\n");
-+ return -EINVAL;
-+ }
-+
-+ switch (rate) {
-+ case 8000:
-+ break;
-+ case 11025:
-+ audio_root = 148500000;
-+ /* 11025 * 512 = 5644800 */
-+ /* But now pll2 is 1188m and mclk should be 5711539 closely. */
-+ mclk = 5711539;
-+ break;
-+ case 16000:
-+ break;
-+ case 22050:
-+ audio_root = 148500000;
-+ mclk = 11423077;
-+ break;
-+ default:
-+ dev_err(dai->dev, "channel:%d sample rate:%d\n", channels, rate);
-+ return -EINVAL;
-+ }
-+
-+ /* use mclk_inner clock from 1188m PLL2 will be better about 11k and 22k*/
-+ if ((rate == 11025) || (rate == 22050)) {
-+ ret = clk_set_parent(spdif->mclk, spdif->mclk_inner);
-+ if (ret) {
-+ dev_err(dai->dev,
-+ "failed to set parent to mclk_inner ret=%d\n", ret);
-+ goto fail_ext;
-+ }
-+
-+ ret = clk_set_rate(spdif->audio_root, audio_root);
-+ if (ret) {
-+ dev_err(dai->dev, "failed to set audio_root rate :%d\n", ret);
-+ goto fail_ext;
-+ }
-+
-+ ret = clk_set_rate(spdif->mclk_inner, mclk);
-+ if (ret) {
-+ dev_err(dai->dev, "failed to set mclk_inner rate :%d\n", ret);
-+ goto fail_ext;
-+ }
-+
-+ mclk = clk_get_rate(spdif->mclk_inner);
-+ } else {
-+ ret = clk_set_parent(spdif->mclk, spdif->mclk_ext);
-+ if (ret) {
-+ dev_err(dai->dev,
-+ "failed to set parent to mclk_ext ret=%d\n", ret);
-+ goto fail_ext;
-+ }
-+
-+ mclk = clk_get_rate(spdif->mclk_ext);
-+ }
-+
-+ /* (FCLK)4096000/128=32000 */
-+ tsamplerate = (mclk / 128 + rate / 2) / rate - 1;
-+ if (tsamplerate < 3)
-+ tsamplerate = 3;
-+
-+ /* transmission sample rate */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL, 0xFF, tsamplerate);
-+
-+ return 0;
-+
-+fail_ext:
-+ return ret;
-+}
-+
-+static int sf_spdif_clks_get(struct platform_device *pdev,
-+ struct sf_spdif_dev *spdif)
-+{
-+ static struct clk_bulk_data clks[] = {
-+ { .id = "apb" }, /* clock-names in dts file */
-+ { .id = "core" },
-+ { .id = "audroot" },
-+ { .id = "mclk_inner"},
-+ { .id = "mclk_ext"},
-+ { .id = "mclk"},
-+ };
-+ int ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks);
-+
-+ spdif->spdif_apb = clks[0].clk;
-+ spdif->spdif_core = clks[1].clk;
-+ spdif->audio_root = clks[2].clk;
-+ spdif->mclk_inner = clks[3].clk;
-+ spdif->mclk_ext = clks[4].clk;
-+ spdif->mclk = clks[5].clk;
-+
-+ return ret;
-+}
-+
-+static int sf_spdif_resets_get(struct platform_device *pdev,
-+ struct sf_spdif_dev *spdif)
-+{
-+ struct reset_control_bulk_data resets[] = {
-+ { .id = "apb" },
-+ };
-+ int ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(resets), resets);
-+
-+ if (ret)
-+ return ret;
-+
-+ spdif->rst_apb = resets[0].rstc;
-+
-+ return 0;
-+}
-+
-+static int starfive_spdif_crg_enable(struct sf_spdif_dev *spdif, bool enable)
-+{
-+ int ret;
-+
-+ dev_dbg(spdif->dev, "starfive_spdif clk&rst %sable.\n", enable ? "en":"dis");
-+ if (enable) {
-+ ret = clk_prepare_enable(spdif->spdif_apb);
-+ if (ret) {
-+ dev_err(spdif->dev, "failed to prepare enable spdif_apb\n");
-+ goto failed_apb_clk;
-+ }
-+
-+ ret = clk_prepare_enable(spdif->spdif_core);
-+ if (ret) {
-+ dev_err(spdif->dev, "failed to prepare enable spdif_core\n");
-+ goto failed_core_clk;
-+ }
-+
-+ ret = reset_control_deassert(spdif->rst_apb);
-+ if (ret) {
-+ dev_err(spdif->dev, "failed to deassert apb\n");
-+ goto failed_rst;
-+ }
-+ } else {
-+ clk_disable_unprepare(spdif->spdif_core);
-+ clk_disable_unprepare(spdif->spdif_apb);
-+ }
-+
-+ return 0;
-+
-+failed_rst:
-+ clk_disable_unprepare(spdif->spdif_core);
-+failed_core_clk:
-+ clk_disable_unprepare(spdif->spdif_apb);
-+failed_apb_clk:
-+ return ret;
-+}
-+
-+static int sf_spdif_dai_probe(struct snd_soc_dai *dai)
-+{
-+ struct sf_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai);
-+
-+ pm_runtime_get_sync(spdif->dev);
-+
-+ /* reset */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_ENABLE | SPDIF_SFR_ENABLE | SPDIF_FIFO_ENABLE, 0);
-+
-+ /* clear irq */
-+ regmap_update_bits(spdif->regmap, SPDIF_INT_REG,
-+ SPDIF_INT_REG_BIT, 0);
-+
-+ /* power save mode */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_CLK_ENABLE, SPDIF_CLK_ENABLE);
-+
-+ /* power save mode */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_CLK_ENABLE, SPDIF_CLK_ENABLE);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_PARITCHECK|SPDIF_VALIDITYCHECK|SPDIF_DUPLICATE,
-+ SPDIF_PARITCHECK|SPDIF_VALIDITYCHECK|SPDIF_DUPLICATE);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_SETPREAMBB, SPDIF_SETPREAMBB);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_INT_REG,
-+ BIT8TO20MASK<<SPDIF_PREAMBLEDEL, 0x3<<SPDIF_PREAMBLEDEL);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_FIFO_CTRL,
-+ ALLBITMASK, 0x20|(0x20<<SPDIF_AFULL_THRESHOLD));
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_PARITYGEN, SPDIF_PARITYGEN);
-+
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_MASK_ENABLE, SPDIF_MASK_ENABLE);
-+
-+ /* APB access to FIFO enable, disable if use DMA/FIFO */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_USE_FIFO_IF, 0);
-+
-+ /* two channel */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ SPDIF_CHANNEL_MODE, 0);
-+
-+ pm_runtime_put_sync(spdif->dev);
-+ return 0;
-+}
-+
-+static const struct snd_soc_dai_ops sf_spdif_dai_ops = {
-+ .probe = sf_spdif_dai_probe,
-+ .trigger = sf_spdif_trigger,
-+ .hw_params = sf_spdif_hw_params,
-+};
-+
-+#ifdef CONFIG_PM_SLEEP
-+static int spdif_system_suspend(struct device *dev)
-+{
-+ struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
-+
-+ /* save the register value */
-+ regmap_read(spdif->regmap, SPDIF_CTRL, &spdif->reg_spdif_ctrl);
-+ regmap_read(spdif->regmap, SPDIF_INT_REG, &spdif->reg_spdif_int);
-+ regmap_read(spdif->regmap, SPDIF_FIFO_CTRL, &spdif->reg_spdif_fifo_ctrl);
-+
-+ return pm_runtime_force_suspend(dev);
-+}
-+
-+static int spdif_system_resume(struct device *dev)
-+{
-+ struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
-+ int ret = pm_runtime_force_resume(dev);
-+
-+ if (ret)
-+ return ret;
-+
-+ /* restore the register value */
-+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
-+ ALLBITMASK, spdif->reg_spdif_ctrl);
-+ regmap_update_bits(spdif->regmap, SPDIF_INT_REG,
-+ ALLBITMASK, spdif->reg_spdif_int);
-+ regmap_update_bits(spdif->regmap, SPDIF_FIFO_CTRL,
-+ ALLBITMASK, spdif->reg_spdif_fifo_ctrl);
-+
-+ return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_PM
-+static int spdif_runtime_suspend(struct device *dev)
-+{
-+ struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
-+
-+ return starfive_spdif_crg_enable(spdif, false);
-+}
-+
-+static int spdif_runtime_resume(struct device *dev)
-+{
-+ struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
-+
-+ return starfive_spdif_crg_enable(spdif, true);
-+}
-+#endif
-+
-+static const struct dev_pm_ops spdif_pm_ops = {
-+ SET_RUNTIME_PM_OPS(spdif_runtime_suspend, spdif_runtime_resume, NULL)
-+ SET_SYSTEM_SLEEP_PM_OPS(spdif_system_suspend, spdif_system_resume)
-+};
-+
-+#define SF_PCM_RATE_44100_192000 (SNDRV_PCM_RATE_44100 | \
-+ SNDRV_PCM_RATE_48000 | \
-+ SNDRV_PCM_RATE_96000 | \
-+ SNDRV_PCM_RATE_192000)
-+
-+#define SF_PCM_RATE_8000_22050 (SNDRV_PCM_RATE_8000 | \
-+ SNDRV_PCM_RATE_11025 | \
-+ SNDRV_PCM_RATE_16000 | \
-+ SNDRV_PCM_RATE_22050)
-+
-+static struct snd_soc_dai_driver sf_spdif_dai = {
-+ .name = "spdif",
-+ .id = 0,
-+ .playback = {
-+ .stream_name = "Playback",
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .rates = SF_PCM_RATE_8000_22050,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE |
-+ SNDRV_PCM_FMTBIT_S24_3LE |
-+ SNDRV_PCM_FMTBIT_S32_LE,
-+ },
-+ .ops = &sf_spdif_dai_ops,
-+ .symmetric_rate = 1,
-+};
-+
-+static const struct snd_soc_component_driver sf_spdif_component = {
-+ .name = "starfive-spdif",
-+};
-+
-+static const struct regmap_config sf_spdif_regmap_config = {
-+ .reg_bits = 32,
-+ .reg_stride = 4,
-+ .val_bits = 32,
-+ .max_register = 0x200,
-+};
-+
-+static int sf_spdif_probe(struct platform_device *pdev)
-+{
-+ struct sf_spdif_dev *spdif;
-+ struct resource *res;
-+ void __iomem *base;
-+ int ret;
-+ int irq;
-+
-+ spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
-+ if (!spdif)
-+ return -ENOMEM;
-+
-+ platform_set_drvdata(pdev, spdif);
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ spdif->spdif_base = base;
-+ spdif->regmap = devm_regmap_init_mmio(&pdev->dev, spdif->spdif_base,
-+ &sf_spdif_regmap_config);
-+ if (IS_ERR(spdif->regmap))
-+ return PTR_ERR(spdif->regmap);
-+
-+ spdif->dev = &pdev->dev;
-+
-+ ret = sf_spdif_clks_get(pdev, spdif);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to get audio clock\n");
-+ return ret;
-+ }
-+
-+ ret = sf_spdif_resets_get(pdev, spdif);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to get audio reset controls\n");
-+ return ret;
-+ }
-+
-+ ret = starfive_spdif_crg_enable(spdif, true);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to enable audio clock\n");
-+ return ret;
-+ }
-+
-+ spdif->fifo_th = 16;
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq >= 0) {
-+ ret = devm_request_irq(&pdev->dev, irq, spdif_irq_handler, 0,
-+ pdev->name, spdif);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "failed to request irq\n");
-+ return ret;
-+ }
-+ }
-+
-+ ret = devm_snd_soc_register_component(&pdev->dev, &sf_spdif_component,
-+ &sf_spdif_dai, 1);
-+ if (ret)
-+ goto err_clk_disable;
-+
-+ if (irq >= 0) {
-+ ret = sf_spdif_pcm_register(pdev);
-+ spdif->use_pio = true;
-+ } else {
-+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
-+ 0);
-+ spdif->use_pio = false;
-+ }
-+
-+ if (ret)
-+ goto err_clk_disable;
-+
-+ starfive_spdif_crg_enable(spdif, false);
-+ pm_runtime_enable(&pdev->dev);
-+ dev_dbg(&pdev->dev, "spdif register done.\n");
-+
-+ return 0;
-+
-+err_clk_disable:
-+ return ret;
-+}
-+
-+static const struct of_device_id sf_spdif_of_match[] = {
-+ { .compatible = "starfive,jh7110-spdif", },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, sf_spdif_of_match);
-+
-+static struct platform_driver sf_spdif_driver = {
-+ .driver = {
-+ .name = "starfive-spdif",
-+ .of_match_table = sf_spdif_of_match,
-+ .pm = &spdif_pm_ops,
-+ },
-+ .probe = sf_spdif_probe,
-+};
-+module_platform_driver(sf_spdif_driver);
-+
-+MODULE_AUTHOR("curry.zhang <curry.zhang@starfive.com>");
-+MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
-+MODULE_DESCRIPTION("starfive SPDIF driver");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/sound/soc/starfive/jh7110_spdif.h
-@@ -0,0 +1,196 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * SPDIF driver for the StarFive JH7110 SoC
-+ *
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+#ifndef __SND_SOC_JH7110_SPDIF_H
-+#define __SND_SOC_JH7110_SPDIF_H
-+
-+#include <linux/clk.h>
-+#include <linux/device.h>
-+#include <linux/dmaengine.h>
-+#include <linux/types.h>
-+#include <sound/dmaengine_pcm.h>
-+#include <sound/pcm.h>
-+
-+#define SPDIF_CTRL 0x0
-+#define SPDIF_INT_REG 0x4
-+#define SPDIF_FIFO_CTRL 0x8
-+#define SPDIF_STAT_REG 0xC
-+
-+#define SPDIF_FIFO_ADDR 0x100
-+#define DMAC_SPDIF_POLLING_LEN 256
-+
-+/* ctrl: sampled on the rising clock edge */
-+#define SPDIF_TSAMPLERATE 0 /* [SRATEW-1:0] */
-+/* 0:SFR reg reset to defualt value; auto set back to '1' after reset */
-+#define SPDIF_SFR_ENABLE (1<<8)
-+/* 0:reset of SPDIF block, SRF bits are unchanged; 1:enables SPDIF module */
-+#define SPDIF_ENABLE (1<<9)
-+/* 0:FIFO pointers are reset to zero,threshold levels for FIFO are unchaned; auto set back to 1 */
-+#define SPDIF_FIFO_ENABLE (1<<10)
-+/* 1:blocked and the modules are in power save mode; 0:block feeds the modules */
-+#define SPDIF_CLK_ENABLE (1<<11)
-+#define SPDIF_TR_MODE (1<<12) /* 0:rx; 1:tx */
-+/* 0:party bit rx in a sub-frame is repeated on the parity; 1:check on a parity error */
-+#define SPDIF_PARITCHECK (1<<13)
-+/*
-+ * 0:parity bit from FIFO is transmitted in sub-frame;
-+ * 1:parity bit generated inside the core and added to a transmitted sub-frame
-+ */
-+#define SPDIF_PARITYGEN (1<<14)
-+/* 0:validity bit in frame isn't checked and all frame are written; 1:validity bit rx is checked */
-+#define SPDIF_VALIDITYCHECK (1<<15)
-+#define SPDIF_CHANNEL_MODE (1<<16) /* 0:two-channel; 1:single-channel */
-+/* only tx -single-channel mode; 0:secondary channel; 1: left(primary) channel */
-+#define SPDIF_DUPLICATE (1<<17)
-+/*
-+ * only tx;
-+ * 0:first preamble B after reset tx valid sub-frame;
-+ * 1:first preamble B is tx after preambleddel(INT_REG)
-+ */
-+#define SPDIF_SETPREAMBB (1<<18)
-+/* 0:FIFO disabled ,APB accese FIFO; 1:FIFO enable, APB access to FIFO disable; */
-+#define SPDIF_USE_FIFO_IF (1<<19)
-+#define SPDIF_PARITY_MASK (1<<21)
-+#define SPDIF_UNDERR_MASK (1<<22)
-+#define SPDIF_OVRERR_MASK (1<<23)
-+#define SPDIF_EMPTY_MASK (1<<24)
-+#define SPDIF_AEMPTY_MASK (1<<25)
-+#define SPDIF_FULL_MASK (1<<26)
-+#define SPDIF_AFULL_MASK (1<<27)
-+#define SPDIF_SYNCERR_MASK (1<<28)
-+#define SPDIF_LOCK_MASK (1<<29)
-+#define SPDIF_BEGIN_MASK (1<<30)
-+#define SPDIF_INTEREQ_MAKS (1<<31)
-+
-+#define SPDIF_MASK_ENABLE (SPDIF_PARITY_MASK | SPDIF_UNDERR_MASK | \
-+ SPDIF_OVRERR_MASK | SPDIF_EMPTY_MASK | \
-+ SPDIF_AEMPTY_MASK | SPDIF_FULL_MASK | \
-+ SPDIF_AFULL_MASK | SPDIF_SYNCERR_MASK | \
-+ SPDIF_LOCK_MASK | SPDIF_BEGIN_MASK | \
-+ SPDIF_INTEREQ_MAKS)
-+
-+#define SPDIF_MASK_FIFO (SPDIF_EMPTY_MASK | SPDIF_AEMPTY_MASK | \
-+ SPDIF_FULL_MASK | SPDIF_AFULL_MASK)
-+
-+/* INT_REG */
-+#define SPDIF_RSAMPLERATE 0 /* [SRATEW-1:0] */
-+#define SPDIF_PREAMBLEDEL 8 /* [PDELAYW+7:8] first B delay */
-+#define SPDIF_PARITYO (1<<21) /* 0:clear parity error */
-+#define SPDIF_TDATA_UNDERR (1<<22) /* tx data underrun error;0:clear */
-+#define SPDIF_RDATA_OVRERR (1<<23) /* rx data overrun error; 0:clear */
-+#define SPDIF_FIFO_EMPTY (1<<24) /* empty; 0:clear */
-+#define SPDIF_FIOF_AEMPTY (1<<25) /* almost empty; 0:clear */
-+#define SPDIF_FIFO_FULL (1<<26) /* FIFO full; 0:clear */
-+#define SPDIF_FIFO_AFULL (1<<27) /* FIFO almost full; 0:clear */
-+#define SPDIF_SYNCERR (1<<28) /* sync error; 0:clear */
-+#define SPDIF_LOCK (1<<29) /* sync; 0:clear */
-+#define SPDIF_BLOCK_BEGIN (1<<30) /* new start block rx data */
-+
-+#define SPDIF_INT_REG_BIT (SPDIF_PARITYO | SPDIF_TDATA_UNDERR | \
-+ SPDIF_RDATA_OVRERR | SPDIF_FIFO_EMPTY | \
-+ SPDIF_FIOF_AEMPTY | SPDIF_FIFO_FULL | \
-+ SPDIF_FIFO_AFULL | SPDIF_SYNCERR | \
-+ SPDIF_LOCK | SPDIF_BLOCK_BEGIN)
-+
-+#define SPDIF_ERROR_INT_STATUS (SPDIF_PARITYO | \
-+ SPDIF_TDATA_UNDERR | SPDIF_RDATA_OVRERR)
-+#define SPDIF_FIFO_INT_STATUS (SPDIF_FIFO_EMPTY | SPDIF_FIOF_AEMPTY | \
-+ SPDIF_FIFO_FULL | SPDIF_FIFO_AFULL)
-+
-+#define SPDIF_INT_PARITY_ERROR (-1)
-+#define SPDIF_INT_TDATA_UNDERR (-2)
-+#define SPDIF_INT_RDATA_OVRERR (-3)
-+#define SPDIF_INT_FIFO_EMPTY 1
-+#define SPDIF_INT_FIFO_AEMPTY 2
-+#define SPDIF_INT_FIFO_FULL 3
-+#define SPDIF_INT_FIFO_AFULL 4
-+#define SPDIF_INT_SYNCERR (-4)
-+#define SPDIF_INT_LOCK 5 /* reciever has become synchronized with input data stream */
-+#define SPDIF_INT_BLOCK_BEGIN 6 /* start a new block in recieve data, written into FIFO */
-+
-+/* FIFO_CTRL */
-+#define SPDIF_AEMPTY_THRESHOLD 0 /* [depth-1:0] */
-+#define SPDIF_AFULL_THRESHOLD 16 /* [depth+15:16] */
-+
-+/* STAT_REG */
-+#define SPDIF_FIFO_LEVEL (1<<0)
-+#define SPDIF_PARITY_FLAG (1<<21) /* 1:error; 0:repeated */
-+#define SPDIF_UNDERR_FLAG (1<<22) /* 1:error */
-+#define SPDIF_OVRERR_FLAG (1<<23) /* 1:error */
-+#define SPDIF_EMPTY_FLAG (1<<24) /* 1:fifo empty */
-+#define SPDIF_AEMPTY_FLAG (1<<25) /* 1:fifo almost empty */
-+#define SPDIF_FULL_FLAG (1<<26) /* 1:fifo full */
-+#define SPDIF_AFULL_FLAG (1<<27) /* 1:fifo almost full */
-+#define SPDIF_SYNCERR_FLAG (1<<28) /* 1:rx sync error */
-+#define SPDIF_LOCK_FLAG (1<<29) /* 1:RX sync */
-+#define SPDIF_BEGIN_FLAG (1<<30) /* 1:start a new block */
-+/* 1:left channel received and tx into FIFO; 0:right channel received and tx into FIFO */
-+#define SPDIF_RIGHT_LEFT (1<<31)
-+
-+#define BIT8TO20MASK 0x1FFF
-+#define ALLBITMASK 0xFFFFFFFF
-+
-+#define SPDIF_STAT (SPDIF_PARITY_FLAG | SPDIF_UNDERR_FLAG | \
-+ SPDIF_OVRERR_FLAG | SPDIF_EMPTY_FLAG | \
-+ SPDIF_AEMPTY_FLAG | SPDIF_FULL_FLAG | \
-+ SPDIF_AFULL_FLAG | SPDIF_SYNCERR_FLAG | \
-+ SPDIF_LOCK_FLAG | SPDIF_BEGIN_FLAG | \
-+ SPDIF_RIGHT_LEFT)
-+struct sf_spdif_dev {
-+ void __iomem *spdif_base;
-+ struct regmap *regmap;
-+ struct device *dev;
-+ u32 fifo_th;
-+ int active;
-+
-+ /* data related to DMA transfers b/w i2s and DMAC */
-+ struct snd_dmaengine_dai_dma_data play_dma_data;
-+ struct snd_dmaengine_dai_dma_data capture_dma_data;
-+
-+ bool use_pio;
-+ struct snd_pcm_substream __rcu *tx_substream;
-+ struct snd_pcm_substream __rcu *rx_substream;
-+
-+ unsigned int (*tx_fn)(struct sf_spdif_dev *dev,
-+ struct snd_pcm_runtime *runtime, unsigned int tx_ptr,
-+ bool *period_elapsed, snd_pcm_format_t format);
-+ unsigned int (*rx_fn)(struct sf_spdif_dev *dev,
-+ struct snd_pcm_runtime *runtime, unsigned int rx_ptr,
-+ bool *period_elapsed, snd_pcm_format_t format);
-+
-+ snd_pcm_format_t format;
-+ bool channels;
-+ unsigned int tx_ptr;
-+ unsigned int rx_ptr;
-+ struct clk *spdif_apb;
-+ struct clk *spdif_core;
-+ struct clk *audio_root;
-+ struct clk *mclk_inner;
-+ struct clk *mclk;
-+ struct clk *mclk_ext;
-+ struct reset_control *rst_apb;
-+ unsigned int reg_spdif_ctrl;
-+ unsigned int reg_spdif_int;
-+ unsigned int reg_spdif_fifo_ctrl;
-+
-+ struct snd_dmaengine_dai_dma_data dma_data;
-+};
-+
-+#if IS_ENABLED(CONFIG_SND_SOC_JH7110_SPDIF_PCM)
-+void sf_spdif_pcm_push_tx(struct sf_spdif_dev *dev);
-+void sf_spdif_pcm_pop_rx(struct sf_spdif_dev *dev);
-+int sf_spdif_pcm_register(struct platform_device *pdev);
-+#else
-+void sf_spdif_pcm_push_tx(struct sf_spdif_dev *dev) { }
-+void sf_spdif_pcm_pop_rx(struct sf_spdif_dev *dev) { }
-+int sf_spdif_pcm_register(struct platform_device *pdev)
-+{
-+ return -EINVAL;
-+}
-+#endif
-+
-+#endif /* __SND_SOC_JH7110_SPDIF_H */
---- /dev/null
-+++ b/sound/soc/starfive/jh7110_spdif_pcm.c
-@@ -0,0 +1,339 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * SPDIF PCM driver for the StarFive JH7110 SoC
-+ *
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+
-+#include <linux/io.h>
-+#include <linux/rcupdate.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+
-+#include "jh7110_spdif.h"
-+
-+#define BUFFER_BYTES_MAX (3 * 2 * 8 * PERIOD_BYTES_MIN)
-+#define PERIOD_BYTES_MIN 4096
-+#define PERIODS_MIN 2
-+
-+static unsigned int sf_spdif_pcm_tx(struct sf_spdif_dev *dev,
-+ struct snd_pcm_runtime *runtime, unsigned int tx_ptr,
-+ bool *period_elapsed, snd_pcm_format_t format)
-+{
-+ unsigned int period_pos = tx_ptr % runtime->period_size;
-+ u32 data[2];
-+ int i;
-+
-+ /* two- channel and signal-channel mode */
-+ if (dev->channels) {
-+ const u16 (*p16)[2] = (void *)runtime->dma_area;
-+ const u32 (*p32)[2] = (void *)runtime->dma_area;
-+
-+ for (i = 0; i < dev->fifo_th; i++) {
-+ if (format == SNDRV_PCM_FORMAT_S16_LE) {
-+ data[0] = p16[tx_ptr][0];
-+ data[0] = data[0]<<8;
-+ data[0] &= 0x00ffff00;
-+ data[1] = p16[tx_ptr][1];
-+ data[1] = data[1]<<8;
-+ data[1] &= 0x00ffff00;
-+ } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
-+ data[0] = p32[tx_ptr][0];
-+ data[1] = p32[tx_ptr][1];
-+
-+ /*
-+ * To adapt S24_3LE and ALSA pass parameter of S24_LE.
-+ * operation of S24_LE should be same to S24_3LE.
-+ * So it would wrong when playback S24_LE file.
-+ * when want to playback S24_LE file, should add in there:
-+ * data[0] = data[0]>>8;
-+ * data[1] = data[1]>>8;
-+ */
-+
-+ data[0] &= 0x00ffffff;
-+ data[1] &= 0x00ffffff;
-+ } else if (format == SNDRV_PCM_FORMAT_S24_3LE) {
-+ data[0] = p32[tx_ptr][0];
-+ data[1] = p32[tx_ptr][1];
-+ data[0] &= 0x00ffffff;
-+ data[1] &= 0x00ffffff;
-+ } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
-+ data[0] = p32[tx_ptr][0];
-+ data[0] = data[0]>>8;
-+ data[1] = p32[tx_ptr][1];
-+ data[1] = data[1]>>8;
-+ }
-+
-+ iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
-+ iowrite32(data[1], dev->spdif_base + SPDIF_FIFO_ADDR);
-+ period_pos++;
-+ if (++tx_ptr >= runtime->buffer_size)
-+ tx_ptr = 0;
-+ }
-+ } else {
-+ const u16 (*p16) = (void *)runtime->dma_area;
-+ const u32 (*p32) = (void *)runtime->dma_area;
-+
-+ for (i = 0; i < dev->fifo_th; i++) {
-+ if (format == SNDRV_PCM_FORMAT_S16_LE) {
-+ data[0] = p16[tx_ptr];
-+ data[0] = data[0]<<8;
-+ data[0] &= 0x00ffff00;
-+ } else if (format == SNDRV_PCM_FORMAT_S24_LE ||
-+ format == SNDRV_PCM_FORMAT_S24_3LE) {
-+ data[0] = p32[tx_ptr];
-+ data[0] &= 0x00ffffff;
-+ } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
-+ data[0] = p32[tx_ptr];
-+ data[0] = data[0]>>8;
-+ }
-+
-+ iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
-+ period_pos++;
-+ if (++tx_ptr >= runtime->buffer_size)
-+ tx_ptr = 0;
-+ }
-+ }
-+
-+ *period_elapsed = period_pos >= runtime->period_size;
-+ return tx_ptr;
-+}
-+
-+static unsigned int sf_spdif_pcm_rx(struct sf_spdif_dev *dev,
-+ struct snd_pcm_runtime *runtime, unsigned int rx_ptr,
-+ bool *period_elapsed, snd_pcm_format_t format)
-+{
-+ u16 (*p16)[2] = (void *)runtime->dma_area;
-+ u32 (*p32)[2] = (void *)runtime->dma_area;
-+ unsigned int period_pos = rx_ptr % runtime->period_size;
-+ u32 data[2];
-+ int i;
-+
-+ for (i = 0; i < dev->fifo_th; i++) {
-+ data[0] = ioread32(dev->spdif_base + SPDIF_FIFO_ADDR);
-+ data[1] = ioread32(dev->spdif_base + SPDIF_FIFO_ADDR);
-+ if (format == SNDRV_PCM_FORMAT_S16_LE) {
-+ p16[rx_ptr][0] = data[0]>>8;
-+ p16[rx_ptr][1] = data[1]>>8;
-+ } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
-+ p32[rx_ptr][0] = data[0];
-+ p32[rx_ptr][1] = data[1];
-+ } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
-+ p32[rx_ptr][0] = data[0]<<8;
-+ p32[rx_ptr][1] = data[1]<<8;
-+ }
-+
-+ period_pos++;
-+ if (++rx_ptr >= runtime->buffer_size)
-+ rx_ptr = 0;
-+ }
-+
-+ *period_elapsed = period_pos >= runtime->period_size;
-+ return rx_ptr;
-+}
-+
-+static const struct snd_pcm_hardware sf_pcm_hardware = {
-+ .info = SNDRV_PCM_INFO_INTERLEAVED |
-+ SNDRV_PCM_INFO_MMAP |
-+ SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_PAUSE |
-+ SNDRV_PCM_INFO_RESUME,
-+ .rates = SNDRV_PCM_RATE_8000 |
-+ SNDRV_PCM_RATE_11025 |
-+ SNDRV_PCM_RATE_16000 |
-+ SNDRV_PCM_RATE_22050 |
-+ SNDRV_PCM_RATE_32000 |
-+ SNDRV_PCM_RATE_44100 |
-+ SNDRV_PCM_RATE_48000,
-+ .rate_min = 8000,
-+ .rate_max = 48000,
-+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
-+ SNDRV_PCM_FMTBIT_S24_LE |
-+ SNDRV_PCM_FMTBIT_S24_3LE |
-+ SNDRV_PCM_FMTBIT_S32_LE,
-+ .channels_min = 1,
-+ .channels_max = 2,
-+ .buffer_bytes_max = BUFFER_BYTES_MAX,
-+ .period_bytes_min = PERIOD_BYTES_MIN,
-+ .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
-+ .periods_min = PERIODS_MIN,
-+ .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
-+ .fifo_size = 16,
-+};
-+
-+static void sf_spdif_pcm_transfer(struct sf_spdif_dev *dev, bool push)
-+{
-+ struct snd_pcm_substream *substream;
-+ bool active, period_elapsed;
-+
-+ rcu_read_lock();
-+ if (push)
-+ substream = rcu_dereference(dev->tx_substream);
-+ else
-+ substream = rcu_dereference(dev->rx_substream);
-+
-+ active = substream && snd_pcm_running(substream);
-+ if (active) {
-+ unsigned int ptr;
-+ unsigned int new_ptr;
-+
-+ if (push) {
-+ ptr = READ_ONCE(dev->tx_ptr);
-+ new_ptr = dev->tx_fn(dev, substream->runtime, ptr,
-+ &period_elapsed, dev->format);
-+ cmpxchg(&dev->tx_ptr, ptr, new_ptr);
-+ } else {
-+ ptr = READ_ONCE(dev->rx_ptr);
-+ new_ptr = dev->rx_fn(dev, substream->runtime, ptr,
-+ &period_elapsed, dev->format);
-+ cmpxchg(&dev->rx_ptr, ptr, new_ptr);
-+ }
-+
-+ if (period_elapsed)
-+ snd_pcm_period_elapsed(substream);
-+ }
-+ rcu_read_unlock();
-+}
-+
-+void sf_spdif_pcm_push_tx(struct sf_spdif_dev *dev)
-+{
-+ sf_spdif_pcm_transfer(dev, true);
-+}
-+
-+void sf_spdif_pcm_pop_rx(struct sf_spdif_dev *dev)
-+{
-+ sf_spdif_pcm_transfer(dev, false);
-+}
-+
-+static int sf_pcm_open(struct snd_soc_component *component,
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-+ struct sf_spdif_dev *dev = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
-+
-+ snd_soc_set_runtime_hwparams(substream, &sf_pcm_hardware);
-+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-+ runtime->private_data = dev;
-+
-+ return 0;
-+}
-+
-+static int sf_pcm_close(struct snd_soc_component *component,
-+ struct snd_pcm_substream *substream)
-+{
-+ synchronize_rcu();
-+ return 0;
-+}
-+
-+static int sf_pcm_hw_params(struct snd_soc_component *component,
-+ struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *hw_params)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct sf_spdif_dev *dev = runtime->private_data;
-+
-+ switch (params_channels(hw_params)) {
-+ case 1:
-+ case 2:
-+ break;
-+ default:
-+ dev_err(dev->dev, "invalid channels number\n");
-+ return -EINVAL;
-+ }
-+
-+ dev->format = params_format(hw_params);
-+ switch (dev->format) {
-+ case SNDRV_PCM_FORMAT_S16_LE:
-+ case SNDRV_PCM_FORMAT_S24_LE:
-+ case SNDRV_PCM_FORMAT_S24_3LE:
-+ case SNDRV_PCM_FORMAT_S32_LE:
-+ break;
-+ default:
-+ dev_err(dev->dev, "invalid format\n");
-+ return -EINVAL;
-+ }
-+
-+ dev->tx_fn = sf_spdif_pcm_tx;
-+ dev->rx_fn = sf_spdif_pcm_rx;
-+
-+ return 0;
-+}
-+
-+static int sf_pcm_trigger(struct snd_soc_component *component,
-+ struct snd_pcm_substream *substream, int cmd)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct sf_spdif_dev *dev = runtime->private_data;
-+ int ret = 0;
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ case SNDRV_PCM_TRIGGER_RESUME:
-+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-+ WRITE_ONCE(dev->tx_ptr, 0);
-+ rcu_assign_pointer(dev->tx_substream, substream);
-+ } else {
-+ WRITE_ONCE(dev->rx_ptr, 0);
-+ rcu_assign_pointer(dev->rx_substream, substream);
-+ }
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ case SNDRV_PCM_TRIGGER_SUSPEND:
-+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-+ rcu_assign_pointer(dev->tx_substream, NULL);
-+ else
-+ rcu_assign_pointer(dev->rx_substream, NULL);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static snd_pcm_uframes_t sf_pcm_pointer(struct snd_soc_component *component,
-+ struct snd_pcm_substream *substream)
-+{
-+ struct snd_pcm_runtime *runtime = substream->runtime;
-+ struct sf_spdif_dev *dev = runtime->private_data;
-+ snd_pcm_uframes_t pos;
-+
-+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-+ pos = READ_ONCE(dev->tx_ptr);
-+ else
-+ pos = READ_ONCE(dev->rx_ptr);
-+
-+ return pos < runtime->buffer_size ? pos : 0;
-+}
-+
-+static int sf_pcm_new(struct snd_soc_component *component,
-+ struct snd_soc_pcm_runtime *rtd)
-+{
-+ size_t size = sf_pcm_hardware.buffer_bytes_max;
-+
-+ snd_pcm_set_managed_buffer_all(rtd->pcm,
-+ SNDRV_DMA_TYPE_CONTINUOUS,
-+ NULL, size, size);
-+
-+ return 0;
-+}
-+
-+static const struct snd_soc_component_driver sf_pcm_component = {
-+ .open = sf_pcm_open,
-+ .close = sf_pcm_close,
-+ .hw_params = sf_pcm_hw_params,
-+ .trigger = sf_pcm_trigger,
-+ .pointer = sf_pcm_pointer,
-+ .pcm_construct = sf_pcm_new,
-+};
-+
-+int sf_spdif_pcm_register(struct platform_device *pdev)
-+{
-+ return devm_snd_soc_register_component(&pdev->dev, &sf_pcm_component,
-+ NULL, 0);
-+}
+++ /dev/null
-From 9c4858f9fe4d8f8fe5cf347b3ca727016b7ba492 Mon Sep 17 00:00:00 2001
-From: Walker Chen <walker.chen@starfivetech.com>
-Date: Tue, 20 Jun 2023 15:57:53 +0800
-Subject: [PATCH 081/116] ASoC: starfive: Add JH7110 PDM driver
-
-Add pdm driver support for the StarFive JH7110 SoC.
-
-Signed-off-by: Walker Chen <walker.chen@starfivetech.com>
----
- sound/soc/starfive/Kconfig | 8 +
- sound/soc/starfive/Makefile | 2 +
- sound/soc/starfive/jh7110_pdm.c | 493 ++++++++++++++++++++++++++++++++
- 3 files changed, 503 insertions(+)
- create mode 100644 sound/soc/starfive/jh7110_pdm.c
-
---- a/sound/soc/starfive/Kconfig
-+++ b/sound/soc/starfive/Kconfig
-@@ -7,6 +7,14 @@ config SND_SOC_STARFIVE
- the Starfive SoCs' Audio interfaces. You will also need to
- select the audio interfaces to support below.
-
-+config SND_SOC_JH7110_PDM
-+ tristate "JH7110 PDM device driver"
-+ depends on HAVE_CLK && SND_SOC_STARFIVE
-+ select SND_SOC_JH7110_I2S
-+ select REGMAP_MMIO
-+ help
-+ Say Y or M if you want to add support for StarFive pdm driver.
-+
- config SND_SOC_JH7110_PWMDAC
- tristate "JH7110 PWM-DAC device driver"
- depends on HAVE_CLK && SND_SOC_STARFIVE
---- a/sound/soc/starfive/Makefile
-+++ b/sound/soc/starfive/Makefile
-@@ -1,4 +1,6 @@
- # StarFive Platform Support
-+obj-$(CONFIG_SND_SOC_JH7110_PDM) += jh7110_pdm.o
-+
- obj-$(CONFIG_SND_SOC_JH7110_PWMDAC) += jh7110_pwmdac.o
-
- obj-$(CONFIG_SND_SOC_JH7110_SPDIF) += spdif.o
---- /dev/null
-+++ b/sound/soc/starfive/jh7110_pdm.c
-@@ -0,0 +1,493 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * PDM driver for the StarFive JH7110 SoC
-+ *
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ */
-+#include <linux/clk.h>
-+#include <linux/device.h>
-+#include <linux/dmaengine.h>
-+#include <linux/reset.h>
-+#include <linux/module.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_platform.h>
-+#include <linux/regmap.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/types.h>
-+#include <sound/dmaengine_pcm.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <sound/soc.h>
-+#include <sound/soc-dai.h>
-+#include <sound/tlv.h>
-+
-+#define PDM_DMIC_CTRL0 0x00
-+#define PDM_DC_SCALE0 0x04
-+#define PDM_DMIC_CTRL1 0x10
-+#define PDM_DC_SCALE1 0x14
-+
-+/* PDM CTRL OFFSET */
-+#define PDM_DMIC_MSB_SHIFT 1
-+#define PDM_DMIC_MSB_MASK (0x7 << PDM_DMIC_MSB_SHIFT)
-+#define PDM_DMIC_VOL_SHIFT 16
-+#define PDM_DMIC_VOL_MASK (0x3f << PDM_DMIC_VOL_SHIFT)
-+#define PDM_VOL_DB_MUTE (0x3f << PDM_DMIC_VOL_SHIFT)
-+#define PDM_VOL_DB_MAX 0
-+
-+#define PDM_DMIC_RVOL_MASK BIT(22)
-+#define PDM_DMIC_LVOL_MASK BIT(23)
-+#define PDM_DMIC_I2S_SLAVE BIT(24)
-+#define PDM_DMIC_HPF_EN BIT(28)
-+#define PDM_DMIC_FASTMODE_MASK BIT(29)
-+#define PDM_DMIC_DC_BYPASS_MASK BIT(30)
-+#define PDM_SW_RST_MASK BIT(31)
-+#define PDM_SW_RST_RELEASE BIT(31)
-+
-+/* PDM SCALE OFFSET */
-+#define DMIC_DCOFF3_SHIFT 24
-+#define DMIC_DCOFF2_SHIFT 16
-+#define DMIC_DCOFF1_SHIFT 8
-+
-+#define DMIC_DCOFF3_MASK (0xf << DMIC_DCOFF3_SHIFT)
-+#define DMIC_DCOFF3_VAL (0xc << DMIC_DCOFF3_SHIFT)
-+#define DMIC_DCOFF1_MASK (0xff << DMIC_DCOFF1_SHIFT)
-+#define DMIC_DCOFF1_VAL (0x5 << DMIC_DCOFF1_SHIFT)
-+#define DMIC_SCALE_MASK 0x3f
-+#define DMIC_SCALE_DEF_VAL 0x8
-+
-+enum PDM_MSB_SHIFT {
-+ PDM_MSB_SHIFT_NONE = 0,
-+ PDM_MSB_SHIFT_1,
-+ PDM_MSB_SHIFT_2,
-+ PDM_MSB_SHIFT_3,
-+ PDM_MSB_SHIFT_4,
-+ PDM_MSB_SHIFT_5,
-+ PDM_MSB_SHIFT_6,
-+ PDM_MSB_SHIFT_7,
-+};
-+
-+struct sf_pdm {
-+ struct regmap *pdm_map;
-+ struct device *dev;
-+ struct clk *clk_pdm_apb;
-+ struct clk *clk_pdm_mclk;
-+ struct clk *clk_mclk;
-+ struct clk *clk_mclk_ext;
-+ struct reset_control *rst_pdm_dmic;
-+ struct reset_control *rst_pdm_apb;
-+ unsigned char flag_first;
-+ unsigned int saved_ctrl0;
-+ unsigned int saved_scale0;
-+};
-+
-+static const DECLARE_TLV_DB_SCALE(volume_tlv, -9450, 150, 0);
-+
-+static const struct snd_kcontrol_new sf_pdm_snd_controls[] = {
-+ SOC_SINGLE("DC compensation Control", PDM_DMIC_CTRL0, 30, 1, 0),
-+ SOC_SINGLE("High Pass Filter Control", PDM_DMIC_CTRL0, 28, 1, 0),
-+ SOC_SINGLE("Left Channel Volume Control", PDM_DMIC_CTRL0, 23, 1, 0),
-+ SOC_SINGLE("Right Channel Volume Control", PDM_DMIC_CTRL0, 22, 1, 0),
-+ SOC_SINGLE_TLV("Volume", PDM_DMIC_CTRL0, 16, 0x3F, 1, volume_tlv),
-+ SOC_SINGLE("Data MSB Shift", PDM_DMIC_CTRL0, 1, 7, 0),
-+ SOC_SINGLE("SCALE", PDM_DC_SCALE0, 0, 0x3F, 0),
-+ SOC_SINGLE("DC offset", PDM_DC_SCALE0, 8, 0xFFFFF, 0),
-+};
-+
-+static void sf_pdm_enable(struct regmap *map)
-+{
-+ /* Left and Right Channel Volume Control Enable */
-+ regmap_update_bits(map, PDM_DMIC_CTRL0, PDM_DMIC_RVOL_MASK, 0);
-+ regmap_update_bits(map, PDM_DMIC_CTRL0, PDM_DMIC_LVOL_MASK, 0);
-+}
-+
-+static void sf_pdm_disable(struct regmap *map)
-+{
-+ /* Left and Right Channel Volume Control Disable */
-+ regmap_update_bits(map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_RVOL_MASK, PDM_DMIC_RVOL_MASK);
-+ regmap_update_bits(map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_LVOL_MASK, PDM_DMIC_LVOL_MASK);
-+}
-+
-+static int sf_pdm_trigger(struct snd_pcm_substream *substream, int cmd,
-+ struct snd_soc_dai *dai)
-+{
-+ struct sf_pdm *priv = snd_soc_dai_get_drvdata(dai);
-+
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ case SNDRV_PCM_TRIGGER_RESUME:
-+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+ if (priv->flag_first) {
-+ priv->flag_first = 0;
-+ mdelay(200);
-+ }
-+
-+ sf_pdm_enable(priv->pdm_map);
-+ return 0;
-+
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ case SNDRV_PCM_TRIGGER_SUSPEND:
-+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+ sf_pdm_disable(priv->pdm_map);
-+ return 0;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+static int sf_pdm_hw_params(struct snd_pcm_substream *substream,
-+ struct snd_pcm_hw_params *params,
-+ struct snd_soc_dai *dai)
-+{
-+ struct sf_pdm *priv = snd_soc_dai_get_drvdata(dai);
-+ unsigned int sample_rate;
-+ unsigned int data_width;
-+ int ret;
-+ const int pdm_mul = 128;
-+
-+ sample_rate = params_rate(params);
-+ switch (sample_rate) {
-+ case 8000:
-+ case 11025:
-+ case 16000:
-+ break;
-+ default:
-+ dev_err(priv->dev, "can't support sample rate:%d\n", sample_rate);
-+ return -EINVAL;
-+ }
-+
-+ data_width = params_width(params);
-+ switch (data_width) {
-+ case 16:
-+ case 32:
-+ break;
-+ default:
-+ dev_err(priv->dev, "can't support bit width %d\n", data_width);
-+ return -EINVAL;
-+ }
-+
-+ /* set pdm_mclk, PDM MCLK = 128 * LRCLK */
-+ ret = clk_set_rate(priv->clk_pdm_mclk, pdm_mul * sample_rate);
-+ if (ret) {
-+ dev_err(priv->dev, "Can't set pdm_mclk: %d\n", ret);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct snd_soc_dai_ops sf_pdm_dai_ops = {
-+ .trigger = sf_pdm_trigger,
-+ .hw_params = sf_pdm_hw_params,
-+};
-+
-+static void sf_pdm_module_init(struct sf_pdm *priv)
-+{
-+ /* Reset */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_SW_RST_MASK, 0x00);
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_SW_RST_MASK, PDM_SW_RST_RELEASE);
-+
-+ /* Make sure the device is initially disabled */
-+ sf_pdm_disable(priv->pdm_map);
-+
-+ /* MUTE */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_VOL_MASK, PDM_VOL_DB_MUTE);
-+
-+ /* UNMUTE */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_VOL_MASK, PDM_VOL_DB_MAX);
-+
-+ /* enable high pass filter */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_HPF_EN, PDM_DMIC_HPF_EN);
-+
-+ /* PDM work as slave mode */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_I2S_SLAVE, PDM_DMIC_I2S_SLAVE);
-+
-+ /* disable fast mode */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_FASTMODE_MASK, 0);
-+
-+ /* dmic msb shift 0 */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_MSB_MASK, 0);
-+
-+ /* scale: 0x8 */
-+ regmap_update_bits(priv->pdm_map, PDM_DC_SCALE0,
-+ DMIC_SCALE_MASK, DMIC_SCALE_DEF_VAL);
-+
-+ regmap_update_bits(priv->pdm_map, PDM_DC_SCALE0,
-+ DMIC_DCOFF1_MASK, DMIC_DCOFF1_VAL);
-+
-+ regmap_update_bits(priv->pdm_map, PDM_DC_SCALE0,
-+ DMIC_DCOFF3_MASK, DMIC_DCOFF3_VAL);
-+
-+ /* scale: 0x3f */
-+ regmap_update_bits(priv->pdm_map, PDM_DC_SCALE0,
-+ DMIC_SCALE_MASK, DMIC_SCALE_MASK);
-+
-+ /* dmic msb shift 2 */
-+ regmap_update_bits(priv->pdm_map, PDM_DMIC_CTRL0,
-+ PDM_DMIC_MSB_MASK, PDM_MSB_SHIFT_4);
-+}
-+
-+#define SF_PDM_RATES (SNDRV_PCM_RATE_8000 | \
-+ SNDRV_PCM_RATE_11025 | \
-+ SNDRV_PCM_RATE_16000)
-+
-+#define SF_PDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
-+ SNDRV_PCM_FMTBIT_S32_LE)
-+
-+static struct snd_soc_dai_driver sf_pdm_dai_drv = {
-+ .name = "PDM",
-+ .id = 0,
-+ .capture = {
-+ .stream_name = "Capture",
-+ .channels_min = 2,
-+ .channels_max = 2,
-+ .rates = SF_PDM_RATES,
-+ .formats = SF_PDM_FORMATS,
-+ },
-+ .ops = &sf_pdm_dai_ops,
-+ .symmetric_rate = 1,
-+};
-+
-+static int sf_pdm_component_probe(struct snd_soc_component *component)
-+{
-+ struct sf_pdm *priv = snd_soc_component_get_drvdata(component);
-+
-+ snd_soc_component_init_regmap(component, priv->pdm_map);
-+ snd_soc_add_component_controls(component, sf_pdm_snd_controls,
-+ ARRAY_SIZE(sf_pdm_snd_controls));
-+
-+ return 0;
-+}
-+
-+static int sf_pdm_clock_enable(struct sf_pdm *priv)
-+{
-+ int ret;
-+
-+ ret = clk_prepare_enable(priv->clk_pdm_mclk);
-+ if (ret) {
-+ dev_err(priv->dev, "failed to prepare enable clk_pdm_mclk\n");
-+ return ret;
-+ }
-+
-+ ret = clk_prepare_enable(priv->clk_pdm_apb);
-+ if (ret) {
-+ dev_err(priv->dev, "failed to prepare enable clk_pdm_apb\n");
-+ goto disable_pdm_mclk;
-+ }
-+
-+ ret = reset_control_deassert(priv->rst_pdm_dmic);
-+ if (ret) {
-+ dev_err(priv->dev, "failed to deassert pdm_dmic\n");
-+ goto disable_pdm_apb;
-+ }
-+
-+ ret = reset_control_deassert(priv->rst_pdm_apb);
-+ if (ret) {
-+ dev_err(priv->dev, "failed to deassert pdm_apb\n");
-+ goto disable_pdm_apb;
-+ }
-+
-+ ret = clk_set_parent(priv->clk_mclk, priv->clk_mclk_ext);
-+ if (ret) {
-+ dev_err(priv->dev, "failed to set parent clk_mclk ret=%d\n", ret);
-+ goto disable_pdm_apb;
-+ }
-+
-+ return 0;
-+
-+disable_pdm_apb:
-+ clk_disable_unprepare(priv->clk_pdm_apb);
-+disable_pdm_mclk:
-+ clk_disable_unprepare(priv->clk_pdm_mclk);
-+
-+ return ret;
-+}
-+
-+#ifdef CONFIG_PM
-+static int sf_pdm_runtime_suspend(struct device *dev)
-+{
-+ struct sf_pdm *priv = dev_get_drvdata(dev);
-+
-+ clk_disable_unprepare(priv->clk_pdm_apb);
-+ clk_disable_unprepare(priv->clk_pdm_mclk);
-+
-+ return 0;
-+}
-+
-+static int sf_pdm_runtime_resume(struct device *dev)
-+{
-+ struct sf_pdm *priv = dev_get_drvdata(dev);
-+ int ret;
-+
-+ ret = sf_pdm_clock_enable(priv);
-+ if (!ret)
-+ sf_pdm_module_init(priv);
-+
-+ return ret;
-+}
-+#endif
-+
-+#ifdef CONFIG_PM_SLEEP
-+static int sf_pdm_suspend(struct snd_soc_component *component)
-+{
-+ return pm_runtime_force_suspend(component->dev);
-+}
-+
-+static int sf_pdm_resume(struct snd_soc_component *component)
-+{
-+ return pm_runtime_force_resume(component->dev);
-+}
-+
-+#else
-+#define sf_pdm_suspend NULL
-+#define sf_pdm_resume NULL
-+#endif
-+
-+static const struct snd_soc_component_driver sf_pdm_component_drv = {
-+ .name = "jh7110-pdm",
-+ .probe = sf_pdm_component_probe,
-+ .suspend = sf_pdm_suspend,
-+ .resume = sf_pdm_resume,
-+};
-+
-+static const struct regmap_config sf_pdm_regmap_cfg = {
-+ .reg_bits = 32,
-+ .val_bits = 32,
-+ .reg_stride = 4,
-+ .max_register = 0x20,
-+};
-+
-+static int sf_pdm_clock_get(struct platform_device *pdev, struct sf_pdm *priv)
-+{
-+ int ret;
-+
-+ static struct clk_bulk_data clks[] = {
-+ { .id = "pdm_mclk" },
-+ { .id = "pdm_apb" },
-+ { .id = "clk_mclk" },
-+ { .id = "mclk_ext" },
-+ };
-+
-+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to get pdm clocks\n");
-+ goto exit;
-+ }
-+
-+ priv->clk_pdm_mclk = clks[0].clk;
-+ priv->clk_pdm_apb = clks[1].clk;
-+ priv->clk_mclk = clks[2].clk;
-+ priv->clk_mclk_ext = clks[3].clk;
-+
-+ priv->rst_pdm_dmic = devm_reset_control_get_exclusive(&pdev->dev, "pdm_dmic");
-+ if (IS_ERR(priv->rst_pdm_dmic)) {
-+ dev_err(&pdev->dev, "failed to get pdm_dmic reset control\n");
-+ ret = PTR_ERR(priv->rst_pdm_dmic);
-+ goto exit;
-+ }
-+
-+ priv->rst_pdm_apb = devm_reset_control_get_exclusive(&pdev->dev, "pdm_apb");
-+ if (IS_ERR(priv->rst_pdm_apb)) {
-+ dev_err(&pdev->dev, "failed to get pdm_apb reset control\n");
-+ ret = PTR_ERR(priv->rst_pdm_apb);
-+ goto exit;
-+ }
-+
-+ /*
-+ * pdm clock must always be enabled as hardware issue that
-+ * no data in the first 4 seconds of the first recording
-+ */
-+ ret = sf_pdm_clock_enable(priv);
-+
-+exit:
-+ return ret;
-+}
-+
-+static int sf_pdm_probe(struct platform_device *pdev)
-+{
-+ struct sf_pdm *priv;
-+ struct resource *res;
-+ void __iomem *regs;
-+ int ret;
-+
-+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+ platform_set_drvdata(pdev, priv);
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pdm");
-+ regs = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(regs))
-+ return PTR_ERR(regs);
-+
-+ priv->pdm_map = devm_regmap_init_mmio(&pdev->dev, regs, &sf_pdm_regmap_cfg);
-+ if (IS_ERR(priv->pdm_map)) {
-+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
-+ PTR_ERR(priv->pdm_map));
-+ return PTR_ERR(priv->pdm_map);
-+ }
-+
-+ priv->dev = &pdev->dev;
-+ priv->flag_first = 1;
-+
-+ ret = sf_pdm_clock_get(pdev, priv);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to enable audio-pdm clock\n");
-+ return ret;
-+ }
-+
-+ dev_set_drvdata(&pdev->dev, priv);
-+
-+ ret = devm_snd_soc_register_component(&pdev->dev, &sf_pdm_component_drv,
-+ &sf_pdm_dai_drv, 1);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to register pdm dai\n");
-+ return ret;
-+ }
-+ pm_runtime_enable(&pdev->dev);
-+
-+ return 0;
-+}
-+
-+static int sf_pdm_dev_remove(struct platform_device *pdev)
-+{
-+ pm_runtime_disable(&pdev->dev);
-+ return 0;
-+}
-+
-+static const struct of_device_id sf_pdm_of_match[] = {
-+ {.compatible = "starfive,jh7110-pdm",},
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, sf_pdm_of_match);
-+
-+static const struct dev_pm_ops sf_pdm_pm_ops = {
-+ SET_RUNTIME_PM_OPS(sf_pdm_runtime_suspend,
-+ sf_pdm_runtime_resume, NULL)
-+};
-+
-+static struct platform_driver sf_pdm_driver = {
-+ .driver = {
-+ .name = "jh7110-pdm",
-+ .of_match_table = sf_pdm_of_match,
-+ .pm = &sf_pdm_pm_ops,
-+ },
-+ .probe = sf_pdm_probe,
-+ .remove = sf_pdm_dev_remove,
-+};
-+module_platform_driver(sf_pdm_driver);
-+
-+MODULE_AUTHOR("Walker Chen <walker.chen@starfivetech.com>");
-+MODULE_DESCRIPTION("Starfive PDM Controller Driver");
-+MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 59cbdfeee0fc1ad382a0bc8f7fa897a9f5d03df0 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Fri, 9 Jun 2023 16:54:36 +0800
-Subject: [PATCH 082/116] dt-binding: input: Add tink_ft5406
-
-Add tink_ft5406.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
----
- .../bindings/input/tinker_ft5406.yaml | 39 +++++++++++++++++++
- 1 file changed, 39 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/input/tinker_ft5406.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/input/tinker_ft5406.yaml
-@@ -0,0 +1,39 @@
-+# SPDX-License-Identifier: GPL-2.0
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/input/touchscreen/goodix.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Tinker FT5406 touchscreen controller Bindings
-+
-+maintainers:
-+ - Changhuang Liang <changhuang.liang@starfivetech.com>
-+
-+allOf:
-+ - $ref: touchscreen.yaml#
-+
-+properties:
-+ compatible:
-+ const: tinker_ft5406
-+
-+ reg:
-+ const: 0x38
-+
-+additionalProperties: false
-+
-+required:
-+ - compatible
-+ - reg
-+
-+examples:
-+ - |
-+ i2c {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ tinker_ft5406@38 {
-+ compatible = "tinker_ft5406";
-+ reg = <0x38>;
-+ };
-+ };
-+
-+...
+++ /dev/null
-From 4800b6e0f2190d991cd4e5352167a9422841f195 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Wed, 21 Dec 2022 16:20:04 +0800
-Subject: [PATCH 083/116] input: touchscreen: Add tinker_ft5406 driver support
-
-Add tinker_ft5406 driver support
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
----
- drivers/input/touchscreen/Kconfig | 6 +
- drivers/input/touchscreen/Makefile | 1 +
- drivers/input/touchscreen/tinker_ft5406.c | 406 ++++++++++++++++++++++
- 3 files changed, 413 insertions(+)
- create mode 100644 drivers/input/touchscreen/tinker_ft5406.c
-
---- a/drivers/input/touchscreen/Kconfig
-+++ b/drivers/input/touchscreen/Kconfig
-@@ -1399,4 +1399,10 @@ config TOUCHSCREEN_HIMAX_HX83112B
- To compile this driver as a module, choose M here: the
- module will be called himax_hx83112b.
-
-+config TOUCHSCREEN_TINKER_FT5406
-+ tristate "tinker ft5406"
-+ depends on I2C
-+ help
-+ Control ft5406 touch ic.
-+
- endif
---- a/drivers/input/touchscreen/Makefile
-+++ b/drivers/input/touchscreen/Makefile
-@@ -118,3 +118,4 @@ obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5
- obj-$(CONFIG_TOUCHSCREEN_IQS7211) += iqs7211.o
- obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o
- obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX83112B) += himax_hx83112b.o
-+obj-$(CONFIG_TOUCHSCREEN_TINKER_FT5406) += tinker_ft5406.o
---- /dev/null
-+++ b/drivers/input/touchscreen/tinker_ft5406.c
-@@ -0,0 +1,406 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ *
-+ * TINKER BOARD FT5406 touch driver.
-+ *
-+ * Copyright (c) 2016 ASUSTek Computer Inc.
-+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program 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 General Public License for more details.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/i2c.h>
-+#include <linux/input.h>
-+#include <linux/input/mt.h>
-+#include <linux/module.h>
-+#include <linux/workqueue.h>
-+
-+#define RETRY_COUNT 10
-+#define FT_ONE_TCH_LEN 6
-+
-+#define FT_REG_FW_VER 0xA6
-+#define FT_REG_FW_MIN_VER 0xB2
-+#define FT_REG_FW_SUB_MIN_VER 0xB3
-+
-+#define VALID_TD_STATUS_VAL 10
-+#define MAX_TOUCH_POINTS 5
-+
-+#define FT_PRESS 0x7F
-+#define FT_MAX_ID 0x0F
-+
-+#define FT_TOUCH_X_H 0
-+#define FT_TOUCH_X_L 1
-+#define FT_TOUCH_Y_H 2
-+#define FT_TOUCH_Y_L 3
-+#define FT_TOUCH_EVENT 0
-+#define FT_TOUCH_ID 2
-+
-+#define FT_TOUCH_X_H_REG 3
-+#define FT_TOUCH_X_L_REG 4
-+#define FT_TOUCH_Y_H_REG 5
-+#define FT_TOUCH_Y_L_REG 6
-+#define FT_TD_STATUS_REG 2
-+#define FT_TOUCH_EVENT_REG 3
-+#define FT_TOUCH_ID_REG 5
-+
-+#define FT_TOUCH_DOWN 0
-+#define FT_TOUCH_CONTACT 2
-+
-+struct ts_event {
-+ u16 au16_x[MAX_TOUCH_POINTS]; /*x coordinate */
-+ u16 au16_y[MAX_TOUCH_POINTS]; /*y coordinate */
-+ u8 au8_touch_event[MAX_TOUCH_POINTS]; /*touch event: 0:down; 1:up; 2:contact */
-+ u8 au8_finger_id[MAX_TOUCH_POINTS]; /*touch ID */
-+ u16 pressure;
-+ u8 touch_point;
-+ u8 point_num;
-+};
-+
-+struct tinker_ft5406_data {
-+ struct device *dev;
-+ struct i2c_client *client;
-+ struct input_dev *input_dev;
-+ struct ts_event event;
-+ struct work_struct ft5406_work;
-+
-+ int screen_width;
-+ int screen_height;
-+ int xy_reverse;
-+ int known_ids;
-+ int retry_count;
-+ bool finish_work;
-+};
-+
-+struct tinker_ft5406_data *g_ts_data;
-+
-+static int fts_i2c_read(struct i2c_client *client, char *writebuf,
-+ int writelen, char *readbuf, int readlen)
-+{
-+ int ret;
-+
-+ if (writelen > 0) {
-+ struct i2c_msg msgs[] = {
-+ {
-+ .addr = client->addr,
-+ .flags = 0,
-+ .len = writelen,
-+ .buf = writebuf,
-+ },
-+ {
-+ .addr = client->addr,
-+ .flags = I2C_M_RD,
-+ .len = readlen,
-+ .buf = readbuf,
-+ },
-+ };
-+ ret = i2c_transfer(client->adapter, msgs, 2);
-+ if (ret < 0)
-+ dev_err(&client->dev, "i2c read error, %d\n", ret);
-+ } else {
-+ struct i2c_msg msgs[] = {
-+ {
-+ .addr = client->addr,
-+ .flags = I2C_M_RD,
-+ .len = readlen,
-+ .buf = readbuf,
-+ },
-+ };
-+ ret = i2c_transfer(client->adapter, msgs, 1);
-+ if (ret < 0)
-+ dev_err(&client->dev, "i2c read error, %d\n", ret);
-+ }
-+
-+ return ret;
-+}
-+
-+static int fts_read_reg(struct i2c_client *client, u8 addr, u8 *val)
-+{
-+ return fts_i2c_read(client, &addr, 1, val, 1);
-+}
-+
-+static int fts_check_fw_ver(struct i2c_client *client)
-+{
-+ u8 reg_addr, fw_ver[3];
-+ int ret;
-+
-+ reg_addr = FT_REG_FW_VER;
-+ ret = fts_i2c_read(client, ®_addr, 1, &fw_ver[0], 1);
-+ if (ret < 0)
-+ goto error;
-+
-+ reg_addr = FT_REG_FW_MIN_VER;
-+ ret = fts_i2c_read(client, ®_addr, 1, &fw_ver[1], 1);
-+ if (ret < 0)
-+ goto error;
-+
-+ reg_addr = FT_REG_FW_SUB_MIN_VER;
-+ ret = fts_i2c_read(client, ®_addr, 1, &fw_ver[2], 1);
-+ if (ret < 0)
-+ goto error;
-+
-+ dev_info(&client->dev, "Firmware version = %d.%d.%d\n",
-+ fw_ver[0], fw_ver[1], fw_ver[2]);
-+ return 0;
-+
-+error:
-+ return ret;
-+}
-+
-+static int fts_read_td_status(struct tinker_ft5406_data *ts_data)
-+{
-+ u8 td_status;
-+ int ret = -1;
-+
-+ ret = fts_read_reg(ts_data->client, FT_TD_STATUS_REG, &td_status);
-+ if (ret < 0) {
-+ dev_err(&ts_data->client->dev,
-+ "Get reg td_status failed, %d\n", ret);
-+ return ret;
-+ }
-+ return (int)td_status;
-+}
-+
-+static int fts_read_touchdata(struct tinker_ft5406_data *ts_data)
-+{
-+ struct ts_event *event = &ts_data->event;
-+ int ret = -1, i;
-+ u8 buf[FT_ONE_TCH_LEN-2] = { 0 };
-+ u8 reg_addr, pointid = FT_MAX_ID;
-+
-+ for (i = 0; i < event->touch_point && i < MAX_TOUCH_POINTS; i++) {
-+ reg_addr = FT_TOUCH_X_H_REG + (i * FT_ONE_TCH_LEN);
-+ ret = fts_i2c_read(ts_data->client, ®_addr, 1, buf, FT_ONE_TCH_LEN-2);
-+ if (ret < 0) {
-+ dev_err(&ts_data->client->dev, "Read touchdata failed.\n");
-+ return ret;
-+ }
-+
-+ pointid = (buf[FT_TOUCH_ID]) >> 4;
-+ if (pointid >= MAX_TOUCH_POINTS)
-+ break;
-+ event->au8_finger_id[i] = pointid;
-+ event->au16_x[i] = (s16) (buf[FT_TOUCH_X_H] & 0x0F) << 8 | (s16) buf[FT_TOUCH_X_L];
-+ event->au16_y[i] = (s16) (buf[FT_TOUCH_Y_H] & 0x0F) << 8 | (s16) buf[FT_TOUCH_Y_L];
-+ event->au8_touch_event[i] = buf[FT_TOUCH_EVENT] >> 6;
-+
-+ if (ts_data->xy_reverse) {
-+ event->au16_x[i] = ts_data->screen_width - event->au16_x[i] - 1;
-+ event->au16_y[i] = ts_data->screen_height - event->au16_y[i] - 1;
-+ }
-+ }
-+ event->pressure = FT_PRESS;
-+
-+ return 0;
-+}
-+
-+static void fts_report_value(struct tinker_ft5406_data *ts_data)
-+{
-+ struct ts_event *event = &ts_data->event;
-+ int i, modified_ids = 0, released_ids;
-+
-+ for (i = 0; i < event->touch_point && i < MAX_TOUCH_POINTS; i++) {
-+ if (event->au8_touch_event[i] == FT_TOUCH_DOWN ||
-+ event->au8_touch_event[i] == FT_TOUCH_CONTACT) {
-+ modified_ids |= 1 << event->au8_finger_id[i];
-+ input_mt_slot(ts_data->input_dev, event->au8_finger_id[i]);
-+ input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER,
-+ true);
-+ input_report_abs(ts_data->input_dev, ABS_MT_TOUCH_MAJOR,
-+ event->pressure);
-+ input_report_abs(ts_data->input_dev, ABS_MT_POSITION_X,
-+ event->au16_x[i]);
-+ input_report_abs(ts_data->input_dev, ABS_MT_POSITION_Y,
-+ event->au16_y[i]);
-+
-+ if (!((1 << event->au8_finger_id[i]) & ts_data->known_ids))
-+ dev_dbg(&ts_data->client->dev, "Touch id-%d: x = %d, y = %d\n",
-+ event->au8_finger_id[i],
-+ event->au16_x[i],
-+ event->au16_y[i]);
-+ }
-+ }
-+
-+ released_ids = ts_data->known_ids & ~modified_ids;
-+ for (i = 0; released_ids && i < MAX_TOUCH_POINTS; i++) {
-+ if (released_ids & (1<<i)) {
-+ dev_dbg(&ts_data->client->dev, "Release id-%d, known = %x modified = %x\n",
-+ i, ts_data->known_ids, modified_ids);
-+ input_mt_slot(ts_data->input_dev, i);
-+ input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, false);
-+ modified_ids &= ~(1 << i);
-+ }
-+ }
-+ ts_data->known_ids = modified_ids;
-+ input_mt_report_pointer_emulation(ts_data->input_dev, true);
-+ input_sync(ts_data->input_dev);
-+}
-+
-+static void fts_retry_clear(struct tinker_ft5406_data *ts_data)
-+{
-+ if (ts_data->retry_count != 0)
-+ ts_data->retry_count = 0;
-+}
-+
-+static int fts_retry_wait(struct tinker_ft5406_data *ts_data)
-+{
-+ if (ts_data->retry_count < RETRY_COUNT) {
-+ dev_info(&ts_data->client->dev,
-+ "Wait and retry, count = %d\n", ts_data->retry_count);
-+ ts_data->retry_count++;
-+ msleep(1000);
-+ return 1;
-+ }
-+ dev_err(&ts_data->client->dev, "Attach retry count\n");
-+ return 0;
-+}
-+
-+static void tinker_ft5406_work(struct work_struct *work)
-+{
-+ struct ts_event *event = &g_ts_data->event;
-+ int ret = 0, td_status;
-+
-+ /* polling 60fps */
-+ while (!g_ts_data->finish_work) {
-+ td_status = fts_read_td_status(g_ts_data);
-+ if (td_status < 0) {
-+ ret = fts_retry_wait(g_ts_data);
-+ if (ret == 0) {
-+ dev_err(&g_ts_data->client->dev, "Stop touch polling\n");
-+ break;
-+ }
-+ } else if (td_status < VALID_TD_STATUS_VAL + 1 &&
-+ (td_status > 0 || g_ts_data->known_ids != 0)) {
-+ fts_retry_clear(g_ts_data);
-+ memset(event, -1, sizeof(struct ts_event));
-+ event->touch_point = td_status;
-+ ret = fts_read_touchdata(g_ts_data);
-+ if (ret == 0)
-+ fts_report_value(g_ts_data);
-+ }
-+ msleep_interruptible(17);
-+ }
-+}
-+
-+static int tinker_ft5406_open(struct input_dev *dev)
-+{
-+ schedule_work(&g_ts_data->ft5406_work);
-+ return 0;
-+}
-+
-+static void tinker_ft5406_close(struct input_dev *dev)
-+{
-+ g_ts_data->finish_work = true;
-+ cancel_work_sync(&g_ts_data->ft5406_work);
-+ g_ts_data->finish_work = false;
-+}
-+
-+static int tinker_ft5406_probe(struct i2c_client *client)
-+{
-+ struct input_dev *input_dev;
-+ int ret = 0;
-+
-+ dev_info(&client->dev, "Address = 0x%x\n", client->addr);
-+
-+ g_ts_data = kzalloc(sizeof(struct tinker_ft5406_data), GFP_KERNEL);
-+ if (g_ts_data == NULL) {
-+ dev_err(&client->dev, "No memory for device\n");
-+ return -ENOMEM;
-+ }
-+
-+ g_ts_data->client = client;
-+ i2c_set_clientdata(client, g_ts_data);
-+
-+ g_ts_data->screen_width = 800;
-+ g_ts_data->screen_height = 480;
-+ g_ts_data->xy_reverse = 1;
-+
-+ dev_info(&client->dev, "width = %d, height = %d, reverse = %d\n",
-+ g_ts_data->screen_width, g_ts_data->screen_height, g_ts_data->xy_reverse);
-+
-+ ret = fts_check_fw_ver(g_ts_data->client);
-+ if (ret) {
-+ dev_err(&client->dev, "Checking touch ic failed\n");
-+ goto check_fw_err;
-+ }
-+
-+ input_dev = input_allocate_device();
-+ if (!input_dev) {
-+ dev_err(&client->dev, "Failed to allocate input device\n");
-+ goto input_allocate_failed;
-+ }
-+ input_dev->name = "fts_ts";
-+ input_dev->id.bustype = BUS_I2C;
-+ input_dev->dev.parent = &g_ts_data->client->dev;
-+ input_dev->open = tinker_ft5406_open;
-+ input_dev->close = tinker_ft5406_close;
-+
-+ g_ts_data->input_dev = input_dev;
-+ input_set_drvdata(input_dev, g_ts_data);
-+
-+ __set_bit(EV_SYN, input_dev->evbit);
-+ __set_bit(EV_KEY, input_dev->evbit);
-+ __set_bit(EV_ABS, input_dev->evbit);
-+ __set_bit(BTN_TOUCH, input_dev->keybit);
-+
-+ input_mt_init_slots(input_dev, MAX_TOUCH_POINTS, 0);
-+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, g_ts_data->screen_width, 0, 0);
-+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, g_ts_data->screen_height, 0, 0);
-+
-+ ret = input_register_device(input_dev);
-+ if (ret) {
-+ dev_err(&client->dev, "Input device registration failed\n");
-+ goto input_register_failed;
-+ }
-+
-+ INIT_WORK(&g_ts_data->ft5406_work, tinker_ft5406_work);
-+
-+ return 0;
-+
-+input_register_failed:
-+ input_free_device(input_dev);
-+input_allocate_failed:
-+check_fw_err:
-+ kfree(g_ts_data);
-+ g_ts_data = NULL;
-+ return ret;
-+}
-+
-+static void tinker_ft5406_remove(struct i2c_client *client)
-+{
-+ cancel_work_sync(&g_ts_data->ft5406_work);
-+ if (g_ts_data->input_dev) {
-+ input_unregister_device(g_ts_data->input_dev);
-+ input_free_device(g_ts_data->input_dev);
-+ }
-+ kfree(g_ts_data);
-+ g_ts_data = NULL;
-+}
-+
-+static const struct i2c_device_id tinker_ft5406_id[] = {
-+ {"tinker_ft5406", 0},
-+ {},
-+};
-+
-+static struct i2c_driver tinker_ft5406_driver = {
-+ .driver = {
-+ .name = "tinker_ft5406",
-+ },
-+ .probe = tinker_ft5406_probe,
-+ .remove = tinker_ft5406_remove,
-+ .id_table = tinker_ft5406_id,
-+};
-+module_i2c_driver(tinker_ft5406_driver);
-+
-+MODULE_DESCRIPTION("TINKER BOARD FT5406 Touch driver");
-+MODULE_LICENSE("GPL v2");
+++ /dev/null
-From b477a1a53553336edcfeb83be1b35817928daed8 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Mon, 5 Jun 2023 14:46:16 +0800
-Subject: [PATCH 084/116] dt-binding: media: Add JH7110 Camera Subsystem.
-
-Add the bindings documentation for Starfive JH7110 Camera Subsystem
-which is used for handing image sensor data.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
-Signed-off-by: Jack Zhu <jack.zhu@starfivetech.com>
----
- .../bindings/media/starfive,jh7110-camss.yaml | 228 ++++++++++++++++++
- 1 file changed, 228 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml
-@@ -0,0 +1,228 @@
-+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/media/starfive,jh7110-camss.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Starfive SoC CAMSS ISP
-+
-+maintainers:
-+ - Jack Zhu <jack.zhu@starfivetech.com>
-+ - Changhuang Liang <changhuang.liang@starfivetech.com>
-+
-+description:
-+ The Starfive CAMSS ISP is a Camera interface for Starfive JH7110 SoC. It
-+ consists of a VIN controller (Video In Controller, a top-level control unit)
-+ and an ISP.
-+
-+properties:
-+ compatible:
-+ const: starfive,jh7110-vin
-+
-+ reg:
-+ maxItems: 8
-+
-+ reg-names:
-+ items:
-+ - const: csi2rx
-+ - const: vclk
-+ - const: vrst
-+ - const: sctrl
-+ - const: isp
-+ - const: trst
-+ - const: pmu
-+ - const: syscrg
-+
-+ clocks:
-+ maxItems: 16
-+
-+ clock-names:
-+ items:
-+ - const: clk_apb_func
-+ - const: clk_pclk
-+ - const: clk_sys_clk
-+ - const: clk_wrapper_clk_c
-+ - const: clk_dvp_inv
-+ - const: clk_axiwr
-+ - const: clk_mipi_rx0_pxl
-+ - const: clk_pixel_clk_if0
-+ - const: clk_pixel_clk_if1
-+ - const: clk_pixel_clk_if2
-+ - const: clk_pixel_clk_if3
-+ - const: clk_m31dphy_cfgclk_in
-+ - const: clk_m31dphy_refclk_in
-+ - const: clk_m31dphy_txclkesc_lan0
-+ - const: clk_ispcore_2x
-+ - const: clk_isp_axi
-+
-+ resets:
-+ maxItems: 14
-+
-+ reset-names:
-+ items:
-+ - const: rst_wrapper_p
-+ - const: rst_wrapper_c
-+ - const: rst_pclk
-+ - const: rst_sys_clk
-+ - const: rst_axird
-+ - const: rst_axiwr
-+ - const: rst_pixel_clk_if0
-+ - const: rst_pixel_clk_if1
-+ - const: rst_pixel_clk_if2
-+ - const: rst_pixel_clk_if3
-+ - const: rst_m31dphy_hw
-+ - const: rst_m31dphy_b09_always_on
-+ - const: rst_isp_top_n
-+ - const: rst_isp_top_axi
-+
-+ power-domains:
-+ items:
-+ - description: JH7110 ISP Power Domain Switch Controller.
-+
-+ interrupts:
-+ maxItems: 5
-+
-+ ports:
-+ $ref: /schemas/graph.yaml#/properties/ports
-+
-+ properties:
-+ port@0:
-+ $ref: /schemas/graph.yaml#/$defs/port-base
-+ unevaluatedProperties: false
-+ description: Input port for receiving DVP data.
-+
-+ properties:
-+ endpoint:
-+ $ref: video-interfaces.yaml#
-+ unevaluatedProperties: false
-+
-+ properties:
-+ bus-type:
-+ enum: [5, 6]
-+
-+ bus-width:
-+ enum: [8, 10, 12]
-+
-+ data-shift:
-+ enum: [0, 2]
-+ default: 0
-+
-+ hsync-active:
-+ enum: [0, 1]
-+ default: 1
-+
-+ vsync-active:
-+ enum: [0, 1]
-+ default: 1
-+
-+ required:
-+ - bus-type
-+ - bus-width
-+
-+ port@1:
-+ $ref: /schemas/graph.yaml#/properties/port
-+ description: Input port for receiving CSI data.
-+
-+ required:
-+ - port@0
-+ - port@1
-+
-+required:
-+ - compatible
-+ - reg
-+ - reg-names
-+ - clocks
-+ - clock-names
-+ - resets
-+ - reset-names
-+ - power-domains
-+ - interrupts
-+ - ports
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ vin_sysctl: vin_sysctl@19800000 {
-+ compatible = "starfive,jh7110-vin";
-+ reg = <0x0 0x19800000 0x0 0x10000>,
-+ <0x0 0x19810000 0x0 0x10000>,
-+ <0x0 0x19820000 0x0 0x10000>,
-+ <0x0 0x19840000 0x0 0x10000>,
-+ <0x0 0x19870000 0x0 0x30000>,
-+ <0x0 0x11840000 0x0 0x10000>,
-+ <0x0 0x17030000 0x0 0x10000>,
-+ <0x0 0x13020000 0x0 0x10000>;
-+ reg-names = "csi2rx", "vclk", "vrst", "sctrl",
-+ "isp", "trst", "pmu", "syscrg";
-+ clocks = <&clkisp JH7110_DOM4_APB_FUNC>,
-+ <&clkisp JH7110_U0_VIN_PCLK>,
-+ <&clkisp JH7110_U0_VIN_SYS_CLK>,
-+ <&clkisp JH7110_U0_ISPV2_TOP_WRAPPER_CLK_C>,
-+ <&clkisp JH7110_DVP_INV>,
-+ <&clkisp JH7110_U0_VIN_CLK_P_AXIWR>,
-+ <&clkisp JH7110_MIPI_RX0_PXL>,
-+ <&clkisp JH7110_U0_VIN_PIXEL_CLK_IF0>,
-+ <&clkisp JH7110_U0_VIN_PIXEL_CLK_IF1>,
-+ <&clkisp JH7110_U0_VIN_PIXEL_CLK_IF2>,
-+ <&clkisp JH7110_U0_VIN_PIXEL_CLK_IF3>,
-+ <&clkisp JH7110_U0_M31DPHY_CFGCLK_IN>,
-+ <&clkisp JH7110_U0_M31DPHY_REFCLK_IN>,
-+ <&clkisp JH7110_U0_M31DPHY_TXCLKESC_LAN0>,
-+ <&clkgen JH7110_ISP_TOP_CLK_ISPCORE_2X>,
-+ <&clkgen JH7110_ISP_TOP_CLK_ISP_AXI>;
-+ clock-names = "clk_apb_func", "clk_pclk", "clk_sys_clk",
-+ "clk_wrapper_clk_c", "clk_dvp_inv", "clk_axiwr",
-+ "clk_mipi_rx0_pxl", "clk_pixel_clk_if0",
-+ "clk_pixel_clk_if1", "clk_pixel_clk_if2",
-+ "clk_pixel_clk_if3", "clk_m31dphy_cfgclk_in",
-+ "clk_m31dphy_refclk_in", "clk_m31dphy_txclkesc_lan0",
-+ "clk_ispcore_2x", "clk_isp_axi";
-+ resets = <&rstgen RSTN_U0_ISPV2_TOP_WRAPPER_P>,
-+ <&rstgen RSTN_U0_ISPV2_TOP_WRAPPER_C>,
-+ <&rstgen RSTN_U0_VIN_N_PCLK>,
-+ <&rstgen RSTN_U0_VIN_N_SYS_CLK>,
-+ <&rstgen RSTN_U0_VIN_P_AXIRD>,
-+ <&rstgen RSTN_U0_VIN_P_AXIWR>,
-+ <&rstgen RSTN_U0_VIN_N_PIXEL_CLK_IF0>,
-+ <&rstgen RSTN_U0_VIN_N_PIXEL_CLK_IF1>,
-+ <&rstgen RSTN_U0_VIN_N_PIXEL_CLK_IF2>,
-+ <&rstgen RSTN_U0_VIN_N_PIXEL_CLK_IF3>,
-+ <&rstgen RSTN_U0_M31DPHY_HW>,
-+ <&rstgen RSTN_U0_M31DPHY_B09_ALWAYS_ON>,
-+ <&rstgen RSTN_U0_DOM_ISP_TOP_N>,
-+ <&rstgen RSTN_U0_DOM_ISP_TOP_AXI>;
-+ reset-names = "rst_wrapper_p", "rst_wrapper_c", "rst_pclk",
-+ "rst_sys_clk", "rst_axird", "rst_axiwr", "rst_pixel_clk_if0",
-+ "rst_pixel_clk_if1", "rst_pixel_clk_if2", "rst_pixel_clk_if3",
-+ "rst_m31dphy_hw", "rst_m31dphy_b09_always_on",
-+ "rst_isp_top_n", "rst_isp_top_axi";
-+ starfive,aon-syscon = <&aon_syscon 0x00>;
-+ power-domains = <&pwrc JH7110_PD_ISP>;
-+ /* irq nr: vin, isp, isp_csi, isp_scd, isp_csiline */
-+ interrupts = <92>, <87>, <88>, <89>, <90>;
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ port@0 {
-+ reg = <0>;
-+ vin_from_sc2235: endpoint {
-+ remote-endpoint = <&sc2235_to_vin>;
-+ bus-type = <5>;
-+ bus-width = <8>;
-+ data-shift = <2>;
-+ hsync-active = <1>;
-+ vsync-active = <0>;
-+ pclk-sample = <1>;
-+ };
-+ };
-+
-+ port@1 {
-+ reg = <1>;
-+ vin_from_csi2rx: endpoint {
-+ remote-endpoint = <&csi2rx_to_vin>;
-+ };
-+ };
-+ };
-+ };
+++ /dev/null
-From 908b10ebc95eb29caae8c4737b23a29af5c6298f Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Mon, 5 Jun 2023 13:54:16 +0800
-Subject: [PATCH 085/116] media: starfive: Add vin driver support
-
-Add vin driver support.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
----
- drivers/media/platform/Kconfig | 1 +
- drivers/media/platform/Makefile | 1 +
- drivers/media/platform/starfive/Kconfig | 56 +
- drivers/media/platform/starfive/Makefile | 24 +
- .../platform/starfive/v4l2_driver/Readme.txt | 11 +
- .../starfive/v4l2_driver/imx219_mipi.c | 1583 ++++++++
- .../starfive/v4l2_driver/ov13850_mipi.c | 1921 ++++++++++
- .../starfive/v4l2_driver/ov4689_mipi.c | 2975 +++++++++++++++
- .../platform/starfive/v4l2_driver/ov5640.c | 3227 +++++++++++++++++
- .../platform/starfive/v4l2_driver/sc2235.c | 1914 ++++++++++
- .../starfive/v4l2_driver/stf_common.h | 185 +
- .../platform/starfive/v4l2_driver/stf_csi.c | 465 +++
- .../platform/starfive/v4l2_driver/stf_csi.h | 61 +
- .../starfive/v4l2_driver/stf_csi_hw_ops.c | 310 ++
- .../starfive/v4l2_driver/stf_csiphy.c | 357 ++
- .../starfive/v4l2_driver/stf_csiphy.h | 188 +
- .../starfive/v4l2_driver/stf_csiphy_hw_ops.c | 335 ++
- .../starfive/v4l2_driver/stf_dmabuf.c | 123 +
- .../starfive/v4l2_driver/stf_dmabuf.h | 12 +
- .../platform/starfive/v4l2_driver/stf_dvp.c | 385 ++
- .../platform/starfive/v4l2_driver/stf_dvp.h | 67 +
- .../starfive/v4l2_driver/stf_dvp_hw_ops.c | 187 +
- .../platform/starfive/v4l2_driver/stf_event.c | 36 +
- .../platform/starfive/v4l2_driver/stf_isp.c | 1521 ++++++++
- .../platform/starfive/v4l2_driver/stf_isp.h | 222 ++
- .../starfive/v4l2_driver/stf_isp_hw_ops.c | 1550 ++++++++
- .../starfive/v4l2_driver/stf_isp_ioctl.h | 133 +
- .../platform/starfive/v4l2_driver/stf_video.c | 1552 ++++++++
- .../platform/starfive/v4l2_driver/stf_video.h | 83 +
- .../platform/starfive/v4l2_driver/stf_vin.c | 1515 ++++++++
- .../platform/starfive/v4l2_driver/stf_vin.h | 182 +
- .../starfive/v4l2_driver/stf_vin_hw_ops.c | 433 +++
- .../platform/starfive/v4l2_driver/stfcamss.c | 1369 +++++++
- .../platform/starfive/v4l2_driver/stfcamss.h | 117 +
- include/uapi/linux/jh7110-isp.h | 253 ++
- include/uapi/linux/v4l2-controls.h | 6 +
- include/video/stf-vin.h | 443 +++
- 37 files changed, 23803 insertions(+)
- create mode 100644 drivers/media/platform/starfive/Kconfig
- create mode 100644 drivers/media/platform/starfive/Makefile
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/Readme.txt
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/imx219_mipi.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/ov13850_mipi.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/ov4689_mipi.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/ov5640.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/sc2235.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_common.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_csi.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_csi.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_csi_hw_ops.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_csiphy.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_csiphy.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_csiphy_hw_ops.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_dmabuf.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_dmabuf.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_dvp.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_dvp.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_dvp_hw_ops.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_event.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_isp.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_isp.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_isp_hw_ops.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_isp_ioctl.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_video.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_video.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_vin.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_vin.h
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stfcamss.c
- create mode 100644 drivers/media/platform/starfive/v4l2_driver/stfcamss.h
- create mode 100644 include/uapi/linux/jh7110-isp.h
- create mode 100644 include/video/stf-vin.h
-
---- a/drivers/media/platform/Kconfig
-+++ b/drivers/media/platform/Kconfig
-@@ -80,6 +80,7 @@ source "drivers/media/platform/renesas/K
- source "drivers/media/platform/rockchip/Kconfig"
- source "drivers/media/platform/samsung/Kconfig"
- source "drivers/media/platform/st/Kconfig"
-+source "drivers/media/platform/starfive/Kconfig"
- source "drivers/media/platform/sunxi/Kconfig"
- source "drivers/media/platform/ti/Kconfig"
- source "drivers/media/platform/verisilicon/Kconfig"
---- a/drivers/media/platform/Makefile
-+++ b/drivers/media/platform/Makefile
-@@ -23,6 +23,7 @@ obj-y += renesas/
- obj-y += rockchip/
- obj-y += samsung/
- obj-y += st/
-+obj-y += starfive/
- obj-y += sunxi/
- obj-y += ti/
- obj-y += verisilicon/
---- /dev/null
-+++ b/drivers/media/platform/starfive/Kconfig
-@@ -0,0 +1,56 @@
-+# SPDX-License-Identifier: GPL-2.0-only
-+
-+comment "Starfive media platform drivers"
-+
-+config VIN_SENSOR_OV5640
-+ tristate "VIN SENSOR support OV5640"
-+ depends on VIDEO_STF_VIN
-+ select V4L2_FWNODE
-+ default n
-+ help
-+ Say Y here if you want to have support for VIN sensor OV5640
-+
-+config VIN_SENSOR_SC2235
-+ tristate "VIN SENSOR support SC2235"
-+ depends on VIDEO_STF_VIN
-+ select V4L2_FWNODE
-+ default n
-+ help
-+ Say Y here if you want to have support for VIN sensor SC2235
-+
-+config VIN_SENSOR_OV4689
-+ tristate "VIN SENSOR support OV4689"
-+ depends on VIDEO_STF_VIN
-+ select V4L2_FWNODE
-+ default n
-+
-+ help
-+ Say Y here if you want to have support for VIN sensor OV4689
-+
-+config VIN_SENSOR_OV13850
-+ bool "VIN SENSOR support OV13850"
-+ depends on VIDEO_STF_VIN
-+ select V4L2_FWNODE
-+ default n
-+ help
-+ Say Y here if you want to have support for VIN sensor OV13850
-+
-+config VIN_SENSOR_IMX219
-+ tristate "VIN SENSOR support IMX219"
-+ depends on VIDEO_STF_VIN
-+ select V4L2_FWNODE
-+ default n
-+ help
-+ Say Y here if you want to have support for VIN sensor IMX219
-+
-+config VIDEO_STF_VIN
-+ tristate "starfive VIC video in support"
-+ depends on V4L_PLATFORM_DRIVERS
-+ depends on VIDEO_DEV
-+ select MEDIA_CONTROLLER
-+ select VIDEOBUF2_DMA_CONTIG
-+ select VIDEO_V4L2_SUBDEV_API
-+ select V4L2_FWNODE
-+ help
-+ To compile this driver as a module, choose M here: the module
-+ will be called stf-vin.
---- /dev/null
-+++ b/drivers/media/platform/starfive/Makefile
-@@ -0,0 +1,24 @@
-+# SPDX-License-Identifier: GPL-2.0
-+
-+obj-$(CONFIG_VIN_SENSOR_OV5640) += v4l2_driver/ov5640.o
-+obj-$(CONFIG_VIN_SENSOR_SC2235) += v4l2_driver/sc2235.o
-+obj-$(CONFIG_VIN_SENSOR_OV4689) += v4l2_driver/ov4689_mipi.o
-+obj-$(CONFIG_VIN_SENSOR_OV13850) += v4l2_driver/ov13850_mipi.o
-+obj-$(CONFIG_VIN_SENSOR_IMX219) += v4l2_driver/imx219_mipi.o
-+
-+starfivecamss-objs += v4l2_driver/stfcamss.o \
-+ v4l2_driver/stf_event.o \
-+ v4l2_driver/stf_dvp.o \
-+ v4l2_driver/stf_csi.o \
-+ v4l2_driver/stf_csiphy.o \
-+ v4l2_driver/stf_isp.o \
-+ v4l2_driver/stf_video.o \
-+ v4l2_driver/stf_vin.o \
-+ v4l2_driver/stf_vin_hw_ops.o \
-+ v4l2_driver/stf_csi_hw_ops.o \
-+ v4l2_driver/stf_csiphy_hw_ops.o \
-+ v4l2_driver/stf_isp_hw_ops.o \
-+ v4l2_driver/stf_dvp_hw_ops.o \
-+ v4l2_driver/stf_dmabuf.o
-+
-+obj-$(CONFIG_VIDEO_STF_VIN) += starfivecamss.o \
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/Readme.txt
-@@ -0,0 +1,11 @@
-+
-+/dev/video0: Output the camera data directly.
-+/dev/video1: Output the data of the camera converted by isp.
-+
-+ensure linux/arch/riscv/configs/starfive_jh7110_defconfig:
-+CONFIG_VIDEO_STF_VIN=y
-+CONFIG_VIN_SENSOR_SC2235=y
-+CONFIG_VIN_SENSOR_OV4689=y
-+
-+Only support the lane0/lane5 of dphy as clock lane, lane1/lane2/lane3/lane4
-+as data lane.
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/imx219_mipi.c
-@@ -0,0 +1,1583 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * A V4L2 driver for Sony IMX219 cameras.
-+ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on Sony imx258 camera driver
-+ * Copyright (C) 2018 Intel Corporation
-+ *
-+ * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver
-+ * Copyright 2018 Qtechnology A/S
-+ *
-+ * Flip handling taken from the Sony IMX319 driver.
-+ * Copyright (C) 2018 Intel Corporation
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regulator/consumer.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-mediabus.h>
-+#include <asm/unaligned.h>
-+
-+#define IMX219_REG_VALUE_08BIT 1
-+#define IMX219_REG_VALUE_16BIT 2
-+
-+#define IMX219_REG_MODE_SELECT 0x0100
-+#define IMX219_MODE_STANDBY 0x00
-+#define IMX219_MODE_STREAMING 0x01
-+
-+/* Chip ID */
-+#define IMX219_REG_CHIP_ID 0x0000
-+#define IMX219_CHIP_ID 0x0219
-+
-+/* External clock frequency is 24.0M */
-+#define IMX219_XCLK_FREQ 24000000
-+
-+/* Pixel rate is fixed at 182.4M for all the modes */
-+#define IMX219_PIXEL_RATE 182400000
-+
-+#define IMX219_DEFAULT_LINK_FREQ 456000000
-+
-+/* V_TIMING internal */
-+#define IMX219_REG_VTS 0x0160
-+#define IMX219_VTS_15FPS 0x0dc6
-+#define IMX219_VTS_30FPS_1080P 0x06e3
-+#define IMX219_VTS_30FPS_BINNED 0x06e3
-+#define IMX219_VTS_30FPS_1280x720 0x06e3
-+#define IMX219_VTS_30FPS_640x480 0x06e3
-+#define IMX219_VTS_MAX 0xffff
-+
-+#define IMX219_VBLANK_MIN 4
-+
-+/*Frame Length Line*/
-+#define IMX219_FLL_MIN 0x08a6
-+#define IMX219_FLL_MAX 0xffff
-+#define IMX219_FLL_STEP 1
-+#define IMX219_FLL_DEFAULT 0x0c98
-+
-+/* HBLANK control - read only */
-+#define IMX219_PPL_DEFAULT 3448
-+
-+/* Exposure control */
-+#define IMX219_REG_EXPOSURE 0x015a
-+#define IMX219_EXPOSURE_MIN 4
-+#define IMX219_EXPOSURE_STEP 1
-+#define IMX219_EXPOSURE_DEFAULT 0x640
-+#define IMX219_EXPOSURE_MAX 65535
-+
-+/* Analog gain control */
-+#define IMX219_REG_ANALOG_GAIN 0x0157
-+#define IMX219_ANA_GAIN_MIN 0
-+#define IMX219_ANA_GAIN_MAX 232
-+#define IMX219_ANA_GAIN_STEP 1
-+#define IMX219_ANA_GAIN_DEFAULT 0xd0
-+
-+/* Digital gain control */
-+#define IMX219_REG_DIGITAL_GAIN 0x0158
-+#define IMX219_DGTL_GAIN_MIN 0x0100
-+#define IMX219_DGTL_GAIN_MAX 0x0fff
-+#define IMX219_DGTL_GAIN_DEFAULT 0x0100
-+#define IMX219_DGTL_GAIN_STEP 1
-+
-+#define IMX219_REG_ORIENTATION 0x0172
-+
-+/* Test Pattern Control */
-+#define IMX219_REG_TEST_PATTERN 0x0600
-+#define IMX219_TEST_PATTERN_DISABLE 0
-+#define IMX219_TEST_PATTERN_SOLID_COLOR 1
-+#define IMX219_TEST_PATTERN_COLOR_BARS 2
-+#define IMX219_TEST_PATTERN_GREY_COLOR 3
-+#define IMX219_TEST_PATTERN_PN9 4
-+
-+/* Test pattern colour components */
-+#define IMX219_REG_TESTP_RED 0x0602
-+#define IMX219_REG_TESTP_GREENR 0x0604
-+#define IMX219_REG_TESTP_BLUE 0x0606
-+#define IMX219_REG_TESTP_GREENB 0x0608
-+#define IMX219_TESTP_COLOUR_MIN 0
-+#define IMX219_TESTP_COLOUR_MAX 0x03ff
-+#define IMX219_TESTP_COLOUR_STEP 1
-+#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX
-+#define IMX219_TESTP_GREENR_DEFAULT 0
-+#define IMX219_TESTP_BLUE_DEFAULT 0
-+#define IMX219_TESTP_GREENB_DEFAULT 0
-+
-+/* IMX219 native and active pixel array size. */
-+#define IMX219_NATIVE_WIDTH 3296U
-+#define IMX219_NATIVE_HEIGHT 2480U
-+#define IMX219_PIXEL_ARRAY_LEFT 8U
-+#define IMX219_PIXEL_ARRAY_TOP 8U
-+#define IMX219_PIXEL_ARRAY_WIDTH 3280U
-+#define IMX219_PIXEL_ARRAY_HEIGHT 2464U
-+
-+struct imx219_reg {
-+ u16 address;
-+ u8 val;
-+};
-+
-+struct imx219_reg_list {
-+ unsigned int num_of_regs;
-+ const struct imx219_reg *regs;
-+};
-+
-+/* Mode : resolution and related config&values */
-+struct imx219_mode {
-+ /* Frame width */
-+ unsigned int width;
-+ /* Frame height */
-+ unsigned int height;
-+
-+ unsigned int fps;
-+
-+ /* Analog crop rectangle. */
-+ struct v4l2_rect crop;
-+
-+ /* V-timing */
-+ unsigned int vts_def;
-+
-+ /* Default register values */
-+ struct imx219_reg_list reg_list;
-+};
-+
-+/*
-+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
-+ * driver.
-+ * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
-+ */
-+
-+static const struct imx219_reg mode_1920_1080_regs[] = {
-+ {0x0100, 0x00},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x0c},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+ {0x0164, 0x02},
-+ {0x0165, 0xa8},
-+ {0x0166, 0x0a},
-+ {0x0167, 0x27},
-+ {0x0168, 0x02},
-+ {0x0169, 0xb4},
-+ {0x016a, 0x06},
-+ {0x016b, 0xeb},
-+ {0x016c, 0x07},
-+ {0x016d, 0x80},
-+ {0x016e, 0x04},
-+ {0x016f, 0x38},
-+ {0x0170, 0x01},
-+ {0x0171, 0x01},
-+ {0x0174, 0x00},
-+ {0x0175, 0x00},
-+ {0x0301, 0x05},
-+ {0x0303, 0x01},
-+ {0x0304, 0x03},
-+ {0x0305, 0x03},
-+ {0x0306, 0x00},
-+ {0x0307, 0x39},
-+ {0x030b, 0x01},
-+ {0x030c, 0x00},
-+ {0x030d, 0x72},
-+ {0x0624, 0x07},
-+ {0x0625, 0x80},
-+ {0x0626, 0x04},
-+ {0x0627, 0x38},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+};
-+
-+static const struct imx219_reg mode_1280_720_regs[] = {
-+ {0x0100, 0x00},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x0c},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+ {0x0164, 0x01},
-+ {0x0165, 0x68},
-+ {0x0166, 0x0b},
-+ {0x0167, 0x67},
-+ {0x0168, 0x02},
-+ {0x0169, 0x00},
-+ {0x016a, 0x07},
-+ {0x016b, 0x9f},
-+ {0x016c, 0x05},
-+ {0x016d, 0x00},
-+ {0x016e, 0x02},
-+ {0x016f, 0xd0},
-+ {0x0170, 0x01},
-+ {0x0171, 0x01},
-+ {0x0174, 0x01},
-+ {0x0175, 0x01},
-+ {0x0301, 0x05},
-+ {0x0303, 0x01},
-+ {0x0304, 0x03},
-+ {0x0305, 0x03},
-+ {0x0306, 0x00},
-+ {0x0307, 0x39},
-+ {0x030b, 0x01},
-+ {0x030c, 0x00},
-+ {0x030d, 0x72},
-+ {0x0624, 0x06},
-+ {0x0625, 0x68},
-+ {0x0626, 0x04},
-+ {0x0627, 0xd0},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+};
-+
-+static const struct imx219_reg mode_640_480_regs[] = {
-+ {0x0100, 0x00},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x0c},
-+ {0x300a, 0xff},
-+ {0x300b, 0xff},
-+ {0x30eb, 0x05},
-+ {0x30eb, 0x09},
-+ {0x0114, 0x01},
-+ {0x0128, 0x00},
-+ {0x012a, 0x18},
-+ {0x012b, 0x00},
-+ {0x0162, 0x0d},
-+ {0x0163, 0x78},
-+ {0x0164, 0x03},
-+ {0x0165, 0xe8},
-+ {0x0166, 0x08},
-+ {0x0167, 0xe7},
-+ {0x0168, 0x02},
-+ {0x0169, 0xf0},
-+ {0x016a, 0x06},
-+ {0x016b, 0xaf},
-+ {0x016c, 0x02},
-+ {0x016d, 0x80},
-+ {0x016e, 0x01},
-+ {0x016f, 0xe0},
-+ {0x0170, 0x01},
-+ {0x0171, 0x01},
-+ {0x0174, 0x03},
-+ {0x0175, 0x03},
-+ {0x0301, 0x05},
-+ {0x0303, 0x01},
-+ {0x0304, 0x03},
-+ {0x0305, 0x03},
-+ {0x0306, 0x00},
-+ {0x0307, 0x39},
-+ {0x030b, 0x01},
-+ {0x030c, 0x00},
-+ {0x030d, 0x72},
-+ {0x0624, 0x06},
-+ {0x0625, 0x68},
-+ {0x0626, 0x04},
-+ {0x0627, 0xd0},
-+ {0x455e, 0x00},
-+ {0x471e, 0x4b},
-+ {0x4767, 0x0f},
-+ {0x4750, 0x14},
-+ {0x4540, 0x00},
-+ {0x47b4, 0x14},
-+ {0x4713, 0x30},
-+ {0x478b, 0x10},
-+ {0x478f, 0x10},
-+ {0x4793, 0x10},
-+ {0x4797, 0x0e},
-+ {0x479b, 0x0e},
-+};
-+
-+static const struct imx219_reg raw8_framefmt_regs[] = {
-+ {0x018c, 0x08},
-+ {0x018d, 0x08},
-+ {0x0309, 0x08},
-+};
-+
-+static const struct imx219_reg raw10_framefmt_regs[] = {
-+ {0x018c, 0x0a},
-+ {0x018d, 0x0a},
-+ {0x0309, 0x0a},
-+};
-+
-+static const s64 imx219_link_freq_menu[] = {
-+ IMX219_DEFAULT_LINK_FREQ,
-+};
-+
-+static const char * const imx219_test_pattern_menu[] = {
-+ "Disabled",
-+ "Color Bars",
-+ "Solid Color",
-+ "Grey Color Bars",
-+ "PN9"
-+};
-+
-+static const int imx219_test_pattern_val[] = {
-+ IMX219_TEST_PATTERN_DISABLE,
-+ IMX219_TEST_PATTERN_COLOR_BARS,
-+ IMX219_TEST_PATTERN_SOLID_COLOR,
-+ IMX219_TEST_PATTERN_GREY_COLOR,
-+ IMX219_TEST_PATTERN_PN9,
-+};
-+
-+/* regulator supplies */
-+static const char * const imx219_supply_name[] = {
-+ /* Supplies can be enabled in any order */
-+ "VANA", /* Analog (2.8V) supply */
-+ "VDIG", /* Digital Core (1.8V) supply */
-+ "VDDL", /* IF (1.2V) supply */
-+};
-+
-+#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
-+
-+/*
-+ * The supported formats.
-+ * This table MUST contain 4 entries per format, to cover the various flip
-+ * combinations in the order
-+ * - no flip
-+ * - h flip
-+ * - v flip
-+ * - h&v flips
-+ */
-+static const u32 codes[] = {
-+ MEDIA_BUS_FMT_SRGGB10_1X10,
-+ MEDIA_BUS_FMT_SGRBG10_1X10,
-+ MEDIA_BUS_FMT_SGBRG10_1X10,
-+ MEDIA_BUS_FMT_SBGGR10_1X10,
-+
-+ MEDIA_BUS_FMT_SRGGB8_1X8,
-+ MEDIA_BUS_FMT_SGRBG8_1X8,
-+ MEDIA_BUS_FMT_SGBRG8_1X8,
-+ MEDIA_BUS_FMT_SBGGR8_1X8,
-+};
-+
-+/*
-+ * Initialisation delay between XCLR low->high and the moment when the sensor
-+ * can start capture (i.e. can leave software stanby) must be not less than:
-+ * t4 + max(t5, t6 + <time to initialize the sensor register over I2C>)
-+ * where
-+ * t4 is fixed, and is max 200uS,
-+ * t5 is fixed, and is 6000uS,
-+ * t6 depends on the sensor external clock, and is max 32000 clock periods.
-+ * As per sensor datasheet, the external clock must be from 6MHz to 27MHz.
-+ * So for any acceptable external clock t6 is always within the range of
-+ * 1185 to 5333 uS, and is always less than t5.
-+ * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then
-+ * initialize the sensor over I2C, and then exit the software standby.
-+ *
-+ * This start-up time can be optimized a bit more, if we start the writes
-+ * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor
-+ * initialization over I2C may complete before (t4+t5) expires, and we must
-+ * ensure that capture is not started before (t4+t5).
-+ *
-+ * This delay doesn't account for the power supply startup time. If needed,
-+ * this should be taken care of via the regulator framework. E.g. in the
-+ * case of DT for regulator-fixed one should define the startup-delay-us
-+ * property.
-+ */
-+#define IMX219_XCLR_MIN_DELAY_US 6200
-+#define IMX219_XCLR_DELAY_RANGE_US 1000
-+
-+/* Mode configs */
-+static const struct imx219_mode supported_modes[] = {
-+ {
-+ /* 1080P 30fps cropped */
-+ .width = 1920,
-+ .height = 1080,
-+ .fps = 30,
-+ .crop = {
-+ .left = 688,
-+ .top = 700,
-+ .width = 1920,
-+ .height = 1080
-+ },
-+ .vts_def = IMX219_VTS_30FPS_1080P,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
-+ .regs = mode_1920_1080_regs,
-+ },
-+ },
-+ {
-+ /* 1280x720 30fps mode */
-+ .width = 1280,
-+ .height = 720,
-+ .fps = 30,
-+ .crop = {
-+ .left = 360,
-+ .top = 512,
-+ .width = 2560,
-+ .height = 1440
-+ },
-+ .vts_def = IMX219_VTS_30FPS_1280x720,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_1280_720_regs),
-+ .regs = mode_1280_720_regs,
-+ },
-+ },
-+ {
-+ /* 640x480 30fps mode */
-+ .width = 640,
-+ .height = 480,
-+ .fps = 30,
-+ .crop = {
-+ .left = 1008,
-+ .top = 760,
-+ .width = 1280,
-+ .height = 960
-+ },
-+ .vts_def = IMX219_VTS_30FPS_640x480,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_640_480_regs),
-+ .regs = mode_640_480_regs,
-+ },
-+ },
-+};
-+
-+struct imx219 {
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+ //struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
-+
-+ struct v4l2_mbus_framefmt fmt;
-+
-+ struct clk *xclk; /* system clock to IMX219 */
-+ u32 xclk_freq;
-+
-+ struct gpio_desc *reset_gpio;
-+ struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
-+
-+ struct v4l2_ctrl_handler ctrl_handler;
-+ /* V4L2 Controls */
-+ struct v4l2_ctrl *pixel_rate;
-+ struct v4l2_ctrl *link_freq;
-+ struct v4l2_ctrl *exposure;
-+ struct v4l2_ctrl *vflip;
-+ struct v4l2_ctrl *hflip;
-+ struct v4l2_ctrl *vblank;
-+ struct v4l2_ctrl *hblank;
-+
-+ /* Current mode */
-+ const struct imx219_mode *mode;
-+ struct v4l2_fract frame_interval;
-+
-+ /*
-+ * Mutex for serialized access:
-+ * Protect sensor module set pad format and start/stop streaming safely.
-+ */
-+ struct mutex mutex;
-+
-+ /* Streaming on/off */
-+ int streaming;
-+};
-+
-+static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
-+{
-+ return container_of(_sd, struct imx219, sd);
-+}
-+
-+/* Read registers up to 2 at a time */
-+static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ struct i2c_msg msgs[2];
-+ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
-+ u8 data_buf[4] = { 0, };
-+ int ret;
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ /* Write register address */
-+ msgs[0].addr = client->addr;
-+ msgs[0].flags = 0;
-+ msgs[0].len = ARRAY_SIZE(addr_buf);
-+ msgs[0].buf = addr_buf;
-+
-+ /* Read data from register */
-+ msgs[1].addr = client->addr;
-+ msgs[1].flags = I2C_M_RD;
-+ msgs[1].len = len;
-+ msgs[1].buf = &data_buf[4 - len];
-+
-+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-+ if (ret != ARRAY_SIZE(msgs))
-+ return -EIO;
-+
-+ *val = get_unaligned_be32(data_buf);
-+
-+ return 0;
-+}
-+
-+/* Write registers up to 2 at a time */
-+static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ u8 buf[6];
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ put_unaligned_be16(reg, buf);
-+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
-+ if (i2c_master_send(client, buf, len + 2) != len + 2)
-+ return -EIO;
-+
-+ return 0;
-+}
-+
-+/* Write a list of registers */
-+static int imx219_write_regs(struct imx219 *imx219,
-+ const struct imx219_reg *regs, u32 len)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ unsigned int i;
-+ int ret;
-+
-+ for (i = 0; i < len; i++) {
-+ ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
-+ if (ret) {
-+ dev_err_ratelimited(&client->dev,
-+ "Failed to write reg 0x%4.4x. error = %d\n",
-+ regs[i].address, ret);
-+
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/* Get bayer order based on flip setting. */
-+static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
-+{
-+ unsigned int i;
-+
-+ lockdep_assert_held(&imx219->mutex);
-+
-+ for (i = 0; i < ARRAY_SIZE(codes); i++)
-+ if (codes[i] == code)
-+ break;
-+
-+ if (i >= ARRAY_SIZE(codes))
-+ i = 0;
-+
-+ i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
-+ (imx219->hflip->val ? 1 : 0);
-+
-+ return codes[i];
-+}
-+
-+static void imx219_set_default_format(struct imx219 *imx219)
-+{
-+ struct v4l2_mbus_framefmt *fmt;
-+
-+ fmt = &imx219->fmt;
-+ fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
-+ fmt->colorspace, fmt->ycbcr_enc);
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+ fmt->width = supported_modes[0].width;
-+ fmt->height = supported_modes[0].height;
-+ fmt->field = V4L2_FIELD_NONE;
-+}
-+
-+static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ struct v4l2_mbus_framefmt *try_fmt =
-+ v4l2_subdev_get_try_format(sd, fh->state, 0);
-+ struct v4l2_rect *try_crop;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ /* Initialize try_fmt */
-+ try_fmt->width = supported_modes[0].width;
-+ try_fmt->height = supported_modes[0].height;
-+ try_fmt->code = imx219_get_format_code(imx219, MEDIA_BUS_FMT_SRGGB10_1X10);
-+ try_fmt->field = V4L2_FIELD_NONE;
-+
-+ /* Initialize try_crop rectangle. */
-+ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
-+ try_crop->top = IMX219_PIXEL_ARRAY_TOP;
-+ try_crop->left = IMX219_PIXEL_ARRAY_LEFT;
-+ try_crop->width = IMX219_PIXEL_ARRAY_WIDTH;
-+ try_crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
-+
-+ mutex_unlock(&imx219->mutex);
-+
-+ return 0;
-+}
-+
-+static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct imx219 *imx219 =
-+ container_of(ctrl->handler, struct imx219, ctrl_handler);
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+
-+ if (ctrl->id == V4L2_CID_VBLANK) {
-+ int exposure_max, exposure_def;
-+
-+ /* Update max exposure while meeting expected vblanking */
-+ exposure_max = imx219->mode->height + ctrl->val - 4;
-+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
-+ exposure_max : IMX219_EXPOSURE_DEFAULT;
-+ __v4l2_ctrl_modify_range(imx219->exposure, imx219->exposure->minimum,
-+ exposure_max, imx219->exposure->step, exposure_def);
-+ }
-+
-+ /*
-+ * Applying V4L2 control value only happens
-+ * when power is up for streaming
-+ */
-+ if (pm_runtime_get_if_in_use(&client->dev) == 0)
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
-+ IMX219_REG_VALUE_08BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE:
-+ ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_DIGITAL_GAIN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
-+ IMX219_REG_VALUE_16BIT, imx219_test_pattern_val[ctrl->val]);
-+ break;
-+ case V4L2_CID_HFLIP:
-+ case V4L2_CID_VFLIP:
-+ ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1,
-+ imx219->hflip->val | imx219->vflip->val << 1);
-+ break;
-+ case V4L2_CID_VBLANK:
-+ ret = imx219_write_reg(imx219, IMX219_REG_VTS, IMX219_REG_VALUE_16BIT,
-+ imx219->mode->height + ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_RED:
-+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_GREENR:
-+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_BLUE:
-+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_GREENB:
-+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB,
-+ IMX219_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ default:
-+ dev_info(&client->dev,
-+ "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val);
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ pm_runtime_put(&client->dev);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
-+ .s_ctrl = imx219_set_ctrl,
-+};
-+
-+static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ if (code->index >= (ARRAY_SIZE(codes) / 4))
-+ return -EINVAL;
-+
-+ mutex_lock(&imx219->mutex);
-+ code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
-+ mutex_unlock(&imx219->mutex);
-+
-+ return 0;
-+}
-+
-+static int imx219_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ u32 code;
-+
-+ if (fse->index >= ARRAY_SIZE(supported_modes))
-+ return -EINVAL;
-+
-+ mutex_lock(&imx219->mutex);
-+ code = imx219_get_format_code(imx219, fse->code);
-+ mutex_unlock(&imx219->mutex);
-+ if (fse->code != code)
-+ return -EINVAL;
-+
-+ fse->min_width = supported_modes[fse->index].width;
-+ fse->max_width = fse->min_width;
-+ fse->min_height = supported_modes[fse->index].height;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static int imx219_try_frame_interval(struct imx219 *imx219,
-+ struct v4l2_fract *fi,
-+ u32 w, u32 h)
-+{
-+ const struct imx219_mode *mode;
-+
-+ mode = v4l2_find_nearest_size(supported_modes, ARRAY_SIZE(supported_modes),
-+ width, height, w, h);
-+ if (!mode || (mode->width != w || mode->height != h))
-+ return -EINVAL;
-+
-+ fi->numerator = 1;
-+ fi->denominator = mode->fps;
-+
-+ return mode->fps;
-+}
-+
-+static int imx219_enum_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_interval_enum *fie)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ struct v4l2_fract tpf;
-+ u32 code;
-+ int ret;
-+
-+ if (fie->index >= ARRAY_SIZE(supported_modes))
-+ return -EINVAL;
-+
-+ mutex_lock(&imx219->mutex);
-+ code = imx219_get_format_code(imx219, fie->code);
-+ if (fie->code != code) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ ret = imx219_try_frame_interval(imx219, &tpf,
-+ fie->width, fie->height);
-+ if (ret < 0) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ mutex_unlock(&imx219->mutex);
-+ fie->interval = tpf;
-+
-+ return 0;
-+
-+out:
-+ mutex_unlock(&imx219->mutex);
-+ return ret;
-+}
-+
-+static int imx219_g_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ mutex_lock(&imx219->mutex);
-+ fi->interval = imx219->frame_interval;
-+ mutex_unlock(&imx219->mutex);
-+
-+ return 0;
-+}
-+
-+static int imx219_s_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ const struct imx219_mode *mode = imx219->mode;
-+ int frame_rate, ret = 0;
-+
-+ if (fi->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ if (imx219->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ frame_rate = imx219_try_frame_interval(imx219, &fi->interval,
-+ mode->width, mode->height);
-+ if (frame_rate < 0) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ imx219->frame_interval = fi->interval;
-+
-+out:
-+ mutex_unlock(&imx219->mutex);
-+ return ret;
-+}
-+
-+static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
-+{
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
-+ fmt->colorspace, fmt->ycbcr_enc);
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+}
-+
-+static void imx219_update_pad_format(struct imx219 *imx219,
-+ const struct imx219_mode *mode,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ fmt->format.width = mode->width;
-+ fmt->format.height = mode->height;
-+ fmt->format.field = V4L2_FIELD_NONE;
-+ imx219_reset_colorspace(&fmt->format);
-+}
-+
-+static int __imx219_get_pad_format(struct imx219 *imx219,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-+ struct v4l2_mbus_framefmt *try_fmt =
-+ v4l2_subdev_get_try_format(&imx219->sd, state, fmt->pad);
-+ /* update the code which could change due to vflip or hflip: */
-+ try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
-+ fmt->format = *try_fmt;
-+ } else {
-+ imx219_update_pad_format(imx219, imx219->mode, fmt);
-+ fmt->format.code = imx219_get_format_code(imx219, imx219->fmt.code);
-+ }
-+
-+ return 0;
-+}
-+
-+static int imx219_get_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret;
-+
-+ mutex_lock(&imx219->mutex);
-+ ret = __imx219_get_pad_format(imx219, state, fmt);
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static int imx219_set_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ const struct imx219_mode *mode;
-+ struct v4l2_mbus_framefmt *framefmt;
-+ int exposure_max, exposure_def, hblank;
-+ unsigned int i;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ for (i = 0; i < ARRAY_SIZE(codes); i++)
-+ if (codes[i] == fmt->format.code)
-+ break;
-+ if (i >= ARRAY_SIZE(codes))
-+ i = 0;
-+
-+ /* Bayer order varies with flips */
-+ fmt->format.code = imx219_get_format_code(imx219, codes[i]);
-+
-+ mode = v4l2_find_nearest_size(supported_modes, ARRAY_SIZE(supported_modes),
-+ width, height, fmt->format.width, fmt->format.height);
-+ imx219_update_pad_format(imx219, mode, fmt);
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-+ framefmt = v4l2_subdev_get_try_format(sd, state, fmt->pad);
-+ *framefmt = fmt->format;
-+ } else if (imx219->mode != mode ||
-+ imx219->fmt.code != fmt->format.code) {
-+ imx219->fmt = fmt->format;
-+ imx219->mode = mode;
-+ /* Update limits and set FPS to default */
-+ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
-+ IMX219_VTS_MAX - mode->height, 1,
-+ mode->vts_def - mode->height);
-+ __v4l2_ctrl_s_ctrl(imx219->vblank, mode->vts_def - mode->height);
-+ /* Update max exposure while meeting expected vblanking */
-+ exposure_max = mode->vts_def - 4;
-+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
-+ exposure_max : IMX219_EXPOSURE_DEFAULT;
-+ __v4l2_ctrl_modify_range(imx219->exposure, imx219->exposure->minimum,
-+ exposure_max, imx219->exposure->step, exposure_def);
-+ /*
-+ * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
-+ * depends on mode->width only, and is not changeble in any
-+ * way other than changing the mode.
-+ */
-+ hblank = IMX219_PPL_DEFAULT - mode->width;
-+ __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, hblank);
-+ }
-+
-+ mutex_unlock(&imx219->mutex);
-+
-+ return 0;
-+}
-+
-+static int imx219_set_framefmt(struct imx219 *imx219)
-+{
-+ switch (imx219->fmt.code) {
-+ case MEDIA_BUS_FMT_SRGGB8_1X8:
-+ case MEDIA_BUS_FMT_SGRBG8_1X8:
-+ case MEDIA_BUS_FMT_SGBRG8_1X8:
-+ case MEDIA_BUS_FMT_SBGGR8_1X8:
-+ return imx219_write_regs(imx219, raw8_framefmt_regs,
-+ ARRAY_SIZE(raw8_framefmt_regs));
-+
-+ case MEDIA_BUS_FMT_SRGGB10_1X10:
-+ case MEDIA_BUS_FMT_SGRBG10_1X10:
-+ case MEDIA_BUS_FMT_SGBRG10_1X10:
-+ case MEDIA_BUS_FMT_SBGGR10_1X10:
-+ return imx219_write_regs(imx219, raw10_framefmt_regs,
-+ ARRAY_SIZE(raw10_framefmt_regs));
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static const struct v4l2_rect *
-+__imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_state *state,
-+ unsigned int pad, enum v4l2_subdev_format_whence which)
-+{
-+ switch (which) {
-+ case V4L2_SUBDEV_FORMAT_TRY:
-+ return v4l2_subdev_get_try_crop(&imx219->sd, state, pad);
-+ case V4L2_SUBDEV_FORMAT_ACTIVE:
-+ return &imx219->mode->crop;
-+ }
-+
-+ return NULL;
-+}
-+
-+static int imx219_get_selection(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_selection *sel)
-+{
-+ switch (sel->target) {
-+ case V4L2_SEL_TGT_CROP: {
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ mutex_lock(&imx219->mutex);
-+ sel->r = *__imx219_get_pad_crop(imx219, state, sel->pad, sel->which);
-+ mutex_unlock(&imx219->mutex);
-+ return 0;
-+ }
-+
-+ case V4L2_SEL_TGT_NATIVE_SIZE:
-+ sel->r.top = 0;
-+ sel->r.left = 0;
-+ sel->r.width = IMX219_NATIVE_WIDTH;
-+ sel->r.height = IMX219_NATIVE_HEIGHT;
-+ return 0;
-+
-+ case V4L2_SEL_TGT_CROP_DEFAULT:
-+ case V4L2_SEL_TGT_CROP_BOUNDS:
-+ sel->r.top = IMX219_PIXEL_ARRAY_TOP;
-+ sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
-+ sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
-+ sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT;
-+ return 0;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static int imx219_start_streaming(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ const struct imx219_reg_list *reg_list;
-+ int ret;
-+
-+ /* Apply default values of current mode */
-+ reg_list = &imx219->mode->reg_list;
-+ ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
-+ if (ret) {
-+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
-+ goto err;
-+ }
-+
-+ ret = imx219_set_framefmt(imx219);
-+ if (ret) {
-+ dev_err(&client->dev, "%s failed to set frame format: %d\n",
-+ __func__, ret);
-+ goto err;
-+ }
-+
-+ /* Apply customized values from user */
-+ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
-+ if (ret)
-+ goto err;
-+
-+ /* set stream on register */
-+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
-+ if (ret)
-+ goto err;
-+
-+ /* vflip and hflip cannot change during streaming */
-+ __v4l2_ctrl_grab(imx219->vflip, true);
-+ __v4l2_ctrl_grab(imx219->hflip, true);
-+
-+ return 0;
-+
-+err:
-+ return ret;
-+}
-+
-+static void imx219_stop_streaming(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+
-+ /* set stream off register */
-+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
-+ if (ret)
-+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
-+
-+ __v4l2_ctrl_grab(imx219->vflip, false);
-+ __v4l2_ctrl_grab(imx219->hflip, false);
-+}
-+
-+static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct imx219 *imx219 = to_imx219(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&imx219->mutex);
-+
-+ if (enable) {
-+ ret = pm_runtime_get_sync(&client->dev);
-+ if (ret < 0) {
-+ pm_runtime_put_noidle(&client->dev);
-+ mutex_unlock(&imx219->mutex);
-+ return ret;
-+ }
-+
-+ if (imx219->streaming)
-+ goto unlock;
-+
-+ /*
-+ * Apply default & customized values
-+ * and then start streaming.
-+ */
-+ ret = imx219_start_streaming(imx219);
-+ if (ret)
-+ goto err_unlock;
-+ } else {
-+ imx219_stop_streaming(imx219);
-+ pm_runtime_put(&client->dev);
-+ }
-+
-+unlock:
-+ imx219->streaming += enable ? 1 : -1;
-+ WARN_ON(imx219->streaming < 0);
-+
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+
-+err_unlock:
-+ pm_runtime_put(&client->dev);
-+ mutex_unlock(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+/* Power/clock management functions */
-+static int imx219_power_on(struct device *dev)
-+{
-+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
-+ struct imx219 *imx219 = to_imx219(sd);
-+ int ret;
-+
-+ ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, imx219->supplies);
-+ if (ret) {
-+ dev_err(dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = clk_prepare_enable(imx219->xclk);
-+ if (ret) {
-+ dev_err(dev, "%s: failed to enable clock\n", __func__);
-+ goto reg_off;
-+ }
-+
-+ gpiod_set_value_cansleep(imx219->reset_gpio, 1);
-+ usleep_range(IMX219_XCLR_MIN_DELAY_US,
-+ IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
-+
-+ return 0;
-+
-+reg_off:
-+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
-+
-+ return ret;
-+}
-+
-+static int imx219_power_off(struct device *dev)
-+{
-+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ gpiod_set_value_cansleep(imx219->reset_gpio, 0);
-+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
-+ clk_disable_unprepare(imx219->xclk);
-+
-+ return 0;
-+}
-+
-+static int imx219_get_regulators(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ unsigned int i;
-+
-+ for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
-+ imx219->supplies[i].supply = imx219_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&client->dev,
-+ IMX219_NUM_SUPPLIES, imx219->supplies);
-+}
-+
-+/* Verify chip ID */
-+static int imx219_identify_module(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ int ret;
-+ u32 val;
-+
-+ ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
-+ IMX219_REG_VALUE_16BIT, &val);
-+ if (ret) {
-+ dev_err(&client->dev, "failed to read chip id %x\n",
-+ IMX219_CHIP_ID);
-+ return ret;
-+ }
-+
-+ if (val != IMX219_CHIP_ID) {
-+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
-+ IMX219_CHIP_ID, val);
-+ return -EIO;
-+ }
-+
-+ dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
-+ __func__, IMX219_CHIP_ID);
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_core_ops imx219_core_ops = {
-+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops imx219_video_ops = {
-+ .g_frame_interval = imx219_g_frame_interval,
-+ .s_frame_interval = imx219_s_frame_interval,
-+ .s_stream = imx219_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
-+ .enum_mbus_code = imx219_enum_mbus_code,
-+ .get_fmt = imx219_get_pad_format,
-+ .set_fmt = imx219_set_pad_format,
-+ .get_selection = imx219_get_selection,
-+ .enum_frame_size = imx219_enum_frame_size,
-+ .enum_frame_interval = imx219_enum_frame_interval,
-+};
-+
-+static const struct v4l2_subdev_ops imx219_subdev_ops = {
-+ .core = &imx219_core_ops,
-+ .video = &imx219_video_ops,
-+ .pad = &imx219_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
-+ .open = imx219_open,
-+};
-+
-+/* Initialize control handlers */
-+static int imx219_init_controls(struct imx219 *imx219)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
-+ struct v4l2_ctrl_handler *ctrl_hdlr;
-+ unsigned int height = imx219->mode->height;
-+ struct v4l2_fwnode_device_properties props;
-+ int exposure_max, exposure_def, hblank;
-+ int i, ret;
-+
-+ ctrl_hdlr = &imx219->ctrl_handler;
-+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
-+ if (ret)
-+ return ret;
-+
-+ mutex_init(&imx219->mutex);
-+ ctrl_hdlr->lock = &imx219->mutex;
-+
-+ /* By default, PIXEL_RATE is read only */
-+ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_PIXEL_RATE, IMX219_PIXEL_RATE,
-+ IMX219_PIXEL_RATE, 1, IMX219_PIXEL_RATE);
-+
-+ imx219->link_freq =
-+ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_LINK_FREQ,
-+ ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, imx219_link_freq_menu);
-+ if (imx219->link_freq)
-+ imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+
-+ /* Initial vblank/hblank/exposure parameters based on current mode */
-+ imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
-+ IMX219_VTS_MAX - height, 1,
-+ imx219->mode->vts_def - height);
-+ hblank = IMX219_PPL_DEFAULT - imx219->mode->width;
-+ imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_HBLANK, hblank, hblank, 1, hblank);
-+ if (imx219->hblank)
-+ imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ exposure_max = imx219->mode->vts_def - 4;
-+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
-+ exposure_max : IMX219_EXPOSURE_DEFAULT;
-+ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_EXPOSURE, IMX219_EXPOSURE_MIN, exposure_max,
-+ IMX219_EXPOSURE_STEP, exposure_def);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
-+ IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
-+ IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
-+ IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
-+ IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
-+
-+ imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_HFLIP, 0, 1, 1, 0);
-+ if (imx219->hflip)
-+ imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
-+
-+ imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_VFLIP, 0, 1, 1, 0);
-+ if (imx219->vflip)
-+ imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
-+
-+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(imx219_test_pattern_menu) - 1,
-+ 0, 0, imx219_test_pattern_menu);
-+ for (i = 0; i < 4; i++) {
-+ /*
-+ * The assumption is that
-+ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
-+ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
-+ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
-+ */
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
-+ V4L2_CID_TEST_PATTERN_RED + i,
-+ IMX219_TESTP_COLOUR_MIN,
-+ IMX219_TESTP_COLOUR_MAX,
-+ IMX219_TESTP_COLOUR_STEP,
-+ IMX219_TESTP_COLOUR_MAX);
-+ /* The "Solid color" pattern is white by default */
-+ }
-+
-+ if (ctrl_hdlr->error) {
-+ ret = ctrl_hdlr->error;
-+ dev_err(&client->dev, "%s control init failed (%d)\n",
-+ __func__, ret);
-+ goto error;
-+ }
-+
-+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
-+ if (ret)
-+ goto error;
-+
-+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, &props);
-+ if (ret)
-+ goto error;
-+
-+ imx219->sd.ctrl_handler = ctrl_hdlr;
-+
-+ return 0;
-+
-+error:
-+ v4l2_ctrl_handler_free(ctrl_hdlr);
-+ mutex_destroy(&imx219->mutex);
-+
-+ return ret;
-+}
-+
-+static void imx219_free_controls(struct imx219 *imx219)
-+{
-+ v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
-+ mutex_destroy(&imx219->mutex);
-+}
-+
-+static int imx219_check_hwcfg(struct device *dev)
-+{
-+ struct fwnode_handle *endpoint;
-+ struct v4l2_fwnode_endpoint ep_cfg = {
-+ .bus_type = V4L2_MBUS_CSI2_DPHY
-+ };
-+ int ret = -EINVAL;
-+
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
-+ dev_err(dev, "could not parse endpoint\n");
-+ goto error_out;
-+ }
-+
-+ /* Check the number of MIPI CSI2 data lanes */
-+ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
-+ dev_err(dev, "only 2 data lanes are currently supported\n");
-+ goto error_out;
-+ }
-+
-+ /* Check the link frequency set in device tree */
-+ if (!ep_cfg.nr_of_link_frequencies) {
-+ dev_err(dev, "link-frequency property not found in DT\n");
-+ goto error_out;
-+ }
-+
-+ if (ep_cfg.nr_of_link_frequencies != 1 ||
-+ ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
-+ dev_err(dev, "Link frequency not supported: %lld\n",
-+ ep_cfg.link_frequencies[0]);
-+ goto error_out;
-+ }
-+
-+ ret = 0;
-+
-+error_out:
-+ v4l2_fwnode_endpoint_free(&ep_cfg);
-+ fwnode_handle_put(endpoint);
-+
-+ return ret;
-+}
-+
-+static int imx219_probe(struct i2c_client *client)
-+{
-+ struct device *dev = &client->dev;
-+ struct imx219 *imx219;
-+ int ret;
-+
-+ imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
-+ if (!imx219)
-+ return -ENOMEM;
-+
-+ v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
-+
-+ /* Check the hardware configuration in device tree */
-+ if (imx219_check_hwcfg(dev))
-+ return -EINVAL;
-+
-+ /* Get system clock (xclk) */
-+ imx219->xclk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(imx219->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(imx219->xclk);
-+ }
-+
-+ imx219->xclk_freq = clk_get_rate(imx219->xclk);
-+ if (imx219->xclk_freq != IMX219_XCLK_FREQ) {
-+ dev_err(dev, "xclk frequency not supported: %d Hz\n",
-+ imx219->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ ret = imx219_get_regulators(imx219);
-+ if (ret) {
-+ dev_err(dev, "failed to get regulators\n");
-+ return ret;
-+ }
-+
-+ /* Request optional enable pin */
-+ imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
-+ usleep_range(IMX219_XCLR_MIN_DELAY_US,
-+ IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
-+
-+ /*
-+ * The sensor must be powered for imx219_identify_module()
-+ * to be able to read the CHIP_ID register
-+ */
-+ ret = imx219_power_on(dev);
-+ if (ret)
-+ return ret;
-+
-+ ret = imx219_identify_module(imx219);
-+ if (ret)
-+ goto error_power_off;
-+
-+ /* Set default mode to max resolution */
-+ imx219->mode = &supported_modes[0];
-+ imx219->frame_interval.numerator = 1;
-+ imx219->frame_interval.denominator = supported_modes[0].fps;
-+
-+ /* sensor doesn't enter LP-11 state upon power up until and unless
-+ * streaming is started, so upon power up switch the modes to:
-+ * streaming -> standby
-+ */
-+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
-+ if (ret < 0)
-+ goto error_power_off;
-+ usleep_range(100, 110);
-+
-+ /* put sensor back to standby mode */
-+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
-+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
-+ if (ret < 0)
-+ goto error_power_off;
-+ usleep_range(100, 110);
-+
-+ ret = imx219_init_controls(imx219);
-+ if (ret)
-+ goto error_power_off;
-+
-+ /* Initialize subdev */
-+ imx219->sd.internal_ops = &imx219_internal_ops;
-+ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
-+ imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+
-+ /* Initialize source pad */
-+ imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
-+
-+ /* Initialize default format */
-+ imx219_set_default_format(imx219);
-+
-+ ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
-+ if (ret) {
-+ dev_err(dev, "failed to init entity pads: %d\n", ret);
-+ goto error_handler_free;
-+ }
-+
-+ ret = v4l2_async_register_subdev_sensor(&imx219->sd);
-+ if (ret < 0) {
-+ dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
-+ goto error_media_entity;
-+ }
-+
-+ /* Enable runtime PM and turn off the device */
-+ pm_runtime_set_active(dev);
-+ pm_runtime_enable(dev);
-+ pm_runtime_idle(dev);
-+
-+ return 0;
-+
-+error_media_entity:
-+ media_entity_cleanup(&imx219->sd.entity);
-+
-+error_handler_free:
-+ imx219_free_controls(imx219);
-+
-+error_power_off:
-+ imx219_power_off(dev);
-+
-+ return ret;
-+}
-+
-+static void imx219_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx219 *imx219 = to_imx219(sd);
-+
-+ v4l2_async_unregister_subdev(sd);
-+ media_entity_cleanup(&sd->entity);
-+ imx219_free_controls(imx219);
-+
-+ pm_runtime_disable(&client->dev);
-+ if (!pm_runtime_status_suspended(&client->dev))
-+ imx219_power_off(&client->dev);
-+ pm_runtime_set_suspended(&client->dev);
-+}
-+
-+static const struct of_device_id imx219_dt_ids[] = {
-+ { .compatible = "sony,imx219" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, imx219_dt_ids);
-+
-+static const struct dev_pm_ops imx219_pm_ops = {
-+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
-+ SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL)
-+};
-+
-+static struct i2c_driver imx219_i2c_driver = {
-+ .driver = {
-+ .name = "imx219",
-+ .of_match_table = imx219_dt_ids,
-+ .pm = &imx219_pm_ops,
-+ },
-+ .probe = imx219_probe,
-+ .remove = imx219_remove,
-+};
-+
-+module_i2c_driver(imx219_i2c_driver);
-+
-+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com");
-+MODULE_DESCRIPTION("Sony IMX219 sensor driver");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/ov13850_mipi.c
-@@ -0,0 +1,1921 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/ctype.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+#include "stfcamss.h"
-+
-+#define OV13850_XCLK_MIN 6000000
-+#define OV13850_XCLK_MAX 54000000
-+
-+#define OV13850_LINK_FREQ_500MHZ 500000000LL
-+
-+/**
-+ *OV13850 PLL
-+ *
-+ *PLL1:
-+ *
-+ *REF_CLK -> /PREDIVP[0] -> /PREDIV[2:0] -> *DIVP[9:8,7:0] -> /DIVM[3:0] -> /DIV_MIPI[1:0] -> PCLK
-+ *(6-64M) 0x030A 0x0300 0x0301,0x302 0x0303 0x0304
-+ * `-> MIPI_PHY_CLK
-+ *
-+ *
-+ *PLL2:
-+ * 000: 1
-+ * 001: 1.5
-+ * 010: 2
-+ * 011: 2.5
-+ * 100: 3
-+ * 101: 4
-+ * 0: /1 110: 6
-+ * 1: /2 111: 8
-+ *REF_CLK -> /PREDIVP[3] -> /PREDIV[2:0] -> /DIVP[9:0] -> /DIVDAC[3:0] -> DAC_CLK =
-+ *(6~64M) 0x3611
-+ * -> /DIVSP[3:0] -> /DIVS[2:0] -> SCLK
-+ *
-+ * -> /(1+DIVSRAM[3:0]) -> SRAM_CLK
-+ */
-+
-+// PREDIVP
-+#define OV13850_REG_PLL1_PREDIVP 0x030a
-+#define OV13850_PREDIVP_1 0
-+#define OV13850_PREDIVP_2 1
-+
-+// PREDIV
-+#define OV13850_REG_PLL1_PREDIV 0x0300
-+#define OV13850_PREDIV_1 0
-+#define OV13850_PREDIV_1_5 1
-+#define OV13850_PREDIV_2 2
-+#define OV13850_PREDIV_2_5 3
-+#define OV13850_PREDIV_3 4
-+#define OV13850_PREDIV_4 5
-+#define OV13850_PREDIV_6 6
-+#define OV13850_PREDIV_8 7
-+
-+// DIVP
-+#define OV13850_REG_PLL1_DIVP_H 0x0301
-+#define OV13850_REG_PLL1_DIVP_L 0x0302
-+#define OV13850_REG_PLL1_DIVP OV13850_REG_PLL1_DIVP_H
-+
-+// DIVM
-+#define OV13850_REG_PLL1_DIVM 0x0303
-+#define OV13850_DIVM(n) ((n)-1) // n=1~16
-+
-+// DIV_MIPI
-+#define OV13850_REG_PLL1_DIV_MIPI 0x0304
-+#define OV13850_DIV_MIPI_4 0
-+#define OV13850_DIV_MIPI_5 1
-+#define OV13850_DIV_MIPI_6 2
-+#define OV13850_DIV_MIPI_8 3
-+
-+// system control
-+#define OV13850_STREAM_CTRL 0x0100
-+#define OV13850_REG_MIPI_SC 0x300f
-+#define OV13850_MIPI_SC_8_BIT 0x0
-+#define OV13850_MIPI_SC_10_BIT 0x1
-+#define OV13850_MIPI_SC_12_BIT 0x2
-+#define OV13850_GET_MIPI_SC_MIPI_BIT(v) ((v) & 0x3)
-+#define OV13850_REG_MIPI_SC_CTRL0 0x3012
-+#define OV13850_GET_MIPI_SC_CTRL0_LANE_NUM(v) ((v)>>4 & 0xf)
-+
-+// timing
-+#define OV13850_REG_H_CROP_START_H 0x3800
-+#define OV13850_REG_H_CROP_START_L 0x3801
-+#define OV13850_REG_H_CROP_START OV13850_REG_H_CROP_START_H
-+#define OV13850_REG_V_CROP_START_H 0x3802
-+#define OV13850_REG_V_CROP_START_L 0x3803
-+#define OV13850_REG_V_CROP_START OV13850_REG_V_CROP_START_H
-+
-+#define OV13850_REG_H_CROP_END_H 0x3804
-+#define OV13850_REG_H_CROP_END_L 0x3805
-+#define OV13850_REG_H_CROP_END OV13850_REG_H_CROP_END_H
-+#define OV13850_REG_V_CROP_END_H 0x3806
-+#define OV13850_REG_V_CROP_END_L 0x3807
-+#define OV13850_REG_V_CROP_END OV13850_REG_V_CROP_END_H
-+
-+#define OV13850_REG_H_OUTPUT_SIZE_H 0x3808
-+#define OV13850_REG_H_OUTPUT_SIZE_L 0x3809
-+#define OV13850_REG_H_OUTPUT_SIZE OV13850_REG_H_OUTPUT_SIZE_H
-+#define OV13850_REG_V_OUTPUT_SIZE_H 0x380a
-+#define OV13850_REG_V_OUTPUT_SIZE_L 0x380b
-+#define OV13850_REG_V_OUTPUT_SIZE OV13850_REG_V_OUTPUT_SIZE_H
-+
-+#define OV13850_REG_TIMING_HTS_H 0x380c
-+#define OV13850_REG_TIMING_HTS_L 0x380d
-+#define OV13850_REG_TIMING_HTS OV13850_REG_TIMING_HTS_H
-+#define OV13850_REG_TIMING_VTS_H 0x380e
-+#define OV13850_REG_TIMING_VTS_L 0x380f
-+#define OV13850_REG_TIMING_VTS OV13850_REG_TIMING_VTS_H
-+
-+
-+#define OV13850_REG_H_WIN_OFF_H 0x3810
-+#define OV13850_REG_H_WIN_OFF_L 0x3811
-+#define OV13850_REG_V_WIN_OFF_H 0x3812
-+#define OV13850_REG_V_WIN_OFF_L 0x3813
-+
-+#define OV13850_REG_H_INC 0x3814
-+#define OV13850_REG_V_INC 0x3815
-+
-+enum ov13850_mode_id {
-+ OV13850_MODE_1080P_1920_1080 = 0,
-+ OV13850_NUM_MODES,
-+};
-+
-+enum ov13850_frame_rate {
-+ OV13850_15_FPS = 0,
-+ OV13850_30_FPS,
-+ OV13850_60_FPS,
-+ OV13850_NUM_FRAMERATES,
-+};
-+
-+static const int ov13850_framerates[] = {
-+ [OV13850_15_FPS] = 15,
-+ [OV13850_30_FPS] = 30,
-+ [OV13850_60_FPS] = 60,
-+};
-+
-+struct ov13850_pixfmt {
-+ u32 code;
-+ u32 colorspace;
-+};
-+
-+static const struct ov13850_pixfmt ov13850_formats[] = {
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, },
-+};
-+
-+/* regulator supplies */
-+static const char * const ov13850_supply_name[] = {
-+ "DOVDD", /* Digital I/O (1.8V) supply */
-+ "AVDD", /* Analog (2.8V) supply */
-+ "DVDD", /* Digital Core (1.5V) supply */
-+};
-+
-+#define OV13850_NUM_SUPPLIES ARRAY_SIZE(ov13850_supply_name)
-+
-+/*
-+ * Image size under 1280 * 960 are SUBSAMPLING
-+ * Image size upper 1280 * 960 are SCALING
-+ */
-+enum ov13850_downsize_mode {
-+ SUBSAMPLING,
-+ SCALING,
-+};
-+
-+struct reg_value {
-+ u16 reg_addr;
-+ u8 val;
-+ u8 mask;
-+ u32 delay_ms;
-+};
-+
-+struct ov13850_mode_info {
-+ enum ov13850_mode_id id;
-+ enum ov13850_downsize_mode dn_mode;
-+ u32 hact;
-+ u32 htot;
-+ u32 vact;
-+ u32 vtot;
-+ const struct reg_value *reg_data;
-+ u32 reg_data_size;
-+ u32 max_fps;
-+};
-+
-+struct ov13850_ctrls {
-+ struct v4l2_ctrl_handler handler;
-+ struct v4l2_ctrl *pixel_rate;
-+ struct {
-+ struct v4l2_ctrl *exposure;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_wb;
-+ struct v4l2_ctrl *blue_balance;
-+ struct v4l2_ctrl *red_balance;
-+ };
-+ struct {
-+ struct v4l2_ctrl *anal_gain;
-+ };
-+ struct v4l2_ctrl *brightness;
-+ struct v4l2_ctrl *light_freq;
-+ struct v4l2_ctrl *link_freq;
-+ struct v4l2_ctrl *saturation;
-+ struct v4l2_ctrl *contrast;
-+ struct v4l2_ctrl *hue;
-+ struct v4l2_ctrl *test_pattern;
-+ struct v4l2_ctrl *hflip;
-+ struct v4l2_ctrl *vflip;
-+};
-+
-+struct ov13850_dev {
-+ struct i2c_client *i2c_client;
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+ struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
-+ struct clk *xclk; /* system clock to OV13850 */
-+ u32 xclk_freq;
-+
-+ struct regulator_bulk_data supplies[OV13850_NUM_SUPPLIES];
-+ struct gpio_desc *reset_gpio;
-+ struct gpio_desc *pwdn_gpio;
-+ bool upside_down;
-+
-+ /* lock to protect all members below */
-+ struct mutex lock;
-+
-+ int power_count;
-+
-+ struct v4l2_mbus_framefmt fmt;
-+ bool pending_fmt_change;
-+
-+ const struct ov13850_mode_info *current_mode;
-+ const struct ov13850_mode_info *last_mode;
-+ enum ov13850_frame_rate current_fr;
-+ struct v4l2_fract frame_interval;
-+
-+ struct ov13850_ctrls ctrls;
-+
-+ u32 prev_sysclk, prev_hts;
-+ u32 ae_low, ae_high, ae_target;
-+
-+ bool pending_mode_change;
-+ bool streaming;
-+};
-+
-+static inline struct ov13850_dev *to_ov13850_dev(struct v4l2_subdev *sd)
-+{
-+ return container_of(sd, struct ov13850_dev, sd);
-+}
-+
-+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
-+{
-+ return &container_of(ctrl->handler, struct ov13850_dev,
-+ ctrls.handler)->sd;
-+}
-+
-+/* ov13850 initial register */
-+static const struct reg_value ov13850_init_setting_30fps_1080P[] = {
-+
-+};
-+
-+static const struct reg_value ov13850_setting_1080P_1920_1080[] = {
-+//;XVCLK=24Mhz, SCLK=4x120Mhz, MIPI 640Mbps, DACCLK=240Mhz
-+/*
-+ * using quarter size to scale down
-+ */
-+ {0x0103, 0x01, 0, 0}, // ; software reset
-+
-+ {0x0300, 0x01, 0, 0}, //; PLL
-+ {0x0301, 0x00, 0, 0}, //; PLL1_DIVP_hi
-+ {0x0302, 0x28, 0, 0}, //; PLL1_DIVP_lo
-+ {0x0303, 0x00, 0, 0}, // ; PLL
-+ {0x030a, 0x00, 0, 0}, // ; PLL
-+ //{0xffff, 20, 0, 0},
-+ {0x300f, 0x11, 0, 0}, // SFC modified, MIPI_SRC, [1:0] 00-8bit, 01-10bit, 10-12bit
-+ {0x3010, 0x01, 0, 0}, // ; MIPI PHY
-+ {0x3011, 0x76, 0, 0}, // ; MIPI PHY
-+ {0x3012, 0x41, 0, 0}, // ; MIPI 4 lane
-+ {0x3013, 0x12, 0, 0}, // ; MIPI control
-+ {0x3014, 0x11, 0, 0}, // ; MIPI control
-+ {0x301f, 0x03, 0, 0}, //
-+ {0x3106, 0x00, 0, 0}, //
-+ {0x3210, 0x47, 0, 0}, //
-+ {0x3500, 0x00, 0, 0}, // ; exposure HH
-+ {0x3501, 0x67, 0, 0}, // ; exposure H
-+ {0x3502, 0x80, 0, 0}, // ; exposure L
-+ {0x3506, 0x00, 0, 0}, // ; short exposure HH
-+ {0x3507, 0x02, 0, 0}, // ; short exposure H
-+ {0x3508, 0x00, 0, 0}, // ; shour exposure L
-+ {0x3509, 0x10, 0, 0},//00},//8},
-+ {0x350a, 0x00, 0, 0}, // ; gain H
-+ {0x350b, 0x10, 0, 0}, // ; gain L
-+ {0x350e, 0x00, 0, 0}, // ; short gain H
-+ {0x350f, 0x10, 0, 0}, // ; short gain L
-+ {0x3600, 0x40, 0, 0}, // ; analog control
-+ {0x3601, 0xfc, 0, 0}, // ; analog control
-+ {0x3602, 0x02, 0, 0}, // ; analog control
-+ {0x3603, 0x48, 0, 0}, // ; analog control
-+ {0x3604, 0xa5, 0, 0}, // ; analog control
-+ {0x3605, 0x9f, 0, 0}, // ; analog control
-+ {0x3607, 0x00, 0, 0}, // ; analog control
-+ {0x360a, 0x40, 0, 0}, // ; analog control
-+ {0x360b, 0x91, 0, 0}, // ; analog control
-+ {0x360c, 0x49, 0, 0}, // ; analog control
-+ {0x360f, 0x8a, 0, 0}, //
-+ {0x3611, 0x10, 0, 0}, // ; PLL2
-+ //{0x3612, 0x23, 0, 0}, // ; PLL2
-+ {0x3612, 0x13, 0, 0}, // ; PLL2
-+ //{0x3613, 0x33, 0, 0}, // ; PLL2
-+ {0x3613, 0x22, 0, 0}, // ; PLL2
-+ //{0xffff, 50, 0, 0},
-+ {0x3614, 0x28, 0, 0}, //[7:0] PLL2_DIVP lo
-+ {0x3615, 0x08, 0, 0}, //[7:6] Debug mode, [5:4] N_pump clock div, [3:2] P_pump clock div, [1:0] PLL2_DIVP hi
-+ {0x3641, 0x02, 0, 0},
-+ {0x3660, 0x82, 0, 0},
-+ {0x3668, 0x54, 0, 0},
-+ {0x3669, 0x40, 0, 0},
-+ {0x3667, 0xa0, 0, 0},
-+ {0x3702, 0x40, 0, 0},
-+ {0x3703, 0x44, 0, 0},
-+ {0x3704, 0x2c, 0, 0},
-+ {0x3705, 0x24, 0, 0},
-+ {0x3706, 0x50, 0, 0},
-+ {0x3707, 0x44, 0, 0},
-+ {0x3708, 0x3c, 0, 0},
-+ {0x3709, 0x1f, 0, 0},
-+ {0x370a, 0x26, 0, 0},
-+ {0x370b, 0x3c, 0, 0},
-+ {0x3720, 0x66, 0, 0},
-+ {0x3722, 0x84, 0, 0},
-+ {0x3728, 0x40, 0, 0},
-+ {0x372a, 0x00, 0, 0},
-+ {0x372f, 0x90, 0, 0},
-+ {0x3710, 0x28, 0, 0},
-+ {0x3716, 0x03, 0, 0},
-+ {0x3718, 0x10, 0, 0},
-+ {0x3719, 0x08, 0, 0},
-+ {0x371c, 0xfc, 0, 0},
-+ {0x3760, 0x13, 0, 0},
-+ {0x3761, 0x34, 0, 0},
-+ {0x3767, 0x24, 0, 0},
-+ {0x3768, 0x06, 0, 0},
-+ {0x3769, 0x45, 0, 0},
-+ {0x376c, 0x23, 0, 0},
-+ {0x3d84, 0x00, 0, 0}, // ; OTP program disable
-+ {0x3d85, 0x17, 0, 0}, // ; OTP power up load data enable, power load setting enable, software load setting
-+ {0x3d8c, 0x73, 0, 0}, // ; OTP start address H
-+ {0x3d8d, 0xbf, 0, 0}, // ; OTP start address L
-+ {0x3800, 0x00, 0, 0}, // ; H crop start H
-+ {0x3801, 0x08, 0, 0}, // ; H crop start L
-+ {0x3802, 0x00, 0, 0}, // ; V crop start H
-+ {0x3803, 0x04, 0, 0}, // ; V crop start L
-+ {0x3804, 0x10, 0, 0}, // ; H crop end H
-+ {0x3805, 0x97, 0, 0}, // ; H crop end L
-+ {0x3806, 0x0c, 0, 0}, // ; V crop end H
-+ {0x3807, 0x4b, 0, 0}, // ; V crop end L
-+ {0x3808, 0x08, 0, 0}, // ; H output size H
-+ {0x3809, 0x40, 0, 0}, // ; H output size L
-+ {0x380a, 0x06, 0, 0}, // ; V output size H
-+ {0x380b, 0x20, 0, 0}, // ; V output size L
-+ {0x380c, 0x25, 0, 0}, // ; HTS H
-+ {0x380d, 0x80, 0, 0}, // ; HTS L
-+ {0x380e, 0x06, 0, 0}, // ; VTS H
-+ {0x380f, 0x80, 0, 0}, // ; VTS L
-+ {0x3810, 0x00, 0, 0}, // ; H win off H
-+ {0x3811, 0x04, 0, 0}, // ; H win off L
-+ {0x3812, 0x00, 0, 0}, // ; V win off H
-+ {0x3813, 0x02, 0, 0}, // ; V win off L
-+ {0x3814, 0x31, 0, 0}, // ; H inc
-+ {0x3815, 0x31, 0, 0}, // ; V inc
-+ {0x3820, 0x02, 0, 0}, // ; V flip off, V bin on
-+ {0x3821, 0x05, 0, 0}, // ; H mirror on, H bin on
-+ {0x3834, 0x00, 0, 0}, //
-+ {0x3835, 0x1c, 0, 0}, // ; cut_en, vts_auto, blk_col_dis
-+ {0x3836, 0x08, 0, 0}, //
-+ {0x3837, 0x02, 0, 0}, //
-+ {0x4000, 0xf1, 0, 0},//c1}, // ; BLC offset trig en, format change trig en, gain trig en, exp trig en, median en
-+ {0x4001, 0x00, 0, 0}, // ; BLC
-+ {0x400b, 0x0c, 0, 0}, // ; BLC
-+ {0x4011, 0x00, 0, 0}, // ; BLC
-+ {0x401a, 0x00, 0, 0}, // ; BLC
-+ {0x401b, 0x00, 0, 0}, // ; BLC
-+ {0x401c, 0x00, 0, 0}, // ; BLC
-+ {0x401d, 0x00, 0, 0}, // ; BLC
-+ {0x4020, 0x00, 0, 0}, // ; BLC
-+ {0x4021, 0xe4, 0, 0}, // ; BLC
-+ {0x4022, 0x07, 0, 0}, // ; BLC
-+ {0x4023, 0x5f, 0, 0}, // ; BLC
-+ {0x4024, 0x08, 0, 0}, // ; BLC
-+ {0x4025, 0x44, 0, 0}, // ; BLC
-+ {0x4026, 0x08, 0, 0}, // ; BLC
-+ {0x4027, 0x47, 0, 0}, // ; BLC
-+ {0x4028, 0x00, 0, 0}, // ; BLC
-+ {0x4029, 0x02, 0, 0}, // ; BLC
-+ {0x402a, 0x04, 0, 0}, // ; BLC
-+ {0x402b, 0x08, 0, 0}, // ; BLC
-+ {0x402c, 0x02, 0, 0}, // ; BLC
-+ {0x402d, 0x02, 0, 0}, // ; BLC
-+ {0x402e, 0x0c, 0, 0}, // ; BLC
-+ {0x402f, 0x08, 0, 0}, // ; BLC
-+ {0x403d, 0x2c, 0, 0}, //
-+ {0x403f, 0x7f, 0, 0}, //
-+ {0x4500, 0x82, 0, 0}, // ; BLC
-+ {0x4501, 0x38, 0, 0}, // ; BLC
-+ {0x4601, 0x04, 0, 0}, //
-+ {0x4602, 0x22, 0, 0}, //
-+ {0x4603, 0x01, 0, 0}, //; VFIFO
-+ {0x4837, 0x19, 0, 0}, //; MIPI global timing
-+ {0x4d00, 0x04, 0, 0}, // ; temperature monitor
-+ {0x4d01, 0x42, 0, 0}, // ; temperature monitor
-+ {0x4d02, 0xd1, 0, 0}, // ; temperature monitor
-+ {0x4d03, 0x90, 0, 0}, // ; temperature monitor
-+ {0x4d04, 0x66, 0, 0}, // ; temperature monitor
-+ {0x4d05, 0x65, 0, 0}, // ; temperature monitor
-+ {0x5000, 0x0e, 0, 0}, // ; windowing enable, BPC on, WPC on, Lenc on
-+ {0x5001, 0x03, 0, 0}, // ; BLC enable, MWB on
-+ {0x5002, 0x07, 0, 0}, //
-+ {0x5013, 0x40, 0, 0},
-+ {0x501c, 0x00, 0, 0},
-+ {0x501d, 0x10, 0, 0},
-+ //{0x5057, 0x56, 0, 0},//add
-+ {0x5056, 0x08, 0, 0},
-+ {0x5058, 0x08, 0, 0},
-+ {0x505a, 0x08, 0, 0},
-+ {0x5242, 0x00, 0, 0},
-+ {0x5243, 0xb8, 0, 0},
-+ {0x5244, 0x00, 0, 0},
-+ {0x5245, 0xf9, 0, 0},
-+ {0x5246, 0x00, 0, 0},
-+ {0x5247, 0xf6, 0, 0},
-+ {0x5248, 0x00, 0, 0},
-+ {0x5249, 0xa6, 0, 0},
-+ {0x5300, 0xfc, 0, 0},
-+ {0x5301, 0xdf, 0, 0},
-+ {0x5302, 0x3f, 0, 0},
-+ {0x5303, 0x08, 0, 0},
-+ {0x5304, 0x0c, 0, 0},
-+ {0x5305, 0x10, 0, 0},
-+ {0x5306, 0x20, 0, 0},
-+ {0x5307, 0x40, 0, 0},
-+ {0x5308, 0x08, 0, 0},
-+ {0x5309, 0x08, 0, 0},
-+ {0x530a, 0x02, 0, 0},
-+ {0x530b, 0x01, 0, 0},
-+ {0x530c, 0x01, 0, 0},
-+ {0x530d, 0x0c, 0, 0},
-+ {0x530e, 0x02, 0, 0},
-+ {0x530f, 0x01, 0, 0},
-+ {0x5310, 0x01, 0, 0},
-+ {0x5400, 0x00, 0, 0},
-+ {0x5401, 0x61, 0, 0},
-+ {0x5402, 0x00, 0, 0},
-+ {0x5403, 0x00, 0, 0},
-+ {0x5404, 0x00, 0, 0},
-+ {0x5405, 0x40, 0, 0},
-+ {0x540c, 0x05, 0, 0},
-+ {0x5b00, 0x00, 0, 0},
-+ {0x5b01, 0x00, 0, 0},
-+ {0x5b02, 0x01, 0, 0},
-+ {0x5b03, 0xff, 0, 0},
-+ {0x5b04, 0x02, 0, 0},
-+ {0x5b05, 0x6c, 0, 0},
-+ {0x5b09, 0x02, 0, 0}, //
-+ //{0x5e00, 0x00, 0, 0}, // ; test pattern disable
-+ //{0x5e00, 0x80, 0, 0}, // ; test pattern enable
-+ {0x5e10, 0x1c, 0, 0}, // ; ISP test disable
-+
-+ //{0x0300, 0x01, 0, 0},// ; PLL
-+ //{0x0302, 0x28, 0, 0},// ; PLL
-+ //{0xffff, 50, 0, 0},
-+ {0x3501, 0x67, 0, 0},// ; Exposure H
-+ {0x370a, 0x26, 0, 0},//
-+ {0x372a, 0x00, 0, 0},
-+ {0x372f, 0x90, 0, 0},
-+ {0x3801, 0x08, 0, 0}, //; H crop start L
-+ {0x3803, 0x04, 0, 0}, //; V crop start L
-+ {0x3805, 0x97, 0, 0}, //; H crop end L
-+ {0x3807, 0x4b, 0, 0}, //; V crop end L
-+ {0x3808, 0x08, 0, 0}, //; H output size H
-+ {0x3809, 0x40, 0, 0}, //; H output size L
-+ {0x380a, 0x06, 0, 0}, //; V output size H
-+ {0x380b, 0x20, 0, 0}, //; V output size L
-+ {0x380c, 0x25, 0, 0}, //; HTS H
-+ {0x380d, 0x80, 0, 0}, //; HTS L
-+ {0x380e, 0x0a, 0, 0},//6}, //; VTS H
-+ {0x380f, 0x80, 0, 0}, //; VTS L
-+ {0x3813, 0x02, 0, 0}, //; V win off
-+ {0x3814, 0x31, 0, 0}, //; H inc
-+ {0x3815, 0x31, 0, 0}, //; V inc
-+ {0x3820, 0x02, 0, 0}, //; V flip off, V bin on
-+ {0x3821, 0x05, 0, 0}, //; H mirror on, H bin on
-+ {0x3836, 0x08, 0, 0}, //
-+ {0x3837, 0x02, 0, 0}, //
-+ {0x4020, 0x00, 0, 0}, //
-+ {0x4021, 0xe4, 0, 0}, //
-+ {0x4022, 0x07, 0, 0}, //
-+ {0x4023, 0x5f, 0, 0}, //
-+ {0x4024, 0x08, 0, 0}, //
-+ {0x4025, 0x44, 0, 0}, //
-+ {0x4026, 0x08, 0, 0}, //
-+ {0x4027, 0x47, 0, 0}, //
-+ {0x4603, 0x01, 0, 0}, //; VFIFO
-+ {0x4837, 0x19, 0, 0}, //; MIPI global timing
-+ {0x4802, 0x42, 0, 0}, //default 0x00
-+ {0x481a, 0x00, 0, 0},
-+ {0x481b, 0x1c, 0, 0}, //default 0x3c prepare
-+ {0x4826, 0x12, 0, 0}, //default 0x32 trail
-+ {0x5401, 0x61, 0, 0}, //
-+ {0x5405, 0x40, 0, 0}, //
-+
-+ //{0xffff, 200, 0, 0},
-+ //{0xffff, 200, 0, 0},
-+ //{0xffff, 200, 0, 0},
-+
-+ //{0x0100, 0x01, 0, 0}, //; wake up, streaming
-+};
-+
-+/* power-on sensor init reg table */
-+static const struct ov13850_mode_info ov13850_mode_init_data = {
-+ OV13850_MODE_1080P_1920_1080, SCALING,
-+ 1920, 0x6e0, 1080, 0x470,
-+ ov13850_init_setting_30fps_1080P,
-+ ARRAY_SIZE(ov13850_init_setting_30fps_1080P),
-+ OV13850_30_FPS,
-+};
-+
-+static const struct ov13850_mode_info
-+ov13850_mode_data[OV13850_NUM_MODES] = {
-+ {OV13850_MODE_1080P_1920_1080, SCALING,
-+ 1920, 0x6e0, 1080, 0x470,
-+ ov13850_setting_1080P_1920_1080,
-+ ARRAY_SIZE(ov13850_setting_1080P_1920_1080),
-+ OV13850_30_FPS},
-+};
-+
-+static int ov13850_write_reg(struct ov13850_dev *sensor, u16 reg, u8 val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg;
-+ u8 buf[3];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+ buf[2] = val;
-+
-+ msg.addr = client->addr;
-+ msg.flags = client->flags;
-+ msg.buf = buf;
-+ msg.len = sizeof(buf);
-+
-+ ret = i2c_transfer(client->adapter, &msg, 1);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
-+ __func__, reg, val);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ov13850_read_reg(struct ov13850_dev *sensor, u16 reg, u8 *val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg[2];
-+ u8 buf[2];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+
-+ msg[0].addr = client->addr;
-+ msg[0].flags = client->flags;
-+ msg[0].buf = buf;
-+ msg[0].len = sizeof(buf);
-+
-+ msg[1].addr = client->addr;
-+ msg[1].flags = client->flags | I2C_M_RD;
-+ msg[1].buf = buf;
-+ msg[1].len = 1;
-+
-+ ret = i2c_transfer(client->adapter, msg, 2);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x\n",
-+ __func__, reg);
-+ return ret;
-+ }
-+
-+ *val = buf[0];
-+ return 0;
-+}
-+
-+static int ov13850_read_reg16(struct ov13850_dev *sensor, u16 reg, u16 *val)
-+{
-+ u8 hi, lo;
-+ int ret;
-+
-+ ret = ov13850_read_reg(sensor, reg, &hi);
-+ if (ret)
-+ return ret;
-+ ret = ov13850_read_reg(sensor, reg + 1, &lo);
-+ if (ret)
-+ return ret;
-+
-+ *val = ((u16)hi << 8) | (u16)lo;
-+ return 0;
-+}
-+
-+static int ov13850_write_reg16(struct ov13850_dev *sensor, u16 reg, u16 val)
-+{
-+ int ret;
-+
-+ ret = ov13850_write_reg(sensor, reg, val >> 8);
-+ if (ret)
-+ return ret;
-+
-+ return ov13850_write_reg(sensor, reg + 1, val & 0xff);
-+}
-+
-+static int ov13850_mod_reg(struct ov13850_dev *sensor, u16 reg,
-+ u8 mask, u8 val)
-+{
-+ u8 readval;
-+ int ret;
-+
-+ ret = ov13850_read_reg(sensor, reg, &readval);
-+ if (ret)
-+ return ret;
-+
-+ readval &= ~mask;
-+ val &= mask;
-+ val |= readval;
-+
-+ return ov13850_write_reg(sensor, reg, val);
-+}
-+
-+static int ov13850_set_timings(struct ov13850_dev *sensor,
-+ const struct ov13850_mode_info *mode)
-+{
-+ int ret;
-+
-+ ret = ov13850_write_reg16(sensor, OV13850_REG_H_OUTPUT_SIZE, mode->hact);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ov13850_write_reg16(sensor, OV13850_REG_V_OUTPUT_SIZE, mode->vact);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int ov13850_load_regs(struct ov13850_dev *sensor,
-+ const struct ov13850_mode_info *mode)
-+{
-+ const struct reg_value *regs = mode->reg_data;
-+ unsigned int i;
-+ u32 delay_ms;
-+ u16 reg_addr;
-+ u8 mask, val;
-+ int ret = 0;
-+
-+ st_info(ST_SENSOR, "%s, mode = 0x%x\n", __func__, mode->id);
-+ for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
-+ delay_ms = regs->delay_ms;
-+ reg_addr = regs->reg_addr;
-+ val = regs->val;
-+ mask = regs->mask;
-+
-+ if (mask)
-+ ret = ov13850_mod_reg(sensor, reg_addr, mask, val);
-+ else
-+ ret = ov13850_write_reg(sensor, reg_addr, val);
-+ if (ret)
-+ break;
-+
-+ if (delay_ms)
-+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
-+ }
-+
-+ return ov13850_set_timings(sensor, mode);
-+}
-+
-+
-+
-+static int ov13850_get_gain(struct ov13850_dev *sensor)
-+{
-+ u32 gain = 0;
-+ return gain;
-+}
-+
-+static int ov13850_set_gain(struct ov13850_dev *sensor, int gain)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_stream_mipi(struct ov13850_dev *sensor, bool on)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_get_sysclk(struct ov13850_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_night_mode(struct ov13850_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_get_hts(struct ov13850_dev *sensor)
-+{
-+ /* read HTS from register settings */
-+ u16 hts;
-+ int ret;
-+
-+ ret = ov13850_read_reg16(sensor, OV13850_REG_TIMING_HTS, &hts);
-+ if (ret)
-+ return ret;
-+ return hts;
-+}
-+
-+static int ov13850_set_hts(struct ov13850_dev *sensor, int hts)
-+{
-+ return ov13850_write_reg16(sensor, OV13850_REG_TIMING_HTS, hts);
-+}
-+
-+
-+static int ov13850_get_vts(struct ov13850_dev *sensor)
-+{
-+ u16 vts;
-+ int ret;
-+
-+ ret = ov13850_read_reg16(sensor, OV13850_REG_TIMING_VTS, &vts);
-+ if (ret)
-+ return ret;
-+ return vts;
-+}
-+
-+static int ov13850_set_vts(struct ov13850_dev *sensor, int vts)
-+{
-+ return ov13850_write_reg16(sensor, OV13850_REG_TIMING_VTS, vts);
-+}
-+
-+static int ov13850_get_light_freq(struct ov13850_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_bandingfilter(struct ov13850_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_ae_target(struct ov13850_dev *sensor, int target)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_get_binning(struct ov13850_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_binning(struct ov13850_dev *sensor, bool enable)
-+{
-+ return 0;
-+}
-+
-+static const struct ov13850_mode_info *
-+ov13850_find_mode(struct ov13850_dev *sensor, enum ov13850_frame_rate fr,
-+ int width, int height, bool nearest)
-+{
-+ const struct ov13850_mode_info *mode;
-+
-+ mode = v4l2_find_nearest_size(ov13850_mode_data,
-+ ARRAY_SIZE(ov13850_mode_data),
-+ hact, vact,
-+ width, height);
-+
-+ if (!mode ||
-+ (!nearest && (mode->hact != width || mode->vact != height)))
-+ return NULL;
-+
-+ /* Check to see if the current mode exceeds the max frame rate */
-+ if (ov13850_framerates[fr] > ov13850_framerates[mode->max_fps])
-+ return NULL;
-+
-+ return mode;
-+}
-+
-+static u64 ov13850_calc_pixel_rate(struct ov13850_dev *sensor)
-+{
-+ u64 rate;
-+
-+ rate = sensor->current_mode->vact * sensor->current_mode->hact;
-+ rate *= ov13850_framerates[sensor->current_fr];
-+
-+ return rate;
-+}
-+
-+/*
-+ * After trying the various combinations, reading various
-+ * documentations spread around the net, and from the various
-+ * feedback, the clock tree is probably as follows:
-+ *
-+ * +--------------+
-+ * | Ext. Clock |
-+ * +-+------------+
-+ * | +----------+
-+ * +->| PLL1 | - reg 0x030a, bit0 for the pre-dividerp
-+ * +-+--------+ - reg 0x0300, bits 0-2 for the pre-divider
-+ * +-+--------+ - reg 0x0301~0x0302, for the multiplier
-+ * | +--------------+
-+ * +->| MIPI Divider | - reg 0x0303, bits 0-3 for the pre-divider
-+ * | +---------> MIPI PHY CLK
-+ * | +-----+
-+ * | +->| PLL1_DIV_MIPI | - reg 0x0304, bits 0-1 for the divider
-+ * | +----------------> PCLK
-+ * | +-----+
-+ *
-+ * +--------------+
-+ * | Ext. Clock |
-+ * +-+------------+
-+ * | +----------+
-+ * +->| PLL2 | - reg 0x0311, bit0 for the pre-dividerp
-+ * +-+--------+ - reg 0x030b, bits 0-2 for the pre-divider
-+ * +-+--------+ - reg 0x030c~0x030d, for the multiplier
-+ * | +--------------+
-+ * +->| SCLK Divider | - reg 0x030F, bits 0-3 for the pre-divider
-+ * +-+--------+ - reg 0x030E, bits 0-2 for the divider
-+ * | +---------> SCLK
-+ *
-+ * | +-----+
-+ * +->| DAC Divider | - reg 0x0312, bits 0-3 for the divider
-+ * | +----------------> DACCLK
-+ **
-+ */
-+
-+/*
-+ * ov13850_set_mipi_pclk() - Calculate the clock tree configuration values
-+ * for the MIPI CSI-2 output.
-+ *
-+ * @rate: The requested bandwidth per lane in bytes per second.
-+ * 'Bandwidth Per Lane' is calculated as:
-+ * bpl = HTOT * VTOT * FPS * bpp / num_lanes;
-+ *
-+ * This function use the requested bandwidth to calculate:
-+ *
-+ * - mipi_pclk = bpl / 2; ( / 2 is for CSI-2 DDR)
-+ * - mipi_phy_clk = mipi_pclk * PLL1_DIV_MIPI;
-+ *
-+ * with these fixed parameters:
-+ * PLL1_PREDIVP = 1;
-+ * PLL1_PREDIV = 1; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
-+ * PLL1_DIVM = 1;
-+ * PLL1_DIV_MIPI = 4;
-+ *
-+ * FIXME: this have been tested with 10-bit raw and 2 lanes setup only.
-+ * MIPI_DIV is fixed to value 2, but it -might- be changed according to the
-+ * above formula for setups with 1 lane or image formats with different bpp.
-+ *
-+ * FIXME: this deviates from the sensor manual documentation which is quite
-+ * thin on the MIPI clock tree generation part.
-+ */
-+
-+
-+
-+static int ov13850_set_mipi_pclk(struct ov13850_dev *sensor,
-+ unsigned long rate)
-+{
-+
-+ return 0;
-+}
-+
-+/*
-+ * if sensor changes inside scaling or subsampling
-+ * change mode directly
-+ */
-+static int ov13850_set_mode_direct(struct ov13850_dev *sensor,
-+ const struct ov13850_mode_info *mode)
-+{
-+ if (!mode->reg_data)
-+ return -EINVAL;
-+
-+ /* Write capture setting */
-+ return ov13850_load_regs(sensor, mode);
-+}
-+
-+static int ov13850_set_mode(struct ov13850_dev *sensor)
-+{
-+ const struct ov13850_mode_info *mode = sensor->current_mode;
-+ const struct ov13850_mode_info *orig_mode = sensor->last_mode;
-+ int ret = 0;
-+
-+ ret = ov13850_set_mode_direct(sensor, mode);
-+ if (ret < 0)
-+ return ret;
-+
-+ /*
-+ * we support have 10 bits raw RGB(mipi)
-+ */
-+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-+ ret = ov13850_set_mipi_pclk(sensor, 0);
-+
-+ if (ret < 0)
-+ return 0;
-+
-+ sensor->pending_mode_change = false;
-+ sensor->last_mode = mode;
-+ return 0;
-+}
-+
-+static int ov13850_set_framefmt(struct ov13850_dev *sensor,
-+ struct v4l2_mbus_framefmt *format);
-+
-+/* restore the last set video mode after chip power-on */
-+static int ov13850_restore_mode(struct ov13850_dev *sensor)
-+{
-+ int ret;
-+
-+ /* first load the initial register values */
-+ ret = ov13850_load_regs(sensor, &ov13850_mode_init_data);
-+ if (ret < 0)
-+ return ret;
-+ sensor->last_mode = &ov13850_mode_init_data;
-+
-+ /* now restore the last capture mode */
-+ ret = ov13850_set_mode(sensor);
-+ if (ret < 0)
-+ return ret;
-+
-+ return ov13850_set_framefmt(sensor, &sensor->fmt);
-+}
-+
-+static void ov13850_power(struct ov13850_dev *sensor, bool enable)
-+{
-+ if (!sensor->pwdn_gpio)
-+ return;
-+ if (enable) {
-+ gpiod_set_value_cansleep(sensor->pwdn_gpio, 0);
-+ gpiod_set_value_cansleep(sensor->pwdn_gpio, 1);
-+ } else {
-+ gpiod_set_value_cansleep(sensor->pwdn_gpio, 0);
-+ }
-+
-+ mdelay(100);
-+}
-+
-+static void ov13850_reset(struct ov13850_dev *sensor)
-+{
-+ if (!sensor->reset_gpio)
-+ return;
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
-+ mdelay(100);
-+}
-+
-+static int ov13850_set_power_on(struct ov13850_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ int ret;
-+
-+ ret = clk_prepare_enable(sensor->xclk);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable clock\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_enable(OV13850_NUM_SUPPLIES,
-+ sensor->supplies);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ goto xclk_off;
-+ }
-+
-+ ov13850_reset(sensor);
-+ ov13850_power(sensor, true);
-+
-+ return 0;
-+
-+xclk_off:
-+ clk_disable_unprepare(sensor->xclk);
-+ return ret;
-+}
-+
-+static void ov13850_set_power_off(struct ov13850_dev *sensor)
-+{
-+ ov13850_power(sensor, false);
-+ regulator_bulk_disable(OV13850_NUM_SUPPLIES, sensor->supplies);
-+ clk_disable_unprepare(sensor->xclk);
-+}
-+
-+static int ov13850_set_power_mipi(struct ov13850_dev *sensor, bool on)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_power(struct ov13850_dev *sensor, bool on)
-+{
-+ int ret = 0;
-+ u16 chip_id;
-+
-+ if (on) {
-+ ret = ov13850_set_power_on(sensor);
-+ if (ret)
-+ return ret;
-+
-+#ifdef UNUSED_CODE
-+ ret = ov13850_read_reg16(sensor, OV13850_REG_CHIP_ID, &chip_id);
-+ if (ret) {
-+ dev_err(&sensor->i2c_client->dev, "%s: failed to read chip identifier\n",
-+ __func__);
-+ ret = -ENODEV;
-+ goto power_off;
-+ }
-+
-+ if (chip_id != OV13850_CHIP_ID) {
-+ dev_err(&sensor->i2c_client->dev,
-+ "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",
-+ __func__, OV13850_CHIP_ID, chip_id);
-+ ret = -ENXIO;
-+ goto power_off;
-+ }
-+ dev_err(&sensor->i2c_client->dev, "%s: chip identifier, got 0x%x\n",
-+ __func__, chip_id);
-+#endif
-+
-+ ret = ov13850_restore_mode(sensor);
-+ if (ret)
-+ goto power_off;
-+ }
-+
-+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-+ ret = ov13850_set_power_mipi(sensor, on);
-+ if (ret)
-+ goto power_off;
-+
-+ if (!on)
-+ ov13850_set_power_off(sensor);
-+
-+ return 0;
-+
-+power_off:
-+ ov13850_set_power_off(sensor);
-+ return ret;
-+}
-+
-+static int ov13850_s_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ /*
-+ * If the power count is modified from 0 to != 0 or from != 0 to 0,
-+ * update the power state.
-+ */
-+ if (sensor->power_count == !on) {
-+ ret = ov13850_set_power(sensor, !!on);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ /* Update the power count. */
-+ sensor->power_count += on ? 1 : -1;
-+ WARN_ON(sensor->power_count < 0);
-+out:
-+ mutex_unlock(&sensor->lock);
-+
-+ if (on && !ret && sensor->power_count == 1) {
-+ /* restore controls */
-+ ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov13850_try_frame_interval(struct ov13850_dev *sensor,
-+ struct v4l2_fract *fi,
-+ u32 width, u32 height)
-+{
-+ const struct ov13850_mode_info *mode;
-+ enum ov13850_frame_rate rate = OV13850_15_FPS;
-+ int minfps, maxfps, best_fps, fps;
-+ int i;
-+
-+ minfps = ov13850_framerates[OV13850_15_FPS];
-+ maxfps = ov13850_framerates[OV13850_NUM_FRAMERATES - 1];
-+
-+ if (fi->numerator == 0) {
-+ fi->denominator = maxfps;
-+ fi->numerator = 1;
-+ rate = OV13850_60_FPS;
-+ goto find_mode;
-+ }
-+
-+ fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
-+ minfps, maxfps);
-+
-+ best_fps = minfps;
-+ for (i = 0; i < ARRAY_SIZE(ov13850_framerates); i++) {
-+ int curr_fps = ov13850_framerates[i];
-+
-+ if (abs(curr_fps - fps) < abs(best_fps - fps)) {
-+ best_fps = curr_fps;
-+ rate = i;
-+ }
-+ }
-+ st_info(ST_SENSOR, "best_fps = %d, fps = %d\n", best_fps, fps);
-+
-+ fi->numerator = 1;
-+ fi->denominator = best_fps;
-+
-+find_mode:
-+ mode = ov13850_find_mode(sensor, rate, width, height, false);
-+ return mode ? rate : -EINVAL;
-+}
-+
-+static int ov13850_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ if (code->pad != 0)
-+ return -EINVAL;
-+
-+ if (code->index >= ARRAY_SIZE(ov13850_formats))
-+ return -EINVAL;
-+
-+ code->code = ov13850_formats[code->index].code;
-+ return 0;
-+}
-+
-+static int ov13850_get_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ struct v4l2_mbus_framefmt *fmt;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(&sensor->sd, state,
-+ format->pad);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ format->format = *fmt;
-+
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int ov13850_try_fmt_internal(struct v4l2_subdev *sd,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum ov13850_frame_rate fr,
-+ const struct ov13850_mode_info **new_mode)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ const struct ov13850_mode_info *mode;
-+ int i;
-+
-+ mode = ov13850_find_mode(sensor, fr, fmt->width, fmt->height, true);
-+ if (!mode)
-+ return -EINVAL;
-+ fmt->width = mode->hact;
-+ fmt->height = mode->vact;
-+
-+ if (new_mode)
-+ *new_mode = mode;
-+
-+ for (i = 0; i < ARRAY_SIZE(ov13850_formats); i++)
-+ if (ov13850_formats[i].code == fmt->code)
-+ break;
-+ if (i >= ARRAY_SIZE(ov13850_formats))
-+ i = 0;
-+
-+ fmt->code = ov13850_formats[i].code;
-+ fmt->colorspace = ov13850_formats[i].colorspace;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+
-+ return 0;
-+}
-+
-+static int ov13850_set_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ const struct ov13850_mode_info *new_mode;
-+ struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
-+ struct v4l2_mbus_framefmt *fmt;
-+ int ret;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ ret = ov13850_try_fmt_internal(sd, mbus_fmt, 0, &new_mode);
-+ if (ret)
-+ goto out;
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(sd, state, 0);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ if (mbus_fmt->code != sensor->fmt.code)
-+ sensor->pending_fmt_change = true;
-+
-+ *fmt = *mbus_fmt;
-+
-+ if (new_mode != sensor->current_mode) {
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+
-+ if (new_mode->max_fps < sensor->current_fr) {
-+ sensor->current_fr = new_mode->max_fps;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator =
-+ ov13850_framerates[sensor->current_fr];
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ ov13850_calc_pixel_rate(sensor));
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int ov13850_set_framefmt(struct ov13850_dev *sensor,
-+ struct v4l2_mbus_framefmt *format)
-+{
-+ u8 fmt;
-+
-+ switch (format->code) {
-+ /* Raw, BGBG... / GRGR... */
-+ case MEDIA_BUS_FMT_SBGGR8_1X8:
-+ case MEDIA_BUS_FMT_SGBRG8_1X8:
-+ case MEDIA_BUS_FMT_SGRBG8_1X8:
-+ case MEDIA_BUS_FMT_SRGGB8_1X8:
-+ fmt = 0x0;
-+ break;
-+ case MEDIA_BUS_FMT_SBGGR10_1X10:
-+ case MEDIA_BUS_FMT_SGBRG10_1X10:
-+ case MEDIA_BUS_FMT_SGRBG10_1X10:
-+ case MEDIA_BUS_FMT_SRGGB10_1X10:
-+ fmt = 0x1;
-+ case MEDIA_BUS_FMT_SBGGR12_1X12:
-+ case MEDIA_BUS_FMT_SGBRG12_1X12:
-+ case MEDIA_BUS_FMT_SGRBG12_1X12:
-+ case MEDIA_BUS_FMT_SRGGB12_1X12:
-+ fmt = 0x2;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return ov13850_mod_reg(sensor, OV13850_REG_MIPI_SC,
-+ BIT(1) | BIT(0), fmt);
-+}
-+
-+/*
-+ * Sensor Controls.
-+ */
-+
-+static int ov13850_set_ctrl_hue(struct ov13850_dev *sensor, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int ov13850_set_ctrl_contrast(struct ov13850_dev *sensor, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int ov13850_set_ctrl_saturation(struct ov13850_dev *sensor, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int ov13850_set_ctrl_white_balance(struct ov13850_dev *sensor, int awb)
-+{
-+ struct ov13850_ctrls *ctrls = &sensor->ctrls;
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int ov13850_set_ctrl_exposure(struct ov13850_dev *sensor,
-+ enum v4l2_exposure_auto_type auto_exposure)
-+{
-+ struct ov13850_ctrls *ctrls = &sensor->ctrls;
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static const s64 link_freq_menu_items[] = {
-+ OV13850_LINK_FREQ_500MHZ
-+};
-+
-+static const char * const test_pattern_menu[] = {
-+ "Disabled",
-+ "Color bars",
-+ "Color bars w/ rolling bar",
-+ "Color squares",
-+ "Color squares w/ rolling bar",
-+};
-+
-+static int ov13850_set_ctrl_test_pattern(struct ov13850_dev *sensor, int value)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_ctrl_light_freq(struct ov13850_dev *sensor, int value)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_ctrl_hflip(struct ov13850_dev *sensor, int value)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_set_ctrl_vflip(struct ov13850_dev *sensor, int value)
-+{
-+ return 0;
-+}
-+
-+static int ov13850_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ int val;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ val = ov13850_get_gain(sensor);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ov13850_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ int ret;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ /*
-+ * If the device is not powered up by the host driver do
-+ * not apply any controls to H/W at this time. Instead
-+ * the controls will be restored right after power-up.
-+ */
-+ if (sensor->power_count == 0)
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ ret = ov13850_set_gain(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE:
-+ ret = ov13850_set_ctrl_exposure(sensor, V4L2_EXPOSURE_MANUAL);
-+ break;
-+ case V4L2_CID_AUTO_WHITE_BALANCE:
-+ ret = ov13850_set_ctrl_white_balance(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HUE:
-+ ret = ov13850_set_ctrl_hue(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_CONTRAST:
-+ ret = ov13850_set_ctrl_contrast(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_SATURATION:
-+ ret = ov13850_set_ctrl_saturation(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = ov13850_set_ctrl_test_pattern(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY:
-+ ret = ov13850_set_ctrl_light_freq(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HFLIP:
-+ ret = ov13850_set_ctrl_hflip(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_VFLIP:
-+ ret = ov13850_set_ctrl_vflip(sensor, ctrl->val);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops ov13850_ctrl_ops = {
-+ .g_volatile_ctrl = ov13850_g_volatile_ctrl,
-+ .s_ctrl = ov13850_s_ctrl,
-+};
-+
-+static int ov13850_init_controls(struct ov13850_dev *sensor)
-+{
-+ const struct v4l2_ctrl_ops *ops = &ov13850_ctrl_ops;
-+ struct ov13850_ctrls *ctrls = &sensor->ctrls;
-+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-+ int ret;
-+
-+ v4l2_ctrl_handler_init(hdl, 32);
-+
-+ /* we can use our own mutex for the ctrl lock */
-+ hdl->lock = &sensor->lock;
-+
-+ /* Clock related controls */
-+ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
-+ 0, INT_MAX, 1,
-+ ov13850_calc_pixel_rate(sensor));
-+
-+ /* Auto/manual white balance */
-+ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
-+ V4L2_CID_AUTO_WHITE_BALANCE,
-+ 0, 1, 1, 0);
-+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
-+ 0, 4095, 1, 1024);
-+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
-+ 0, 4095, 1, 1024);
-+
-+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-+ 4, 0xfff8, 1, 0x4c00);
-+ ctrls->anal_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
-+ 0x10, 0xfff8, 1, 0x0080);
-+ ctrls->test_pattern =
-+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(test_pattern_menu) - 1,
-+ 0, 0, test_pattern_menu);
-+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
-+ 0, 1, 1, 0);
-+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
-+ 0, 1, 1, 0);
-+ ctrls->light_freq =
-+ v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_POWER_LINE_FREQUENCY,
-+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
-+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
-+ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
-+ 0, 0, link_freq_menu_items);
-+ if (hdl->error) {
-+ ret = hdl->error;
-+ goto free_ctrls;
-+ }
-+
-+ ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ // ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+ // ctrls->anal_gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+
-+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
-+
-+ sensor->sd.ctrl_handler = hdl;
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(hdl);
-+ return ret;
-+}
-+
-+static int ov13850_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ if (fse->pad != 0)
-+ return -EINVAL;
-+ if (fse->index >= OV13850_NUM_MODES)
-+ return -EINVAL;
-+
-+ fse->min_width =
-+ ov13850_mode_data[fse->index].hact;
-+ fse->max_width = fse->min_width;
-+ fse->min_height =
-+ ov13850_mode_data[fse->index].vact;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static int ov13850_enum_frame_interval(
-+ struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_interval_enum *fie)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ struct v4l2_fract tpf;
-+ int ret;
-+
-+ if (fie->pad != 0)
-+ return -EINVAL;
-+ if (fie->index >= OV13850_NUM_FRAMERATES)
-+ return -EINVAL;
-+
-+ tpf.numerator = 1;
-+ tpf.denominator = ov13850_framerates[fie->index];
-+
-+/* ret = ov13850_try_frame_interval(sensor, &tpf,
-+ * fie->width, fie->height);
-+ * if (ret < 0)
-+ * return -EINVAL;
-+ */
-+ fie->interval = tpf;
-+
-+ return 0;
-+}
-+
-+static int ov13850_g_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+
-+ mutex_lock(&sensor->lock);
-+ fi->interval = sensor->frame_interval;
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int ov13850_s_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ const struct ov13850_mode_info *mode;
-+ int frame_rate, ret = 0;
-+
-+ if (fi->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ mode = sensor->current_mode;
-+
-+ frame_rate = ov13850_try_frame_interval(sensor, &fi->interval,
-+ mode->hact, mode->vact);
-+ if (frame_rate < 0) {
-+ /* Always return a valid frame interval value */
-+ fi->interval = sensor->frame_interval;
-+ goto out;
-+ }
-+
-+ mode = ov13850_find_mode(sensor, frame_rate, mode->hact,
-+ mode->vact, true);
-+ if (!mode) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (mode != sensor->current_mode ||
-+ frame_rate != sensor->current_fr) {
-+ sensor->current_fr = frame_rate;
-+ sensor->frame_interval = fi->interval;
-+ sensor->current_mode = mode;
-+ sensor->pending_mode_change = true;
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ ov13850_calc_pixel_rate(sensor));
-+ }
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int ov13850_stream_start(struct ov13850_dev *sensor, int enable)
-+{
-+ int ret;
-+
-+ if (enable) { //stream on
-+ mdelay(1000);
-+ ret = ov13850_write_reg(sensor, OV13850_STREAM_CTRL, enable);
-+ } else { //stream off
-+ ret = ov13850_write_reg(sensor, OV13850_STREAM_CTRL, enable);
-+ mdelay(100);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov13850_s_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming == !enable) {
-+ if (enable && sensor->pending_mode_change) {
-+ ret = ov13850_set_mode(sensor);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ if (enable && sensor->pending_fmt_change) {
-+ ret = ov13850_set_framefmt(sensor, &sensor->fmt);
-+ if (ret)
-+ goto out;
-+ sensor->pending_fmt_change = false;
-+ }
-+
-+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-+ ret = ov13850_set_stream_mipi(sensor, enable);
-+
-+ ret = ov13850_stream_start(sensor, enable);
-+
-+ if (!ret)
-+ sensor->streaming = enable;
-+ }
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static const struct v4l2_subdev_core_ops ov13850_core_ops = {
-+ .s_power = ov13850_s_power,
-+ .log_status = v4l2_ctrl_subdev_log_status,
-+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops ov13850_video_ops = {
-+ .g_frame_interval = ov13850_g_frame_interval,
-+ .s_frame_interval = ov13850_s_frame_interval,
-+ .s_stream = ov13850_s_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops ov13850_pad_ops = {
-+ .enum_mbus_code = ov13850_enum_mbus_code,
-+ .get_fmt = ov13850_get_fmt,
-+ .set_fmt = ov13850_set_fmt,
-+ .enum_frame_size = ov13850_enum_frame_size,
-+ .enum_frame_interval = ov13850_enum_frame_interval,
-+};
-+
-+static const struct v4l2_subdev_ops ov13850_subdev_ops = {
-+ .core = &ov13850_core_ops,
-+ .video = &ov13850_video_ops,
-+ .pad = &ov13850_pad_ops,
-+};
-+
-+static int ov13850_get_regulators(struct ov13850_dev *sensor)
-+{
-+ int i;
-+
-+ for (i = 0; i < OV13850_NUM_SUPPLIES; i++)
-+ sensor->supplies[i].supply = ov13850_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&sensor->i2c_client->dev,
-+ OV13850_NUM_SUPPLIES,
-+ sensor->supplies);
-+}
-+
-+static int ov13850_check_chip_id(struct ov13850_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ int ret = 0;
-+ u16 chip_id;
-+
-+ ret = ov13850_set_power_on(sensor);
-+ if (ret)
-+ return ret;
-+
-+#ifdef UNUSED_CODE
-+ ret = ov13850_read_reg16(sensor, OV13850_REG_CHIP_ID, &chip_id);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to read chip identifier\n",
-+ __func__);
-+ goto power_off;
-+ }
-+
-+ if (chip_id != OV13850_CHIP_ID) {
-+ dev_err(&client->dev, "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",
-+ __func__, OV13850_CHIP_ID, chip_id);
-+ ret = -ENXIO;
-+ }
-+ dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
-+ __func__, chip_id);
-+#endif
-+
-+power_off:
-+ ov13850_set_power_off(sensor);
-+ return ret;
-+}
-+
-+static int ov13850_probe(struct i2c_client *client)
-+{
-+ struct device *dev = &client->dev;
-+ struct fwnode_handle *endpoint;
-+ struct ov13850_dev *sensor;
-+ struct v4l2_mbus_framefmt *fmt;
-+ u32 rotation;
-+ int ret;
-+ u8 chip_id_high, chip_id_low;
-+
-+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
-+ if (!sensor)
-+ return -ENOMEM;
-+
-+ sensor->i2c_client = client;
-+
-+ fmt = &sensor->fmt;
-+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+ fmt->width = 1920;
-+ fmt->height = 1080;
-+ fmt->field = V4L2_FIELD_NONE;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator = ov13850_framerates[OV13850_30_FPS];
-+ sensor->current_fr = OV13850_30_FPS;
-+ sensor->current_mode =
-+ &ov13850_mode_data[OV13850_MODE_1080P_1920_1080];
-+ sensor->last_mode = sensor->current_mode;
-+
-+ sensor->ae_target = 52;
-+
-+ /* optional indication of physical rotation of sensor */
-+ ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
-+ &rotation);
-+ if (!ret) {
-+ switch (rotation) {
-+ case 180:
-+ sensor->upside_down = true;
-+ fallthrough;
-+ case 0:
-+ break;
-+ default:
-+ dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
-+ rotation);
-+ }
-+ }
-+
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
-+ sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
-+ sensor->ep.bus_type != V4L2_MBUS_BT656) {
-+ dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
-+ return -EINVAL;
-+ }
-+
-+ /* get system clock (xclk) */
-+ sensor->xclk = devm_clk_get(dev, "xclk");
-+ if (IS_ERR(sensor->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(sensor->xclk);
-+ }
-+
-+ sensor->xclk_freq = clk_get_rate(sensor->xclk);
-+ if (sensor->xclk_freq < OV13850_XCLK_MIN ||
-+ sensor->xclk_freq > OV13850_XCLK_MAX) {
-+ dev_err(dev, "xclk frequency out of range: %d Hz\n",
-+ sensor->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ /* request optional power down pin */
-+ sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->pwdn_gpio))
-+ return PTR_ERR(sensor->pwdn_gpio);
-+
-+ /* request optional reset pin */
-+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->reset_gpio))
-+ return PTR_ERR(sensor->reset_gpio);
-+
-+ v4l2_i2c_subdev_init(&sensor->sd, client, &ov13850_subdev_ops);
-+
-+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
-+ V4L2_SUBDEV_FL_HAS_EVENTS;
-+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
-+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov13850_get_regulators(sensor);
-+ if (ret)
-+ return ret;
-+
-+ mutex_init(&sensor->lock);
-+
-+ ret = ov13850_check_chip_id(sensor);
-+ if (ret)
-+ goto entity_cleanup;
-+
-+ ret = ov13850_init_controls(sensor);
-+ if (ret)
-+ goto entity_cleanup;
-+
-+ ret = v4l2_async_register_subdev_sensor(&sensor->sd);
-+ if (ret)
-+ goto free_ctrls;
-+
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+entity_cleanup:
-+ media_entity_cleanup(&sensor->sd.entity);
-+ mutex_destroy(&sensor->lock);
-+ return ret;
-+}
-+
-+static int ov13850_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct ov13850_dev *sensor = to_ov13850_dev(sd);
-+
-+ v4l2_async_unregister_subdev(&sensor->sd);
-+ media_entity_cleanup(&sensor->sd.entity);
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+ mutex_destroy(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static const struct i2c_device_id ov13850_id[] = {
-+ {"ov13850", 0},
-+ {},
-+};
-+MODULE_DEVICE_TABLE(i2c, ov13850_id);
-+
-+static const struct of_device_id ov13850_dt_ids[] = {
-+ { .compatible = "ovti,ov13850" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, ov13850_dt_ids);
-+
-+static struct i2c_driver ov13850_i2c_driver = {
-+ .driver = {
-+ .name = "ov13850",
-+ .of_match_table = ov13850_dt_ids,
-+ },
-+ .id_table = ov13850_id,
-+ .probe_new = ov13850_probe,
-+ .remove = ov13850_remove,
-+};
-+
-+module_i2c_driver(ov13850_i2c_driver);
-+
-+MODULE_DESCRIPTION("OV13850 MIPI Camera Subdev Driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/ov4689_mipi.c
-@@ -0,0 +1,2975 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/ctype.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/of_device.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+#include "stfcamss.h"
-+
-+
-+#define OV4689_LANES 4
-+
-+#define OV4689_LINK_FREQ_500MHZ 500000000LL
-+
-+/* min/typical/max system clock (xclk) frequencies */
-+#define OV4689_XCLK_MIN 6000000
-+#define OV4689_XCLK_MAX 64000000
-+
-+#define OV4689_CHIP_ID (0x4688)
-+
-+#define OV4689_CHIP_ID_HIGH_BYTE 0x300a // max should be 0x46
-+#define OV4689_CHIP_ID_LOW_BYTE 0x300b // max should be 0x88
-+#define OV4689_REG_CHIP_ID 0x300a
-+
-+#define OV4689_REG_H_OUTPUT_SIZE 0x3808
-+#define OV4689_REG_V_OUTPUT_SIZE 0x380a
-+#define OV4689_REG_TIMING_HTS 0x380c
-+#define OV4689_REG_TIMING_VTS 0x380e
-+
-+#define OV4689_REG_EXPOSURE_HI 0x3500
-+#define OV4689_REG_EXPOSURE_MED 0x3501
-+#define OV4689_REG_EXPOSURE_LO 0x3502
-+#define OV4689_REG_GAIN_H 0x3507
-+#define OV4689_REG_GAIN_M 0x3508
-+#define OV4689_REG_GAIN_L 0x3509
-+#define OV4689_REG_TEST_PATTERN 0x5040
-+#define OV4689_REG_TIMING_TC_REG20 0x3820
-+#define OV4689_REG_TIMING_TC_REG21 0x3821
-+
-+#define OV4689_REG_AWB_R_GAIN 0x500C
-+#define OV4689_REG_AWB_B_GAIN 0x5010
-+#define OV4689_REG_STREAM_ON 0x0100
-+
-+#define OV4689_REG_MIPI_SC_CTRL_HI 0x3018
-+#define OV4689_REG_MIPI_SC_CTRL_LOW 0x3019
-+
-+enum ov4689_mode_id {
-+ //OV4689_MODE_720P_1280_720 = 0,
-+ OV4689_MODE_1080P_1920_1080 = 0,
-+ //OV4689_MODE_4M_2688_1520,
-+ OV4689_NUM_MODES,
-+};
-+
-+enum ov4689_frame_rate {
-+ OV4689_15_FPS = 0,
-+ OV4689_30_FPS,
-+ OV4689_45_FPS,
-+ OV4689_60_FPS,
-+ OV4689_90_FPS,
-+ OV4689_120_FPS,
-+ OV4689_150_FPS,
-+ OV4689_180_FPS,
-+ OV4689_330_FPS,
-+ OV4689_NUM_FRAMERATES,
-+};
-+
-+enum ov4689_format_mux {
-+ OV4689_FMT_MUX_RAW,
-+};
-+
-+static const int ov4689_framerates[] = {
-+ [OV4689_15_FPS] = 15,
-+ [OV4689_30_FPS] = 30,
-+ [OV4689_45_FPS] = 45,
-+ [OV4689_60_FPS] = 60,
-+ [OV4689_90_FPS] = 90,
-+ [OV4689_120_FPS] = 120,
-+ [OV4689_150_FPS] = 150,
-+ [OV4689_180_FPS] = 180,
-+ [OV4689_330_FPS] = 330,
-+};
-+
-+/* regulator supplies */
-+static const char * const ov4689_supply_name[] = {
-+ "DOVDD", /* Digital I/O (1.8V) supply */
-+ "AVDD", /* Analog (2.8V) supply */
-+ "DVDD", /* Digital Core (1.5V) supply */
-+};
-+
-+#define OV4689_NUM_SUPPLIES ARRAY_SIZE(ov4689_supply_name)
-+
-+/*
-+ * Image size under 1280 * 960 are SUBSAMPLING
-+ * Image size upper 1280 * 960 are SCALING
-+ */
-+enum ov4689_downsize_mode {
-+ SUBSAMPLING,
-+ SCALING,
-+};
-+
-+struct reg_value {
-+ u16 reg_addr;
-+ u8 val;
-+ u8 mask;
-+ u32 delay_ms;
-+};
-+
-+struct ov4689_mode_info {
-+ enum ov4689_mode_id id;
-+ enum ov4689_downsize_mode dn_mode;
-+ u32 hact;
-+ u32 htot;
-+ u32 vact;
-+ u32 vtot;
-+ const struct reg_value *reg_data;
-+ u32 reg_data_size;
-+ u32 max_fps;
-+};
-+
-+struct ov4689_ctrls {
-+ struct v4l2_ctrl_handler handler;
-+ struct v4l2_ctrl *pixel_rate;
-+ struct {
-+ struct v4l2_ctrl *exposure;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_wb;
-+ struct v4l2_ctrl *blue_balance;
-+ struct v4l2_ctrl *red_balance;
-+ };
-+ struct {
-+ struct v4l2_ctrl *anal_gain;
-+ };
-+ struct v4l2_ctrl *brightness;
-+ struct v4l2_ctrl *light_freq;
-+ struct v4l2_ctrl *link_freq;
-+ struct v4l2_ctrl *saturation;
-+ struct v4l2_ctrl *contrast;
-+ struct v4l2_ctrl *hue;
-+ struct v4l2_ctrl *test_pattern;
-+ struct v4l2_ctrl *hflip;
-+ struct v4l2_ctrl *vflip;
-+};
-+
-+struct ov4689_dev {
-+ struct i2c_client *i2c_client;
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+ struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
-+ struct clk *xclk; /* system clock to OV4689 */
-+ u32 xclk_freq;
-+
-+ struct regulator_bulk_data supplies[OV4689_NUM_SUPPLIES];
-+ struct gpio_desc *reset_gpio;
-+ struct gpio_desc *pwdn_gpio;
-+ bool upside_down;
-+
-+ /* lock to protect all members below */
-+ struct mutex lock;
-+
-+ struct v4l2_mbus_framefmt fmt;
-+
-+ const struct ov4689_mode_info *current_mode;
-+ const struct ov4689_mode_info *last_mode;
-+ enum ov4689_frame_rate current_fr;
-+ struct v4l2_fract frame_interval;
-+
-+ struct ov4689_ctrls ctrls;
-+
-+ bool pending_mode_change;
-+ int streaming;
-+};
-+
-+static inline struct ov4689_dev *to_ov4689_dev(struct v4l2_subdev *sd)
-+{
-+ return container_of(sd, struct ov4689_dev, sd);
-+}
-+
-+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
-+{
-+ return &container_of(ctrl->handler, struct ov4689_dev,
-+ ctrls.handler)->sd;
-+}
-+
-+/* ov4689 initial register */
-+static const struct reg_value ov4689_init_setting_30fps_1080P[] = {
-+/* ov4689_1080p_30fps_4d */
-+ {0x0103, 0x01, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+ {0x0300, 0x02, 0, 0},
-+ {0x0302, 0x32, 0, 0},
-+ {0x0303, 0x00, 0, 0},
-+ {0x0304, 0x03, 0, 0},
-+ {0x030b, 0x00, 0, 0},
-+ {0x030d, 0x1e, 0, 0},
-+ {0x030e, 0x04, 0, 0},
-+ {0x030f, 0x01, 0, 0},
-+ {0x0312, 0x01, 0, 0},
-+ {0x031e, 0x00, 0, 0},
-+ {0x3000, 0x20, 0, 0},
-+ {0x3002, 0x00, 0, 0},
-+ {0x3020, 0x93, 0, 0},
-+ {0x3021, 0x03, 0, 0},
-+ {0x3022, 0x01, 0, 0},
-+ {0x3031, 0x0a, 0, 0},
-+ {0x3305, 0xf1, 0, 0},
-+ {0x3307, 0x04, 0, 0},
-+ {0x3309, 0x29, 0, 0},
-+ {0x3500, 0x00, 0, 0},
-+ {0x3501, 0x4c, 0, 0},
-+ {0x3502, 0x00, 0, 0},
-+ {0x3503, 0x04, 0, 0},
-+ {0x3504, 0x00, 0, 0},
-+ {0x3505, 0x00, 0, 0},
-+ {0x3506, 0x00, 0, 0},
-+ {0x3507, 0x00, 0, 0},
-+ {0x3508, 0x00, 0, 0},
-+ {0x3509, 0x80, 0, 0},
-+ {0x350a, 0x00, 0, 0},
-+ {0x350b, 0x00, 0, 0},
-+ {0x350c, 0x00, 0, 0},
-+ {0x350d, 0x00, 0, 0},
-+ {0x350e, 0x00, 0, 0},
-+ {0x350f, 0x80, 0, 0},
-+ {0x3510, 0x00, 0, 0},
-+ {0x3511, 0x00, 0, 0},
-+ {0x3512, 0x00, 0, 0},
-+ {0x3513, 0x00, 0, 0},
-+ {0x3514, 0x00, 0, 0},
-+ {0x3515, 0x80, 0, 0},
-+ {0x3516, 0x00, 0, 0},
-+ {0x3517, 0x00, 0, 0},
-+ {0x3518, 0x00, 0, 0},
-+ {0x3519, 0x00, 0, 0},
-+ {0x351a, 0x00, 0, 0},
-+ {0x351b, 0x80, 0, 0},
-+ {0x351c, 0x00, 0, 0},
-+ {0x351d, 0x00, 0, 0},
-+ {0x351e, 0x00, 0, 0},
-+ {0x351f, 0x00, 0, 0},
-+ {0x3520, 0x00, 0, 0},
-+ {0x3521, 0x80, 0, 0},
-+ {0x3522, 0x08, 0, 0},
-+ {0x3524, 0x08, 0, 0},
-+ {0x3526, 0x08, 0, 0},
-+ {0x3528, 0x08, 0, 0},
-+ {0x352a, 0x08, 0, 0},
-+ {0x3602, 0x00, 0, 0},
-+ {0x3603, 0x40, 0, 0},
-+ {0x3604, 0x02, 0, 0},
-+ {0x3605, 0x00, 0, 0},
-+ {0x3606, 0x00, 0, 0},
-+ {0x3607, 0x00, 0, 0},
-+ {0x3609, 0x12, 0, 0},
-+ {0x360a, 0x40, 0, 0},
-+ {0x360c, 0x08, 0, 0},
-+ {0x360f, 0xe5, 0, 0},
-+ {0x3608, 0x8f, 0, 0},
-+ {0x3611, 0x00, 0, 0},
-+ {0x3613, 0xf7, 0, 0},
-+ {0x3616, 0x58, 0, 0},
-+ {0x3619, 0x99, 0, 0},
-+ {0x361b, 0x60, 0, 0},
-+ {0x361c, 0x7a, 0, 0},
-+ {0x361e, 0x79, 0, 0},
-+ {0x361f, 0x02, 0, 0},
-+ {0x3632, 0x00, 0, 0},
-+ {0x3633, 0x10, 0, 0},
-+ {0x3634, 0x10, 0, 0},
-+ {0x3635, 0x10, 0, 0},
-+ {0x3636, 0x15, 0, 0},
-+ {0x3646, 0x86, 0, 0},
-+ {0x364a, 0x0b, 0, 0},
-+ {0x3700, 0x17, 0, 0},
-+ {0x3701, 0x22, 0, 0},
-+ {0x3703, 0x10, 0, 0},
-+ {0x370a, 0x37, 0, 0},
-+ {0x3705, 0x00, 0, 0},
-+ {0x3706, 0x63, 0, 0},
-+ {0x3709, 0x3c, 0, 0},
-+ {0x370b, 0x01, 0, 0},
-+ {0x370c, 0x30, 0, 0},
-+ {0x3710, 0x24, 0, 0},
-+ {0x3711, 0x0c, 0, 0},
-+ {0x3716, 0x00, 0, 0},
-+ {0x3720, 0x28, 0, 0},
-+ {0x3729, 0x7b, 0, 0},
-+ {0x372a, 0x84, 0, 0},
-+ {0x372b, 0xbd, 0, 0},
-+ {0x372c, 0xbc, 0, 0},
-+ {0x372e, 0x52, 0, 0},
-+ {0x373c, 0x0e, 0, 0},
-+ {0x373e, 0x33, 0, 0},
-+ {0x3743, 0x10, 0, 0},
-+ {0x3744, 0x88, 0, 0},
-+ {0x3745, 0xc0, 0, 0},
-+ {0x374a, 0x43, 0, 0},
-+ {0x374c, 0x00, 0, 0},
-+ {0x374e, 0x23, 0, 0},
-+ {0x3751, 0x7b, 0, 0},
-+ {0x3752, 0x84, 0, 0},
-+ {0x3753, 0xbd, 0, 0},
-+ {0x3754, 0xbc, 0, 0},
-+ {0x3756, 0x52, 0, 0},
-+ {0x375c, 0x00, 0, 0},
-+ {0x3760, 0x00, 0, 0},
-+ {0x3761, 0x00, 0, 0},
-+ {0x3762, 0x00, 0, 0},
-+ {0x3763, 0x00, 0, 0},
-+ {0x3764, 0x00, 0, 0},
-+ {0x3767, 0x04, 0, 0},
-+ {0x3768, 0x04, 0, 0},
-+ {0x3769, 0x08, 0, 0},
-+ {0x376a, 0x08, 0, 0},
-+ {0x376b, 0x20, 0, 0},
-+ {0x376c, 0x00, 0, 0},
-+ {0x376d, 0x00, 0, 0},
-+ {0x376e, 0x00, 0, 0},
-+ {0x3773, 0x00, 0, 0},
-+ {0x3774, 0x51, 0, 0},
-+ {0x3776, 0xbd, 0, 0},
-+ {0x3777, 0xbd, 0, 0},
-+ {0x3781, 0x18, 0, 0},
-+ {0x3783, 0x25, 0, 0},
-+ {0x3798, 0x1b, 0, 0},
-+ {0x3800, 0x01, 0, 0},
-+ {0x3801, 0x88, 0, 0},
-+ {0x3802, 0x00, 0, 0},
-+ {0x3803, 0xe0, 0, 0},
-+ {0x3804, 0x09, 0, 0},
-+ {0x3805, 0x17, 0, 0},
-+ {0x3806, 0x05, 0, 0},
-+ {0x3807, 0x1f, 0, 0},
-+ {0x3808, 0x07, 0, 0},
-+ {0x3809, 0x80, 0, 0},
-+ {0x380a, 0x04, 0, 0},
-+ {0x380b, 0x38, 0, 0},
-+ {0x380c, 0x0d, 0, 0},
-+ {0x380d, 0x70, 0, 0},
-+ {0x380e, 0x04, 0, 0},
-+ {0x380f, 0x8A, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x08, 0, 0},
-+ {0x3812, 0x00, 0, 0},
-+ {0x3813, 0x04, 0, 0},
-+ {0x3814, 0x01, 0, 0},
-+ {0x3815, 0x01, 0, 0},
-+ {0x3819, 0x01, 0, 0},
-+ {0x3820, 0x06, 0, 0},
-+ {0x3821, 0x00, 0, 0},
-+ {0x3829, 0x00, 0, 0},
-+ {0x382a, 0x01, 0, 0},
-+ {0x382b, 0x01, 0, 0},
-+ {0x382d, 0x7f, 0, 0},
-+ {0x3830, 0x04, 0, 0},
-+ {0x3836, 0x01, 0, 0},
-+ {0x3837, 0x00, 0, 0},
-+ {0x3841, 0x02, 0, 0},
-+ {0x3846, 0x08, 0, 0},
-+ {0x3847, 0x07, 0, 0},
-+ {0x3d85, 0x36, 0, 0},
-+ {0x3d8c, 0x71, 0, 0},
-+ {0x3d8d, 0xcb, 0, 0},
-+ {0x3f0a, 0x00, 0, 0},
-+ {0x4000, 0xf1, 0, 0},
-+ {0x4001, 0x40, 0, 0},
-+ {0x4002, 0x04, 0, 0},
-+ {0x4003, 0x14, 0, 0},
-+ {0x400e, 0x00, 0, 0},
-+ {0x4011, 0x00, 0, 0},
-+ {0x401a, 0x00, 0, 0},
-+ {0x401b, 0x00, 0, 0},
-+ {0x401c, 0x00, 0, 0},
-+ {0x401d, 0x00, 0, 0},
-+ {0x401f, 0x00, 0, 0},
-+ {0x4020, 0x00, 0, 0},
-+ {0x4021, 0x10, 0, 0},
-+ {0x4022, 0x06, 0, 0},
-+ {0x4023, 0x13, 0, 0},
-+ {0x4024, 0x07, 0, 0},
-+ {0x4025, 0x40, 0, 0},
-+ {0x4026, 0x07, 0, 0},
-+ {0x4027, 0x50, 0, 0},
-+ {0x4028, 0x00, 0, 0},
-+ {0x4029, 0x02, 0, 0},
-+ {0x402a, 0x06, 0, 0},
-+ {0x402b, 0x04, 0, 0},
-+ {0x402c, 0x02, 0, 0},
-+ {0x402d, 0x02, 0, 0},
-+ {0x402e, 0x0e, 0, 0},
-+ {0x402f, 0x04, 0, 0},
-+ {0x4302, 0xff, 0, 0},
-+ {0x4303, 0xff, 0, 0},
-+ {0x4304, 0x00, 0, 0},
-+ {0x4305, 0x00, 0, 0},
-+ {0x4306, 0x00, 0, 0},
-+ {0x4308, 0x02, 0, 0},
-+ {0x4500, 0x6c, 0, 0},
-+ {0x4501, 0xc4, 0, 0},
-+ {0x4502, 0x40, 0, 0},
-+ {0x4503, 0x01, 0, 0},
-+ {0x4601, 0x77, 0, 0},
-+ {0x4800, 0x04, 0, 0},
-+ {0x4813, 0x08, 0, 0},
-+ {0x481f, 0x40, 0, 0},
-+ {0x4829, 0x78, 0, 0},
-+ {0x4837, 0x10, 0, 0},
-+ {0x4b00, 0x2a, 0, 0},
-+ {0x4b0d, 0x00, 0, 0},
-+ {0x4d00, 0x04, 0, 0},
-+ {0x4d01, 0x42, 0, 0},
-+ {0x4d02, 0xd1, 0, 0},
-+ {0x4d03, 0x93, 0, 0},
-+ {0x4d04, 0xf5, 0, 0},
-+ {0x4d05, 0xc1, 0, 0},
-+ {0x5000, 0xf3, 0, 0},
-+ {0x5001, 0x11, 0, 0},
-+ {0x5004, 0x00, 0, 0},
-+ {0x500a, 0x00, 0, 0},
-+ {0x500b, 0x00, 0, 0},
-+ {0x5032, 0x00, 0, 0},
-+ {0x5040, 0x00, 0, 0},
-+ {0x5050, 0x0c, 0, 0},
-+ {0x5500, 0x00, 0, 0},
-+ {0x5501, 0x10, 0, 0},
-+ {0x5502, 0x01, 0, 0},
-+ {0x5503, 0x0f, 0, 0},
-+ {0x8000, 0x00, 0, 0},
-+ {0x8001, 0x00, 0, 0},
-+ {0x8002, 0x00, 0, 0},
-+ {0x8003, 0x00, 0, 0},
-+ {0x8004, 0x00, 0, 0},
-+ {0x8005, 0x00, 0, 0},
-+ {0x8006, 0x00, 0, 0},
-+ {0x8007, 0x00, 0, 0},
-+ {0x8008, 0x00, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+};
-+
-+static const struct reg_value ov4689_setting_VGA_640_480[] = {
-+ //@@ RES_640x480_2x_Bin_330fps_816Mbps
-+ //OV4689_AM01B_640x480_24M_2lane_816Mbps_330fps_20140210.txt
-+ {0x0103, 0x01, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+ {0x0300, 0x00, 0, 0}, // 00
-+ {0x0302, 0x22, 0, 0}, // 816Mbps 5a ; 64 ; 5a ; 78 ; 78 ; 2a
-+ {0x0303, 0x00, 0, 0}, // 03 ; 01 ; 02 ;
-+ {0x0304, 0x03, 0, 0},
-+ {0x030b, 0x00, 0, 0},
-+ {0x030d, 0x1e, 0, 0},
-+ {0x030e, 0x04, 0, 0},
-+ {0x030f, 0x01, 0, 0},
-+ {0x0312, 0x01, 0, 0},
-+ {0x031e, 0x00, 0, 0},
-+ {0x3000, 0x20, 0, 0},
-+ {0x3002, 0x00, 0, 0},
-+ {0x3020, 0x93, 0, 0},
-+ {0x3021, 0x03, 0, 0},
-+ {0x3022, 0x01, 0, 0},
-+ {0x3031, 0x0a, 0, 0},
-+ {0x303f, 0x0c, 0, 0},
-+ {0x3305, 0xf1, 0, 0},
-+ {0x3307, 0x04, 0, 0},
-+ {0x3309, 0x29, 0, 0},
-+ {0x3500, 0x00, 0, 0},
-+ {0x3501, 0x4c, 0, 0},
-+ {0x3502, 0x00, 0, 0},
-+ {0x3503, 0x04, 0, 0},
-+ {0x3504, 0x00, 0, 0},
-+ {0x3505, 0x00, 0, 0},
-+ {0x3506, 0x00, 0, 0},
-+ {0x3507, 0x00, 0, 0},
-+ {0x3508, 0x00, 0, 0},
-+ {0x3509, 0x80, 0, 0}, // 8X
-+ {0x350a, 0x00, 0, 0},
-+ {0x350b, 0x00, 0, 0},
-+ {0x350c, 0x00, 0, 0},
-+ {0x350d, 0x00, 0, 0},
-+ {0x350e, 0x00, 0, 0},
-+ {0x350f, 0x80, 0, 0},
-+ {0x3510, 0x00, 0, 0},
-+ {0x3511, 0x00, 0, 0},
-+ {0x3512, 0x00, 0, 0},
-+ {0x3513, 0x00, 0, 0},
-+ {0x3514, 0x00, 0, 0},
-+ {0x3515, 0x80, 0, 0},
-+ {0x3516, 0x00, 0, 0},
-+ {0x3517, 0x00, 0, 0},
-+ {0x3518, 0x00, 0, 0},
-+ {0x3519, 0x00, 0, 0},
-+ {0x351a, 0x00, 0, 0},
-+ {0x351b, 0x80, 0, 0},
-+ {0x351c, 0x00, 0, 0},
-+ {0x351d, 0x00, 0, 0},
-+ {0x351e, 0x00, 0, 0},
-+ {0x351f, 0x00, 0, 0},
-+ {0x3520, 0x00, 0, 0},
-+ {0x3521, 0x80, 0, 0},
-+ {0x3522, 0x08, 0, 0},
-+ {0x3524, 0x08, 0, 0},
-+ {0x3526, 0x08, 0, 0},
-+ {0x3528, 0x08, 0, 0},
-+ {0x352a, 0x08, 0, 0},
-+ {0x3602, 0x00, 0, 0},
-+ {0x3603, 0x40, 0, 0},
-+ {0x3604, 0x02, 0, 0},
-+ {0x3605, 0x00, 0, 0},
-+ {0x3606, 0x00, 0, 0},
-+ {0x3607, 0x00, 0, 0},
-+ {0x3609, 0x12, 0, 0},
-+ {0x360a, 0x40, 0, 0},
-+ {0x360c, 0x08, 0, 0},
-+ {0x360f, 0xe5, 0, 0},
-+ {0x3608, 0x8f, 0, 0},
-+ {0x3611, 0x00, 0, 0},
-+ {0x3613, 0xf7, 0, 0},
-+ {0x3616, 0x58, 0, 0},
-+ {0x3619, 0x99, 0, 0},
-+ {0x361b, 0x60, 0, 0},
-+ {0x361c, 0x7a, 0, 0},
-+ {0x361e, 0x79, 0, 0},
-+ {0x361f, 0x02, 0, 0},
-+ {0x3632, 0x05, 0, 0},
-+ {0x3633, 0x10, 0, 0},
-+ {0x3634, 0x10, 0, 0},
-+ {0x3635, 0x10, 0, 0},
-+ {0x3636, 0x15, 0, 0},
-+ {0x3646, 0x86, 0, 0},
-+ {0x364a, 0x0b, 0, 0},
-+ {0x3700, 0x17, 0, 0},
-+ {0x3701, 0x22, 0, 0},
-+ {0x3703, 0x10, 0, 0},
-+ {0x370a, 0x37, 0, 0},
-+ {0x3705, 0x00, 0, 0},
-+ {0x3706, 0x63, 0, 0},
-+ {0x3709, 0x3c, 0, 0},
-+ {0x370b, 0x01, 0, 0},
-+ {0x370c, 0x30, 0, 0},
-+ {0x3710, 0x24, 0, 0},
-+ {0x3711, 0x0c, 0, 0},
-+ {0x3716, 0x00, 0, 0},
-+ {0x3720, 0x28, 0, 0},
-+ {0x3729, 0x7b, 0, 0},
-+ {0x372a, 0x84, 0, 0},
-+ {0x372b, 0xbd, 0, 0},
-+ {0x372c, 0xbc, 0, 0},
-+ {0x372e, 0x52, 0, 0},
-+ {0x373c, 0x0e, 0, 0},
-+ {0x373e, 0x33, 0, 0},
-+ {0x3743, 0x10, 0, 0},
-+ {0x3744, 0x88, 0, 0},
-+ {0x3745, 0xc0, 0, 0},
-+ {0x374a, 0x43, 0, 0},
-+ {0x374c, 0x00, 0, 0},
-+ {0x374e, 0x23, 0, 0},
-+ {0x3751, 0x7b, 0, 0},
-+ {0x3752, 0x84, 0, 0},
-+ {0x3753, 0xbd, 0, 0},
-+ {0x3754, 0xbc, 0, 0},
-+ {0x3756, 0x52, 0, 0},
-+ {0x375c, 0x00, 0, 0},
-+ {0x3760, 0x00, 0, 0},
-+ {0x3761, 0x00, 0, 0},
-+ {0x3762, 0x00, 0, 0},
-+ {0x3763, 0x00, 0, 0},
-+ {0x3764, 0x00, 0, 0},
-+ {0x3767, 0x04, 0, 0},
-+ {0x3768, 0x04, 0, 0},
-+ {0x3769, 0x08, 0, 0},
-+ {0x376a, 0x08, 0, 0},
-+ {0x376b, 0x40, 0, 0},
-+ {0x376c, 0x00, 0, 0},
-+ {0x376d, 0x00, 0, 0},
-+ {0x376e, 0x00, 0, 0},
-+ {0x3773, 0x00, 0, 0},
-+ {0x3774, 0x51, 0, 0},
-+ {0x3776, 0xbd, 0, 0},
-+ {0x3777, 0xbd, 0, 0},
-+ {0x3781, 0x18, 0, 0},
-+ {0x3783, 0x25, 0, 0},
-+ {0x3798, 0x1b, 0, 0},
-+ {0x3800, 0x00, 0, 0},
-+ {0x3801, 0x48, 0, 0},
-+ {0x3802, 0x00, 0, 0},
-+ {0x3803, 0x2C, 0, 0},
-+ {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x57, 0, 0},
-+ {0x3806, 0x05, 0, 0},
-+ {0x3807, 0xD3, 0, 0},
-+ {0x3808, 0x02, 0, 0},
-+ {0x3809, 0x80, 0, 0},
-+ {0x380a, 0x01, 0, 0},
-+ {0x380b, 0xe0, 0, 0},
-+
-+ {0x380c, 0x02, 0, 0}, // 0a ; 03
-+ {0x380d, 0x04, 0, 0}, // 1c ; 5C
-+
-+ {0x380e, 0x03, 0, 0},
-+ {0x380f, 0x05, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x04, 0, 0},
-+ {0x3812, 0x00, 0, 0},
-+ {0x3813, 0x02, 0, 0},
-+ {0x3814, 0x03, 0, 0},
-+ {0x3815, 0x01, 0, 0},
-+ {0x3819, 0x01, 0, 0},
-+ {0x3820, 0x06, 0, 0},
-+ {0x3821, 0x00, 0, 0},
-+ {0x3829, 0x00, 0, 0},
-+ {0x382a, 0x03, 0, 0},
-+ {0x382b, 0x01, 0, 0},
-+ {0x382d, 0x7f, 0, 0},
-+ {0x3830, 0x08, 0, 0},
-+ {0x3836, 0x02, 0, 0},
-+ {0x3837, 0x00, 0, 0},
-+ {0x3841, 0x02, 0, 0},
-+ {0x3846, 0x08, 0, 0},
-+ {0x3847, 0x07, 0, 0},
-+ {0x3d85, 0x36, 0, 0},
-+ {0x3d8c, 0x71, 0, 0},
-+ {0x3d8d, 0xcb, 0, 0},
-+ {0x3f0a, 0x00, 0, 0},
-+ {0x4000, 0x71, 0, 0},
-+ {0x4001, 0x50, 0, 0},
-+ {0x4002, 0x04, 0, 0},
-+ {0x4003, 0x14, 0, 0},
-+ {0x400e, 0x00, 0, 0},
-+ {0x4011, 0x00, 0, 0},
-+ {0x401a, 0x00, 0, 0},
-+ {0x401b, 0x00, 0, 0},
-+ {0x401c, 0x00, 0, 0},
-+ {0x401d, 0x00, 0, 0},
-+ {0x401f, 0x00, 0, 0},
-+ {0x4020, 0x00, 0, 0},
-+ {0x4021, 0x10, 0, 0},
-+ {0x4022, 0x03, 0, 0},
-+ {0x4023, 0x93, 0, 0},
-+ {0x4024, 0x04, 0, 0},
-+ {0x4025, 0xC0, 0, 0},
-+ {0x4026, 0x04, 0, 0},
-+ {0x4027, 0xD0, 0, 0},
-+ {0x4028, 0x00, 0, 0},
-+ {0x4029, 0x02, 0, 0},
-+ {0x402a, 0x06, 0, 0},
-+ {0x402b, 0x04, 0, 0},
-+ {0x402c, 0x02, 0, 0},
-+ {0x402d, 0x02, 0, 0},
-+ {0x402e, 0x0e, 0, 0},
-+ {0x402f, 0x04, 0, 0},
-+ {0x4302, 0xff, 0, 0},
-+ {0x4303, 0xff, 0, 0},
-+ {0x4304, 0x00, 0, 0},
-+ {0x4305, 0x00, 0, 0},
-+ {0x4306, 0x00, 0, 0},
-+ {0x4308, 0x02, 0, 0},
-+ {0x4500, 0x6c, 0, 0},
-+ {0x4501, 0xc4, 0, 0},
-+ {0x4502, 0x44, 0, 0},
-+ {0x4503, 0x01, 0, 0},
-+ {0x4600, 0x00, 0, 0},
-+ {0x4601, 0x4F, 0, 0},
-+ {0x4800, 0x04, 0, 0},
-+ {0x4813, 0x08, 0, 0},
-+ {0x481f, 0x40, 0, 0},
-+ {0x4829, 0x78, 0, 0},
-+ {0x4837, 0x10, 0, 0}, // 20 ; 10
-+ {0x4b00, 0x2a, 0, 0},
-+ {0x4b0d, 0x00, 0, 0},
-+ {0x4d00, 0x04, 0, 0},
-+ {0x4d01, 0x42, 0, 0},
-+ {0x4d02, 0xd1, 0, 0},
-+ {0x4d03, 0x93, 0, 0},
-+ {0x4d04, 0xf5, 0, 0},
-+ {0x4d05, 0xc1, 0, 0},
-+ {0x5000, 0xf3, 0, 0},
-+ {0x5001, 0x11, 0, 0},
-+ {0x5004, 0x00, 0, 0},
-+ {0x500a, 0x00, 0, 0},
-+ {0x500b, 0x00, 0, 0},
-+ {0x5032, 0x00, 0, 0},
-+ {0x5040, 0x00, 0, 0},
-+ {0x5050, 0x3c, 0, 0},
-+ {0x5500, 0x00, 0, 0},
-+ {0x5501, 0x10, 0, 0},
-+ {0x5502, 0x01, 0, 0},
-+ {0x5503, 0x0f, 0, 0},
-+ {0x8000, 0x00, 0, 0},
-+ {0x8001, 0x00, 0, 0},
-+ {0x8002, 0x00, 0, 0},
-+ {0x8003, 0x00, 0, 0},
-+ {0x8004, 0x00, 0, 0},
-+ {0x8005, 0x00, 0, 0},
-+ {0x8006, 0x00, 0, 0},
-+ {0x8007, 0x00, 0, 0},
-+ {0x8008, 0x00, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+};
-+
-+static const struct reg_value ov4689_setting_720P_1280_720[] = {
-+ //@@ RES_1280x720_2x_Bin_150fps_816Mbps
-+ //OV4689_AM01B_1280x720_24M_2lane_816Mbps_150fps_20140210.txt
-+ {0x0103, 0x01, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+ {0x0300, 0x00, 0, 0}, // 00
-+ {0x0302, 0x22, 0, 0}, // 816Mbps 5a ; 64 ; 5a ; 78 ; 78 ; 2a
-+ {0x0303, 0x00, 0, 0}, // 03 ; 01 ; 02 ;
-+ {0x0304, 0x03, 0, 0},
-+ {0x030b, 0x00, 0, 0},
-+ {0x030d, 0x1e, 0, 0},
-+ {0x030e, 0x04, 0, 0},
-+ {0x030f, 0x01, 0, 0},
-+ {0x0312, 0x01, 0, 0},
-+ {0x031e, 0x00, 0, 0},
-+ {0x3000, 0x20, 0, 0},
-+ {0x3002, 0x00, 0, 0},
-+ {0x3020, 0x93, 0, 0},
-+ {0x3021, 0x03, 0, 0},
-+ {0x3022, 0x01, 0, 0},
-+ {0x3031, 0x0a, 0, 0},
-+ {0x303f, 0x0c, 0, 0},
-+ {0x3305, 0xf1, 0, 0},
-+ {0x3307, 0x04, 0, 0},
-+ {0x3309, 0x29, 0, 0},
-+ {0x3500, 0x00, 0, 0},
-+ {0x3501, 0x30, 0, 0},
-+ {0x3502, 0x00, 0, 0},
-+ {0x3503, 0x04, 0, 0},
-+ {0x3504, 0x00, 0, 0},
-+ {0x3505, 0x00, 0, 0},
-+ {0x3506, 0x00, 0, 0},
-+ {0x3507, 0x00, 0, 0},
-+ {0x3508, 0x07, 0, 0},
-+ {0x3509, 0x78, 0, 0}, // 8X
-+ {0x350a, 0x00, 0, 0},
-+ {0x350b, 0x00, 0, 0},
-+ {0x350c, 0x00, 0, 0},
-+ {0x350d, 0x00, 0, 0},
-+ {0x350e, 0x00, 0, 0},
-+ {0x350f, 0x80, 0, 0},
-+ {0x3510, 0x00, 0, 0},
-+ {0x3511, 0x00, 0, 0},
-+ {0x3512, 0x00, 0, 0},
-+ {0x3513, 0x00, 0, 0},
-+ {0x3514, 0x00, 0, 0},
-+ {0x3515, 0x80, 0, 0},
-+ {0x3516, 0x00, 0, 0},
-+ {0x3517, 0x00, 0, 0},
-+ {0x3518, 0x00, 0, 0},
-+ {0x3519, 0x00, 0, 0},
-+ {0x351a, 0x00, 0, 0},
-+ {0x351b, 0x80, 0, 0},
-+ {0x351c, 0x00, 0, 0},
-+ {0x351d, 0x00, 0, 0},
-+ {0x351e, 0x00, 0, 0},
-+ {0x351f, 0x00, 0, 0},
-+ {0x3520, 0x00, 0, 0},
-+ {0x3521, 0x80, 0, 0},
-+ {0x3522, 0x08, 0, 0},
-+ {0x3524, 0x08, 0, 0},
-+ {0x3526, 0x08, 0, 0},
-+ {0x3528, 0x08, 0, 0},
-+ {0x352a, 0x08, 0, 0},
-+ {0x3602, 0x00, 0, 0},
-+ {0x3603, 0x40, 0, 0},
-+ {0x3604, 0x02, 0, 0},
-+ {0x3605, 0x00, 0, 0},
-+ {0x3606, 0x00, 0, 0},
-+ {0x3607, 0x00, 0, 0},
-+ {0x3609, 0x12, 0, 0},
-+ {0x360a, 0x40, 0, 0},
-+ {0x360c, 0x08, 0, 0},
-+ {0x360f, 0xe5, 0, 0},
-+ {0x3608, 0x8f, 0, 0},
-+ {0x3611, 0x00, 0, 0},
-+ {0x3613, 0xf7, 0, 0},
-+ {0x3616, 0x58, 0, 0},
-+ {0x3619, 0x99, 0, 0},
-+ {0x361b, 0x60, 0, 0},
-+ {0x361c, 0x7a, 0, 0},
-+ {0x361e, 0x79, 0, 0},
-+ {0x361f, 0x02, 0, 0},
-+ {0x3632, 0x05, 0, 0},
-+ {0x3633, 0x10, 0, 0},
-+ {0x3634, 0x10, 0, 0},
-+ {0x3635, 0x10, 0, 0},
-+ {0x3636, 0x15, 0, 0},
-+ {0x3646, 0x86, 0, 0},
-+ {0x364a, 0x0b, 0, 0},
-+ {0x3700, 0x17, 0, 0},
-+ {0x3701, 0x22, 0, 0},
-+ {0x3703, 0x10, 0, 0},
-+ {0x370a, 0x37, 0, 0},
-+ {0x3705, 0x00, 0, 0},
-+ {0x3706, 0x63, 0, 0},
-+ {0x3709, 0x3c, 0, 0},
-+ {0x370b, 0x01, 0, 0},
-+ {0x370c, 0x30, 0, 0},
-+ {0x3710, 0x24, 0, 0},
-+ {0x3711, 0x0c, 0, 0},
-+ {0x3716, 0x00, 0, 0},
-+ {0x3720, 0x28, 0, 0},
-+ {0x3729, 0x7b, 0, 0},
-+ {0x372a, 0x84, 0, 0},
-+ {0x372b, 0xbd, 0, 0},
-+ {0x372c, 0xbc, 0, 0},
-+ {0x372e, 0x52, 0, 0},
-+ {0x373c, 0x0e, 0, 0},
-+ {0x373e, 0x33, 0, 0},
-+ {0x3743, 0x10, 0, 0},
-+ {0x3744, 0x88, 0, 0},
-+ {0x3745, 0xc0, 0, 0},
-+ {0x374a, 0x43, 0, 0},
-+ {0x374c, 0x00, 0, 0},
-+ {0x374e, 0x23, 0, 0},
-+ {0x3751, 0x7b, 0, 0},
-+ {0x3752, 0x84, 0, 0},
-+ {0x3753, 0xbd, 0, 0},
-+ {0x3754, 0xbc, 0, 0},
-+ {0x3756, 0x52, 0, 0},
-+ {0x375c, 0x00, 0, 0},
-+ {0x3760, 0x00, 0, 0},
-+ {0x3761, 0x00, 0, 0},
-+ {0x3762, 0x00, 0, 0},
-+ {0x3763, 0x00, 0, 0},
-+ {0x3764, 0x00, 0, 0},
-+ {0x3767, 0x04, 0, 0},
-+ {0x3768, 0x04, 0, 0},
-+ {0x3769, 0x08, 0, 0},
-+ {0x376a, 0x08, 0, 0},
-+ {0x376b, 0x40, 0, 0},
-+ {0x376c, 0x00, 0, 0},
-+ {0x376d, 0x00, 0, 0},
-+ {0x376e, 0x00, 0, 0},
-+ {0x3773, 0x00, 0, 0},
-+ {0x3774, 0x51, 0, 0},
-+ {0x3776, 0xbd, 0, 0},
-+ {0x3777, 0xbd, 0, 0},
-+ {0x3781, 0x18, 0, 0},
-+ {0x3783, 0x25, 0, 0},
-+ {0x3798, 0x1b, 0, 0},
-+ {0x3800, 0x00, 0, 0},
-+ {0x3801, 0x48, 0, 0},
-+ {0x3802, 0x00, 0, 0},
-+ {0x3803, 0x2C, 0, 0},
-+ {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x57, 0, 0},
-+ {0x3806, 0x05, 0, 0},
-+ {0x3807, 0xD3, 0, 0},
-+ {0x3808, 0x05, 0, 0},
-+ {0x3809, 0x00, 0, 0},
-+ {0x380a, 0x02, 0, 0},
-+ {0x380b, 0xD0, 0, 0},
-+#ifndef UNUSED_CODE
-+ {0x380c, 0x04, 0, 0}, // 0a ; 03
-+ {0x380d, 0x08, 0, 0}, // 1c ; 5C
-+#else
-+ {0x380c, 0x05, 0, 0}, // 120fps
-+ {0x380d, 0x0A, 0, 0},
-+#endif
-+ {0x380e, 0x03, 0, 0},
-+ {0x380f, 0x05, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x04, 0, 0},
-+ {0x3812, 0x00, 0, 0},
-+ {0x3813, 0x02, 0, 0},
-+ {0x3814, 0x03, 0, 0},
-+ {0x3815, 0x01, 0, 0},
-+ {0x3819, 0x01, 0, 0},
-+ {0x3820, 0x06, 0, 0},
-+ {0x3821, 0x00, 0, 0},
-+ {0x3829, 0x00, 0, 0},
-+ {0x382a, 0x03, 0, 0},
-+ {0x382b, 0x01, 0, 0},
-+ {0x382d, 0x7f, 0, 0},
-+ {0x3830, 0x08, 0, 0},
-+ {0x3836, 0x02, 0, 0},
-+ {0x3837, 0x00, 0, 0},
-+ {0x3841, 0x02, 0, 0},
-+ {0x3846, 0x08, 0, 0},
-+ {0x3847, 0x07, 0, 0},
-+ {0x3d85, 0x36, 0, 0},
-+ {0x3d8c, 0x71, 0, 0},
-+ {0x3d8d, 0xcb, 0, 0},
-+ {0x3f0a, 0x00, 0, 0},
-+ {0x4000, 0x71, 0, 0},
-+ {0x4001, 0x50, 0, 0},
-+ {0x4002, 0x04, 0, 0},
-+ {0x4003, 0x14, 0, 0},
-+ {0x400e, 0x00, 0, 0},
-+ {0x4011, 0x00, 0, 0},
-+ {0x401a, 0x00, 0, 0},
-+ {0x401b, 0x00, 0, 0},
-+ {0x401c, 0x00, 0, 0},
-+ {0x401d, 0x00, 0, 0},
-+ {0x401f, 0x00, 0, 0},
-+ {0x4020, 0x00, 0, 0},
-+ {0x4021, 0x10, 0, 0},
-+ {0x4022, 0x03, 0, 0},
-+ {0x4023, 0x93, 0, 0},
-+ {0x4024, 0x04, 0, 0},
-+ {0x4025, 0xC0, 0, 0},
-+ {0x4026, 0x04, 0, 0},
-+ {0x4027, 0xD0, 0, 0},
-+ {0x4028, 0x00, 0, 0},
-+ {0x4029, 0x02, 0, 0},
-+ {0x402a, 0x06, 0, 0},
-+ {0x402b, 0x04, 0, 0},
-+ {0x402c, 0x02, 0, 0},
-+ {0x402d, 0x02, 0, 0},
-+ {0x402e, 0x0e, 0, 0},
-+ {0x402f, 0x04, 0, 0},
-+ {0x4302, 0xff, 0, 0},
-+ {0x4303, 0xff, 0, 0},
-+ {0x4304, 0x00, 0, 0},
-+ {0x4305, 0x00, 0, 0},
-+ {0x4306, 0x00, 0, 0},
-+ {0x4308, 0x02, 0, 0},
-+ {0x4500, 0x6c, 0, 0},
-+ {0x4501, 0xc4, 0, 0},
-+ {0x4502, 0x44, 0, 0},
-+ {0x4503, 0x01, 0, 0},
-+ {0x4600, 0x00, 0, 0},
-+ {0x4601, 0x4F, 0, 0},
-+ {0x4800, 0x04, 0, 0},
-+ {0x4813, 0x08, 0, 0},
-+ {0x481f, 0x40, 0, 0},
-+ {0x4829, 0x78, 0, 0},
-+ {0x4837, 0x10, 0, 0}, // 20 ; 10
-+ {0x4b00, 0x2a, 0, 0},
-+ {0x4b0d, 0x00, 0, 0},
-+ {0x4d00, 0x04, 0, 0},
-+ {0x4d01, 0x42, 0, 0},
-+ {0x4d02, 0xd1, 0, 0},
-+ {0x4d03, 0x93, 0, 0},
-+ {0x4d04, 0xf5, 0, 0},
-+ {0x4d05, 0xc1, 0, 0},
-+ {0x5000, 0xf3, 0, 0},
-+ {0x5001, 0x11, 0, 0},
-+ {0x5004, 0x00, 0, 0},
-+ {0x500a, 0x00, 0, 0},
-+ {0x500b, 0x00, 0, 0},
-+ {0x5032, 0x00, 0, 0},
-+ {0x5040, 0x00, 0, 0},
-+ {0x5050, 0x3c, 0, 0},
-+ {0x5500, 0x00, 0, 0},
-+ {0x5501, 0x10, 0, 0},
-+ {0x5502, 0x01, 0, 0},
-+ {0x5503, 0x0f, 0, 0},
-+ {0x8000, 0x00, 0, 0},
-+ {0x8001, 0x00, 0, 0},
-+ {0x8002, 0x00, 0, 0},
-+ {0x8003, 0x00, 0, 0},
-+ {0x8004, 0x00, 0, 0},
-+ {0x8005, 0x00, 0, 0},
-+ {0x8006, 0x00, 0, 0},
-+ {0x8007, 0x00, 0, 0},
-+ {0x8008, 0x00, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+};
-+
-+static const struct reg_value ov4689_setting_1080P_1920_1080[] = {
-+ //@@ RES_1920x1080_60fps_816Mbps 2lanes
-+ {0x0103, 0x01, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+ {0x0300, 0x00, 0, 0}, // clk
-+ {0x0302, 0x22, 0, 0},
-+ {0x0303, 0x00, 0, 0},
-+ {0x0304, 0x03, 0, 0},
-+ {0x030b, 0x00, 0, 0},
-+ {0x030d, 0x1e, 0, 0},
-+ {0x030e, 0x04, 0, 0},
-+ {0x030f, 0x01, 0, 0},
-+ {0x0312, 0x01, 0, 0},
-+ {0x031e, 0x00, 0, 0},
-+ {0x3000, 0x20, 0, 0},
-+ {0x3002, 0x00, 0, 0},
-+ {0x3020, 0x93, 0, 0},
-+ {0x3021, 0x03, 0, 0},
-+ {0x3022, 0x01, 0, 0},
-+ {0x3031, 0x0a, 0, 0},
-+ {0x303f, 0x0c, 0, 0},
-+ {0x3305, 0xf1, 0, 0},
-+ {0x3307, 0x04, 0, 0},
-+ {0x3309, 0x29, 0, 0},
-+ {0x3500, 0x00, 0, 0}, // AEC
-+ {0x3501, 0x4c, 0, 0},
-+ {0x3502, 0x00, 0, 0},
-+ {0x3503, 0x04, 0, 0},
-+ {0x3504, 0x00, 0, 0},
-+ {0x3505, 0x00, 0, 0},
-+ {0x3506, 0x00, 0, 0},
-+ {0x3507, 0x00, 0, 0},
-+ {0x3508, 0x00, 0, 0},
-+ {0x3509, 0x80, 0, 0},
-+ {0x350a, 0x00, 0, 0},
-+ {0x350b, 0x00, 0, 0},
-+ {0x350c, 0x00, 0, 0},
-+ {0x350d, 0x00, 0, 0},
-+ {0x350e, 0x00, 0, 0},
-+ {0x350f, 0x80, 0, 0},
-+ {0x3510, 0x00, 0, 0},
-+ {0x3511, 0x00, 0, 0},
-+ {0x3512, 0x00, 0, 0},
-+ {0x3513, 0x00, 0, 0},
-+ {0x3514, 0x00, 0, 0},
-+ {0x3515, 0x80, 0, 0},
-+ {0x3516, 0x00, 0, 0},
-+ {0x3517, 0x00, 0, 0},
-+ {0x3518, 0x00, 0, 0},
-+ {0x3519, 0x00, 0, 0},
-+ {0x351a, 0x00, 0, 0},
-+ {0x351b, 0x80, 0, 0},
-+ {0x351c, 0x00, 0, 0},
-+ {0x351d, 0x00, 0, 0},
-+ {0x351e, 0x00, 0, 0},
-+ {0x351f, 0x00, 0, 0},
-+ {0x3520, 0x00, 0, 0},
-+ {0x3521, 0x80, 0, 0},
-+ {0x3522, 0x08, 0, 0},
-+ {0x3524, 0x08, 0, 0},
-+ {0x3526, 0x08, 0, 0},
-+ {0x3528, 0x08, 0, 0},
-+ {0x352a, 0x08, 0, 0},
-+ {0x3602, 0x00, 0, 0},
-+ {0x3603, 0x40, 0, 0},
-+ {0x3604, 0x02, 0, 0},
-+ {0x3605, 0x00, 0, 0},
-+ {0x3606, 0x00, 0, 0},
-+ {0x3607, 0x00, 0, 0},
-+ {0x3609, 0x12, 0, 0},
-+ {0x360a, 0x40, 0, 0},
-+ {0x360c, 0x08, 0, 0},
-+ {0x360f, 0xe5, 0, 0},
-+ {0x3608, 0x8f, 0, 0},
-+ {0x3611, 0x00, 0, 0},
-+ {0x3613, 0xf7, 0, 0},
-+ {0x3616, 0x58, 0, 0},
-+ {0x3619, 0x99, 0, 0},
-+ {0x361b, 0x60, 0, 0},
-+ {0x361c, 0x7a, 0, 0},
-+ {0x361e, 0x79, 0, 0},
-+ {0x361f, 0x02, 0, 0},
-+ {0x3632, 0x00, 0, 0},
-+ {0x3633, 0x10, 0, 0},
-+ {0x3634, 0x10, 0, 0},
-+ {0x3635, 0x10, 0, 0},
-+ {0x3636, 0x15, 0, 0},
-+ {0x3646, 0x86, 0, 0},
-+ {0x364a, 0x0b, 0, 0},
-+ {0x3700, 0x17, 0, 0},
-+ {0x3701, 0x22, 0, 0},
-+ {0x3703, 0x10, 0, 0},
-+ {0x370a, 0x37, 0, 0},
-+ {0x3705, 0x00, 0, 0},
-+ {0x3706, 0x63, 0, 0},
-+ {0x3709, 0x3c, 0, 0},
-+ {0x370b, 0x01, 0, 0},
-+ {0x370c, 0x30, 0, 0},
-+ {0x3710, 0x24, 0, 0},
-+ {0x3711, 0x0c, 0, 0},
-+ {0x3716, 0x00, 0, 0},
-+ {0x3720, 0x28, 0, 0},
-+ {0x3729, 0x7b, 0, 0},
-+ {0x372a, 0x84, 0, 0},
-+ {0x372b, 0xbd, 0, 0},
-+ {0x372c, 0xbc, 0, 0},
-+ {0x372e, 0x52, 0, 0},
-+ {0x373c, 0x0e, 0, 0},
-+ {0x373e, 0x33, 0, 0},
-+ {0x3743, 0x10, 0, 0},
-+ {0x3744, 0x88, 0, 0},
-+ {0x3745, 0xc0, 0, 0},
-+ {0x374a, 0x43, 0, 0},
-+ {0x374c, 0x00, 0, 0},
-+ {0x374e, 0x23, 0, 0},
-+ {0x3751, 0x7b, 0, 0},
-+ {0x3752, 0x84, 0, 0},
-+ {0x3753, 0xbd, 0, 0},
-+ {0x3754, 0xbc, 0, 0},
-+ {0x3756, 0x52, 0, 0},
-+ {0x375c, 0x00, 0, 0},
-+ {0x3760, 0x00, 0, 0},
-+ {0x3761, 0x00, 0, 0},
-+ {0x3762, 0x00, 0, 0},
-+ {0x3763, 0x00, 0, 0},
-+ {0x3764, 0x00, 0, 0},
-+ {0x3767, 0x04, 0, 0},
-+ {0x3768, 0x04, 0, 0},
-+ {0x3769, 0x08, 0, 0},
-+ {0x376a, 0x08, 0, 0},
-+ {0x376b, 0x20, 0, 0},
-+ {0x376c, 0x00, 0, 0},
-+ {0x376d, 0x00, 0, 0},
-+ {0x376e, 0x00, 0, 0},
-+ {0x3773, 0x00, 0, 0},
-+ {0x3774, 0x51, 0, 0},
-+ {0x3776, 0xbd, 0, 0},
-+ {0x3777, 0xbd, 0, 0},
-+ {0x3781, 0x18, 0, 0},
-+ {0x3783, 0x25, 0, 0},
-+ {0x3798, 0x1b, 0, 0},
-+ {0x3800, 0x01, 0, 0}, // timings
-+ {0x3801, 0x88, 0, 0},
-+ {0x3802, 0x00, 0, 0},
-+ {0x3803, 0xe0, 0, 0},
-+ {0x3804, 0x09, 0, 0},
-+ {0x3805, 0x17, 0, 0},
-+ {0x3806, 0x05, 0, 0},
-+ {0x3807, 0x1f, 0, 0},
-+ {0x3808, 0x07, 0, 0},
-+ {0x3809, 0x80, 0, 0},
-+ {0x380a, 0x04, 0, 0},
-+ {0x380b, 0x38, 0, 0},
-+ {0x380c, 0x06, 0, 0},
-+ {0x380d, 0xe0, 0, 0},
-+ {0x380e, 0x04, 0, 0},
-+ {0x380f, 0x70, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x08, 0, 0},
-+ {0x3812, 0x00, 0, 0},
-+ {0x3813, 0x04, 0, 0},
-+ {0x3814, 0x01, 0, 0},
-+ {0x3815, 0x01, 0, 0},
-+ {0x3819, 0x01, 0, 0},
-+ {0x3820, 0x06, 0, 0},
-+ {0x3821, 0x00, 0, 0},
-+ {0x3829, 0x00, 0, 0},
-+ {0x382a, 0x01, 0, 0},
-+ {0x382b, 0x01, 0, 0},
-+ {0x382d, 0x7f, 0, 0},
-+ {0x3830, 0x04, 0, 0},
-+ {0x3836, 0x01, 0, 0},
-+ {0x3837, 0x00, 0, 0},
-+ {0x3841, 0x02, 0, 0},
-+ {0x3846, 0x08, 0, 0},
-+ {0x3847, 0x07, 0, 0},
-+ {0x3d85, 0x36, 0, 0},
-+ {0x3d8c, 0x71, 0, 0},
-+ {0x3d8d, 0xcb, 0, 0},
-+ {0x3f0a, 0x00, 0, 0},
-+ {0x4000, 0xf1, 0, 0},
-+ {0x4001, 0x40, 0, 0},
-+ {0x4002, 0x04, 0, 0},
-+ {0x4003, 0x14, 0, 0},
-+ {0x400e, 0x00, 0, 0},
-+ {0x4011, 0x00, 0, 0},
-+ {0x401a, 0x00, 0, 0},
-+ {0x401b, 0x00, 0, 0},
-+ {0x401c, 0x00, 0, 0},
-+ {0x401d, 0x00, 0, 0},
-+ {0x401f, 0x00, 0, 0},
-+ {0x4020, 0x00, 0, 0},
-+ {0x4021, 0x10, 0, 0},
-+ {0x4022, 0x06, 0, 0},
-+ {0x4023, 0x13, 0, 0},
-+ {0x4024, 0x07, 0, 0},
-+ {0x4025, 0x40, 0, 0},
-+ {0x4026, 0x07, 0, 0},
-+ {0x4027, 0x50, 0, 0},
-+ {0x4028, 0x00, 0, 0},
-+ {0x4029, 0x02, 0, 0},
-+ {0x402a, 0x06, 0, 0},
-+ {0x402b, 0x04, 0, 0},
-+ {0x402c, 0x02, 0, 0},
-+ {0x402d, 0x02, 0, 0},
-+ {0x402e, 0x0e, 0, 0},
-+ {0x402f, 0x04, 0, 0},
-+ {0x4302, 0xff, 0, 0},
-+ {0x4303, 0xff, 0, 0},
-+ {0x4304, 0x00, 0, 0},
-+ {0x4305, 0x00, 0, 0},
-+ {0x4306, 0x00, 0, 0},
-+ {0x4308, 0x02, 0, 0},
-+ {0x4500, 0x6c, 0, 0},
-+ {0x4501, 0xc4, 0, 0},
-+ {0x4502, 0x40, 0, 0},
-+ {0x4503, 0x01, 0, 0},
-+ {0x4601, 0x77, 0, 0},
-+ {0x4800, 0x04, 0, 0},
-+ {0x4813, 0x08, 0, 0},
-+ {0x481f, 0x40, 0, 0},
-+ {0x4829, 0x78, 0, 0},
-+ {0x4837, 0x10, 0, 0},
-+ {0x4b00, 0x2a, 0, 0},
-+ {0x4b0d, 0x00, 0, 0},
-+ {0x4d00, 0x04, 0, 0},
-+ {0x4d01, 0x42, 0, 0},
-+ {0x4d02, 0xd1, 0, 0},
-+ {0x4d03, 0x93, 0, 0},
-+ {0x4d04, 0xf5, 0, 0},
-+ {0x4d05, 0xc1, 0, 0},
-+ {0x5000, 0xf3, 0, 0},
-+ {0x5001, 0x11, 0, 0},
-+ {0x5004, 0x00, 0, 0},
-+ {0x500a, 0x00, 0, 0},
-+ {0x500b, 0x00, 0, 0},
-+ {0x5032, 0x00, 0, 0},
-+ {0x5040, 0x00, 0, 0},
-+ {0x5050, 0x0c, 0, 0},
-+ {0x5500, 0x00, 0, 0},
-+ {0x5501, 0x10, 0, 0},
-+ {0x5502, 0x01, 0, 0},
-+ {0x5503, 0x0f, 0, 0},
-+ {0x8000, 0x00, 0, 0},
-+ {0x8001, 0x00, 0, 0},
-+ {0x8002, 0x00, 0, 0},
-+ {0x8003, 0x00, 0, 0},
-+ {0x8004, 0x00, 0, 0},
-+ {0x8005, 0x00, 0, 0},
-+ {0x8006, 0x00, 0, 0},
-+ {0x8007, 0x00, 0, 0},
-+ {0x8008, 0x00, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+};
-+
-+static const struct reg_value ov4689_setting_4M_2688_1520[] = {
-+ //@@ 0 10 RES_2688x1520_default(60fps)
-+ //102 2630 960
-+ {0x0103, 0x01, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+ {0x0300, 0x00, 0, 0},
-+ {0x0302, 0x22, 0, 0}, // 2a ;1008Mbps,23 ;; 840Mbps
-+ {0x0304, 0x03, 0, 0},
-+ {0x030b, 0x00, 0, 0},
-+ {0x030d, 0x1e, 0, 0},
-+ {0x030e, 0x04, 0, 0},
-+ {0x030f, 0x01, 0, 0},
-+ {0x0312, 0x01, 0, 0},
-+ {0x031e, 0x00, 0, 0},
-+ {0x3000, 0x20, 0, 0},
-+ {0x3002, 0x00, 0, 0},
-+ {0x3020, 0x93, 0, 0},
-+ {0x3021, 0x03, 0, 0},
-+ {0x3022, 0x01, 0, 0},
-+ {0x3031, 0x0a, 0, 0},
-+ {0x303f, 0x0c, 0, 0},
-+ {0x3305, 0xf1, 0, 0},
-+ {0x3307, 0x04, 0, 0},
-+ {0x3309, 0x29, 0, 0},
-+ {0x3500, 0x00, 0, 0},
-+ {0x3501, 0x60, 0, 0},
-+ {0x3502, 0x00, 0, 0},
-+ {0x3503, 0x04, 0, 0},
-+ {0x3504, 0x00, 0, 0},
-+ {0x3505, 0x00, 0, 0},
-+ {0x3506, 0x00, 0, 0},
-+ {0x3507, 0x00, 0, 0},
-+ {0x3508, 0x00, 0, 0},
-+ {0x3509, 0x80, 0, 0},
-+ {0x350a, 0x00, 0, 0},
-+ {0x350b, 0x00, 0, 0},
-+ {0x350c, 0x00, 0, 0},
-+ {0x350d, 0x00, 0, 0},
-+ {0x350e, 0x00, 0, 0},
-+ {0x350f, 0x80, 0, 0},
-+ {0x3510, 0x00, 0, 0},
-+ {0x3511, 0x00, 0, 0},
-+ {0x3512, 0x00, 0, 0},
-+ {0x3513, 0x00, 0, 0},
-+ {0x3514, 0x00, 0, 0},
-+ {0x3515, 0x80, 0, 0},
-+ {0x3516, 0x00, 0, 0},
-+ {0x3517, 0x00, 0, 0},
-+ {0x3518, 0x00, 0, 0},
-+ {0x3519, 0x00, 0, 0},
-+ {0x351a, 0x00, 0, 0},
-+ {0x351b, 0x80, 0, 0},
-+ {0x351c, 0x00, 0, 0},
-+ {0x351d, 0x00, 0, 0},
-+ {0x351e, 0x00, 0, 0},
-+ {0x351f, 0x00, 0, 0},
-+ {0x3520, 0x00, 0, 0},
-+ {0x3521, 0x80, 0, 0},
-+ {0x3522, 0x08, 0, 0},
-+ {0x3524, 0x08, 0, 0},
-+ {0x3526, 0x08, 0, 0},
-+ {0x3528, 0x08, 0, 0},
-+ {0x352a, 0x08, 0, 0},
-+ {0x3602, 0x00, 0, 0},
-+ {0x3603, 0x40, 0, 0},
-+ {0x3604, 0x02, 0, 0},
-+ {0x3605, 0x00, 0, 0},
-+ {0x3606, 0x00, 0, 0},
-+ {0x3607, 0x00, 0, 0},
-+ {0x3609, 0x12, 0, 0},
-+ {0x360a, 0x40, 0, 0},
-+ {0x360c, 0x08, 0, 0},
-+ {0x360f, 0xe5, 0, 0},
-+ {0x3608, 0x8f, 0, 0},
-+ {0x3611, 0x00, 0, 0},
-+ {0x3613, 0xf7, 0, 0},
-+ {0x3616, 0x58, 0, 0},
-+ {0x3619, 0x99, 0, 0},
-+ {0x361b, 0x60, 0, 0},
-+ {0x361c, 0x7a, 0, 0},
-+ {0x361e, 0x79, 0, 0},
-+ {0x361f, 0x02, 0, 0},
-+ {0x3632, 0x00, 0, 0},
-+ {0x3633, 0x10, 0, 0},
-+ {0x3634, 0x10, 0, 0},
-+ {0x3635, 0x10, 0, 0},
-+ {0x3636, 0x15, 0, 0},
-+ {0x3646, 0x86, 0, 0},
-+ {0x364a, 0x0b, 0, 0},
-+ {0x3700, 0x17, 0, 0},
-+ {0x3701, 0x22, 0, 0},
-+ {0x3703, 0x10, 0, 0},
-+ {0x370a, 0x37, 0, 0},
-+ {0x3705, 0x00, 0, 0},
-+ {0x3706, 0x63, 0, 0},
-+ {0x3709, 0x3c, 0, 0},
-+ {0x370b, 0x01, 0, 0},
-+ {0x370c, 0x30, 0, 0},
-+ {0x3710, 0x24, 0, 0},
-+ {0x3711, 0x0c, 0, 0},
-+ {0x3716, 0x00, 0, 0},
-+ {0x3720, 0x28, 0, 0},
-+ {0x3729, 0x7b, 0, 0},
-+ {0x372a, 0x84, 0, 0},
-+ {0x372b, 0xbd, 0, 0},
-+ {0x372c, 0xbc, 0, 0},
-+ {0x372e, 0x52, 0, 0},
-+ {0x373c, 0x0e, 0, 0},
-+ {0x373e, 0x33, 0, 0},
-+ {0x3743, 0x10, 0, 0},
-+ {0x3744, 0x88, 0, 0},
-+ {0x3745, 0xc0, 0, 0},
-+ {0x374a, 0x43, 0, 0},
-+ {0x374c, 0x00, 0, 0},
-+ {0x374e, 0x23, 0, 0},
-+ {0x3751, 0x7b, 0, 0},
-+ {0x3752, 0x84, 0, 0},
-+ {0x3753, 0xbd, 0, 0},
-+ {0x3754, 0xbc, 0, 0},
-+ {0x3756, 0x52, 0, 0},
-+ {0x375c, 0x00, 0, 0},
-+ {0x3760, 0x00, 0, 0},
-+ {0x3761, 0x00, 0, 0},
-+ {0x3762, 0x00, 0, 0},
-+ {0x3763, 0x00, 0, 0},
-+ {0x3764, 0x00, 0, 0},
-+ {0x3767, 0x04, 0, 0},
-+ {0x3768, 0x04, 0, 0},
-+ {0x3769, 0x08, 0, 0},
-+ {0x376a, 0x08, 0, 0},
-+ {0x376b, 0x20, 0, 0},
-+ {0x376c, 0x00, 0, 0},
-+ {0x376d, 0x00, 0, 0},
-+ {0x376e, 0x00, 0, 0},
-+ {0x3773, 0x00, 0, 0},
-+ {0x3774, 0x51, 0, 0},
-+ {0x3776, 0xbd, 0, 0},
-+ {0x3777, 0xbd, 0, 0},
-+ {0x3781, 0x18, 0, 0},
-+ {0x3783, 0x25, 0, 0},
-+ {0x3798, 0x1b, 0, 0},
-+ {0x3800, 0x00, 0, 0},
-+ {0x3801, 0x08, 0, 0},
-+ {0x3802, 0x00, 0, 0},
-+ {0x3803, 0x04, 0, 0},
-+ {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x97, 0, 0},
-+ {0x3806, 0x05, 0, 0},
-+ {0x3807, 0xfb, 0, 0},
-+ {0x3808, 0x0a, 0, 0},
-+ {0x3809, 0x80, 0, 0},
-+ {0x380a, 0x05, 0, 0},
-+ {0x380b, 0xf0, 0, 0},
-+ {0x380c, 0x03, 0, 0},
-+ {0x380d, 0x5c, 0, 0},
-+ {0x380e, 0x06, 0, 0},
-+ {0x380f, 0x12, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x08, 0, 0},
-+ {0x3812, 0x00, 0, 0},
-+ {0x3813, 0x04, 0, 0},
-+ {0x3814, 0x01, 0, 0},
-+ {0x3815, 0x01, 0, 0},
-+ {0x3819, 0x01, 0, 0},
-+ {0x3820, 0x00, 0, 0},
-+ {0x3821, 0x06, 0, 0},
-+ {0x3829, 0x00, 0, 0},
-+ {0x382a, 0x01, 0, 0},
-+ {0x382b, 0x01, 0, 0},
-+ {0x382d, 0x7f, 0, 0},
-+ {0x3830, 0x04, 0, 0},
-+ {0x3836, 0x01, 0, 0},
-+ {0x3837, 0x00, 0, 0},
-+ {0x3841, 0x02, 0, 0},
-+ {0x3846, 0x08, 0, 0},
-+ {0x3847, 0x07, 0, 0},
-+ {0x3d85, 0x36, 0, 0},
-+ {0x3d8c, 0x71, 0, 0},
-+ {0x3d8d, 0xcb, 0, 0},
-+ {0x3f0a, 0x00, 0, 0},
-+ {0x4000, 0x71, 0, 0},
-+ {0x4001, 0x40, 0, 0},
-+ {0x4002, 0x04, 0, 0},
-+ {0x4003, 0x14, 0, 0},
-+ {0x400e, 0x00, 0, 0},
-+ {0x4011, 0x00, 0, 0},
-+ {0x401a, 0x00, 0, 0},
-+ {0x401b, 0x00, 0, 0},
-+ {0x401c, 0x00, 0, 0},
-+ {0x401d, 0x00, 0, 0},
-+ {0x401f, 0x00, 0, 0},
-+ {0x4020, 0x00, 0, 0},
-+ {0x4021, 0x10, 0, 0},
-+ {0x4022, 0x07, 0, 0},
-+ {0x4023, 0xcf, 0, 0},
-+ {0x4024, 0x09, 0, 0},
-+ {0x4025, 0x60, 0, 0},
-+ {0x4026, 0x09, 0, 0},
-+ {0x4027, 0x6f, 0, 0},
-+ {0x4028, 0x00, 0, 0},
-+ {0x4029, 0x02, 0, 0},
-+ {0x402a, 0x06, 0, 0},
-+ {0x402b, 0x04, 0, 0},
-+ {0x402c, 0x02, 0, 0},
-+ {0x402d, 0x02, 0, 0},
-+ {0x402e, 0x0e, 0, 0},
-+ {0x402f, 0x04, 0, 0},
-+ {0x4302, 0xff, 0, 0},
-+ {0x4303, 0xff, 0, 0},
-+ {0x4304, 0x00, 0, 0},
-+ {0x4305, 0x00, 0, 0},
-+ {0x4306, 0x00, 0, 0},
-+ {0x4308, 0x02, 0, 0},
-+ {0x4500, 0x6c, 0, 0},
-+ {0x4501, 0xc4, 0, 0},
-+ {0x4502, 0x40, 0, 0},
-+ {0x4503, 0x01, 0, 0},
-+ {0x4601, 0x04, 0, 0},
-+ {0x4800, 0x04, 0, 0},
-+ {0x4813, 0x08, 0, 0},
-+ {0x481f, 0x40, 0, 0},
-+ {0x4829, 0x78, 0, 0},
-+ {0x4837, 0x14, 0, 0}, // 10
-+ {0x4b00, 0x2a, 0, 0},
-+ {0x4b0d, 0x00, 0, 0},
-+ {0x4d00, 0x04, 0, 0},
-+ {0x4d01, 0x42, 0, 0},
-+ {0x4d02, 0xd1, 0, 0},
-+ {0x4d03, 0x93, 0, 0},
-+ {0x4d04, 0xf5, 0, 0},
-+ {0x4d05, 0xc1, 0, 0},
-+ {0x5000, 0xf3, 0, 0},
-+ {0x5001, 0x11, 0, 0},
-+ {0x5004, 0x00, 0, 0},
-+ {0x500a, 0x00, 0, 0},
-+ {0x500b, 0x00, 0, 0},
-+ {0x5032, 0x00, 0, 0},
-+ {0x5040, 0x00, 0, 0},
-+ {0x5050, 0x0c, 0, 0},
-+ {0x5500, 0x00, 0, 0},
-+ {0x5501, 0x10, 0, 0},
-+ {0x5502, 0x01, 0, 0},
-+ {0x5503, 0x0f, 0, 0},
-+ {0x8000, 0x00, 0, 0},
-+ {0x8001, 0x00, 0, 0},
-+ {0x8002, 0x00, 0, 0},
-+ {0x8003, 0x00, 0, 0},
-+ {0x8004, 0x00, 0, 0},
-+ {0x8005, 0x00, 0, 0},
-+ {0x8006, 0x00, 0, 0},
-+ {0x8007, 0x00, 0, 0},
-+ {0x8008, 0x00, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+// {0x0100, 0x01, 0, 0},
-+
-+// {0x0100, 0x00, 0, 0},
-+ {0x380c, 0x0A, 0, 0}, // 05
-+ {0x380d, 0x0A, 0, 0}, // 10
-+ {0x380e, 0x06, 0, 0},
-+ {0x380f, 0x12, 0, 0},
-+// {0x0100, 0x01, 0, 0},
-+ {0x3105, 0x31, 0, 0},
-+ {0x301a, 0xf9, 0, 0},
-+ {0x3508, 0x07, 0, 0},
-+ {0x484b, 0x05, 0, 0},
-+ {0x4805, 0x03, 0, 0},
-+ {0x3601, 0x01, 0, 0},
-+ {0x3745, 0xc0, 0, 0},
-+ {0x3798, 0x1b, 0, 0},
-+// {0x0100, 0x01, 0, 0},
-+ {0xffff, 0x0a, 0, 0},
-+ {0x3105, 0x11, 0, 0},
-+ {0x301a, 0xf1, 0, 0},
-+ {0x4805, 0x00, 0, 0},
-+ {0x301a, 0xf0, 0, 0},
-+ {0x3208, 0x00, 0, 0},
-+ {0x302a, 0x00, 0, 0},
-+ {0x302a, 0x00, 0, 0},
-+ {0x302a, 0x00, 0, 0},
-+ {0x302a, 0x00, 0, 0},
-+ {0x302a, 0x00, 0, 0},
-+ {0x3601, 0x00, 0, 0},
-+ {0x3638, 0x00, 0, 0},
-+ {0x3208, 0x10, 0, 0},
-+ {0x3208, 0xa0, 0, 0},
-+};
-+
-+/* power-on sensor init reg table */
-+static const struct ov4689_mode_info ov4689_mode_init_data = {
-+
-+};
-+
-+static const struct ov4689_mode_info
-+ov4689_mode_data[OV4689_NUM_MODES] = {
-+ // {OV4689_MODE_720P_1280_720, SUBSAMPLING,
-+ // 1280, 0x408, 720, 0x305,
-+ // ov4689_setting_720P_1280_720,
-+ // ARRAY_SIZE(ov4689_setting_720P_1280_720),
-+ // OV4689_150_FPS},
-+ // {OV4689_MODE_1080P_1920_1080, SCALING,
-+ // 1920, 0x6e0, 1080, 0x470,
-+ // ov4689_setting_1080P_1920_1080,
-+ // ARRAY_SIZE(ov4689_setting_1080P_1920_1080),
-+ // OV4689_60_FPS},
-+ // {OV4689_MODE_4M_2688_1520, SCALING,
-+ // 2688, 0xa0a, 1520, 0x612,
-+ // ov4689_setting_4M_2688_1520,
-+ // ARRAY_SIZE(ov4689_setting_4M_2688_1520),
-+ // OV4689_60_FPS},
-+
-+ {OV4689_MODE_1080P_1920_1080, SCALING,
-+ 1920, 0x6e0, 1080, 0x470,
-+ ov4689_init_setting_30fps_1080P,
-+ ARRAY_SIZE(ov4689_init_setting_30fps_1080P),
-+ OV4689_60_FPS},
-+};
-+
-+static int ov4689_write_reg(struct ov4689_dev *sensor, u16 reg, u8 val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg;
-+ u8 buf[3];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+ buf[2] = val;
-+
-+ msg.addr = client->addr;
-+ msg.flags = client->flags;
-+ msg.buf = buf;
-+ msg.len = sizeof(buf);
-+
-+ ret = i2c_transfer(client->adapter, &msg, 1);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
-+ __func__, reg, val);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ov4689_read_reg(struct ov4689_dev *sensor, u16 reg, u8 *val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg[2];
-+ u8 buf[2];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+
-+ msg[0].addr = client->addr;
-+ msg[0].flags = client->flags;
-+ msg[0].buf = buf;
-+ msg[0].len = sizeof(buf);
-+
-+ msg[1].addr = client->addr;
-+ msg[1].flags = client->flags | I2C_M_RD;
-+ msg[1].buf = buf;
-+ msg[1].len = 1;
-+
-+ ret = i2c_transfer(client->adapter, msg, 2);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x\n",
-+ __func__, reg);
-+ return ret;
-+ }
-+
-+ *val = buf[0];
-+ return 0;
-+}
-+
-+static int ov4689_read_reg16(struct ov4689_dev *sensor, u16 reg, u16 *val)
-+{
-+ u8 hi, lo;
-+ int ret;
-+
-+ ret = ov4689_read_reg(sensor, reg, &hi);
-+ if (ret)
-+ return ret;
-+ ret = ov4689_read_reg(sensor, reg + 1, &lo);
-+ if (ret)
-+ return ret;
-+
-+ *val = ((u16)hi << 8) | (u16)lo;
-+ return 0;
-+}
-+
-+static int ov4689_write_reg16(struct ov4689_dev *sensor, u16 reg, u16 val)
-+{
-+ int ret;
-+
-+ ret = ov4689_write_reg(sensor, reg, val >> 8);
-+ if (ret)
-+ return ret;
-+
-+ return ov4689_write_reg(sensor, reg + 1, val & 0xff);
-+}
-+
-+static int ov4689_mod_reg(struct ov4689_dev *sensor, u16 reg,
-+ u8 mask, u8 val)
-+{
-+ u8 readval;
-+ int ret;
-+
-+ ret = ov4689_read_reg(sensor, reg, &readval);
-+ if (ret)
-+ return ret;
-+
-+ readval &= ~mask;
-+ val &= mask;
-+ val |= readval;
-+
-+ return ov4689_write_reg(sensor, reg, val);
-+}
-+
-+static int ov4689_set_timings(struct ov4689_dev *sensor,
-+ const struct ov4689_mode_info *mode)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_load_regs(struct ov4689_dev *sensor,
-+ const struct ov4689_mode_info *mode)
-+{
-+ const struct reg_value *regs = mode->reg_data;
-+ unsigned int i;
-+ u32 delay_ms;
-+ u16 reg_addr;
-+ u8 mask, val;
-+ int ret = 0;
-+
-+ st_info(ST_SENSOR, "%s, mode = 0x%x\n", __func__, mode->id);
-+ for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
-+ delay_ms = regs->delay_ms;
-+ reg_addr = regs->reg_addr;
-+ val = regs->val;
-+ mask = regs->mask;
-+
-+ if (mask)
-+ ret = ov4689_mod_reg(sensor, reg_addr, mask, val);
-+ else
-+ ret = ov4689_write_reg(sensor, reg_addr, val);
-+ if (ret)
-+ break;
-+
-+ if (delay_ms)
-+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
-+ }
-+
-+ return ov4689_set_timings(sensor, mode);
-+}
-+
-+#ifdef UNUSED_CODE
-+static int ov4689_get_exposure(struct ov4689_dev *sensor)
-+{
-+ int exp, ret;
-+ u8 temp;
-+
-+ ret = ov4689_read_reg(sensor, OV4689_REG_EXPOSURE_HI, &temp);
-+ if (ret)
-+ return ret;
-+ exp = ((int)temp & 0x0f) << 16;
-+ ret = ov4689_read_reg(sensor, OV4689_REG_EXPOSURE_MED, &temp);
-+ if (ret)
-+ return ret;
-+ exp |= ((int)temp << 8);
-+ ret = ov4689_read_reg(sensor, OV4689_REG_EXPOSURE_LO, &temp);
-+ if (ret)
-+ return ret;
-+ exp |= (int)temp;
-+
-+ return exp >> 4;
-+}
-+#endif
-+
-+static int ov4689_set_exposure(struct ov4689_dev *sensor, u32 exposure)
-+{
-+ int ret;
-+
-+ st_info(ST_SENSOR, "%s, exposure = 0x%x\n", __func__, exposure);
-+ exposure <<= 4;
-+
-+ ret = ov4689_write_reg(sensor,
-+ OV4689_REG_EXPOSURE_LO,
-+ exposure & 0xff);
-+ if (ret)
-+ return ret;
-+ ret = ov4689_write_reg(sensor,
-+ OV4689_REG_EXPOSURE_MED,
-+ (exposure >> 8) & 0xff);
-+ if (ret)
-+ return ret;
-+ return ov4689_write_reg(sensor,
-+ OV4689_REG_EXPOSURE_HI,
-+ (exposure >> 16) & 0x0f);
-+}
-+
-+static int ov4689_get_gain(struct ov4689_dev *sensor)
-+{
-+ u32 gain = 0;
-+ u8 val;
-+
-+ ov4689_read_reg(sensor, OV4689_REG_GAIN_H, &val);
-+ gain = (val & 0x3) << 16;
-+ ov4689_read_reg(sensor, OV4689_REG_GAIN_M, &val);
-+ gain |= val << 8;
-+ ov4689_read_reg(sensor, OV4689_REG_GAIN_L, &val);
-+ gain |= val;
-+
-+ return gain;
-+}
-+
-+static int ov4689_set_gain(struct ov4689_dev *sensor, int gain)
-+{
-+ ov4689_write_reg(sensor, OV4689_REG_GAIN_H,
-+ (gain >> 16) & 0x3);
-+ ov4689_write_reg(sensor, OV4689_REG_GAIN_M,
-+ (gain >> 8) & 0xff);
-+ ov4689_write_reg(sensor, OV4689_REG_GAIN_L,
-+ gain & 0xff);
-+ return 0;
-+}
-+
-+#ifdef UNUSED_CODE
-+static int ov4689_get_sysclk(struct ov4689_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_set_night_mode(struct ov4689_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_get_hts(struct ov4689_dev *sensor)
-+{
-+ /* read HTS from register settings */
-+ u16 hts;
-+ int ret;
-+
-+ ret = ov4689_read_reg16(sensor, OV4689_REG_TIMING_HTS, &hts);
-+ if (ret)
-+ return ret;
-+ return hts;
-+}
-+#endif
-+
-+static int ov4689_get_vts(struct ov4689_dev *sensor)
-+{
-+ u16 vts;
-+ int ret;
-+
-+ ret = ov4689_read_reg16(sensor, OV4689_REG_TIMING_VTS, &vts);
-+ if (ret)
-+ return ret;
-+ return vts;
-+}
-+
-+#ifdef UNUSED_CODE
-+static int ov4689_set_vts(struct ov4689_dev *sensor, int vts)
-+{
-+ return ov4689_write_reg16(sensor, OV4689_REG_TIMING_VTS, vts);
-+}
-+
-+static int ov4689_get_light_freq(struct ov4689_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_set_bandingfilter(struct ov4689_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_set_ae_target(struct ov4689_dev *sensor, int target)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_get_binning(struct ov4689_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_set_binning(struct ov4689_dev *sensor, bool enable)
-+{
-+ return 0;
-+}
-+#endif
-+
-+static const struct ov4689_mode_info *
-+ov4689_find_mode(struct ov4689_dev *sensor, enum ov4689_frame_rate fr,
-+ int width, int height, bool nearest)
-+{
-+ const struct ov4689_mode_info *mode;
-+
-+ mode = v4l2_find_nearest_size(ov4689_mode_data,
-+ ARRAY_SIZE(ov4689_mode_data),
-+ hact, vact,
-+ width, height);
-+
-+ if (!mode ||
-+ (!nearest && (mode->hact != width || mode->vact != height)))
-+ return NULL;
-+
-+ /* Check to see if the current mode exceeds the max frame rate */
-+ if (ov4689_framerates[fr] > ov4689_framerates[mode->max_fps])
-+ return NULL;
-+
-+ return mode;
-+}
-+
-+static u64 ov4689_calc_pixel_rate(struct ov4689_dev *sensor)
-+{
-+ u64 rate;
-+
-+ rate = sensor->current_mode->vact * sensor->current_mode->hact;
-+ rate *= ov4689_framerates[sensor->current_fr];
-+
-+ return rate;
-+}
-+
-+/*
-+ * After trying the various combinations, reading various
-+ * documentations spread around the net, and from the various
-+ * feedback, the clock tree is probably as follows:
-+ *
-+ * +--------------+
-+ * | Ext. Clock |
-+ * +-+------------+
-+ * | +----------+
-+ * +->| PLL1 | - reg 0x030a, bit0 for the pre-dividerp
-+ * +-+--------+ - reg 0x0300, bits 0-2 for the pre-divider
-+ * +-+--------+ - reg 0x0301~0x0302, for the multiplier
-+ * | +--------------+
-+ * +->| MIPI Divider | - reg 0x0303, bits 0-3 for the pre-divider
-+ * | +---------> MIPI PHY CLK
-+ * | +-----+
-+ * | +->| PLL1_DIV_MIPI | - reg 0x0304, bits 0-1 for the divider
-+ * | +----------------> PCLK
-+ * | +-----+
-+ *
-+ * +--------------+
-+ * | Ext. Clock |
-+ * +-+------------+
-+ * | +----------+
-+ * +->| PLL2 | - reg 0x0311, bit0 for the pre-dividerp
-+ * +-+--------+ - reg 0x030b, bits 0-2 for the pre-divider
-+ * +-+--------+ - reg 0x030c~0x030d, for the multiplier
-+ * | +--------------+
-+ * +->| SCLK Divider | - reg 0x030F, bits 0-3 for the pre-divider
-+ * +-+--------+ - reg 0x030E, bits 0-2 for the divider
-+ * | +---------> SCLK
-+ *
-+ * | +-----+
-+ * +->| DAC Divider | - reg 0x0312, bits 0-3 for the divider
-+ * | +----------------> DACCLK
-+ **
-+ */
-+
-+/*
-+ * ov4689_set_mipi_pclk() - Calculate the clock tree configuration values
-+ * for the MIPI CSI-2 output.
-+ *
-+ * @rate: The requested bandwidth per lane in bytes per second.
-+ * 'Bandwidth Per Lane' is calculated as:
-+ * bpl = HTOT * VTOT * FPS * bpp / num_lanes;
-+ *
-+ * This function use the requested bandwidth to calculate:
-+ *
-+ * - mipi_pclk = bpl / 2; ( / 2 is for CSI-2 DDR)
-+ * - mipi_phy_clk = mipi_pclk * PLL1_DIV_MIPI;
-+ *
-+ * with these fixed parameters:
-+ * PLL1_PREDIVP = 1;
-+ * PLL1_PREDIV = 1; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
-+ * PLL1_DIVM = 1;
-+ * PLL1_DIV_MIPI = 4;
-+ *
-+ * FIXME: this have been tested with 10-bit raw and 2 lanes setup only.
-+ * MIPI_DIV is fixed to value 2, but it -might- be changed according to the
-+ * above formula for setups with 1 lane or image formats with different bpp.
-+ *
-+ * FIXME: this deviates from the sensor manual documentation which is quite
-+ * thin on the MIPI clock tree generation part.
-+ */
-+
-+#define PLL1_PREDIVP 1 // bypass
-+#define PLL1_PREDIV 1 // bypass
-+#define PLL1_DIVM 1 // bypass
-+#define PLL1_DIV_MIPI 3 // div
-+#define PLL1_DIV_MIPI_BASE 1 // div
-+
-+#define PLL1_DIVSP 1 // no use
-+#define PLL1_DIVS 1 // no use
-+
-+#define PLL2_PREDIVP 0
-+#define PLL2_PREDIV 0
-+#define PLL2_DIVSP 1
-+#define PLL2_DIVS 4
-+#define PLL2_DIVDAC 1
-+
-+#define OV4689_PLL1_PREDIVP 0x030a // bits[0]
-+#define OV4689_PLL1_PREDIV 0x0300 // bits[2:0]
-+#define OV4689_PLL1_MULTIPLIER 0x0301 // bits[9:8] 0x0302 bits[7:0]
-+#define OV4689_PLL1_DIVM 0x0303 // bits[3:0]
-+#define OV4689_PLL1_DIV_MIPI 0x0304 // bits[1:0]
-+
-+#define OV4689_PLL1_DIVSP 0x0305 //bits[1:0]
-+#define OV4689_PLL1_DIVS 0x0306 // bits[0]
-+
-+#define OV4689_PLL2_PREDIVP 0x0311 // bits[0]
-+#define OV4689_PLL2_PREDIV 0x030b // bits[2:0]
-+#define OV4689_PLL2_MULTIPLIER 0x030c // bits[9:8] 0x030d bits[7:0]
-+#define OV4689_PLL2_DIVSP 0x030f // bits[3:0]
-+#define OV4689_PLL2_DIVS 0x030e // bits[2:0]
-+#define OV4689_PLL2_DIVDAC 0x0312 // bits[3:0]
-+
-+static int ov4689_set_mipi_pclk(struct ov4689_dev *sensor,
-+ unsigned long rate)
-+{
-+ const struct ov4689_mode_info *mode = sensor->current_mode;
-+ //const struct ov4689_mode_info *orig_mode = sensor->last_mode;
-+ u8 val;
-+ int ret = 0;
-+ int fps = ov4689_framerates[sensor->current_fr];
-+ u16 htot, val16;
-+
-+ htot = mode->htot * ov4689_framerates[mode->max_fps] / fps;
-+
-+ ret = ov4689_write_reg16(sensor, OV4689_REG_TIMING_HTS, htot);
-+
-+ ret = ov4689_read_reg(sensor, OV4689_REG_TIMING_HTS, &val);
-+ val16 = val << 8;
-+ ret = ov4689_read_reg(sensor, OV4689_REG_TIMING_HTS + 1, &val);
-+ val16 |= val;
-+
-+ st_info(ST_SENSOR, "fps = %d, max_fps = %d\n", fps, mode->max_fps);
-+ st_info(ST_SENSOR, "mode->htot = 0x%x, htot = 0x%x\n", mode->htot,
-+ htot);
-+ st_info(ST_SENSOR, "reg: 0x%x = 0x%x\n", OV4689_REG_TIMING_HTS, val16);
-+
-+ return 0;
-+}
-+
-+/*
-+ * if sensor changes inside scaling or subsampling
-+ * change mode directly
-+ */
-+static int ov4689_set_mode_direct(struct ov4689_dev *sensor,
-+ const struct ov4689_mode_info *mode)
-+{
-+ if (!mode->reg_data)
-+ return -EINVAL;
-+
-+ /* Write capture setting */
-+ return ov4689_load_regs(sensor, mode);
-+}
-+
-+static int ov4689_set_mode(struct ov4689_dev *sensor)
-+{
-+ const struct ov4689_mode_info *mode = sensor->current_mode;
-+
-+ int ret = 0;
-+
-+ ret = ov4689_set_mode_direct(sensor, mode);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ov4689_set_mipi_pclk(sensor, 0);
-+ if (ret < 0)
-+ return 0;
-+
-+ sensor->pending_mode_change = false;
-+ sensor->last_mode = mode;
-+ return 0;
-+}
-+
-+/* restore the last set video mode after chip power-on */
-+static int ov4689_restore_mode(struct ov4689_dev *sensor)
-+{
-+ int ret;
-+
-+ /* first load the initial register values */
-+ ret = ov4689_load_regs(sensor, &ov4689_mode_init_data);
-+ if (ret < 0)
-+ return ret;
-+ sensor->last_mode = &ov4689_mode_init_data;
-+
-+ /* now restore the last capture mode */
-+ ret = ov4689_set_mode(sensor);
-+ if (ret < 0)
-+ return ret;
-+
-+ return ret;
-+}
-+
-+static void ov4689_power(struct ov4689_dev *sensor, bool enable)
-+{
-+ if (!sensor->pwdn_gpio)
-+ return;
-+ gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
-+}
-+
-+static void ov4689_reset(struct ov4689_dev *sensor)
-+{
-+ if (!sensor->reset_gpio)
-+ return;
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
-+
-+ usleep_range(5000, 25000);
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
-+ usleep_range(1000, 2000);
-+}
-+
-+static int ov4689_set_power_on(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ int ret;
-+
-+ ret = clk_prepare_enable(sensor->xclk);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable clock\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_enable(OV4689_NUM_SUPPLIES,
-+ sensor->supplies);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ goto xclk_off;
-+ }
-+
-+ ov4689_reset(sensor);
-+ ov4689_power(sensor, true);
-+
-+ return 0;
-+
-+xclk_off:
-+ clk_disable_unprepare(sensor->xclk);
-+ return ret;
-+}
-+
-+static int ov4689_set_power_off(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+
-+ ov4689_power(sensor, false);
-+ regulator_bulk_disable(OV4689_NUM_SUPPLIES, sensor->supplies);
-+ clk_disable_unprepare(sensor->xclk);
-+
-+ return 0;
-+}
-+
-+static int ov4689_try_frame_interval(struct ov4689_dev *sensor,
-+ struct v4l2_fract *fi,
-+ u32 width, u32 height)
-+{
-+ const struct ov4689_mode_info *mode;
-+ enum ov4689_frame_rate rate = OV4689_15_FPS;
-+ int minfps, maxfps, best_fps, fps;
-+ int i;
-+
-+ minfps = ov4689_framerates[OV4689_15_FPS];
-+ maxfps = ov4689_framerates[OV4689_NUM_FRAMERATES - 1];
-+
-+ if (fi->numerator == 0) {
-+ fi->denominator = maxfps;
-+ fi->numerator = 1;
-+ rate = OV4689_60_FPS;
-+ goto find_mode;
-+ }
-+
-+ fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
-+ minfps, maxfps);
-+
-+ best_fps = minfps;
-+ for (i = 0; i < ARRAY_SIZE(ov4689_framerates); i++) {
-+ int curr_fps = ov4689_framerates[i];
-+
-+ if (abs(curr_fps - fps) < abs(best_fps - fps)) {
-+ best_fps = curr_fps;
-+ rate = i;
-+ }
-+ }
-+ st_info(ST_SENSOR, "best_fps = %d, fps = %d\n", best_fps, fps);
-+
-+ fi->numerator = 1;
-+ fi->denominator = best_fps;
-+
-+find_mode:
-+ mode = ov4689_find_mode(sensor, rate, width, height, false);
-+ return mode ? rate : -EINVAL;
-+}
-+
-+static int ov4689_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ if (code->pad != 0)
-+ return -EINVAL;
-+
-+ if (code->index)
-+ return -EINVAL;
-+
-+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ return 0;
-+}
-+
-+static int ov4689_get_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ struct v4l2_mbus_framefmt *fmt;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(&sensor->sd, state,
-+ format->pad);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ format->format = *fmt;
-+
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int ov4689_try_fmt_internal(struct v4l2_subdev *sd,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum ov4689_frame_rate fr,
-+ const struct ov4689_mode_info **new_mode)
-+{
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ const struct ov4689_mode_info *mode;
-+
-+ mode = ov4689_find_mode(sensor, fr, fmt->width, fmt->height, true);
-+ if (!mode)
-+ return -EINVAL;
-+ fmt->width = mode->hact;
-+ fmt->height = mode->vact;
-+
-+ if (new_mode)
-+ *new_mode = mode;
-+
-+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+
-+ return 0;
-+}
-+
-+static int ov4689_set_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ const struct ov4689_mode_info *new_mode;
-+ struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
-+ struct v4l2_mbus_framefmt *fmt;
-+ int ret;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ ret = ov4689_try_fmt_internal(sd, mbus_fmt, 0, &new_mode);
-+ if (ret)
-+ goto out;
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(sd, state, 0);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ *fmt = *mbus_fmt;
-+
-+ if (new_mode != sensor->current_mode) {
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+ if (new_mode->max_fps < sensor->current_fr) {
-+ sensor->current_fr = new_mode->max_fps;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator =
-+ ov4689_framerates[sensor->current_fr];
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ ov4689_calc_pixel_rate(sensor));
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+/*
-+ * Sensor Controls.
-+ */
-+
-+static int ov4689_set_ctrl_hue(struct ov4689_dev *sensor, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int ov4689_set_ctrl_contrast(struct ov4689_dev *sensor, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int ov4689_set_ctrl_saturation(struct ov4689_dev *sensor, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int ov4689_set_ctrl_white_balance(struct ov4689_dev *sensor, int awb)
-+{
-+ struct ov4689_ctrls *ctrls = &sensor->ctrls;
-+ int ret = 0;
-+
-+ if (!awb && (ctrls->red_balance->is_new
-+ || ctrls->blue_balance->is_new)) {
-+ u16 red = (u16)ctrls->red_balance->val;
-+ u16 blue = (u16)ctrls->blue_balance->val;
-+
-+ st_info(ST_SENSOR, "red = 0x%x, blue = 0x%x\n", red, blue);
-+ ret = ov4689_write_reg16(sensor, OV4689_REG_AWB_R_GAIN, red);
-+ if (ret)
-+ return ret;
-+ ret = ov4689_write_reg16(sensor, OV4689_REG_AWB_B_GAIN, blue);
-+ }
-+ return ret;
-+}
-+
-+static int ov4689_set_ctrl_exposure(struct ov4689_dev *sensor,
-+ enum v4l2_exposure_auto_type auto_exposure)
-+{
-+ struct ov4689_ctrls *ctrls = &sensor->ctrls;
-+ bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
-+ int ret = 0;
-+
-+ if (!auto_exp && ctrls->exposure->is_new) {
-+ u16 max_exp = 0;
-+
-+ ret = ov4689_read_reg16(sensor, OV4689_REG_V_OUTPUT_SIZE,
-+ &max_exp);
-+
-+ ret = ov4689_get_vts(sensor);
-+ if (ret < 0)
-+ return ret;
-+ max_exp += ret;
-+ ret = 0;
-+
-+ st_info(ST_SENSOR, "%s, max_exp = 0x%x\n", __func__, max_exp);
-+ if (ctrls->exposure->val < max_exp)
-+ ret = ov4689_set_exposure(sensor, ctrls->exposure->val);
-+ }
-+
-+ return ret;
-+}
-+
-+static const s64 link_freq_menu_items[] = {
-+ OV4689_LINK_FREQ_500MHZ
-+};
-+
-+static const char * const test_pattern_menu[] = {
-+ "Disabled",
-+ "Color bars",
-+ "Color bars w/ rolling bar",
-+ "Color squares",
-+ "Color squares w/ rolling bar",
-+};
-+
-+#define OV4689_TEST_ENABLE BIT(7)
-+#define OV4689_TEST_ROLLING BIT(6) /* rolling horizontal bar */
-+#define OV4689_TEST_TRANSPARENT BIT(5)
-+#define OV4689_TEST_SQUARE_BW BIT(4) /* black & white squares */
-+#define OV4689_TEST_BAR_STANDARD (0 << 2)
-+#define OV4689_TEST_BAR_DARKER_1 (1 << 2)
-+#define OV4689_TEST_BAR_DARKER_2 (2 << 2)
-+#define OV4689_TEST_BAR_DARKER_3 (3 << 2)
-+#define OV4689_TEST_BAR (0 << 0)
-+#define OV4689_TEST_RANDOM (1 << 0)
-+#define OV4689_TEST_SQUARE (2 << 0)
-+#define OV4689_TEST_BLACK (3 << 0)
-+
-+static const u8 test_pattern_val[] = {
-+ 0,
-+ OV4689_TEST_ENABLE | OV4689_TEST_BAR_STANDARD |
-+ OV4689_TEST_BAR,
-+ OV4689_TEST_ENABLE | OV4689_TEST_ROLLING |
-+ OV4689_TEST_BAR_DARKER_1 | OV4689_TEST_BAR,
-+ OV4689_TEST_ENABLE | OV4689_TEST_SQUARE,
-+ OV4689_TEST_ENABLE | OV4689_TEST_ROLLING | OV4689_TEST_SQUARE,
-+};
-+
-+static int ov4689_set_ctrl_test_pattern(struct ov4689_dev *sensor, int value)
-+{
-+ return ov4689_write_reg(sensor, OV4689_REG_TEST_PATTERN,
-+ test_pattern_val[value]);
-+}
-+
-+static int ov4689_set_ctrl_light_freq(struct ov4689_dev *sensor, int value)
-+{
-+ return 0;
-+}
-+
-+static int ov4689_set_ctrl_hflip(struct ov4689_dev *sensor, int value)
-+{
-+ /*
-+ * TIMING TC REG21:
-+ * - [2]: Digital mirror
-+ * - [1]: Array mirror
-+ */
-+ return ov4689_mod_reg(sensor, OV4689_REG_TIMING_TC_REG21,
-+ BIT(2) | BIT(1),
-+ (!(value ^ sensor->upside_down)) ?
-+ (BIT(2) | BIT(1)) : 0);
-+}
-+
-+static int ov4689_set_ctrl_vflip(struct ov4689_dev *sensor, int value)
-+{
-+ /*
-+ * TIMING TC REG20:
-+ * - [2]: Digital vflip
-+ * - [1]: Array vflip
-+ */
-+ return ov4689_mod_reg(sensor, OV4689_REG_TIMING_TC_REG20,
-+ BIT(2) | BIT(1),
-+ (value ^ sensor->upside_down) ?
-+ (BIT(2) | BIT(1)) : 0);
-+}
-+
-+static int ov4689_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ int val;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ val = ov4689_get_gain(sensor);
-+ break;
-+ }
-+
-+ pm_runtime_put(&sensor->i2c_client->dev);
-+
-+ return 0;
-+}
-+
-+static int ov4689_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ int ret;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ /*
-+ * If the device is not powered up by the host driver do
-+ * not apply any controls to H/W at this time. Instead
-+ * the controls will be restored at start streaming time.
-+ */
-+ if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ ret = ov4689_set_gain(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE:
-+ ret = ov4689_set_ctrl_exposure(sensor, V4L2_EXPOSURE_MANUAL);
-+ break;
-+ case V4L2_CID_AUTO_WHITE_BALANCE:
-+ ret = ov4689_set_ctrl_white_balance(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HUE:
-+ ret = ov4689_set_ctrl_hue(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_CONTRAST:
-+ ret = ov4689_set_ctrl_contrast(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_SATURATION:
-+ ret = ov4689_set_ctrl_saturation(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = ov4689_set_ctrl_test_pattern(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY:
-+ ret = ov4689_set_ctrl_light_freq(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HFLIP:
-+ ret = ov4689_set_ctrl_hflip(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_VFLIP:
-+ ret = ov4689_set_ctrl_vflip(sensor, ctrl->val);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ pm_runtime_put(&sensor->i2c_client->dev);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops ov4689_ctrl_ops = {
-+ .g_volatile_ctrl = ov4689_g_volatile_ctrl,
-+ .s_ctrl = ov4689_s_ctrl,
-+};
-+
-+static int ov4689_init_controls(struct ov4689_dev *sensor)
-+{
-+ const struct v4l2_ctrl_ops *ops = &ov4689_ctrl_ops;
-+ struct ov4689_ctrls *ctrls = &sensor->ctrls;
-+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-+ int ret;
-+
-+ v4l2_ctrl_handler_init(hdl, 32);
-+
-+ /* we can use our own mutex for the ctrl lock */
-+ hdl->lock = &sensor->lock;
-+
-+ /* Clock related controls */
-+ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
-+ 0, INT_MAX, 1,
-+ ov4689_calc_pixel_rate(sensor));
-+
-+ /* Auto/manual white balance */
-+ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
-+ V4L2_CID_AUTO_WHITE_BALANCE,
-+ 0, 1, 1, 0);
-+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
-+ 0, 4095, 1, 1024);
-+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
-+ 0, 4095, 1, 1024);
-+
-+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-+ 4, 0xfff8, 1, 0x4c00);
-+ ctrls->anal_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
-+ 0x10, 0xfff8, 1, 0x0080);
-+ ctrls->test_pattern =
-+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(test_pattern_menu) - 1,
-+ 0, 0, test_pattern_menu);
-+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
-+ 0, 1, 1, 0);
-+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
-+ 0, 1, 1, 0);
-+ ctrls->light_freq =
-+ v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_POWER_LINE_FREQUENCY,
-+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
-+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
-+ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
-+ 0, 0, link_freq_menu_items);
-+ if (hdl->error) {
-+ ret = hdl->error;
-+ goto free_ctrls;
-+ }
-+
-+ ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ // ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+ // ctrls->anal_gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+
-+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
-+
-+ sensor->sd.ctrl_handler = hdl;
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(hdl);
-+ return ret;
-+}
-+
-+static int ov4689_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ if (fse->pad != 0)
-+ return -EINVAL;
-+ if (fse->index >= OV4689_NUM_MODES)
-+ return -EINVAL;
-+
-+ fse->min_width =
-+ ov4689_mode_data[fse->index].hact;
-+ fse->max_width = fse->min_width;
-+ fse->min_height =
-+ ov4689_mode_data[fse->index].vact;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static int ov4689_enum_frame_interval(
-+ struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_interval_enum *fie)
-+{
-+ //struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ struct v4l2_fract tpf;
-+ int i = 0;
-+
-+ if (fie->pad != 0)
-+ return -EINVAL;
-+ if (fie->index >= OV4689_NUM_FRAMERATES)
-+ return -EINVAL;
-+
-+ tpf.numerator = 1;
-+ tpf.denominator = ov4689_framerates[fie->index];
-+
-+ // ret = ov4689_try_frame_interval(sensor, &tpf,
-+ // fie->width, fie->height);
-+ // if (ret < 0)
-+ // return -EINVAL;
-+
-+ pr_debug("fie->width = %d, fie->height = %d\n", fie->width, fie->height);
-+ for (i = 0; i < OV4689_NUM_MODES; i++) {
-+ if (fie->width == ov4689_mode_data[i].hact &&
-+ fie->height == ov4689_mode_data[i].vact)
-+ break;
-+ }
-+ if (i == OV4689_NUM_MODES)
-+ return -ENOTTY;
-+
-+ fie->interval = tpf;
-+ fie->width = ov4689_mode_data[i].hact;
-+ fie->height = ov4689_mode_data[i].vact;
-+
-+ return 0;
-+}
-+
-+static int ov4689_g_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+
-+ mutex_lock(&sensor->lock);
-+ fi->interval = sensor->frame_interval;
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int ov4689_s_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ const struct ov4689_mode_info *mode;
-+ int frame_rate, ret = 0;
-+
-+ if (fi->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ mode = sensor->current_mode;
-+
-+ frame_rate = ov4689_try_frame_interval(sensor, &fi->interval,
-+ mode->hact, mode->vact);
-+ if (frame_rate < 0) {
-+ /* Always return a valid frame interval value */
-+ fi->interval = sensor->frame_interval;
-+ goto out;
-+ }
-+
-+ mode = ov4689_find_mode(sensor, frame_rate, mode->hact,
-+ mode->vact, true);
-+ if (!mode) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (mode != sensor->current_mode ||
-+ frame_rate != sensor->current_fr) {
-+ sensor->current_fr = frame_rate;
-+ sensor->frame_interval = fi->interval;
-+ sensor->current_mode = mode;
-+ sensor->pending_mode_change = true;
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ ov4689_calc_pixel_rate(sensor));
-+ }
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int ov4689_stream_start(struct ov4689_dev *sensor, int enable)
-+{
-+ return ov4689_write_reg(sensor, OV4689_REG_STREAM_ON, enable);
-+}
-+
-+static int ov4689_s_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+ int ret = 0;
-+
-+ if (enable) {
-+ pm_runtime_get_sync(&sensor->i2c_client->dev);
-+
-+ ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
-+ if (ret) {
-+ pm_runtime_put_sync(&sensor->i2c_client->dev);
-+ return ret;
-+ }
-+ }
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming == !enable) {
-+ if (enable) {
-+ ret = ov4689_restore_mode(sensor);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ if (enable && sensor->pending_mode_change) {
-+ ret = ov4689_set_mode(sensor);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ if (sensor->ep.bus.mipi_csi2.num_data_lanes == 2) {
-+ ov4689_write_reg(sensor, OV4689_REG_MIPI_SC_CTRL_HI, 0x32);
-+ ov4689_write_reg(sensor, OV4689_REG_MIPI_SC_CTRL_LOW, 0x0c);
-+ } else if (sensor->ep.bus.mipi_csi2.num_data_lanes == 4) {
-+ ov4689_write_reg(sensor, OV4689_REG_MIPI_SC_CTRL_HI, 0x72);
-+ ov4689_write_reg(sensor, OV4689_REG_MIPI_SC_CTRL_LOW, 0x00);
-+ } else {
-+ dev_err(&sensor->i2c_client->dev, "Unsupport lane num\n");
-+ }
-+
-+ ret = ov4689_stream_start(sensor, enable);
-+ if (ret)
-+ goto out;
-+ }
-+ sensor->streaming += enable ? 1 : -1;
-+ WARN_ON(sensor->streaming < 0);
-+out:
-+ mutex_unlock(&sensor->lock);
-+
-+ if (!enable || ret)
-+ pm_runtime_put_sync(&sensor->i2c_client->dev);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_subdev_core_ops ov4689_core_ops = {
-+ .log_status = v4l2_ctrl_subdev_log_status,
-+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops ov4689_video_ops = {
-+ .g_frame_interval = ov4689_g_frame_interval,
-+ .s_frame_interval = ov4689_s_frame_interval,
-+ .s_stream = ov4689_s_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops ov4689_pad_ops = {
-+ .enum_mbus_code = ov4689_enum_mbus_code,
-+ .get_fmt = ov4689_get_fmt,
-+ .set_fmt = ov4689_set_fmt,
-+ .enum_frame_size = ov4689_enum_frame_size,
-+ .enum_frame_interval = ov4689_enum_frame_interval,
-+};
-+
-+static const struct v4l2_subdev_ops ov4689_subdev_ops = {
-+ .core = &ov4689_core_ops,
-+ .video = &ov4689_video_ops,
-+ .pad = &ov4689_pad_ops,
-+};
-+
-+static int ov4689_get_regulators(struct ov4689_dev *sensor)
-+{
-+ int i;
-+
-+ for (i = 0; i < OV4689_NUM_SUPPLIES; i++)
-+ sensor->supplies[i].supply = ov4689_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&sensor->i2c_client->dev,
-+ OV4689_NUM_SUPPLIES,
-+ sensor->supplies);
-+}
-+
-+static int ov4689_check_chip_id(struct ov4689_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ int ret = 0;
-+ u16 chip_id;
-+
-+ ret = ov4689_read_reg16(sensor, OV4689_REG_CHIP_ID, &chip_id);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to read chip identifier\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ if (chip_id != OV4689_CHIP_ID) {
-+ dev_err(&client->dev, "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",
-+ __func__, OV4689_CHIP_ID, chip_id);
-+ return -ENXIO;
-+ }
-+ dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
-+ __func__, chip_id);
-+
-+ return 0;
-+}
-+
-+static int ov4689_probe(struct i2c_client *client)
-+{
-+ struct device *dev = &client->dev;
-+ struct fwnode_handle *endpoint;
-+ struct ov4689_dev *sensor;
-+ struct v4l2_mbus_framefmt *fmt;
-+ u32 rotation;
-+ int ret;
-+
-+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
-+ if (!sensor)
-+ return -ENOMEM;
-+
-+ sensor->i2c_client = client;
-+
-+ fmt = &sensor->fmt;
-+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+ fmt->width = 1920;
-+ fmt->height = 1080;
-+ fmt->field = V4L2_FIELD_NONE;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator = ov4689_framerates[OV4689_30_FPS];
-+ sensor->current_fr = OV4689_30_FPS;
-+ sensor->current_mode =
-+ &ov4689_mode_data[OV4689_MODE_1080P_1920_1080];
-+ sensor->last_mode = sensor->current_mode;
-+
-+
-+ /* optional indication of physical rotation of sensor */
-+ ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
-+ &rotation);
-+ if (!ret) {
-+ switch (rotation) {
-+ case 180:
-+ sensor->upside_down = true;
-+ fallthrough;
-+ case 0:
-+ break;
-+ default:
-+ dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
-+ rotation);
-+ }
-+ }
-+
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ if (sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
-+ dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
-+ return -EINVAL;
-+ }
-+
-+ /* get system clock (xclk) */
-+ sensor->xclk = devm_clk_get(dev, "xclk");
-+ if (IS_ERR(sensor->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(sensor->xclk);
-+ }
-+
-+ sensor->xclk_freq = clk_get_rate(sensor->xclk);
-+ if (sensor->xclk_freq < OV4689_XCLK_MIN ||
-+ sensor->xclk_freq > OV4689_XCLK_MAX) {
-+ dev_err(dev, "xclk frequency out of range: %d Hz\n",
-+ sensor->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ /* request optional power down pin */
-+ sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->pwdn_gpio))
-+ return PTR_ERR(sensor->pwdn_gpio);
-+
-+ /* request optional reset pin */
-+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->reset_gpio))
-+ return PTR_ERR(sensor->reset_gpio);
-+
-+ v4l2_i2c_subdev_init(&sensor->sd, client, &ov4689_subdev_ops);
-+
-+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
-+ V4L2_SUBDEV_FL_HAS_EVENTS;
-+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
-+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov4689_get_regulators(sensor);
-+ if (ret)
-+ return ret;
-+
-+ mutex_init(&sensor->lock);
-+
-+ ret = ov4689_set_power_on(dev);
-+ if (ret) {
-+ dev_err(dev, "failed to power on\n");
-+ goto entity_cleanup;
-+ }
-+
-+ ret = ov4689_check_chip_id(sensor);
-+ if (ret)
-+ goto error_power_off;
-+
-+ ret = ov4689_init_controls(sensor);
-+ if (ret)
-+ goto error_power_off;
-+
-+ ret = v4l2_async_register_subdev_sensor(&sensor->sd);
-+ if (ret)
-+ goto free_ctrls;
-+
-+ pm_runtime_set_active(dev);
-+ pm_runtime_enable(dev);
-+
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+error_power_off:
-+ ov4689_set_power_off(dev);
-+entity_cleanup:
-+ media_entity_cleanup(&sensor->sd.entity);
-+ mutex_destroy(&sensor->lock);
-+ return ret;
-+}
-+
-+static void ov4689_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct ov4689_dev *sensor = to_ov4689_dev(sd);
-+
-+ v4l2_async_unregister_subdev(&sensor->sd);
-+ media_entity_cleanup(&sensor->sd.entity);
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+ mutex_destroy(&sensor->lock);
-+
-+ pm_runtime_disable(&client->dev);
-+ if (!pm_runtime_status_suspended(&client->dev))
-+ ov4689_set_power_off(&client->dev);
-+ pm_runtime_set_suspended(&client->dev);
-+}
-+
-+static const struct i2c_device_id ov4689_id[] = {
-+ { "ov4689", 0 },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(i2c, ov4689_id);
-+
-+static const struct of_device_id ov4689_dt_ids[] = {
-+ { .compatible = "ovti,ov4689" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, ov4689_dt_ids);
-+
-+static const struct dev_pm_ops ov4689_pm_ops = {
-+ SET_RUNTIME_PM_OPS(ov4689_set_power_off, ov4689_set_power_on, NULL)
-+};
-+
-+static struct i2c_driver ov4689_i2c_driver = {
-+ .driver = {
-+ .name = "ov4689",
-+ .of_match_table = ov4689_dt_ids,
-+ .pm = &ov4689_pm_ops,
-+ },
-+ .id_table = ov4689_id,
-+ .probe = ov4689_probe,
-+ .remove = ov4689_remove,
-+};
-+
-+module_i2c_driver(ov4689_i2c_driver);
-+
-+MODULE_DESCRIPTION("OV4689 MIPI Camera Subdev Driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/ov5640.c
-@@ -0,0 +1,3227 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
-+ * Copyright (C) 2014-2017 Mentor Graphics Inc.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/ctype.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+#include "stfcamss.h"
-+
-+/* min/typical/max system clock (xclk) frequencies */
-+#define OV5640_XCLK_MIN 6000000
-+#define OV5640_XCLK_MAX 54000000
-+
-+#define OV5640_SKIP_FRAMES 4
-+
-+#define OV5640_CHIP_ID 0x5640
-+#define OV5640_DEFAULT_SLAVE_ID 0x3c
-+
-+#define OV5640_REG_SYS_RESET02 0x3002
-+#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006
-+#define OV5640_REG_SYS_CTRL0 0x3008
-+#define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42
-+#define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02
-+#define OV5640_REG_CHIP_ID 0x300a
-+#define OV5640_REG_IO_MIPI_CTRL00 0x300e
-+#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017
-+#define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018
-+#define OV5640_REG_PAD_OUTPUT00 0x3019
-+#define OV5640_REG_SYSTEM_CONTROL1 0x302e
-+#define OV5640_REG_SC_PLL_CTRL0 0x3034
-+#define OV5640_REG_SC_PLL_CTRL1 0x3035
-+#define OV5640_REG_SC_PLL_CTRL2 0x3036
-+#define OV5640_REG_SC_PLL_CTRL3 0x3037
-+#define OV5640_REG_SLAVE_ID 0x3100
-+#define OV5640_REG_SCCB_SYS_CTRL1 0x3103
-+#define OV5640_REG_SYS_ROOT_DIVIDER 0x3108
-+#define OV5640_REG_AWB_R_GAIN 0x3400
-+#define OV5640_REG_AWB_G_GAIN 0x3402
-+#define OV5640_REG_AWB_B_GAIN 0x3404
-+#define OV5640_REG_AWB_MANUAL_CTRL 0x3406
-+#define OV5640_REG_AEC_PK_EXPOSURE_HI 0x3500
-+#define OV5640_REG_AEC_PK_EXPOSURE_MED 0x3501
-+#define OV5640_REG_AEC_PK_EXPOSURE_LO 0x3502
-+#define OV5640_REG_AEC_PK_MANUAL 0x3503
-+#define OV5640_REG_AEC_PK_REAL_GAIN 0x350a
-+#define OV5640_REG_AEC_PK_VTS 0x350c
-+#define OV5640_REG_TIMING_DVPHO 0x3808
-+#define OV5640_REG_TIMING_DVPVO 0x380a
-+#define OV5640_REG_TIMING_HTS 0x380c
-+#define OV5640_REG_TIMING_VTS 0x380e
-+#define OV5640_REG_TIMING_TC_REG20 0x3820
-+#define OV5640_REG_TIMING_TC_REG21 0x3821
-+#define OV5640_REG_AEC_CTRL00 0x3a00
-+#define OV5640_REG_AEC_B50_STEP 0x3a08
-+#define OV5640_REG_AEC_B60_STEP 0x3a0a
-+#define OV5640_REG_AEC_CTRL0D 0x3a0d
-+#define OV5640_REG_AEC_CTRL0E 0x3a0e
-+#define OV5640_REG_AEC_CTRL0F 0x3a0f
-+#define OV5640_REG_AEC_CTRL10 0x3a10
-+#define OV5640_REG_AEC_CTRL11 0x3a11
-+#define OV5640_REG_AEC_CTRL1B 0x3a1b
-+#define OV5640_REG_AEC_CTRL1E 0x3a1e
-+#define OV5640_REG_AEC_CTRL1F 0x3a1f
-+#define OV5640_REG_HZ5060_CTRL00 0x3c00
-+#define OV5640_REG_HZ5060_CTRL01 0x3c01
-+#define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c
-+#define OV5640_REG_FRAME_CTRL01 0x4202
-+#define OV5640_REG_FORMAT_CONTROL00 0x4300
-+#define OV5640_REG_VFIFO_HSIZE 0x4602
-+#define OV5640_REG_VFIFO_VSIZE 0x4604
-+#define OV5640_REG_JPG_MODE_SELECT 0x4713
-+#define OV5640_REG_CCIR656_CTRL00 0x4730
-+#define OV5640_REG_POLARITY_CTRL00 0x4740
-+#define OV5640_REG_MIPI_CTRL00 0x4800
-+#define OV5640_REG_DEBUG_MODE 0x4814
-+#define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f
-+#define OV5640_REG_PRE_ISP_TEST_SET1 0x503d
-+#define OV5640_REG_SDE_CTRL0 0x5580
-+#define OV5640_REG_SDE_CTRL1 0x5581
-+#define OV5640_REG_SDE_CTRL3 0x5583
-+#define OV5640_REG_SDE_CTRL4 0x5584
-+#define OV5640_REG_SDE_CTRL5 0x5585
-+#define OV5640_REG_AVG_READOUT 0x56a1
-+
-+enum ov5640_mode_id {
-+ OV5640_MODE_QCIF_176_144 = 0,
-+ OV5640_MODE_QVGA_320_240,
-+ OV5640_MODE_VGA_640_480,
-+ OV5640_MODE_NTSC_720_480,
-+ OV5640_MODE_PAL_720_576,
-+ OV5640_MODE_XGA_1024_768,
-+ OV5640_MODE_720P_1280_720,
-+ OV5640_MODE_1080P_1920_1080,
-+ OV5640_MODE_QSXGA_2592_1944,
-+ OV5640_NUM_MODES,
-+};
-+
-+enum ov5640_frame_rate {
-+ OV5640_15_FPS = 0,
-+ OV5640_30_FPS,
-+ OV5640_60_FPS,
-+ OV5640_NUM_FRAMERATES,
-+};
-+
-+enum ov5640_format_mux {
-+ OV5640_FMT_MUX_YUV422 = 0,
-+ OV5640_FMT_MUX_RGB,
-+ OV5640_FMT_MUX_DITHER,
-+ OV5640_FMT_MUX_RAW_DPC,
-+ OV5640_FMT_MUX_SNR_RAW,
-+ OV5640_FMT_MUX_RAW_CIP,
-+};
-+
-+struct ov5640_pixfmt {
-+ u32 code;
-+ u32 colorspace;
-+};
-+
-+static const struct ov5640_pixfmt ov5640_formats[] = {
-+ { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, },
-+ { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, },
-+ { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, },
-+};
-+
-+/*
-+ * FIXME: remove this when a subdev API becomes available
-+ * to set the MIPI CSI-2 virtual channel.
-+ */
-+static unsigned int virtual_channel;
-+module_param(virtual_channel, uint, 0444);
-+MODULE_PARM_DESC(virtual_channel,
-+ "MIPI CSI-2 virtual channel (0..3), default 0");
-+
-+static const int ov5640_framerates[] = {
-+ [OV5640_15_FPS] = 15,
-+ [OV5640_30_FPS] = 30,
-+ [OV5640_60_FPS] = 60,
-+};
-+
-+/* regulator supplies */
-+static const char * const ov5640_supply_name[] = {
-+ "DOVDD", /* Digital I/O (1.8V) supply */
-+ "AVDD", /* Analog (2.8V) supply */
-+ "DVDD", /* Digital Core (1.5V) supply */
-+};
-+
-+#define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
-+
-+/*
-+ * Image size under 1280 * 960 are SUBSAMPLING
-+ * Image size upper 1280 * 960 are SCALING
-+ */
-+enum ov5640_downsize_mode {
-+ SUBSAMPLING,
-+ SCALING,
-+};
-+
-+struct reg_value {
-+ u16 reg_addr;
-+ u8 val;
-+ u8 mask;
-+ u32 delay_ms;
-+};
-+
-+struct ov5640_mode_info {
-+ enum ov5640_mode_id id;
-+ enum ov5640_downsize_mode dn_mode;
-+ u32 hact;
-+ u32 htot;
-+ u32 vact;
-+ u32 vtot;
-+ const struct reg_value *reg_data;
-+ u32 reg_data_size;
-+ u32 max_fps;
-+};
-+
-+struct ov5640_ctrls {
-+ struct v4l2_ctrl_handler handler;
-+ struct v4l2_ctrl *pixel_rate;
-+ struct {
-+ struct v4l2_ctrl *auto_exp;
-+ struct v4l2_ctrl *exposure;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_wb;
-+ struct v4l2_ctrl *blue_balance;
-+ struct v4l2_ctrl *red_balance;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_gain;
-+ struct v4l2_ctrl *gain;
-+ };
-+ struct v4l2_ctrl *brightness;
-+ struct v4l2_ctrl *light_freq;
-+ struct v4l2_ctrl *saturation;
-+ struct v4l2_ctrl *contrast;
-+ struct v4l2_ctrl *hue;
-+ struct v4l2_ctrl *test_pattern;
-+ struct v4l2_ctrl *hflip;
-+ struct v4l2_ctrl *vflip;
-+};
-+
-+struct ov5640_dev {
-+ struct i2c_client *i2c_client;
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+ struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
-+ struct clk *xclk; /* system clock to OV5640 */
-+ u32 xclk_freq;
-+
-+ struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
-+ struct gpio_desc *reset_gpio;
-+ struct gpio_desc *pwdn_gpio;
-+ bool upside_down;
-+
-+ /* lock to protect all members below */
-+ struct mutex lock;
-+
-+ int power_count;
-+
-+ struct v4l2_mbus_framefmt fmt;
-+ bool pending_fmt_change;
-+
-+ const struct ov5640_mode_info *current_mode;
-+ const struct ov5640_mode_info *last_mode;
-+ enum ov5640_frame_rate current_fr;
-+ struct v4l2_fract frame_interval;
-+
-+ struct ov5640_ctrls ctrls;
-+
-+ u32 prev_sysclk, prev_hts;
-+ u32 ae_low, ae_high, ae_target;
-+
-+ bool pending_mode_change;
-+ int streaming;
-+};
-+
-+static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
-+{
-+ return container_of(sd, struct ov5640_dev, sd);
-+}
-+
-+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
-+{
-+ return &container_of(ctrl->handler, struct ov5640_dev,
-+ ctrls.handler)->sd;
-+}
-+
-+/*
-+ * FIXME: all of these register tables are likely filled with
-+ * entries that set the register to their power-on default values,
-+ * and which are otherwise not touched by this driver. Those entries
-+ * should be identified and removed to speed register load time
-+ * over i2c.
-+ */
-+/* YUV422 UYVY VGA@30fps */
-+static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
-+ {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
-+ {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
-+ {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
-+ {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
-+ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
-+ {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
-+ {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
-+ {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
-+ {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
-+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
-+ {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
-+ {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
-+ {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
-+ {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
-+ {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
-+ {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
-+ {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
-+ {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
-+ {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
-+ {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
-+ {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
-+ {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
-+ {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
-+ {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
-+ {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
-+ {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
-+ {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
-+ {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
-+ {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
-+ {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
-+ {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
-+ {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
-+ {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
-+ {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
-+ {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
-+ {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
-+ {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
-+ {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
-+ {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
-+ {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
-+ {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
-+ {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
-+ {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
-+ {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
-+ {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
-+ {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
-+ {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
-+ {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
-+ {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
-+ {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
-+ {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
-+ {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
-+ {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
-+ {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
-+ {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
-+ {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
-+ {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
-+ {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
-+ {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
-+ {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
-+ {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
-+ {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
-+ {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
-+ {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
-+ {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
-+ {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
-+ {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
-+};
-+
-+static const struct reg_value ov5640_setting_VGA_640_480[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_XGA_1024_768[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_QVGA_320_240[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_QCIF_176_144[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_NTSC_720_480[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_PAL_720_576[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_720P_1280_720[] = {
-+ {0x3c07, 0x07, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x31, 0, 0},
-+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
-+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
-+ {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
-+ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
-+ {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
-+ {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x11, 0, 0},
-+ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
-+ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
-+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-+ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
-+ {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
-+ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
-+ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
-+ {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
-+ {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
-+ {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
-+ {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
-+ {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
-+ {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
-+ {0x4005, 0x1a, 0, 0},
-+};
-+
-+static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
-+ {0x3c07, 0x08, 0, 0},
-+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-+ {0x3814, 0x11, 0, 0},
-+ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
-+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
-+ {0x3810, 0x00, 0, 0},
-+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
-+ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
-+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
-+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
-+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
-+ {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 70},
-+};
-+
-+/* power-on sensor init reg table */
-+static const struct ov5640_mode_info ov5640_mode_init_data = {
-+ 0, SUBSAMPLING, 640, 1896, 480, 984,
-+ ov5640_init_setting_30fps_VGA,
-+ ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
-+ OV5640_30_FPS,
-+};
-+
-+static const struct ov5640_mode_info
-+ov5640_mode_data[OV5640_NUM_MODES] = {
-+ {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
-+ 176, 1896, 144, 984,
-+ ov5640_setting_QCIF_176_144,
-+ ARRAY_SIZE(ov5640_setting_QCIF_176_144),
-+ OV5640_30_FPS},
-+ {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
-+ 320, 1896, 240, 984,
-+ ov5640_setting_QVGA_320_240,
-+ ARRAY_SIZE(ov5640_setting_QVGA_320_240),
-+ OV5640_30_FPS},
-+ {OV5640_MODE_VGA_640_480, SUBSAMPLING,
-+ 640, 1896, 480, 1080,
-+ ov5640_setting_VGA_640_480,
-+ ARRAY_SIZE(ov5640_setting_VGA_640_480),
-+ OV5640_60_FPS},
-+ {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
-+ 720, 1896, 480, 984,
-+ ov5640_setting_NTSC_720_480,
-+ ARRAY_SIZE(ov5640_setting_NTSC_720_480),
-+ OV5640_30_FPS},
-+ {OV5640_MODE_PAL_720_576, SUBSAMPLING,
-+ 720, 1896, 576, 984,
-+ ov5640_setting_PAL_720_576,
-+ ARRAY_SIZE(ov5640_setting_PAL_720_576),
-+ OV5640_30_FPS},
-+ {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
-+ 1024, 1896, 768, 1080,
-+ ov5640_setting_XGA_1024_768,
-+ ARRAY_SIZE(ov5640_setting_XGA_1024_768),
-+ OV5640_30_FPS},
-+ {OV5640_MODE_720P_1280_720, SUBSAMPLING,
-+ 1280, 1892, 720, 740,
-+ ov5640_setting_720P_1280_720,
-+ ARRAY_SIZE(ov5640_setting_720P_1280_720),
-+ OV5640_30_FPS},
-+ {OV5640_MODE_1080P_1920_1080, SCALING,
-+ 1920, 2500, 1080, 1120,
-+ ov5640_setting_1080P_1920_1080,
-+ ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
-+ OV5640_30_FPS},
-+ {OV5640_MODE_QSXGA_2592_1944, SCALING,
-+ 2592, 2844, 1944, 1968,
-+ ov5640_setting_QSXGA_2592_1944,
-+ ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
-+ OV5640_15_FPS},
-+};
-+
-+static int ov5640_init_slave_id(struct ov5640_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg;
-+ u8 buf[3];
-+ int ret;
-+
-+ if (client->addr == OV5640_DEFAULT_SLAVE_ID)
-+ return 0;
-+
-+ buf[0] = OV5640_REG_SLAVE_ID >> 8;
-+ buf[1] = OV5640_REG_SLAVE_ID & 0xff;
-+ buf[2] = client->addr << 1;
-+
-+ msg.addr = OV5640_DEFAULT_SLAVE_ID;
-+ msg.flags = 0;
-+ msg.buf = buf;
-+ msg.len = sizeof(buf);
-+
-+ ret = i2c_transfer(client->adapter, &msg, 1);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg;
-+ u8 buf[3];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+ buf[2] = val;
-+
-+ msg.addr = client->addr;
-+ msg.flags = client->flags;
-+ msg.buf = buf;
-+ msg.len = sizeof(buf);
-+
-+ ret = i2c_transfer(client->adapter, &msg, 1);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
-+ __func__, reg, val);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg[2];
-+ u8 buf[2];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+
-+ msg[0].addr = client->addr;
-+ msg[0].flags = client->flags;
-+ msg[0].buf = buf;
-+ msg[0].len = sizeof(buf);
-+
-+ msg[1].addr = client->addr;
-+ msg[1].flags = client->flags | I2C_M_RD;
-+ msg[1].buf = buf;
-+ msg[1].len = 1;
-+
-+ ret = i2c_transfer(client->adapter, msg, 2);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x\n",
-+ __func__, reg);
-+ return ret;
-+ }
-+
-+ *val = buf[0];
-+ return 0;
-+}
-+
-+static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
-+{
-+ u8 hi, lo;
-+ int ret;
-+
-+ ret = ov5640_read_reg(sensor, reg, &hi);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_read_reg(sensor, reg + 1, &lo);
-+ if (ret)
-+ return ret;
-+
-+ *val = ((u16)hi << 8) | (u16)lo;
-+ return 0;
-+}
-+
-+static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
-+{
-+ int ret;
-+
-+ ret = ov5640_write_reg(sensor, reg, val >> 8);
-+ if (ret)
-+ return ret;
-+
-+ return ov5640_write_reg(sensor, reg + 1, val & 0xff);
-+}
-+
-+static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
-+ u8 mask, u8 val)
-+{
-+ u8 readval;
-+ int ret;
-+
-+ ret = ov5640_read_reg(sensor, reg, &readval);
-+ if (ret)
-+ return ret;
-+
-+ readval &= ~mask;
-+ val &= mask;
-+ val |= readval;
-+
-+ return ov5640_write_reg(sensor, reg, val);
-+}
-+
-+/*
-+ * After trying the various combinations, reading various
-+ * documentations spread around the net, and from the various
-+ * feedback, the clock tree is probably as follows:
-+ *
-+ * +--------------+
-+ * | Ext. Clock |
-+ * +-+------------+
-+ * | +----------+
-+ * +->| PLL1 | - reg 0x3036, for the multiplier
-+ * +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
-+ * | +--------------+
-+ * +->| System Clock | - reg 0x3035, bits 4-7
-+ * +-+------------+
-+ * | +--------------+
-+ * +->| MIPI Divider | - reg 0x3035, bits 0-3
-+ * | +-+------------+
-+ * | +----------------> MIPI SCLK
-+ * | + +-----+
-+ * | +->| / 2 |-------> MIPI BIT CLK
-+ * | +-----+
-+ * | +--------------+
-+ * +->| PLL Root Div | - reg 0x3037, bit 4
-+ * +-+------------+
-+ * | +---------+
-+ * +->| Bit Div | - reg 0x3034, bits 0-3
-+ * +-+-------+
-+ * | +-------------+
-+ * +->| SCLK Div | - reg 0x3108, bits 0-1
-+ * | +-+-----------+
-+ * | +---------------> SCLK
-+ * | +-------------+
-+ * +->| SCLK 2X Div | - reg 0x3108, bits 2-3
-+ * | +-+-----------+
-+ * | +---------------> SCLK 2X
-+ * | +-------------+
-+ * +->| PCLK Div | - reg 0x3108, bits 4-5
-+ * ++------------+
-+ * + +-----------+
-+ * +->| P_DIV | - reg 0x3035, bits 0-3
-+ * +-----+-----+
-+ * +------------> PCLK
-+ *
-+ * This is deviating from the datasheet at least for the register
-+ * 0x3108, since it's said here that the PCLK would be clocked from
-+ * the PLL.
-+ *
-+ * There seems to be also (unverified) constraints:
-+ * - the PLL pre-divider output rate should be in the 4-27MHz range
-+ * - the PLL multiplier output rate should be in the 500-1000MHz range
-+ * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
-+ *
-+ * In the two latter cases, these constraints are met since our
-+ * factors are hardcoded. If we were to change that, we would need to
-+ * take this into account. The only varying parts are the PLL
-+ * multiplier and the system clock divider, which are shared between
-+ * all these clocks so won't cause any issue.
-+ */
-+
-+/*
-+ * This is supposed to be ranging from 1 to 8, but the value is always
-+ * set to 3 in the vendor kernels.
-+ */
-+#define OV5640_PLL_PREDIV 3
-+
-+#define OV5640_PLL_MULT_MIN 4
-+#define OV5640_PLL_MULT_MAX 252
-+
-+/*
-+ * This is supposed to be ranging from 1 to 16, but the value is
-+ * always set to either 1 or 2 in the vendor kernels.
-+ */
-+#define OV5640_SYSDIV_MIN 1
-+#define OV5640_SYSDIV_MAX 16
-+
-+/*
-+ * Hardcode these values for scaler and non-scaler modes.
-+ * FIXME: to be re-calcualted for 1 data lanes setups
-+ */
-+#define OV5640_MIPI_DIV_PCLK 2
-+#define OV5640_MIPI_DIV_SCLK 1
-+
-+/*
-+ * This is supposed to be ranging from 1 to 2, but the value is always
-+ * set to 2 in the vendor kernels.
-+ */
-+#define OV5640_PLL_ROOT_DIV 2
-+#define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4)
-+
-+/*
-+ * We only supports 8-bit formats at the moment
-+ */
-+#define OV5640_BIT_DIV 2
-+#define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08
-+
-+/*
-+ * This is supposed to be ranging from 1 to 8, but the value is always
-+ * set to 2 in the vendor kernels.
-+ */
-+#define OV5640_SCLK_ROOT_DIV 2
-+
-+/*
-+ * This is hardcoded so that the consistency is maintained between SCLK and
-+ * SCLK 2x.
-+ */
-+#define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
-+
-+/*
-+ * This is supposed to be ranging from 1 to 8, but the value is always
-+ * set to 1 in the vendor kernels.
-+ */
-+#define OV5640_PCLK_ROOT_DIV 1
-+#define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00
-+
-+static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
-+ u8 pll_prediv, u8 pll_mult,
-+ u8 sysdiv)
-+{
-+ unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
-+
-+ /* PLL1 output cannot exceed 1GHz. */
-+ if (sysclk / 1000000 > 1000)
-+ return 0;
-+
-+ return sysclk / sysdiv;
-+}
-+
-+static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
-+ unsigned long rate,
-+ u8 *pll_prediv, u8 *pll_mult,
-+ u8 *sysdiv)
-+{
-+ unsigned long best = ~0;
-+ u8 best_sysdiv = 1, best_mult = 1;
-+ u8 _sysdiv, _pll_mult;
-+
-+ for (_sysdiv = OV5640_SYSDIV_MIN;
-+ _sysdiv <= OV5640_SYSDIV_MAX;
-+ _sysdiv++) {
-+ for (_pll_mult = OV5640_PLL_MULT_MIN;
-+ _pll_mult <= OV5640_PLL_MULT_MAX;
-+ _pll_mult++) {
-+ unsigned long _rate;
-+
-+ /*
-+ * The PLL multiplier cannot be odd if above
-+ * 127.
-+ */
-+ if (_pll_mult > 127 && (_pll_mult % 2))
-+ continue;
-+
-+ _rate = ov5640_compute_sys_clk(sensor,
-+ OV5640_PLL_PREDIV,
-+ _pll_mult, _sysdiv);
-+
-+ /*
-+ * We have reached the maximum allowed PLL1 output,
-+ * increase sysdiv.
-+ */
-+ if (!_rate)
-+ break;
-+
-+ /*
-+ * Prefer rates above the expected clock rate than
-+ * below, even if that means being less precise.
-+ */
-+ if (_rate < rate)
-+ continue;
-+
-+ if (abs(rate - _rate) < abs(rate - best)) {
-+ best = _rate;
-+ best_sysdiv = _sysdiv;
-+ best_mult = _pll_mult;
-+ }
-+
-+ if (_rate == rate)
-+ goto out;
-+ }
-+ }
-+
-+out:
-+ *sysdiv = best_sysdiv;
-+ *pll_prediv = OV5640_PLL_PREDIV;
-+ *pll_mult = best_mult;
-+
-+ return best;
-+}
-+
-+/*
-+ * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
-+ * for the MIPI CSI-2 output.
-+ *
-+ * @rate: The requested bandwidth per lane in bytes per second.
-+ * 'Bandwidth Per Lane' is calculated as:
-+ * bpl = HTOT * VTOT * FPS * bpp / num_lanes;
-+ *
-+ * This function use the requested bandwidth to calculate:
-+ * - sample_rate = bpl / (bpp / num_lanes);
-+ * = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes);
-+ *
-+ * - mipi_sclk = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR)
-+ *
-+ * with these fixed parameters:
-+ * PLL_RDIV = 2;
-+ * BIT_DIVIDER = 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
-+ * PCLK_DIV = 1;
-+ *
-+ * The MIPI clock generation differs for modes that use the scaler and modes
-+ * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI
-+ * BIT CLk, and thus:
-+ *
-+ * - mipi_sclk = bpl / MIPI_DIV / 2;
-+ * MIPI_DIV = 1;
-+ *
-+ * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated
-+ * from the pixel clock, and thus:
-+ *
-+ * - sample_rate = bpl / (bpp / num_lanes);
-+ * = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes);
-+ * = bpl / (4 * MIPI_DIV / num_lanes);
-+ * - MIPI_DIV = bpp / (4 * num_lanes);
-+ *
-+ * FIXME: this have been tested with 16bpp and 2 lanes setup only.
-+ * MIPI_DIV is fixed to value 2, but it -might- be changed according to the
-+ * above formula for setups with 1 lane or image formats with different bpp.
-+ *
-+ * FIXME: this deviates from the sensor manual documentation which is quite
-+ * thin on the MIPI clock tree generation part.
-+ */
-+static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
-+ unsigned long rate)
-+{
-+ const struct ov5640_mode_info *mode = sensor->current_mode;
-+ u8 prediv, mult, sysdiv;
-+ u8 mipi_div;
-+ int ret;
-+
-+ /*
-+ * 1280x720 is reported to use 'SUBSAMPLING' only,
-+ * but according to the sensor manual it goes through the
-+ * scaler before subsampling.
-+ */
-+ if (mode->dn_mode == SCALING ||
-+ (mode->id == OV5640_MODE_720P_1280_720))
-+ mipi_div = OV5640_MIPI_DIV_SCLK;
-+ else
-+ mipi_div = OV5640_MIPI_DIV_PCLK;
-+
-+ ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv);
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
-+ 0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT);
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
-+ 0xff, sysdiv << 4 | mipi_div);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
-+ 0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv);
-+ if (ret)
-+ return ret;
-+
-+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER,
-+ 0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS);
-+}
-+
-+static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
-+ unsigned long rate,
-+ u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
-+ u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
-+{
-+ unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
-+ OV5640_PCLK_ROOT_DIV;
-+
-+ _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
-+ sysdiv);
-+ *pll_rdiv = OV5640_PLL_ROOT_DIV;
-+ *bit_div = OV5640_BIT_DIV;
-+ *pclk_div = OV5640_PCLK_ROOT_DIV;
-+
-+ return _rate / *pll_rdiv / *bit_div / *pclk_div;
-+}
-+
-+static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
-+{
-+ u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
-+ int ret;
-+
-+ ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
-+ &bit_div, &pclk_div);
-+
-+#ifndef CONFIG_VIN_SENSOR_OV5640
-+ if (bit_div == 2)
-+ bit_div = 8;
-+#else
-+ bit_div = 0xa;
-+#endif
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
-+ 0x0f, bit_div);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * We need to set sysdiv according to the clock, and to clear
-+ * the MIPI divider.
-+ */
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
-+ 0xff, sysdiv << 4);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
-+ 0xff, mult);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
-+ 0x1f, prediv | ((pll_rdiv - 1) << 4));
-+ if (ret)
-+ return ret;
-+
-+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
-+ (ilog2(pclk_div) << 4));
-+}
-+
-+/* set JPEG framing sizes */
-+static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
-+ const struct ov5640_mode_info *mode)
-+{
-+ int ret;
-+
-+ /*
-+ * compression mode 3 timing
-+ *
-+ * Data is transmitted with programmable width (VFIFO_HSIZE).
-+ * No padding done. Last line may have less data. Varying
-+ * number of lines per frame, depending on amount of data.
-+ */
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact);
-+ if (ret < 0)
-+ return ret;
-+
-+ return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact);
-+}
-+
-+/* download ov5640 settings to sensor through i2c */
-+static int ov5640_set_timings(struct ov5640_dev *sensor,
-+ const struct ov5640_mode_info *mode)
-+{
-+ int ret;
-+
-+ if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
-+ ret = ov5640_set_jpeg_timings(sensor, mode);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
-+ if (ret < 0)
-+ return ret;
-+
-+ return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot);
-+}
-+
-+static int ov5640_load_regs(struct ov5640_dev *sensor,
-+ const struct ov5640_mode_info *mode)
-+{
-+ const struct reg_value *regs = mode->reg_data;
-+ unsigned int i;
-+ u32 delay_ms;
-+ u16 reg_addr;
-+ u8 mask, val;
-+ int ret = 0;
-+
-+ st_info(ST_SENSOR, "%s, mode = 0x%x\n", __func__, mode->id);
-+ for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
-+ delay_ms = regs->delay_ms;
-+ reg_addr = regs->reg_addr;
-+ val = regs->val;
-+ mask = regs->mask;
-+
-+ /* remain in power down mode for DVP */
-+ if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
-+ val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
-+ sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
-+ continue;
-+
-+ if (mask)
-+ ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
-+ else
-+ ret = ov5640_write_reg(sensor, reg_addr, val);
-+ if (ret)
-+ break;
-+
-+ if (delay_ms)
-+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
-+ }
-+
-+ return ov5640_set_timings(sensor, mode);
-+}
-+
-+static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
-+{
-+ return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
-+ BIT(0), on ? 0 : BIT(0));
-+}
-+
-+/* read exposure, in number of line periods */
-+static int ov5640_get_exposure(struct ov5640_dev *sensor)
-+{
-+ int exp, ret;
-+ u8 temp;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
-+ if (ret)
-+ return ret;
-+ exp = ((int)temp & 0x0f) << 16;
-+ ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
-+ if (ret)
-+ return ret;
-+ exp |= ((int)temp << 8);
-+ ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
-+ if (ret)
-+ return ret;
-+ exp |= (int)temp;
-+
-+ return exp >> 4;
-+}
-+
-+/* write exposure, given number of line periods */
-+static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
-+{
-+ int ret;
-+
-+ exposure <<= 4;
-+
-+ ret = ov5640_write_reg(sensor,
-+ OV5640_REG_AEC_PK_EXPOSURE_LO,
-+ exposure & 0xff);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor,
-+ OV5640_REG_AEC_PK_EXPOSURE_MED,
-+ (exposure >> 8) & 0xff);
-+ if (ret)
-+ return ret;
-+ return ov5640_write_reg(sensor,
-+ OV5640_REG_AEC_PK_EXPOSURE_HI,
-+ (exposure >> 16) & 0x0f);
-+}
-+
-+static int ov5640_get_gain(struct ov5640_dev *sensor)
-+{
-+ u16 gain;
-+ int ret;
-+
-+ ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
-+ if (ret)
-+ return ret;
-+
-+ return gain & 0x3ff;
-+}
-+
-+static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
-+{
-+ return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
-+ (u16)gain & 0x3ff);
-+}
-+
-+static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
-+{
-+ return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
-+ BIT(1), on ? 0 : BIT(1));
-+}
-+
-+static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
-+{
-+ return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
-+ OV5640_REG_SYS_CTRL0_SW_PWUP :
-+ OV5640_REG_SYS_CTRL0_SW_PWDN);
-+}
-+
-+static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
-+{
-+ int ret;
-+
-+ /*
-+ * Enable/disable the MIPI interface
-+ *
-+ * 0x300e = on ? 0x45 : 0x40
-+ *
-+ * FIXME: the sensor manual (version 2.03) reports
-+ * [7:5] = 000 : 1 data lane mode
-+ * [7:5] = 001 : 2 data lanes mode
-+ * But this settings do not work, while the following ones
-+ * have been validated for 2 data lanes mode.
-+ *
-+ * [7:5] = 010 : 2 data lanes mode
-+ * [4] = 0 : Power up MIPI HS Tx
-+ * [3] = 0 : Power up MIPI LS Rx
-+ * [2] = 1/0 : MIPI interface enable/disable
-+ * [1:0] = 01/00: FIXME: 'debug'
-+ */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
-+ on ? 0x45 : 0x40);
-+ if (ret)
-+ return ret;
-+
-+ return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
-+ on ? 0x00 : 0x0f);
-+}
-+
-+static int ov5640_get_sysclk(struct ov5640_dev *sensor)
-+{
-+ /* calculate sysclk */
-+ u32 xvclk = sensor->xclk_freq / 10000;
-+ u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
-+ u32 sclk_rdiv_map[] = {1, 2, 4, 8};
-+ u32 bit_div2x = 1, sclk_rdiv, sysclk;
-+ u8 temp1, temp2;
-+ int ret;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
-+ if (ret)
-+ return ret;
-+ temp2 = temp1 & 0x0f;
-+ if (temp2 == 8 || temp2 == 10)
-+ bit_div2x = temp2 / 2;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
-+ if (ret)
-+ return ret;
-+ sysdiv = temp1 >> 4;
-+ if (sysdiv == 0)
-+ sysdiv = 16;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
-+ if (ret)
-+ return ret;
-+ multiplier = temp1;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
-+ if (ret)
-+ return ret;
-+ prediv = temp1 & 0x0f;
-+ pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
-+ if (ret)
-+ return ret;
-+ temp2 = temp1 & 0x03;
-+ sclk_rdiv = sclk_rdiv_map[temp2];
-+
-+ if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
-+ return -EINVAL;
-+
-+ VCO = xvclk * multiplier / prediv;
-+
-+ sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
-+
-+ return sysclk;
-+}
-+
-+static int ov5640_set_night_mode(struct ov5640_dev *sensor)
-+{
-+ /* read HTS from register settings */
-+ u8 mode;
-+ int ret;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
-+ if (ret)
-+ return ret;
-+ mode &= 0xfb;
-+ return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
-+}
-+
-+static int ov5640_get_hts(struct ov5640_dev *sensor)
-+{
-+ /* read HTS from register settings */
-+ u16 hts;
-+ int ret;
-+
-+ ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
-+ if (ret)
-+ return ret;
-+ return hts;
-+}
-+
-+static int ov5640_get_vts(struct ov5640_dev *sensor)
-+{
-+ u16 vts;
-+ int ret;
-+
-+ ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
-+ if (ret)
-+ return ret;
-+ return vts;
-+}
-+
-+static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
-+{
-+ return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
-+}
-+
-+static int ov5640_get_light_freq(struct ov5640_dev *sensor)
-+{
-+ /* get banding filter value */
-+ int ret, light_freq = 0;
-+ u8 temp, temp1;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
-+ if (ret)
-+ return ret;
-+
-+ if (temp & 0x80) {
-+ /* manual */
-+ ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
-+ &temp1);
-+ if (ret)
-+ return ret;
-+ if (temp1 & 0x04) {
-+ /* 50Hz */
-+ light_freq = 50;
-+ } else {
-+ /* 60Hz */
-+ light_freq = 60;
-+ }
-+ } else {
-+ /* auto */
-+ ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
-+ &temp1);
-+ if (ret)
-+ return ret;
-+
-+ if (temp1 & 0x01) {
-+ /* 50Hz */
-+ light_freq = 50;
-+ } else {
-+ /* 60Hz */
-+ }
-+ }
-+
-+ return light_freq;
-+}
-+
-+static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
-+{
-+ u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
-+ int ret;
-+
-+ /* read preview PCLK */
-+ ret = ov5640_get_sysclk(sensor);
-+ if (ret < 0)
-+ return ret;
-+ if (ret == 0)
-+ return -EINVAL;
-+ sensor->prev_sysclk = ret;
-+ /* read preview HTS */
-+ ret = ov5640_get_hts(sensor);
-+ if (ret < 0)
-+ return ret;
-+ if (ret == 0)
-+ return -EINVAL;
-+ sensor->prev_hts = ret;
-+
-+ /* read preview VTS */
-+ ret = ov5640_get_vts(sensor);
-+ if (ret < 0)
-+ return ret;
-+ prev_vts = ret;
-+
-+ /* calculate banding filter */
-+ /* 60Hz */
-+ band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
-+ if (ret)
-+ return ret;
-+ if (!band_step60)
-+ return -EINVAL;
-+ max_band60 = (int)((prev_vts - 4) / band_step60);
-+ ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
-+ if (ret)
-+ return ret;
-+
-+ /* 50Hz */
-+ band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
-+ if (ret)
-+ return ret;
-+ if (!band_step50)
-+ return -EINVAL;
-+ max_band50 = (int)((prev_vts - 4) / band_step50);
-+ return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
-+}
-+
-+static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
-+{
-+ /* stable in high */
-+ u32 fast_high, fast_low;
-+ int ret;
-+
-+ sensor->ae_low = target * 23 / 25; /* 0.92 */
-+ sensor->ae_high = target * 27 / 25; /* 1.08 */
-+
-+ fast_high = sensor->ae_high << 1;
-+ if (fast_high > 255)
-+ fast_high = 255;
-+
-+ fast_low = sensor->ae_low >> 1;
-+
-+ ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
-+ if (ret)
-+ return ret;
-+ return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
-+}
-+
-+static int ov5640_get_binning(struct ov5640_dev *sensor)
-+{
-+ u8 temp;
-+ int ret;
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
-+ if (ret)
-+ return ret;
-+
-+ return temp & BIT(0);
-+}
-+
-+static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
-+{
-+ int ret;
-+
-+ /*
-+ * TIMING TC REG21:
-+ * - [0]: Horizontal binning enable
-+ */
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
-+ BIT(0), enable ? BIT(0) : 0);
-+ if (ret)
-+ return ret;
-+ /*
-+ * TIMING TC REG20:
-+ * - [0]: Undocumented, but hardcoded init sequences
-+ * are always setting REG21/REG20 bit 0 to same value...
-+ */
-+ return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
-+ BIT(0), enable ? BIT(0) : 0);
-+}
-+
-+static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ u8 temp, channel = virtual_channel;
-+ int ret;
-+
-+ if (channel > 3) {
-+ dev_err(&client->dev,
-+ "%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
-+ __func__, channel);
-+ return -EINVAL;
-+ }
-+
-+ ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
-+ if (ret)
-+ return ret;
-+ temp &= ~(3 << 6);
-+ temp |= (channel << 6);
-+ return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
-+}
-+
-+static const struct ov5640_mode_info *
-+ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
-+ int width, int height, bool nearest)
-+{
-+ const struct ov5640_mode_info *mode;
-+
-+ mode = v4l2_find_nearest_size(ov5640_mode_data,
-+ ARRAY_SIZE(ov5640_mode_data),
-+ hact, vact,
-+ width, height);
-+
-+ if (!mode ||
-+ (!nearest && (mode->hact != width || mode->vact != height)))
-+ return NULL;
-+
-+ /* Check to see if the current mode exceeds the max frame rate */
-+ if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
-+ return NULL;
-+
-+ return mode;
-+}
-+
-+static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
-+{
-+ u64 rate;
-+
-+ rate = sensor->current_mode->vtot * sensor->current_mode->htot;
-+ rate *= ov5640_framerates[sensor->current_fr];
-+
-+ return rate;
-+}
-+
-+/*
-+ * sensor changes between scaling and subsampling, go through
-+ * exposure calculation
-+ */
-+static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
-+ const struct ov5640_mode_info *mode)
-+{
-+ u32 prev_shutter, prev_gain16;
-+ u32 cap_shutter, cap_gain16;
-+ u32 cap_sysclk, cap_hts, cap_vts;
-+ u32 light_freq, cap_bandfilt, cap_maxband;
-+ u32 cap_gain16_shutter;
-+ u8 average;
-+ int ret;
-+
-+ if (!mode->reg_data)
-+ return -EINVAL;
-+
-+ /* read preview shutter */
-+ ret = ov5640_get_exposure(sensor);
-+ if (ret < 0)
-+ return ret;
-+ prev_shutter = ret;
-+ ret = ov5640_get_binning(sensor);
-+ if (ret < 0)
-+ return ret;
-+ if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
-+ mode->id != OV5640_MODE_1080P_1920_1080)
-+ prev_shutter *= 2;
-+
-+ /* read preview gain */
-+ ret = ov5640_get_gain(sensor);
-+ if (ret < 0)
-+ return ret;
-+ prev_gain16 = ret;
-+
-+ /* get average */
-+ ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
-+ if (ret)
-+ return ret;
-+
-+ /* turn off night mode for capture */
-+ ret = ov5640_set_night_mode(sensor);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Write capture setting */
-+ ret = ov5640_load_regs(sensor, mode);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* read capture VTS */
-+ ret = ov5640_get_vts(sensor);
-+ if (ret < 0)
-+ return ret;
-+ cap_vts = ret;
-+ ret = ov5640_get_hts(sensor);
-+ if (ret < 0)
-+ return ret;
-+ if (ret == 0)
-+ return -EINVAL;
-+ cap_hts = ret;
-+
-+ ret = ov5640_get_sysclk(sensor);
-+ if (ret < 0)
-+ return ret;
-+ if (ret == 0)
-+ return -EINVAL;
-+ cap_sysclk = ret;
-+
-+ /* calculate capture banding filter */
-+ ret = ov5640_get_light_freq(sensor);
-+ if (ret < 0)
-+ return ret;
-+ light_freq = ret;
-+
-+ if (light_freq == 60) {
-+ /* 60Hz */
-+ cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
-+ } else {
-+ /* 50Hz */
-+ cap_bandfilt = cap_sysclk * 100 / cap_hts;
-+ }
-+
-+ if (!sensor->prev_sysclk) {
-+ ret = ov5640_get_sysclk(sensor);
-+ if (ret < 0)
-+ return ret;
-+ if (ret == 0)
-+ return -EINVAL;
-+ sensor->prev_sysclk = ret;
-+ }
-+
-+ if (!cap_bandfilt)
-+ return -EINVAL;
-+
-+ cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
-+
-+ /* calculate capture shutter/gain16 */
-+ if (average > sensor->ae_low && average < sensor->ae_high) {
-+ /* in stable range */
-+ cap_gain16_shutter =
-+ prev_gain16 * prev_shutter *
-+ cap_sysclk / sensor->prev_sysclk *
-+ sensor->prev_hts / cap_hts *
-+ sensor->ae_target / average;
-+ } else {
-+ cap_gain16_shutter =
-+ prev_gain16 * prev_shutter *
-+ cap_sysclk / sensor->prev_sysclk *
-+ sensor->prev_hts / cap_hts;
-+ }
-+
-+ /* gain to shutter */
-+ if (cap_gain16_shutter < (cap_bandfilt * 16)) {
-+ /* shutter < 1/100 */
-+ cap_shutter = cap_gain16_shutter / 16;
-+ if (cap_shutter < 1)
-+ cap_shutter = 1;
-+
-+ cap_gain16 = cap_gain16_shutter / cap_shutter;
-+ if (cap_gain16 < 16)
-+ cap_gain16 = 16;
-+ } else {
-+ if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
-+ /* exposure reach max */
-+ cap_shutter = cap_bandfilt * cap_maxband;
-+ if (!cap_shutter)
-+ return -EINVAL;
-+
-+ cap_gain16 = cap_gain16_shutter / cap_shutter;
-+ } else {
-+ /* 1/100 < (cap_shutter = n/100) =< max */
-+ cap_shutter =
-+ ((int)(cap_gain16_shutter / 16 / cap_bandfilt))
-+ * cap_bandfilt;
-+ if (!cap_shutter)
-+ return -EINVAL;
-+
-+ cap_gain16 = cap_gain16_shutter / cap_shutter;
-+ }
-+ }
-+
-+ /* set capture gain */
-+ ret = ov5640_set_gain(sensor, cap_gain16);
-+ if (ret)
-+ return ret;
-+
-+ /* write capture shutter */
-+ if (cap_shutter > (cap_vts - 4)) {
-+ cap_vts = cap_shutter + 4;
-+ ret = ov5640_set_vts(sensor, cap_vts);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ /* set exposure */
-+ return ov5640_set_exposure(sensor, cap_shutter);
-+}
-+
-+/*
-+ * if sensor changes inside scaling or subsampling
-+ * change mode directly
-+ */
-+static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
-+ const struct ov5640_mode_info *mode)
-+{
-+ if (!mode->reg_data)
-+ return -EINVAL;
-+
-+ /* Write capture setting */
-+ return ov5640_load_regs(sensor, mode);
-+}
-+
-+static int ov5640_set_mode(struct ov5640_dev *sensor)
-+{
-+ const struct ov5640_mode_info *mode = sensor->current_mode;
-+ const struct ov5640_mode_info *orig_mode = sensor->last_mode;
-+ enum ov5640_downsize_mode dn_mode, orig_dn_mode;
-+ bool auto_gain = sensor->ctrls.auto_gain->val == 1;
-+ bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
-+ unsigned long rate;
-+ int ret;
-+
-+ dn_mode = mode->dn_mode;
-+ orig_dn_mode = orig_mode->dn_mode;
-+
-+ /* auto gain and exposure must be turned off when changing modes */
-+ if (auto_gain) {
-+ ret = ov5640_set_autogain(sensor, false);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ if (auto_exp) {
-+ ret = ov5640_set_autoexposure(sensor, false);
-+ if (ret)
-+ goto restore_auto_gain;
-+ }
-+
-+ /*
-+ * All the formats we support have 16 bits per pixel, seems to require
-+ * the same rate than YUV, so we can just use 16 bpp all the time.
-+ */
-+ rate = ov5640_calc_pixel_rate(sensor) * 16;
-+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
-+ rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
-+ ret = ov5640_set_mipi_pclk(sensor, rate);
-+ } else {
-+ rate = rate / sensor->ep.bus.parallel.bus_width;
-+ ret = ov5640_set_dvp_pclk(sensor, rate);
-+ }
-+
-+ if (ret < 0)
-+ return 0;
-+
-+ if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
-+ (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
-+ /*
-+ * change between subsampling and scaling
-+ * go through exposure calculation
-+ */
-+ ret = ov5640_set_mode_exposure_calc(sensor, mode);
-+ } else {
-+ /*
-+ * change inside subsampling or scaling
-+ * download firmware directly
-+ */
-+ ret = ov5640_set_mode_direct(sensor, mode);
-+ }
-+ if (ret < 0)
-+ goto restore_auto_exp_gain;
-+
-+ /* restore auto gain and exposure */
-+ if (auto_gain)
-+ ov5640_set_autogain(sensor, true);
-+ if (auto_exp)
-+ ov5640_set_autoexposure(sensor, true);
-+
-+ ret = ov5640_set_binning(sensor, dn_mode != SCALING);
-+ if (ret < 0)
-+ return ret;
-+ ret = ov5640_set_ae_target(sensor, sensor->ae_target);
-+ if (ret < 0)
-+ return ret;
-+ ret = ov5640_get_light_freq(sensor);
-+ if (ret < 0)
-+ return ret;
-+ ret = ov5640_set_bandingfilter(sensor);
-+ if (ret < 0)
-+ return ret;
-+ ret = ov5640_set_virtual_channel(sensor);
-+ if (ret < 0)
-+ return ret;
-+
-+ sensor->pending_mode_change = false;
-+ sensor->last_mode = mode;
-+
-+ return 0;
-+
-+restore_auto_exp_gain:
-+ if (auto_exp)
-+ ov5640_set_autoexposure(sensor, true);
-+restore_auto_gain:
-+ if (auto_gain)
-+ ov5640_set_autogain(sensor, true);
-+
-+ return ret;
-+}
-+
-+static int ov5640_set_framefmt(struct ov5640_dev *sensor,
-+ struct v4l2_mbus_framefmt *format);
-+
-+/* restore the last set video mode after chip power-on */
-+static int ov5640_restore_mode(struct ov5640_dev *sensor)
-+{
-+ int ret;
-+
-+ /* first load the initial register values */
-+ ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
-+ if (ret < 0)
-+ return ret;
-+ sensor->last_mode = &ov5640_mode_init_data;
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
-+ (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
-+ ilog2(OV5640_SCLK_ROOT_DIV));
-+ if (ret)
-+ return ret;
-+
-+ /* now restore the last capture mode */
-+ ret = ov5640_set_mode(sensor);
-+ if (ret < 0)
-+ return ret;
-+
-+ return ov5640_set_framefmt(sensor, &sensor->fmt);
-+}
-+
-+static void ov5640_power(struct ov5640_dev *sensor, bool enable)
-+{
-+ if (!sensor->pwdn_gpio)
-+ return;
-+ gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
-+}
-+
-+static void ov5640_reset(struct ov5640_dev *sensor)
-+{
-+ if (!sensor->reset_gpio)
-+ return;
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
-+
-+ /* camera power cycle */
-+ ov5640_power(sensor, false);
-+ usleep_range(5000, 10000);
-+ ov5640_power(sensor, true);
-+ usleep_range(5000, 10000);
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
-+ usleep_range(1000, 2000);
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
-+ usleep_range(20000, 25000);
-+}
-+
-+static int ov5640_set_power_on(struct ov5640_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ int ret;
-+
-+ ret = clk_prepare_enable(sensor->xclk);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable clock\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
-+ sensor->supplies);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ goto xclk_off;
-+ }
-+
-+ ov5640_reset(sensor);
-+ ov5640_power(sensor, true);
-+
-+ ret = ov5640_init_slave_id(sensor);
-+ if (ret)
-+ goto power_off;
-+
-+ return 0;
-+
-+power_off:
-+ ov5640_power(sensor, false);
-+ regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
-+xclk_off:
-+ clk_disable_unprepare(sensor->xclk);
-+ return ret;
-+}
-+
-+static void ov5640_set_power_off(struct ov5640_dev *sensor)
-+{
-+ ov5640_power(sensor, false);
-+ regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
-+ clk_disable_unprepare(sensor->xclk);
-+}
-+
-+static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
-+{
-+ int ret;
-+
-+ if (!on) {
-+ /* Reset MIPI bus settings to their default values. */
-+ ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
-+ ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
-+ ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
-+ return 0;
-+ }
-+
-+ /*
-+ * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
-+ *
-+ * 0x300e = 0x40
-+ * [7:5] = 010 : 2 data lanes mode (see FIXME note in
-+ * "ov5640_set_stream_mipi()")
-+ * [4] = 0 : Power up MIPI HS Tx
-+ * [3] = 0 : Power up MIPI LS Rx
-+ * [2] = 0 : MIPI interface disabled
-+ */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * Gate clock and set LP11 in 'no packets mode' (idle)
-+ *
-+ * 0x4800 = 0x24
-+ * [5] = 1 : Gate clock when 'no packets'
-+ * [2] = 1 : MIPI bus in LP11 when 'no packets'
-+ */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * Set data lanes and clock in LP11 when 'sleeping'
-+ *
-+ * 0x3019 = 0x70
-+ * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping'
-+ * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping'
-+ * [4] = 1 : MIPI clock lane in LP11 when 'sleeping'
-+ */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
-+ if (ret)
-+ return ret;
-+
-+ /* Give lanes some time to coax into LP11 state. */
-+ usleep_range(500, 1000);
-+
-+ return 0;
-+}
-+
-+static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
-+{
-+ unsigned int flags = sensor->ep.bus.parallel.flags;
-+ bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
-+ u8 polarities = 0;
-+ int ret;
-+
-+ if (!on) {
-+ /* Reset settings to their default values. */
-+ ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
-+ ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
-+ ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
-+ ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
-+ ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
-+ return 0;
-+ }
-+
-+ /*
-+ * Note about parallel port configuration.
-+ *
-+ * When configured in parallel mode, the OV5640 will
-+ * output 10 bits data on DVP data lines [9:0].
-+ * If only 8 bits data are wanted, the 8 bits data lines
-+ * of the camera interface must be physically connected
-+ * on the DVP data lines [9:2].
-+ *
-+ * Control lines polarity can be configured through
-+ * devicetree endpoint control lines properties.
-+ * If no endpoint control lines properties are set,
-+ * polarity will be as below:
-+ * - VSYNC: active high
-+ * - HREF: active low
-+ * - PCLK: active low
-+ *
-+ * VSYNC & HREF are not configured if BT656 bus mode is selected
-+ */
-+
-+ /*
-+ * BT656 embedded synchronization configuration
-+ *
-+ * CCIR656 CTRL00
-+ * - [7]: SYNC code selection (0: auto generate sync code,
-+ * 1: sync code from regs 0x4732-0x4735)
-+ * - [6]: f value in CCIR656 SYNC code when fixed f value
-+ * - [5]: Fixed f value
-+ * - [4:3]: Blank toggle data options (00: data=1'h040/1'h200,
-+ * 01: data from regs 0x4736-0x4738, 10: always keep 0)
-+ * - [1]: Clip data disable
-+ * - [0]: CCIR656 mode enable
-+ *
-+ * Default CCIR656 SAV/EAV mode with default codes
-+ * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
-+ * - CCIR656 mode enable
-+ * - auto generation of sync codes
-+ * - blank toggle data 1'h040/1'h200
-+ * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
-+ */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
-+ bt656 ? 0x01 : 0x00);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * configure parallel port control lines polarity
-+ *
-+ * POLARITY CTRL0
-+ * - [5]: PCLK polarity (0: active low, 1: active high)
-+ * - [1]: HREF polarity (0: active low, 1: active high)
-+ * - [0]: VSYNC polarity (mismatch here between
-+ * datasheet and hardware, 0 is active high
-+ * and 1 is active low...)
-+ */
-+ if (!bt656) {
-+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
-+ polarities |= BIT(1);
-+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
-+ polarities |= BIT(0);
-+ }
-+ if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
-+ polarities |= BIT(5);
-+
-+ ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * powerdown MIPI TX/RX PHY & enable DVP
-+ *
-+ * MIPI CONTROL 00
-+ * [4] = 1 : Power down MIPI HS Tx
-+ * [3] = 1 : Power down MIPI LS Rx
-+ * [2] = 0 : DVP enable (MIPI disable)
-+ */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * enable VSYNC/HREF/PCLK DVP control lines
-+ * & D[9:6] DVP data lines
-+ *
-+ * PAD OUTPUT ENABLE 01
-+ * - 6: VSYNC output enable
-+ * - 5: HREF output enable
-+ * - 4: PCLK output enable
-+ * - [3:0]: D[9:6] output enable
-+ */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
-+ bt656 ? 0x1f : 0x7f);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * enable D[5:0] DVP data lines
-+ *
-+ * PAD OUTPUT ENABLE 02
-+ * - [7:2]: D[5:0] output enable
-+ */
-+ return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
-+}
-+
-+static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
-+{
-+ int ret = 0;
-+
-+ if (on) {
-+ ret = ov5640_set_power_on(sensor);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov5640_restore_mode(sensor);
-+ if (ret)
-+ goto power_off;
-+ }
-+
-+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-+ ret = ov5640_set_power_mipi(sensor, on);
-+ else
-+ ret = ov5640_set_power_dvp(sensor, on);
-+ if (ret)
-+ goto power_off;
-+
-+ if (!on)
-+ ov5640_set_power_off(sensor);
-+
-+ return 0;
-+
-+power_off:
-+ ov5640_set_power_off(sensor);
-+ return ret;
-+}
-+
-+/* --------------- Subdev Operations --------------- */
-+
-+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ /*
-+ * If the power count is modified from 0 to != 0 or from != 0 to 0,
-+ * update the power state.
-+ */
-+ if (sensor->power_count == !on) {
-+ ret = ov5640_set_power(sensor, !!on);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ /* Update the power count. */
-+ sensor->power_count += on ? 1 : -1;
-+ WARN_ON(sensor->power_count < 0);
-+out:
-+ mutex_unlock(&sensor->lock);
-+
-+ if (on && !ret && sensor->power_count == 1) {
-+ /* restore controls */
-+ ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
-+ struct v4l2_fract *fi,
-+ u32 width, u32 height)
-+{
-+ const struct ov5640_mode_info *mode;
-+ enum ov5640_frame_rate rate = OV5640_15_FPS;
-+ int minfps, maxfps, best_fps, fps;
-+ int i;
-+
-+ minfps = ov5640_framerates[OV5640_15_FPS];
-+ maxfps = ov5640_framerates[OV5640_60_FPS];
-+
-+ if (fi->numerator == 0) {
-+ fi->denominator = maxfps;
-+ fi->numerator = 1;
-+ rate = OV5640_60_FPS;
-+ goto find_mode;
-+ }
-+
-+ fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
-+ minfps, maxfps);
-+
-+ best_fps = minfps;
-+ for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
-+ int curr_fps = ov5640_framerates[i];
-+
-+ if (abs(curr_fps - fps) < abs(best_fps - fps)) {
-+ best_fps = curr_fps;
-+ rate = i;
-+ }
-+ }
-+
-+ fi->numerator = 1;
-+ fi->denominator = best_fps;
-+
-+find_mode:
-+ mode = ov5640_find_mode(sensor, rate, width, height, false);
-+ return mode ? rate : -EINVAL;
-+}
-+
-+static int ov5640_get_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ struct v4l2_mbus_framefmt *fmt;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(&sensor->sd, state,
-+ format->pad);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ format->format = *fmt;
-+
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum ov5640_frame_rate fr,
-+ const struct ov5640_mode_info **new_mode)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ const struct ov5640_mode_info *mode;
-+ int i;
-+
-+ mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
-+ if (!mode)
-+ return -EINVAL;
-+ fmt->width = mode->hact;
-+ fmt->height = mode->vact;
-+
-+ if (new_mode)
-+ *new_mode = mode;
-+
-+ for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
-+ if (ov5640_formats[i].code == fmt->code)
-+ break;
-+ if (i >= ARRAY_SIZE(ov5640_formats))
-+ i = 0;
-+
-+ fmt->code = ov5640_formats[i].code;
-+ fmt->colorspace = ov5640_formats[i].colorspace;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+
-+ return 0;
-+}
-+
-+static int ov5640_set_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ const struct ov5640_mode_info *new_mode;
-+ struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
-+ struct v4l2_mbus_framefmt *fmt;
-+ int ret;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ ret = ov5640_try_fmt_internal(sd, mbus_fmt, 0, &new_mode);
-+ if (ret)
-+ goto out;
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(sd, state, 0);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ if (mbus_fmt->code != sensor->fmt.code)
-+ sensor->pending_fmt_change = true;
-+
-+ *fmt = *mbus_fmt;
-+
-+ if (new_mode != sensor->current_mode) {
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+ if (new_mode->max_fps < sensor->current_fr) {
-+ sensor->current_fr = new_mode->max_fps;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator =
-+ ov5640_framerates[sensor->current_fr];
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ ov5640_calc_pixel_rate(sensor));
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int ov5640_set_framefmt(struct ov5640_dev *sensor,
-+ struct v4l2_mbus_framefmt *format)
-+{
-+ int ret = 0;
-+ bool is_jpeg = false;
-+ u8 fmt, mux;
-+
-+ switch (format->code) {
-+ case MEDIA_BUS_FMT_UYVY8_2X8:
-+ /* YUV422, UYVY */
-+ fmt = 0x3f;
-+ mux = OV5640_FMT_MUX_YUV422;
-+ break;
-+ case MEDIA_BUS_FMT_YUYV8_2X8:
-+ /* YUV422, YUYV */
-+ fmt = 0x30;
-+ mux = OV5640_FMT_MUX_YUV422;
-+ break;
-+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
-+ /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
-+ fmt = 0x6F;
-+ mux = OV5640_FMT_MUX_RGB;
-+ break;
-+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
-+ /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
-+ fmt = 0x61;
-+ mux = OV5640_FMT_MUX_RGB;
-+ break;
-+ case MEDIA_BUS_FMT_JPEG_1X8:
-+ /* YUV422, YUYV */
-+ fmt = 0x30;
-+ mux = OV5640_FMT_MUX_YUV422;
-+ is_jpeg = true;
-+ break;
-+ case MEDIA_BUS_FMT_SBGGR8_1X8:
-+ /* Raw, BGBG... / GRGR... */
-+ fmt = 0x00;
-+ mux = OV5640_FMT_MUX_RAW_DPC;
-+ break;
-+ case MEDIA_BUS_FMT_SGBRG8_1X8:
-+ /* Raw bayer, GBGB... / RGRG... */
-+ fmt = 0x01;
-+ mux = OV5640_FMT_MUX_RAW_DPC;
-+ break;
-+ case MEDIA_BUS_FMT_SGRBG8_1X8:
-+ /* Raw bayer, GRGR... / BGBG... */
-+ fmt = 0x02;
-+ mux = OV5640_FMT_MUX_RAW_DPC;
-+ break;
-+ case MEDIA_BUS_FMT_SRGGB8_1X8:
-+ /* Raw bayer, RGRG... / GBGB... */
-+ fmt = 0x03;
-+ mux = OV5640_FMT_MUX_RAW_DPC;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ /* FORMAT CONTROL00: YUV and RGB formatting */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
-+ if (ret)
-+ return ret;
-+
-+ /* FORMAT MUX CONTROL: ISP YUV or RGB */
-+ ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * TIMING TC REG21:
-+ * - [5]: JPEG enable
-+ */
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
-+ BIT(5), is_jpeg ? BIT(5) : 0);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * SYSTEM RESET02:
-+ * - [4]: Reset JFIFO
-+ * - [3]: Reset SFIFO
-+ * - [2]: Reset JPEG
-+ */
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
-+ BIT(4) | BIT(3) | BIT(2),
-+ is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * CLOCK ENABLE02:
-+ * - [5]: Enable JPEG 2x clock
-+ * - [3]: Enable JPEG clock
-+ */
-+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
-+ BIT(5) | BIT(3),
-+ is_jpeg ? (BIT(5) | BIT(3)) : 0);
-+}
-+
-+/*
-+ * Sensor Controls.
-+ */
-+
-+static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
-+{
-+ int ret;
-+
-+ if (value) {
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
-+ BIT(0), BIT(0));
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
-+ } else {
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
-+{
-+ int ret;
-+
-+ if (value) {
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
-+ BIT(2), BIT(2));
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
-+ value & 0xff);
-+ } else {
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
-+{
-+ int ret;
-+
-+ if (value) {
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
-+ BIT(1), BIT(1));
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
-+ value & 0xff);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
-+ value & 0xff);
-+ } else {
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
-+{
-+ int ret;
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
-+ BIT(0), awb ? 0 : 1);
-+ if (ret)
-+ return ret;
-+
-+ if (!awb) {
-+ u16 red = (u16)sensor->ctrls.red_balance->val;
-+ u16 blue = (u16)sensor->ctrls.blue_balance->val;
-+
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
-+ enum v4l2_exposure_auto_type auto_exposure)
-+{
-+ struct ov5640_ctrls *ctrls = &sensor->ctrls;
-+ bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
-+ int ret = 0;
-+
-+ if (ctrls->auto_exp->is_new) {
-+ ret = ov5640_set_autoexposure(sensor, auto_exp);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ if (!auto_exp && ctrls->exposure->is_new) {
-+ u16 max_exp;
-+
-+ ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
-+ &max_exp);
-+ if (ret)
-+ return ret;
-+ ret = ov5640_get_vts(sensor);
-+ if (ret < 0)
-+ return ret;
-+ max_exp += ret;
-+ ret = 0;
-+
-+ if (ctrls->exposure->val < max_exp)
-+ ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
-+{
-+ struct ov5640_ctrls *ctrls = &sensor->ctrls;
-+ int ret = 0;
-+
-+ if (ctrls->auto_gain->is_new) {
-+ ret = ov5640_set_autogain(sensor, auto_gain);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ if (!auto_gain && ctrls->gain->is_new)
-+ ret = ov5640_set_gain(sensor, ctrls->gain->val);
-+
-+ return ret;
-+}
-+
-+static const char * const test_pattern_menu[] = {
-+ "Disabled",
-+ "Color bars",
-+ "Color bars w/ rolling bar",
-+ "Color squares",
-+ "Color squares w/ rolling bar",
-+};
-+
-+#define OV5640_TEST_ENABLE BIT(7)
-+#define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */
-+#define OV5640_TEST_TRANSPARENT BIT(5)
-+#define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */
-+#define OV5640_TEST_BAR_STANDARD (0 << 2)
-+#define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2)
-+#define OV5640_TEST_BAR_HOR_CHANGE (2 << 2)
-+#define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2)
-+#define OV5640_TEST_BAR (0 << 0)
-+#define OV5640_TEST_RANDOM (1 << 0)
-+#define OV5640_TEST_SQUARE (2 << 0)
-+#define OV5640_TEST_BLACK (3 << 0)
-+
-+static const u8 test_pattern_val[] = {
-+ 0,
-+ OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
-+ OV5640_TEST_BAR,
-+ OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
-+ OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
-+ OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
-+ OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
-+};
-+
-+static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
-+{
-+ return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
-+ test_pattern_val[value]);
-+}
-+
-+static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
-+{
-+ int ret;
-+
-+ ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
-+ (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
-+ 0 : BIT(7));
-+ if (ret)
-+ return ret;
-+
-+ return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
-+ (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
-+ BIT(2) : 0);
-+}
-+
-+static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
-+{
-+ /*
-+ * If sensor is mounted upside down, mirror logic is inversed.
-+ *
-+ * Sensor is a BSI (Back Side Illuminated) one,
-+ * so image captured is physically mirrored.
-+ * This is why mirror logic is inversed in
-+ * order to cancel this mirror effect.
-+ */
-+
-+ /*
-+ * TIMING TC REG21:
-+ * - [2]: ISP mirror
-+ * - [1]: Sensor mirror
-+ */
-+ return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
-+ BIT(2) | BIT(1),
-+ (!(value ^ sensor->upside_down)) ?
-+ (BIT(2) | BIT(1)) : 0);
-+}
-+
-+static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
-+{
-+ /* If sensor is mounted upside down, flip logic is inversed */
-+
-+ /*
-+ * TIMING TC REG20:
-+ * - [2]: ISP vflip
-+ * - [1]: Sensor vflip
-+ */
-+ return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
-+ BIT(2) | BIT(1),
-+ (value ^ sensor->upside_down) ?
-+ (BIT(2) | BIT(1)) : 0);
-+}
-+
-+static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ int val;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_AUTOGAIN:
-+ val = ov5640_get_gain(sensor);
-+ if (val < 0)
-+ return val;
-+ sensor->ctrls.gain->val = val;
-+ break;
-+ case V4L2_CID_EXPOSURE_AUTO:
-+ val = ov5640_get_exposure(sensor);
-+ if (val < 0)
-+ return val;
-+ sensor->ctrls.exposure->val = val;
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ int ret;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ /*
-+ * If the device is not powered up by the host driver do
-+ * not apply any controls to H/W at this time. Instead
-+ * the controls will be restored right after power-up.
-+ */
-+ if (sensor->power_count == 0)
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_AUTOGAIN:
-+ ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE_AUTO:
-+ ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_AUTO_WHITE_BALANCE:
-+ ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HUE:
-+ ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_CONTRAST:
-+ ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_SATURATION:
-+ ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY:
-+ ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HFLIP:
-+ ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_VFLIP:
-+ ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
-+ .g_volatile_ctrl = ov5640_g_volatile_ctrl,
-+ .s_ctrl = ov5640_s_ctrl,
-+};
-+
-+static int ov5640_init_controls(struct ov5640_dev *sensor)
-+{
-+ const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
-+ struct ov5640_ctrls *ctrls = &sensor->ctrls;
-+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-+ int ret;
-+
-+ v4l2_ctrl_handler_init(hdl, 32);
-+
-+ /* we can use our own mutex for the ctrl lock */
-+ hdl->lock = &sensor->lock;
-+
-+ /* Clock related controls */
-+ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
-+ 0, INT_MAX, 1,
-+ ov5640_calc_pixel_rate(sensor));
-+
-+ /* Auto/manual white balance */
-+ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
-+ V4L2_CID_AUTO_WHITE_BALANCE,
-+ 0, 1, 1, 1);
-+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
-+ 0, 4095, 1, 0);
-+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
-+ 0, 4095, 1, 0);
-+ /* Auto/manual exposure */
-+ ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_EXPOSURE_AUTO,
-+ V4L2_EXPOSURE_MANUAL, 0,
-+ V4L2_EXPOSURE_AUTO);
-+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-+ 0, 65535, 1, 0);
-+ /* Auto/manual gain */
-+ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
-+ 0, 1, 1, 1);
-+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
-+ 0, 1023, 1, 0);
-+
-+ ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
-+ 0, 255, 1, 64);
-+ ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
-+ 0, 359, 1, 0);
-+ ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
-+ 0, 255, 1, 0);
-+ ctrls->test_pattern =
-+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(test_pattern_menu) - 1,
-+ 0, 0, test_pattern_menu);
-+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
-+ 0, 1, 1, 0);
-+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
-+ 0, 1, 1, 0);
-+
-+ ctrls->light_freq =
-+ v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_POWER_LINE_FREQUENCY,
-+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
-+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
-+
-+ if (hdl->error) {
-+ ret = hdl->error;
-+ goto free_ctrls;
-+ }
-+
-+ ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+ ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+
-+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
-+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
-+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
-+
-+ sensor->sd.ctrl_handler = hdl;
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(hdl);
-+ return ret;
-+}
-+
-+static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ if (fse->pad != 0)
-+ return -EINVAL;
-+ if (fse->index >= OV5640_NUM_MODES)
-+ return -EINVAL;
-+
-+ fse->min_width =
-+ ov5640_mode_data[fse->index].hact;
-+ fse->max_width = fse->min_width;
-+ fse->min_height =
-+ ov5640_mode_data[fse->index].vact;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static int ov5640_enum_frame_interval(
-+ struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_interval_enum *fie)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ struct v4l2_fract tpf;
-+ int ret;
-+
-+ if (fie->pad != 0)
-+ return -EINVAL;
-+ if (fie->index >= OV5640_NUM_FRAMERATES)
-+ return -EINVAL;
-+
-+ tpf.numerator = 1;
-+ tpf.denominator = ov5640_framerates[fie->index];
-+
-+ ret = ov5640_try_frame_interval(sensor, &tpf,
-+ fie->width, fie->height);
-+ if (ret < 0)
-+ return -EINVAL;
-+
-+ fie->interval = tpf;
-+ return 0;
-+}
-+
-+static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+
-+ mutex_lock(&sensor->lock);
-+ fi->interval = sensor->frame_interval;
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ const struct ov5640_mode_info *mode;
-+ int frame_rate, ret = 0;
-+
-+ if (fi->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ mode = sensor->current_mode;
-+
-+ frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
-+ mode->hact, mode->vact);
-+ if (frame_rate < 0) {
-+ /* Always return a valid frame interval value */
-+ fi->interval = sensor->frame_interval;
-+ goto out;
-+ }
-+
-+ mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
-+ mode->vact, true);
-+ if (!mode) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (mode != sensor->current_mode ||
-+ frame_rate != sensor->current_fr) {
-+ sensor->current_fr = frame_rate;
-+ sensor->frame_interval = fi->interval;
-+ sensor->current_mode = mode;
-+ sensor->pending_mode_change = true;
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ ov5640_calc_pixel_rate(sensor));
-+ }
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ if (code->pad != 0)
-+ return -EINVAL;
-+ if (code->index >= ARRAY_SIZE(ov5640_formats))
-+ return -EINVAL;
-+
-+ code->code = ov5640_formats[code->index].code;
-+ return 0;
-+}
-+
-+static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming == !enable) {
-+ if (enable && sensor->pending_mode_change) {
-+ ret = ov5640_set_mode(sensor);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ if (enable && sensor->pending_fmt_change) {
-+ ret = ov5640_set_framefmt(sensor, &sensor->fmt);
-+ if (ret)
-+ goto out;
-+ sensor->pending_fmt_change = false;
-+ }
-+
-+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
-+ ret = ov5640_set_stream_mipi(sensor, enable);
-+ else
-+ ret = ov5640_set_stream_dvp(sensor, enable);
-+
-+ if (ret)
-+ goto out;
-+ }
-+ sensor->streaming += enable ? 1 : -1;
-+ WARN_ON(sensor->streaming < 0);
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+int ov5640_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-+{
-+ *frames = OV5640_SKIP_FRAMES;
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_core_ops ov5640_core_ops = {
-+ .s_power = ov5640_s_power,
-+ .log_status = v4l2_ctrl_subdev_log_status,
-+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops ov5640_video_ops = {
-+ .g_frame_interval = ov5640_g_frame_interval,
-+ .s_frame_interval = ov5640_s_frame_interval,
-+ .s_stream = ov5640_s_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
-+ .enum_mbus_code = ov5640_enum_mbus_code,
-+ .get_fmt = ov5640_get_fmt,
-+ .set_fmt = ov5640_set_fmt,
-+ .enum_frame_size = ov5640_enum_frame_size,
-+ .enum_frame_interval = ov5640_enum_frame_interval,
-+};
-+
-+static const struct v4l2_subdev_sensor_ops ov5640_sensor_ops = {
-+ .g_skip_frames = ov5640_skip_frames,
-+};
-+
-+static const struct v4l2_subdev_ops ov5640_subdev_ops = {
-+ .core = &ov5640_core_ops,
-+ .video = &ov5640_video_ops,
-+ .pad = &ov5640_pad_ops,
-+ .sensor = &ov5640_sensor_ops,
-+};
-+
-+static int ov5640_get_regulators(struct ov5640_dev *sensor)
-+{
-+ int i;
-+
-+ for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
-+ sensor->supplies[i].supply = ov5640_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&sensor->i2c_client->dev,
-+ OV5640_NUM_SUPPLIES,
-+ sensor->supplies);
-+}
-+
-+static int ov5640_check_chip_id(struct ov5640_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ int ret = 0;
-+ u16 chip_id;
-+
-+ ret = ov5640_set_power_on(sensor);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to read chip identifier\n",
-+ __func__);
-+ goto power_off;
-+ }
-+
-+ if (chip_id != OV5640_CHIP_ID) {
-+ dev_err(&client->dev, "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",
-+ __func__, OV5640_CHIP_ID, chip_id);
-+ ret = -ENXIO;
-+ }
-+ dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
-+ __func__, chip_id);
-+
-+power_off:
-+ ov5640_set_power_off(sensor);
-+ return ret;
-+}
-+
-+static int ov5640_probe(struct i2c_client *client)
-+{
-+ struct device *dev = &client->dev;
-+ struct fwnode_handle *endpoint;
-+ struct ov5640_dev *sensor;
-+ struct v4l2_mbus_framefmt *fmt;
-+ u32 rotation;
-+ int ret;
-+
-+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
-+ if (!sensor)
-+ return -ENOMEM;
-+
-+ sensor->i2c_client = client;
-+
-+ /*
-+ * default init sequence initialize sensor to
-+ * YUV422 UYVY VGA@30fps
-+ */
-+ fmt = &sensor->fmt;
-+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+ fmt->width = 640;
-+ fmt->height = 480;
-+ fmt->field = V4L2_FIELD_NONE;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
-+ sensor->current_fr = OV5640_30_FPS;
-+ sensor->current_mode =
-+ &ov5640_mode_data[OV5640_MODE_VGA_640_480];
-+ sensor->last_mode = sensor->current_mode;
-+
-+ sensor->ae_target = 52;
-+
-+ /* optional indication of physical rotation of sensor */
-+ ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
-+ &rotation);
-+ if (!ret) {
-+ switch (rotation) {
-+ case 180:
-+ sensor->upside_down = true;
-+ fallthrough;
-+ case 0:
-+ break;
-+ default:
-+ dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
-+ rotation);
-+ }
-+ }
-+
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
-+ sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
-+ sensor->ep.bus_type != V4L2_MBUS_BT656) {
-+ dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
-+ return -EINVAL;
-+ }
-+
-+ /* get system clock (xclk) */
-+ sensor->xclk = devm_clk_get(dev, "xclk");
-+ if (IS_ERR(sensor->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(sensor->xclk);
-+ }
-+
-+ sensor->xclk_freq = clk_get_rate(sensor->xclk);
-+ if (sensor->xclk_freq < OV5640_XCLK_MIN ||
-+ sensor->xclk_freq > OV5640_XCLK_MAX) {
-+ dev_err(dev, "xclk frequency out of range: %d Hz\n",
-+ sensor->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ /* request optional power down pin */
-+ sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->pwdn_gpio))
-+ return PTR_ERR(sensor->pwdn_gpio);
-+
-+ /* request optional reset pin */
-+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->reset_gpio))
-+ return PTR_ERR(sensor->reset_gpio);
-+
-+ v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
-+
-+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
-+ V4L2_SUBDEV_FL_HAS_EVENTS;
-+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
-+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
-+ if (ret)
-+ return ret;
-+
-+ ret = ov5640_get_regulators(sensor);
-+ if (ret)
-+ return ret;
-+
-+ mutex_init(&sensor->lock);
-+
-+ ret = ov5640_check_chip_id(sensor);
-+ if (ret)
-+ goto entity_cleanup;
-+
-+ ret = ov5640_init_controls(sensor);
-+ if (ret)
-+ goto entity_cleanup;
-+
-+ ret = v4l2_async_register_subdev_sensor(&sensor->sd);
-+ if (ret)
-+ goto free_ctrls;
-+
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+entity_cleanup:
-+ media_entity_cleanup(&sensor->sd.entity);
-+ mutex_destroy(&sensor->lock);
-+ return ret;
-+}
-+
-+static int ov5640_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
-+
-+ v4l2_async_unregister_subdev(&sensor->sd);
-+ media_entity_cleanup(&sensor->sd.entity);
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+ mutex_destroy(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static const struct i2c_device_id ov5640_id[] = {
-+ {"ov5640", 0},
-+ {},
-+};
-+MODULE_DEVICE_TABLE(i2c, ov5640_id);
-+
-+static const struct of_device_id ov5640_dt_ids[] = {
-+ { .compatible = "ovti,ov5640" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
-+
-+static struct i2c_driver ov5640_i2c_driver = {
-+ .driver = {
-+ .name = "ov5640",
-+ .of_match_table = ov5640_dt_ids,
-+ },
-+ .id_table = ov5640_id,
-+ .probe_new = ov5640_probe,
-+ .remove = ov5640_remove,
-+};
-+
-+module_i2c_driver(ov5640_i2c_driver);
-+
-+MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/sc2235.c
-@@ -0,0 +1,1914 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/clkdev.h>
-+#include <linux/ctype.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/of_device.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+#include "stfcamss.h"
-+
-+/* min/typical/max system clock (xclk) frequencies */
-+#define SC2235_XCLK_MIN 6000000
-+#define SC2235_XCLK_MAX 27000000
-+
-+#define SC2235_CHIP_ID (0x2235)
-+
-+#define SC2235_REG_CHIP_ID 0x3107
-+#define SC2235_REG_AEC_PK_MANUAL 0x3e03
-+#define SC2235_REG_AEC_PK_EXPOSURE_HI 0x3e01
-+#define SC2235_REG_AEC_PK_EXPOSURE_LO 0x3e02
-+#define SC2235_REG_AEC_PK_REAL_GAIN 0x3e08
-+#define SC2235_REG_TIMING_HTS 0x320c
-+#define SC2235_REG_TIMING_VTS 0x320e
-+#define SC2235_REG_TEST_SET0 0x4501
-+#define SC2235_REG_TEST_SET1 0x3902
-+#define SC2235_REG_TIMING_TC_REG21 0x3221
-+#define SC2235_REG_SC_PLL_CTRL0 0x3039
-+#define SC2235_REG_SC_PLL_CTRL1 0x303a
-+#define SC2235_REG_STREAM_ON 0x0100
-+
-+enum sc2235_mode_id {
-+ SC2235_MODE_1080P_1920_1080 = 0,
-+ SC2235_NUM_MODES,
-+};
-+
-+enum sc2235_frame_rate {
-+ SC2235_15_FPS = 0,
-+ SC2235_30_FPS,
-+ SC2235_NUM_FRAMERATES,
-+};
-+
-+struct sc2235_pixfmt {
-+ u32 code;
-+ u32 colorspace;
-+};
-+
-+static const struct sc2235_pixfmt sc2235_formats[] = {
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB, },
-+};
-+
-+static const int sc2235_framerates[] = {
-+ [SC2235_15_FPS] = 15,
-+ [SC2235_30_FPS] = 30,
-+};
-+
-+/* regulator supplies */
-+static const char * const sc2235_supply_name[] = {
-+ "DOVDD", /* Digital I/O (1.8V) supply */
-+ "AVDD", /* Analog (2.8V) supply */
-+ "DVDD", /* Digital Core (1.5V) supply */
-+};
-+
-+#define SC2235_NUM_SUPPLIES ARRAY_SIZE(sc2235_supply_name)
-+
-+struct reg_value {
-+ u16 reg_addr;
-+ u8 val;
-+ u8 mask;
-+ u32 delay_ms;
-+};
-+
-+struct sc2235_mode_info {
-+ enum sc2235_mode_id id;
-+ u32 hact;
-+ u32 htot;
-+ u32 vact;
-+ u32 vtot;
-+ const struct reg_value *reg_data;
-+ u32 reg_data_size;
-+ u32 max_fps;
-+};
-+
-+struct sc2235_ctrls {
-+ struct v4l2_ctrl_handler handler;
-+ struct v4l2_ctrl *pixel_rate;
-+ struct {
-+ struct v4l2_ctrl *auto_exp;
-+ struct v4l2_ctrl *exposure;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_wb;
-+ struct v4l2_ctrl *blue_balance;
-+ struct v4l2_ctrl *red_balance;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_gain;
-+ struct v4l2_ctrl *gain;
-+ };
-+ struct v4l2_ctrl *brightness;
-+ struct v4l2_ctrl *light_freq;
-+ struct v4l2_ctrl *saturation;
-+ struct v4l2_ctrl *contrast;
-+ struct v4l2_ctrl *hue;
-+ struct v4l2_ctrl *test_pattern;
-+ struct v4l2_ctrl *hflip;
-+ struct v4l2_ctrl *vflip;
-+};
-+
-+struct sc2235_dev {
-+ struct i2c_client *i2c_client;
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+ struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
-+ struct clk *xclk; /* system clock to SC2235 */
-+ u32 xclk_freq;
-+
-+ struct regulator_bulk_data supplies[SC2235_NUM_SUPPLIES];
-+ struct gpio_desc *reset_gpio;
-+ struct gpio_desc *pwdn_gpio;
-+ bool upside_down;
-+
-+ /* lock to protect all members below */
-+ struct mutex lock;
-+
-+ struct v4l2_mbus_framefmt fmt;
-+ bool pending_fmt_change;
-+
-+ const struct sc2235_mode_info *current_mode;
-+ const struct sc2235_mode_info *last_mode;
-+ enum sc2235_frame_rate current_fr;
-+ struct v4l2_fract frame_interval;
-+
-+ struct sc2235_ctrls ctrls;
-+
-+ bool pending_mode_change;
-+ int streaming;
-+};
-+
-+static inline struct sc2235_dev *to_sc2235_dev(struct v4l2_subdev *sd)
-+{
-+ return container_of(sd, struct sc2235_dev, sd);
-+}
-+
-+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
-+{
-+ return &container_of(ctrl->handler, struct sc2235_dev,
-+ ctrls.handler)->sd;
-+}
-+
-+/* sc2235 initial register 30fps*/
-+static struct reg_value sc2235_init_regs_tbl_1080[] = {
-+ {0x0103, 0x01, 0, 50},
-+ {0x0100, 0x00, 0, 0},
-+ {0x3039, 0x80, 0, 0},
-+ {0x3621, 0x28, 0, 0},
-+
-+ {0x3309, 0x60, 0, 0},
-+ {0x331f, 0x4d, 0, 0},
-+ {0x3321, 0x4f, 0, 0},
-+ {0x33b5, 0x10, 0, 0},
-+
-+ {0x3303, 0x20, 0, 0},
-+ {0x331e, 0x0d, 0, 0},
-+ {0x3320, 0x0f, 0, 0},
-+
-+ {0x3622, 0x02, 0, 0},
-+ {0x3633, 0x42, 0, 0},
-+ {0x3634, 0x42, 0, 0},
-+
-+ {0x3306, 0x66, 0, 0},
-+ {0x330b, 0xd1, 0, 0},
-+
-+ {0x3301, 0x0e, 0, 0},
-+
-+ {0x320c, 0x08, 0, 0},
-+ {0x320d, 0x98, 0, 0},
-+
-+ {0x3364, 0x05, 0, 0}, // [2] 1: write at sampling ending
-+
-+ {0x363c, 0x28, 0, 0}, //bypass nvdd
-+ {0x363b, 0x0a, 0, 0}, //HVDD
-+ {0x3635, 0xa0, 0, 0}, //TXVDD
-+
-+ {0x4500, 0x59, 0, 0},
-+ {0x3d08, 0x00, 0, 0},
-+ {0x3908, 0x11, 0, 0},
-+
-+ {0x363c, 0x08, 0, 0},
-+
-+ {0x3e03, 0x03, 0, 0},
-+ {0x3e01, 0x46, 0, 0},
-+
-+ //0703
-+ {0x3381, 0x0a, 0, 0},
-+ {0x3348, 0x09, 0, 0},
-+ {0x3349, 0x50, 0, 0},
-+ {0x334a, 0x02, 0, 0},
-+ {0x334b, 0x60, 0, 0},
-+
-+ {0x3380, 0x04, 0, 0},
-+ {0x3340, 0x06, 0, 0},
-+ {0x3341, 0x50, 0, 0},
-+ {0x3342, 0x02, 0, 0},
-+ {0x3343, 0x60, 0, 0},
-+
-+ //0707
-+
-+ {0x3632, 0x88, 0, 0}, //anti sm
-+ {0x3309, 0xa0, 0, 0},
-+ {0x331f, 0x8d, 0, 0},
-+ {0x3321, 0x8f, 0, 0},
-+
-+ {0x335e, 0x01, 0, 0}, //ana dithering
-+ {0x335f, 0x03, 0, 0},
-+ {0x337c, 0x04, 0, 0},
-+ {0x337d, 0x06, 0, 0},
-+ {0x33a0, 0x05, 0, 0},
-+ {0x3301, 0x05, 0, 0},
-+
-+ {0x337f, 0x03, 0, 0},
-+ {0x3368, 0x02, 0, 0},
-+ {0x3369, 0x00, 0, 0},
-+ {0x336a, 0x00, 0, 0},
-+ {0x336b, 0x00, 0, 0},
-+ {0x3367, 0x08, 0, 0},
-+ {0x330e, 0x30, 0, 0},
-+
-+ {0x3366, 0x7c, 0, 0}, // div_rst gap
-+
-+ {0x3635, 0xc1, 0, 0},
-+ {0x363b, 0x09, 0, 0},
-+ {0x363c, 0x07, 0, 0},
-+
-+ {0x391e, 0x00, 0, 0},
-+
-+ {0x3637, 0x14, 0, 0}, //fullwell 7K
-+
-+ {0x3306, 0x54, 0, 0},
-+ {0x330b, 0xd8, 0, 0},
-+ {0x366e, 0x08, 0, 0}, // ofs auto en [3]
-+ {0x366f, 0x2f, 0, 0},
-+
-+ {0x3631, 0x84, 0, 0},
-+ {0x3630, 0x48, 0, 0},
-+ {0x3622, 0x06, 0, 0},
-+
-+ //ramp by sc
-+ {0x3638, 0x1f, 0, 0},
-+ {0x3625, 0x02, 0, 0},
-+ {0x3636, 0x24, 0, 0},
-+
-+ //0714
-+ {0x3348, 0x08, 0, 0},
-+ {0x3e03, 0x0b, 0, 0},
-+
-+ //7.17 fpn
-+ {0x3342, 0x03, 0, 0},
-+ {0x3343, 0xa0, 0, 0},
-+ {0x334a, 0x03, 0, 0},
-+ {0x334b, 0xa0, 0, 0},
-+
-+ //0718
-+ {0x3343, 0xb0, 0, 0},
-+ {0x334b, 0xb0, 0, 0},
-+
-+ //0720
-+ //digital ctrl
-+ {0x3802, 0x01, 0, 0},
-+ {0x3235, 0x04, 0, 0},
-+ {0x3236, 0x63, 0, 0}, // vts-2
-+
-+ //fpn
-+ {0x3343, 0xd0, 0, 0},
-+ {0x334b, 0xd0, 0, 0},
-+ {0x3348, 0x07, 0, 0},
-+ {0x3349, 0x80, 0, 0},
-+
-+ //0724
-+ {0x391b, 0x4d, 0, 0},
-+
-+ {0x3342, 0x04, 0, 0},
-+ {0x3343, 0x20, 0, 0},
-+ {0x334a, 0x04, 0, 0},
-+ {0x334b, 0x20, 0, 0},
-+
-+ //0804
-+ {0x3222, 0x29, 0, 0},
-+ {0x3901, 0x02, 0, 0},
-+
-+ //0808
-+
-+ // auto blc
-+ {0x3900, 0xD5, 0, 0}, // Bit[0]: blc_enable
-+ {0x3902, 0x45, 0, 0}, // Bit[6]: blc_auto_en
-+
-+ // blc target
-+ {0x3907, 0x00, 0, 0},
-+ {0x3908, 0x00, 0, 0},
-+
-+ // auto dpc
-+ {0x5000, 0x00, 0, 0}, // Bit[2]: white dead pixel cancel enable, Bit[1]: black dead pixel cancel enable
-+
-+ //digital ctrl
-+ {0x3f00, 0x07, 0, 0}, // bit[2] = 1
-+ {0x3f04, 0x08, 0, 0},
-+ {0x3f05, 0x74, 0, 0}, // hts - { 0x24
-+
-+ //0809
-+ {0x330b, 0xc8, 0, 0},
-+
-+ //0817
-+ {0x3306, 0x4a, 0, 0},
-+ {0x330b, 0xca, 0, 0},
-+ {0x3639, 0x09, 0, 0},
-+
-+ //manual DPC
-+ {0x5780, 0xff, 0, 0},
-+ {0x5781, 0x04, 0, 0},
-+ {0x5785, 0x18, 0, 0},
-+
-+ //0822
-+ {0x3039, 0x35, 0, 0}, //fps
-+ {0x303a, 0x2e, 0, 0},
-+ {0x3034, 0x05, 0, 0},
-+ {0x3035, 0x2a, 0, 0},
-+
-+ {0x320c, 0x08, 0, 0},
-+ {0x320d, 0xca, 0, 0},
-+ {0x320e, 0x04, 0, 0},
-+ {0x320f, 0xb0, 0, 0},
-+
-+ {0x3f04, 0x08, 0, 0},
-+ {0x3f05, 0xa6, 0, 0}, // hts - { 0x24
-+
-+ {0x3235, 0x04, 0, 0},
-+ {0x3236, 0xae, 0, 0}, // vts-2
-+
-+ //0825
-+ {0x3313, 0x05, 0, 0},
-+ {0x3678, 0x42, 0, 0},
-+
-+ //for AE control per frame
-+ {0x3670, 0x00, 0, 0},
-+ {0x3633, 0x42, 0, 0},
-+
-+ {0x3802, 0x00, 0, 0},
-+
-+ //20180126
-+ {0x3677, 0x3f, 0, 0},
-+ {0x3306, 0x44, 0, 0}, //20180126[3c },4a]
-+ {0x330b, 0xca, 0, 0}, //20180126[c2 },d3]
-+
-+ //20180202
-+ {0x3237, 0x08, 0, 0},
-+ {0x3238, 0x9a, 0, 0}, //hts-0x30
-+
-+ //20180417
-+ {0x3640, 0x01, 0, 0},
-+ {0x3641, 0x02, 0, 0},
-+
-+ {0x3301, 0x12, 0, 0}, //[8 },15]20180126
-+ {0x3631, 0x84, 0, 0},
-+ {0x366f, 0x2f, 0, 0},
-+ {0x3622, 0xc6, 0, 0}, //20180117
-+
-+ {0x3e03, 0x03, 0, 0}, // Bit[3]: AGC table mapping method, Bit[1]: AGC manual, BIt[0]: AEC manual
-+
-+ // {0x0100, 0x00, 0, 0},
-+ // {0x4501, 0xc8, 0, 0}, //bar testing
-+ // {0x3902, 0x45, 0, 0},
-+};
-+
-+static struct reg_value sc2235_setting_1080P_1920_1080[] = {
-+
-+};
-+
-+/* power-on sensor init reg table */
-+static const struct sc2235_mode_info sc2235_mode_init_data = {
-+ SC2235_MODE_1080P_1920_1080,
-+ 1920, 0x8ca, 1080, 0x4b0,
-+ sc2235_init_regs_tbl_1080,
-+ ARRAY_SIZE(sc2235_init_regs_tbl_1080),
-+ SC2235_30_FPS,
-+};
-+
-+static const struct sc2235_mode_info
-+sc2235_mode_data[SC2235_NUM_MODES] = {
-+ {SC2235_MODE_1080P_1920_1080,
-+ 1920, 0x8ca, 1080, 0x4b0,
-+ sc2235_setting_1080P_1920_1080,
-+ ARRAY_SIZE(sc2235_setting_1080P_1920_1080),
-+ SC2235_30_FPS},
-+};
-+
-+static int sc2235_write_reg(struct sc2235_dev *sensor, u16 reg, u8 val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg;
-+ u8 buf[3];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+ buf[2] = val;
-+
-+ msg.addr = client->addr;
-+ msg.flags = client->flags;
-+ msg.buf = buf;
-+ msg.len = sizeof(buf);
-+
-+ ret = i2c_transfer(client->adapter, &msg, 1);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
-+ __func__, reg, val);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int sc2235_read_reg(struct sc2235_dev *sensor, u16 reg, u8 *val)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ struct i2c_msg msg[2];
-+ u8 buf[2];
-+ int ret;
-+
-+ buf[0] = reg >> 8;
-+ buf[1] = reg & 0xff;
-+
-+ msg[0].addr = client->addr;
-+ msg[0].flags = client->flags;
-+ msg[0].buf = buf;
-+ msg[0].len = sizeof(buf);
-+
-+ msg[1].addr = client->addr;
-+ msg[1].flags = client->flags | I2C_M_RD;
-+ msg[1].buf = buf;
-+ msg[1].len = 1;
-+
-+ ret = i2c_transfer(client->adapter, msg, 2);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "%s: error: reg=%x\n",
-+ __func__, reg);
-+ return ret;
-+ }
-+
-+ *val = buf[0];
-+ return 0;
-+}
-+
-+static int sc2235_read_reg16(struct sc2235_dev *sensor, u16 reg, u16 *val)
-+{
-+ u8 hi, lo;
-+ int ret;
-+
-+ ret = sc2235_read_reg(sensor, reg, &hi);
-+ if (ret)
-+ return ret;
-+ ret = sc2235_read_reg(sensor, reg + 1, &lo);
-+ if (ret)
-+ return ret;
-+
-+ *val = ((u16)hi << 8) | (u16)lo;
-+ return 0;
-+}
-+
-+static int sc2235_write_reg16(struct sc2235_dev *sensor, u16 reg, u16 val)
-+{
-+ int ret;
-+
-+ ret = sc2235_write_reg(sensor, reg, val >> 8);
-+ if (ret)
-+ return ret;
-+
-+ return sc2235_write_reg(sensor, reg + 1, val & 0xff);
-+}
-+
-+static int sc2235_mod_reg(struct sc2235_dev *sensor, u16 reg,
-+ u8 mask, u8 val)
-+{
-+ u8 readval;
-+ int ret;
-+
-+ ret = sc2235_read_reg(sensor, reg, &readval);
-+ if (ret)
-+ return ret;
-+
-+ readval &= ~mask;
-+ val &= mask;
-+ val |= readval;
-+
-+ return sc2235_write_reg(sensor, reg, val);
-+}
-+
-+#define SC2235_PLL_PREDIV 3
-+
-+#define SC2235_SYSDIV_MIN 0
-+#define SC2235_SYSDIV_MAX 7
-+
-+#define SC2235_PLL_MULT_MIN 0
-+#define SC2235_PLL_MULT_MAX 63
-+
-+#ifdef UNUSED_CODE
-+static unsigned long sc2235_compute_sys_clk(struct sc2235_dev *sensor,
-+ u8 pll_pre, u8 pll_mult,
-+ u8 sysdiv)
-+{
-+ unsigned long sysclk =
-+ sensor->xclk_freq * (64 - pll_mult) / (pll_pre * (sysdiv + 1));
-+
-+ /* PLL1 output cannot exceed 1GHz. */
-+ if (sysclk / 1000000 > 1000)
-+ return 0;
-+
-+ return sysclk;
-+}
-+
-+static unsigned long sc2235_calc_sys_clk(struct sc2235_dev *sensor,
-+ unsigned long rate,
-+ u8 *pll_prediv, u8 *pll_mult,
-+ u8 *sysdiv)
-+{
-+ unsigned long best = ~0;
-+ u8 best_sysdiv = 1, best_mult = 1;
-+ u8 _sysdiv, _pll_mult;
-+
-+ for (_sysdiv = SC2235_SYSDIV_MIN;
-+ _sysdiv <= SC2235_SYSDIV_MAX;
-+ _sysdiv++) {
-+ for (_pll_mult = SC2235_PLL_MULT_MIN;
-+ _pll_mult <= SC2235_PLL_MULT_MAX;
-+ _pll_mult++) {
-+ unsigned long _rate;
-+
-+ _rate = sc2235_compute_sys_clk(sensor,
-+ SC2235_PLL_PREDIV,
-+ _pll_mult, _sysdiv);
-+
-+ /*
-+ * We have reached the maximum allowed PLL1 output,
-+ * increase sysdiv.
-+ */
-+ if (!_rate)
-+ break;
-+
-+ /*
-+ * Prefer rates above the expected clock rate than
-+ * below, even if that means being less precise.
-+ */
-+ if (_rate < rate)
-+ continue;
-+
-+ if (abs(rate - _rate) < abs(rate - best)) {
-+ best = _rate;
-+ best_sysdiv = _sysdiv;
-+ best_mult = _pll_mult;
-+ }
-+
-+ if (_rate == rate)
-+ goto out;
-+ }
-+ }
-+
-+out:
-+ *sysdiv = best_sysdiv;
-+ *pll_prediv = SC2235_PLL_PREDIV;
-+ *pll_mult = best_mult;
-+
-+ return best;
-+}
-+#endif
-+
-+static int sc2235_set_timings(struct sc2235_dev *sensor,
-+ const struct sc2235_mode_info *mode)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int sc2235_load_regs(struct sc2235_dev *sensor,
-+ const struct sc2235_mode_info *mode)
-+{
-+ const struct reg_value *regs = mode->reg_data;
-+ unsigned int i;
-+ u32 delay_ms;
-+ u16 reg_addr;
-+ u8 mask, val;
-+ int ret = 0;
-+
-+ for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
-+ delay_ms = regs->delay_ms;
-+ reg_addr = regs->reg_addr;
-+ val = regs->val;
-+ mask = regs->mask;
-+
-+ if (mask)
-+ ret = sc2235_mod_reg(sensor, reg_addr, mask, val);
-+ else
-+ ret = sc2235_write_reg(sensor, reg_addr, val);
-+ if (ret)
-+ break;
-+
-+ if (delay_ms)
-+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
-+ }
-+
-+ return sc2235_set_timings(sensor, mode);
-+}
-+
-+static int sc2235_set_autoexposure(struct sc2235_dev *sensor, bool on)
-+{
-+ return sc2235_mod_reg(sensor, SC2235_REG_AEC_PK_MANUAL,
-+ BIT(0), on ? 0 : BIT(0));
-+}
-+
-+static int sc2235_get_exposure(struct sc2235_dev *sensor)
-+{
-+ int exp = 0, ret = 0;
-+ u8 temp;
-+
-+ ret = sc2235_read_reg(sensor, SC2235_REG_AEC_PK_EXPOSURE_HI, &temp);
-+ if (ret)
-+ return ret;
-+ exp |= (int)temp << 8;
-+ ret = sc2235_read_reg(sensor, SC2235_REG_AEC_PK_EXPOSURE_LO, &temp);
-+ if (ret)
-+ return ret;
-+ exp |= (int)temp;
-+
-+ return exp >> 4;
-+}
-+
-+static int sc2235_set_exposure(struct sc2235_dev *sensor, u32 exposure)
-+{
-+ int ret;
-+
-+ exposure <<= 4;
-+
-+ ret = sc2235_write_reg(sensor,
-+ SC2235_REG_AEC_PK_EXPOSURE_LO,
-+ exposure & 0xff);
-+ if (ret)
-+ return ret;
-+ return sc2235_write_reg(sensor,
-+ SC2235_REG_AEC_PK_EXPOSURE_HI,
-+ (exposure >> 8) & 0xff);
-+}
-+
-+static int sc2235_get_gain(struct sc2235_dev *sensor)
-+{
-+ u16 gain;
-+ int ret;
-+
-+ ret = sc2235_read_reg16(sensor, SC2235_REG_AEC_PK_REAL_GAIN, &gain);
-+ if (ret)
-+ return ret;
-+
-+ return gain & 0x1fff;
-+}
-+
-+static int sc2235_set_gain(struct sc2235_dev *sensor, int gain)
-+{
-+ return sc2235_write_reg16(sensor, SC2235_REG_AEC_PK_REAL_GAIN,
-+ (u16)gain & 0x1fff);
-+}
-+
-+static int sc2235_set_autogain(struct sc2235_dev *sensor, bool on)
-+{
-+ return sc2235_mod_reg(sensor, SC2235_REG_AEC_PK_MANUAL,
-+ BIT(1), on ? 0 : BIT(1));
-+}
-+
-+#ifdef UNUSED_CODE
-+static int sc2235_get_sysclk(struct sc2235_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int sc2235_set_night_mode(struct sc2235_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int sc2235_get_hts(struct sc2235_dev *sensor)
-+{
-+ u16 hts;
-+ int ret;
-+
-+ ret = sc2235_read_reg16(sensor, SC2235_REG_TIMING_HTS, &hts);
-+ if (ret)
-+ return ret;
-+ return hts;
-+}
-+#endif
-+
-+static int sc2235_get_vts(struct sc2235_dev *sensor)
-+{
-+ u16 vts;
-+ int ret;
-+
-+ ret = sc2235_read_reg16(sensor, SC2235_REG_TIMING_VTS, &vts);
-+ if (ret)
-+ return ret;
-+ return vts;
-+}
-+
-+#ifdef UNUSED_CODE
-+static int sc2235_set_vts(struct sc2235_dev *sensor, int vts)
-+{
-+ return sc2235_write_reg16(sensor, SC2235_REG_TIMING_VTS, vts);
-+}
-+
-+static int sc2235_get_light_freq(struct sc2235_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int sc2235_set_bandingfilter(struct sc2235_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int sc2235_set_ae_target(struct sc2235_dev *sensor, int target)
-+{
-+ return 0;
-+}
-+
-+static int sc2235_get_binning(struct sc2235_dev *sensor)
-+{
-+ return 0;
-+}
-+
-+static int sc2235_set_binning(struct sc2235_dev *sensor, bool enable)
-+{
-+ return 0;
-+}
-+
-+#endif
-+
-+static const struct sc2235_mode_info *
-+sc2235_find_mode(struct sc2235_dev *sensor, enum sc2235_frame_rate fr,
-+ int width, int height, bool nearest)
-+{
-+ const struct sc2235_mode_info *mode;
-+
-+ mode = v4l2_find_nearest_size(sc2235_mode_data,
-+ ARRAY_SIZE(sc2235_mode_data),
-+ hact, vact,
-+ width, height);
-+
-+ if (!mode ||
-+ (!nearest && (mode->hact != width || mode->vact != height)))
-+ return NULL;
-+
-+ /* Check to see if the current mode exceeds the max frame rate */
-+ if (sc2235_framerates[fr] > sc2235_framerates[mode->max_fps])
-+ return NULL;
-+
-+ return mode;
-+}
-+
-+static u64 sc2235_calc_pixel_rate(struct sc2235_dev *sensor)
-+{
-+ u64 rate;
-+
-+ rate = sensor->current_mode->vtot * sensor->current_mode->htot;
-+ rate *= sc2235_framerates[sensor->current_fr];
-+
-+ return rate;
-+}
-+
-+#ifdef UNUSED_CODE
-+/*
-+ * sc2235_set_dvp_pclk() - Calculate the clock tree configuration values
-+ * for the dvp output.
-+ *
-+ * @rate: The requested bandwidth per lane in bytes per second.
-+ * 'Bandwidth Per Lane' is calculated as:
-+ * rate = HTOT * VTOT * FPS;
-+ *
-+ * This function use the requested bandwidth to calculate:
-+ * - rate = xclk * (64 - M) / (N * (S + 1));
-+ *
-+ */
-+
-+#define PLL_PREDIV 1
-+#define PLL_SYSEL 0
-+
-+static int sc2235_set_dvp_pclk(struct sc2235_dev *sensor,
-+ unsigned long rate)
-+{
-+ u8 prediv, mult, sysdiv;
-+ int ret = 0;
-+
-+ sc2235_calc_sys_clk(sensor, rate, &prediv, &mult,
-+ &sysdiv);
-+
-+
-+ return ret;
-+}
-+
-+/*
-+ * if sensor changes inside scaling or subsampling
-+ * change mode directly
-+ */
-+static int sc2235_set_mode_direct(struct sc2235_dev *sensor,
-+ const struct sc2235_mode_info *mode)
-+{
-+ if (!mode->reg_data)
-+ return -EINVAL;
-+
-+ /* Write capture setting */
-+ return sc2235_load_regs(sensor, mode);
-+}
-+#endif
-+
-+static int sc2235_set_mode(struct sc2235_dev *sensor)
-+{
-+#ifdef UNUSED_CODE
-+ bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
-+ const struct sc2235_mode_info *mode = sensor->current_mode;
-+#endif
-+ bool auto_gain = sensor->ctrls.auto_gain->val == 1;
-+ int ret = 0;
-+
-+ /* auto gain and exposure must be turned off when changing modes */
-+ if (auto_gain) {
-+ ret = sc2235_set_autogain(sensor, false);
-+ if (ret)
-+ return ret;
-+ }
-+#ifdef UNUSED_CODE
-+ /* This issue will be addressed in the EVB board*/
-+ /* This action will result in poor image display 2021 1111*/
-+ if (auto_exp) {
-+ ret = sc2235_set_autoexposure(sensor, false);
-+ if (ret)
-+ goto restore_auto_gain;
-+ }
-+
-+ rate = sc2235_calc_pixel_rate(sensor);
-+
-+ ret = sc2235_set_dvp_pclk(sensor, rate);
-+ if (ret < 0)
-+ return 0;
-+
-+ ret = sc2235_set_mode_direct(sensor, mode);
-+ if (ret < 0)
-+ goto restore_auto_exp_gain;
-+
-+ /* restore auto gain and exposure */
-+ if (auto_gain)
-+ sc2235_set_autogain(sensor, true);
-+ if (auto_exp)
-+ sc2235_set_autoexposure(sensor, true);
-+
-+
-+ sensor->pending_mode_change = false;
-+ sensor->last_mode = mode;
-+ return 0;
-+
-+restore_auto_exp_gain:
-+ if (auto_exp)
-+ sc2235_set_autoexposure(sensor, true);
-+restore_auto_gain:
-+ if (auto_gain)
-+ sc2235_set_autogain(sensor, true);
-+#endif
-+ return ret;
-+}
-+
-+static int sc2235_set_framefmt(struct sc2235_dev *sensor,
-+ struct v4l2_mbus_framefmt *format);
-+
-+/* restore the last set video mode after chip power-on */
-+static int sc2235_restore_mode(struct sc2235_dev *sensor)
-+{
-+ int ret;
-+
-+ /* first load the initial register values */
-+ ret = sc2235_load_regs(sensor, &sc2235_mode_init_data);
-+ if (ret < 0)
-+ return ret;
-+ sensor->last_mode = &sc2235_mode_init_data;
-+ /* now restore the last capture mode */
-+ ret = sc2235_set_mode(sensor);
-+ if (ret < 0)
-+ return ret;
-+
-+ return sc2235_set_framefmt(sensor, &sensor->fmt);
-+}
-+
-+static void sc2235_power(struct sc2235_dev *sensor, bool enable)
-+{
-+ if (!sensor->pwdn_gpio)
-+ return;
-+ gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
-+}
-+
-+static void sc2235_reset(struct sc2235_dev *sensor)
-+{
-+ if (!sensor->reset_gpio)
-+ return;
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
-+
-+ /* camera power cycle */
-+ sc2235_power(sensor, false);
-+ usleep_range(5000, 10000);
-+ sc2235_power(sensor, true);
-+ usleep_range(5000, 10000);
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 1);
-+ usleep_range(1000, 2000);
-+
-+ gpiod_set_value_cansleep(sensor->reset_gpio, 0);
-+ usleep_range(20000, 25000);
-+}
-+
-+static int sc2235_set_power_on(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ int ret;
-+
-+ ret = clk_prepare_enable(sensor->xclk);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable clock\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = regulator_bulk_enable(SC2235_NUM_SUPPLIES,
-+ sensor->supplies);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ goto xclk_off;
-+ }
-+
-+ sc2235_reset(sensor);
-+ sc2235_power(sensor, true);
-+
-+ return 0;
-+
-+xclk_off:
-+ clk_disable_unprepare(sensor->xclk);
-+ return ret;
-+}
-+
-+static int sc2235_set_power_off(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+
-+ sc2235_power(sensor, false);
-+ regulator_bulk_disable(SC2235_NUM_SUPPLIES, sensor->supplies);
-+ clk_disable_unprepare(sensor->xclk);
-+
-+ return 0;
-+}
-+
-+static int sc2235_set_power(struct sc2235_dev *sensor, bool on)
-+{
-+ int ret = 0;
-+
-+ if (on) {
-+ pm_runtime_get_sync(&sensor->i2c_client->dev);
-+
-+ ret = sc2235_restore_mode(sensor);
-+ if (ret)
-+ goto power_off;
-+ }
-+
-+ if (!on)
-+ pm_runtime_put_sync(&sensor->i2c_client->dev);
-+
-+ return 0;
-+
-+power_off:
-+ pm_runtime_put_sync(&sensor->i2c_client->dev);
-+
-+ return ret;
-+}
-+
-+static int sc2235_s_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ ret = sc2235_set_power(sensor, !!on);
-+ if (ret)
-+ goto out;
-+
-+ mutex_unlock(&sensor->lock);
-+ return 0;
-+
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int sc2235_try_frame_interval(struct sc2235_dev *sensor,
-+ struct v4l2_fract *fi,
-+ u32 width, u32 height)
-+{
-+ const struct sc2235_mode_info *mode;
-+ enum sc2235_frame_rate rate = SC2235_15_FPS;
-+ int minfps, maxfps, best_fps, fps;
-+ int i;
-+
-+ minfps = sc2235_framerates[SC2235_15_FPS];
-+ maxfps = sc2235_framerates[SC2235_30_FPS];
-+
-+ if (fi->numerator == 0) {
-+ fi->denominator = maxfps;
-+ fi->numerator = 1;
-+ rate = SC2235_30_FPS;
-+ goto find_mode;
-+ }
-+
-+ fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
-+ minfps, maxfps);
-+
-+ best_fps = minfps;
-+ for (i = 0; i < ARRAY_SIZE(sc2235_framerates); i++) {
-+ int curr_fps = sc2235_framerates[i];
-+
-+ if (abs(curr_fps - fps) < abs(best_fps - fps)) {
-+ best_fps = curr_fps;
-+ rate = i;
-+ }
-+ }
-+
-+ fi->numerator = 1;
-+ fi->denominator = best_fps;
-+
-+find_mode:
-+ mode = sc2235_find_mode(sensor, rate, width, height, false);
-+ return mode ? rate : -EINVAL;
-+}
-+
-+static int sc2235_get_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ struct v4l2_mbus_framefmt *fmt;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(&sensor->sd, state,
-+ format->pad);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ format->format = *fmt;
-+
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int sc2235_try_fmt_internal(struct v4l2_subdev *sd,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum sc2235_frame_rate fr,
-+ const struct sc2235_mode_info **new_mode)
-+{
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ const struct sc2235_mode_info *mode;
-+ int i;
-+
-+ mode = sc2235_find_mode(sensor, fr, fmt->width, fmt->height, true);
-+ if (!mode)
-+ return -EINVAL;
-+ fmt->width = mode->hact;
-+ fmt->height = mode->vact;
-+
-+ if (new_mode)
-+ *new_mode = mode;
-+
-+ for (i = 0; i < ARRAY_SIZE(sc2235_formats); i++)
-+ if (sc2235_formats[i].code == fmt->code)
-+ break;
-+ if (i >= ARRAY_SIZE(sc2235_formats))
-+ i = 0;
-+
-+ fmt->code = sc2235_formats[i].code;
-+ fmt->colorspace = sc2235_formats[i].colorspace;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+
-+ return 0;
-+}
-+
-+static int sc2235_set_fmt(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *format)
-+{
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ const struct sc2235_mode_info *new_mode;
-+ struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
-+ struct v4l2_mbus_framefmt *fmt;
-+ int ret;
-+
-+ if (format->pad != 0)
-+ return -EINVAL;
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ ret = sc2235_try_fmt_internal(sd, mbus_fmt, 0, &new_mode);
-+ if (ret)
-+ goto out;
-+
-+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
-+ fmt = v4l2_subdev_get_try_format(sd, state, 0);
-+ else
-+ fmt = &sensor->fmt;
-+
-+ if (mbus_fmt->code != sensor->fmt.code)
-+ sensor->pending_fmt_change = true;
-+
-+ *fmt = *mbus_fmt;
-+
-+ if (new_mode != sensor->current_mode) {
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+ if (new_mode->max_fps < sensor->current_fr) {
-+ sensor->current_fr = new_mode->max_fps;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator =
-+ sc2235_framerates[sensor->current_fr];
-+ sensor->current_mode = new_mode;
-+ sensor->pending_mode_change = true;
-+ }
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ sc2235_calc_pixel_rate(sensor));
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int sc2235_set_framefmt(struct sc2235_dev *sensor,
-+ struct v4l2_mbus_framefmt *format)
-+{
-+ int ret = 0;
-+
-+ switch (format->code) {
-+ default:
-+ return ret;
-+ }
-+ return ret;
-+}
-+
-+/*
-+ * Sensor Controls.
-+ */
-+
-+static int sc2235_set_ctrl_hue(struct sc2235_dev *sensor, int value)
-+{
-+ int ret = 0;
-+ return ret;
-+}
-+
-+static int sc2235_set_ctrl_contrast(struct sc2235_dev *sensor, int value)
-+{
-+ int ret = 0;
-+ return ret;
-+}
-+
-+static int sc2235_set_ctrl_saturation(struct sc2235_dev *sensor, int value)
-+{
-+ int ret = 0;
-+ return ret;
-+}
-+
-+static int sc2235_set_ctrl_white_balance(struct sc2235_dev *sensor, int awb)
-+{
-+ int ret = 0;
-+ return ret;
-+}
-+
-+static int sc2235_set_ctrl_exposure(struct sc2235_dev *sensor,
-+ enum v4l2_exposure_auto_type auto_exposure)
-+{
-+ struct sc2235_ctrls *ctrls = &sensor->ctrls;
-+ bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
-+ int ret = 0;
-+
-+ if (ctrls->auto_exp->is_new) {
-+ ret = sc2235_set_autoexposure(sensor, auto_exp);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ if (!auto_exp && ctrls->exposure->is_new) {
-+ u16 max_exp = 0;
-+
-+ ret = sc2235_get_vts(sensor);
-+ if (ret < 0)
-+ return ret;
-+ max_exp += ret - 4;
-+ ret = 0;
-+
-+ if (ctrls->exposure->val < max_exp)
-+ ret = sc2235_set_exposure(sensor, ctrls->exposure->val);
-+ }
-+
-+ return ret;
-+}
-+
-+static int sc2235_set_ctrl_gain(struct sc2235_dev *sensor, bool auto_gain)
-+{
-+ struct sc2235_ctrls *ctrls = &sensor->ctrls;
-+ int ret = 0;
-+
-+ if (ctrls->auto_gain->is_new) {
-+ ret = sc2235_set_autogain(sensor, auto_gain);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ if (!auto_gain && ctrls->gain->is_new)
-+ ret = sc2235_set_gain(sensor, ctrls->gain->val);
-+
-+ return ret;
-+}
-+
-+static const char * const test_pattern_menu[] = {
-+ "Disabled",
-+ "Black bars",
-+ "Auto Black bars",
-+};
-+
-+#define SC2235_TEST_ENABLE BIT(3)
-+#define SC2235_TEST_BLACK (3 << 0)
-+
-+static int sc2235_set_ctrl_test_pattern(struct sc2235_dev *sensor, int value)
-+{
-+ int ret = 0;
-+ /*
-+ *For 7110 platform, refer to 1125 FW code configuration. This operation will cause the image to be white.
-+ */
-+#ifdef UNUSED_CODE
-+ ret = sc2235_mod_reg(sensor, SC2235_REG_TEST_SET0, BIT(3),
-+ !!value << 3);
-+
-+ ret |= sc2235_mod_reg(sensor, SC2235_REG_TEST_SET1, BIT(6),
-+ (value >> 1) << 6);
-+#endif
-+ return ret;
-+}
-+
-+static int sc2235_set_ctrl_light_freq(struct sc2235_dev *sensor, int value)
-+{
-+ return 0;
-+}
-+
-+static int sc2235_set_ctrl_hflip(struct sc2235_dev *sensor, int value)
-+{
-+ return sc2235_mod_reg(sensor, SC2235_REG_TIMING_TC_REG21,
-+ BIT(2) | BIT(1),
-+ (!(value ^ sensor->upside_down)) ?
-+ (BIT(2) | BIT(1)) : 0);
-+}
-+
-+static int sc2235_set_ctrl_vflip(struct sc2235_dev *sensor, int value)
-+{
-+ return sc2235_mod_reg(sensor, SC2235_REG_TIMING_TC_REG21,
-+ BIT(6) | BIT(5),
-+ (value ^ sensor->upside_down) ?
-+ (BIT(6) | BIT(5)) : 0);
-+}
-+
-+static int sc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ int val;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_AUTOGAIN:
-+ val = sc2235_get_gain(sensor);
-+ if (val < 0)
-+ return val;
-+ sensor->ctrls.gain->val = val;
-+ break;
-+ case V4L2_CID_EXPOSURE_AUTO:
-+ val = sc2235_get_exposure(sensor);
-+ if (val < 0)
-+ return val;
-+ sensor->ctrls.exposure->val = val;
-+ break;
-+ }
-+
-+ pm_runtime_put(&sensor->i2c_client->dev);
-+
-+ return 0;
-+}
-+
-+static int sc2235_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ int ret;
-+
-+ /* v4l2_ctrl_lock() locks our own mutex */
-+
-+ /*
-+ * If the device is not powered up by the host driver do
-+ * not apply any controls to H/W at this time. Instead
-+ * the controls will be restored at start streaming time.
-+ */
-+ if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_AUTOGAIN:
-+ ret = sc2235_set_ctrl_gain(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE_AUTO:
-+ ret = sc2235_set_ctrl_exposure(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_AUTO_WHITE_BALANCE:
-+ ret = sc2235_set_ctrl_white_balance(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HUE:
-+ ret = sc2235_set_ctrl_hue(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_CONTRAST:
-+ ret = sc2235_set_ctrl_contrast(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_SATURATION:
-+ ret = sc2235_set_ctrl_saturation(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = sc2235_set_ctrl_test_pattern(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY:
-+ ret = sc2235_set_ctrl_light_freq(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_HFLIP:
-+ ret = sc2235_set_ctrl_hflip(sensor, ctrl->val);
-+ break;
-+ case V4L2_CID_VFLIP:
-+ ret = sc2235_set_ctrl_vflip(sensor, ctrl->val);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ pm_runtime_put(&sensor->i2c_client->dev);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops sc2235_ctrl_ops = {
-+ .g_volatile_ctrl = sc2235_g_volatile_ctrl,
-+ .s_ctrl = sc2235_s_ctrl,
-+};
-+
-+static int sc2235_init_controls(struct sc2235_dev *sensor)
-+{
-+ const struct v4l2_ctrl_ops *ops = &sc2235_ctrl_ops;
-+ struct sc2235_ctrls *ctrls = &sensor->ctrls;
-+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-+ int ret;
-+
-+ v4l2_ctrl_handler_init(hdl, 32);
-+
-+ /* we can use our own mutex for the ctrl lock */
-+ hdl->lock = &sensor->lock;
-+
-+ /* Clock related controls */
-+ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
-+ 0, INT_MAX, 1,
-+ sc2235_calc_pixel_rate(sensor));
-+
-+ /* Auto/manual white balance */
-+ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
-+ V4L2_CID_AUTO_WHITE_BALANCE,
-+ 0, 1, 1, 1);
-+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
-+ 0, 4095, 1, 0);
-+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
-+ 0, 4095, 1, 0);
-+ /* Auto/manual exposure */
-+#ifdef UNUSED_CODE
-+ /*
-+ *For 7110 platform, This operation will cause the image to be white.
-+ */
-+ ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_EXPOSURE_AUTO,
-+ V4L2_EXPOSURE_MANUAL, 0,
-+ V4L2_EXPOSURE_AUTO);
-+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-+ 0, 65535, 1, 0);
-+ /* Auto/manual gain */
-+ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
-+ 0, 1, 1, 1);
-+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
-+ 0, 1023, 1, 0);
-+#else
-+ ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_EXPOSURE_AUTO,
-+ V4L2_EXPOSURE_MANUAL, 0,
-+ 1);
-+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-+ 0, 65535, 1, 720);
-+ /* Auto/manual gain */
-+ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
-+ 0, 1, 1, 0);
-+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
-+ 0, 1023, 1, 0x10);
-+#endif
-+ ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
-+ 0, 255, 1, 64);
-+ ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
-+ 0, 359, 1, 0);
-+ ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
-+ 0, 255, 1, 0);
-+ ctrls->test_pattern =
-+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(test_pattern_menu) - 1,
-+ 0, 0, test_pattern_menu); //0x02
-+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
-+ 0, 1, 1, 1);
-+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
-+ 0, 1, 1, 0);
-+
-+ ctrls->light_freq =
-+ v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_POWER_LINE_FREQUENCY,
-+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
-+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
-+
-+ if (hdl->error) {
-+ ret = hdl->error;
-+ goto free_ctrls;
-+ }
-+
-+ ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+ ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+
-+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
-+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
-+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
-+
-+ sensor->sd.ctrl_handler = hdl;
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(hdl);
-+ return ret;
-+}
-+
-+static int sc2235_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ if (fse->pad != 0)
-+ return -EINVAL;
-+ if (fse->index >= SC2235_NUM_MODES)
-+ return -EINVAL;
-+
-+ fse->min_width =
-+ sc2235_mode_data[fse->index].hact;
-+ fse->max_width = fse->min_width;
-+ fse->min_height =
-+ sc2235_mode_data[fse->index].vact;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static int sc2235_enum_frame_interval(
-+ struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_interval_enum *fie)
-+{
-+ struct v4l2_fract tpf;
-+ int i;
-+
-+ if (fie->pad != 0)
-+ return -EINVAL;
-+
-+ if (fie->index >= SC2235_NUM_FRAMERATES)
-+ return -EINVAL;
-+
-+ tpf.numerator = 1;
-+ tpf.denominator = sc2235_framerates[fie->index];
-+
-+ for (i = 0; i < SC2235_NUM_MODES; i++) {
-+ if (fie->width == sc2235_mode_data[i].hact &&
-+ fie->height == sc2235_mode_data[i].vact)
-+ break;
-+ }
-+ if (i == SC2235_NUM_MODES)
-+ return -ENOTTY;
-+
-+ fie->interval = tpf;
-+ return 0;
-+}
-+
-+static int sc2235_g_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+
-+ mutex_lock(&sensor->lock);
-+ fi->interval = sensor->frame_interval;
-+ mutex_unlock(&sensor->lock);
-+
-+ return 0;
-+}
-+
-+static int sc2235_s_frame_interval(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_frame_interval *fi)
-+{
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ const struct sc2235_mode_info *mode;
-+ int frame_rate, ret = 0;
-+
-+ if (fi->pad != 0)
-+ return -EINVAL;
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+
-+ mode = sensor->current_mode;
-+
-+ frame_rate = sc2235_try_frame_interval(sensor, &fi->interval,
-+ mode->hact, mode->vact);
-+ if (frame_rate < 0) {
-+ /* Always return a valid frame interval value */
-+ fi->interval = sensor->frame_interval;
-+ goto out;
-+ }
-+
-+ mode = sc2235_find_mode(sensor, frame_rate, mode->hact,
-+ mode->vact, true);
-+ if (!mode) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (mode != sensor->current_mode ||
-+ frame_rate != sensor->current_fr) {
-+ sensor->current_fr = frame_rate;
-+ sensor->frame_interval = fi->interval;
-+ sensor->current_mode = mode;
-+ sensor->pending_mode_change = true;
-+
-+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
-+ sc2235_calc_pixel_rate(sensor));
-+ }
-+out:
-+ mutex_unlock(&sensor->lock);
-+ return ret;
-+}
-+
-+static int sc2235_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ if (code->pad != 0)
-+ return -EINVAL;
-+ if (code->index >= ARRAY_SIZE(sc2235_formats))
-+ return -EINVAL;
-+
-+ code->code = sc2235_formats[code->index].code;
-+ return 0;
-+}
-+
-+static int sc2235_stream_start(struct sc2235_dev *sensor, int enable)
-+{
-+ return sc2235_mod_reg(sensor, SC2235_REG_STREAM_ON, BIT(0), !!enable);
-+}
-+
-+static int sc2235_s_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+ int ret = 0;
-+
-+ if (enable) {
-+ ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ mutex_lock(&sensor->lock);
-+
-+ if (sensor->streaming == !enable) {
-+ if (enable && sensor->pending_mode_change) {
-+ ret = sc2235_set_mode(sensor);
-+ if (ret)
-+ goto out;
-+ }
-+
-+ if (enable && sensor->pending_fmt_change) {
-+ ret = sc2235_set_framefmt(sensor, &sensor->fmt);
-+ if (ret)
-+ goto out;
-+ sensor->pending_fmt_change = false;
-+ }
-+
-+ ret = sc2235_stream_start(sensor, enable);
-+ if (ret)
-+ goto out;
-+ }
-+ sensor->streaming += enable ? 1 : -1;
-+ WARN_ON(sensor->streaming < 0);
-+out:
-+ mutex_unlock(&sensor->lock);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_subdev_core_ops sc2235_core_ops = {
-+ .s_power = sc2235_s_power,
-+ .log_status = v4l2_ctrl_subdev_log_status,
-+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops sc2235_video_ops = {
-+ .g_frame_interval = sc2235_g_frame_interval,
-+ .s_frame_interval = sc2235_s_frame_interval,
-+ .s_stream = sc2235_s_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops sc2235_pad_ops = {
-+ .enum_mbus_code = sc2235_enum_mbus_code,
-+ .get_fmt = sc2235_get_fmt,
-+ .set_fmt = sc2235_set_fmt,
-+ .enum_frame_size = sc2235_enum_frame_size,
-+ .enum_frame_interval = sc2235_enum_frame_interval,
-+};
-+
-+static const struct v4l2_subdev_ops sc2235_subdev_ops = {
-+ .core = &sc2235_core_ops,
-+ .video = &sc2235_video_ops,
-+ .pad = &sc2235_pad_ops,
-+};
-+
-+static int sc2235_get_regulators(struct sc2235_dev *sensor)
-+{
-+ int i;
-+
-+ for (i = 0; i < SC2235_NUM_SUPPLIES; i++)
-+ sensor->supplies[i].supply = sc2235_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&sensor->i2c_client->dev,
-+ SC2235_NUM_SUPPLIES,
-+ sensor->supplies);
-+}
-+
-+static int sc2235_check_chip_id(struct sc2235_dev *sensor)
-+{
-+ struct i2c_client *client = sensor->i2c_client;
-+ int ret = 0;
-+ u16 chip_id;
-+
-+ ret = sc2235_read_reg16(sensor, SC2235_REG_CHIP_ID, &chip_id);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to read chip identifier\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ if (chip_id != SC2235_CHIP_ID) {
-+ dev_err(&client->dev, "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",
-+ __func__, SC2235_CHIP_ID, chip_id);
-+ return -ENXIO;
-+ }
-+ dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
-+ __func__, chip_id);
-+
-+ return 0;
-+}
-+
-+static int sc2235_probe(struct i2c_client *client)
-+{
-+ struct device *dev = &client->dev;
-+ struct fwnode_handle *endpoint;
-+ struct sc2235_dev *sensor;
-+ struct v4l2_mbus_framefmt *fmt;
-+ u32 rotation;
-+ int ret;
-+
-+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
-+ if (!sensor)
-+ return -ENOMEM;
-+
-+ sensor->i2c_client = client;
-+
-+ fmt = &sensor->fmt;
-+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+ fmt->width = 1920;
-+ fmt->height = 1080;
-+ fmt->field = V4L2_FIELD_NONE;
-+ sensor->frame_interval.numerator = 1;
-+ sensor->frame_interval.denominator = sc2235_framerates[SC2235_30_FPS];
-+ sensor->current_fr = SC2235_30_FPS;
-+ sensor->current_mode =
-+ &sc2235_mode_data[SC2235_MODE_1080P_1920_1080];
-+ sensor->last_mode = sensor->current_mode;
-+
-+ /* optional indication of physical rotation of sensor */
-+ ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
-+ &rotation);
-+ if (!ret) {
-+ switch (rotation) {
-+ case 180:
-+ sensor->upside_down = true;
-+ fallthrough;
-+ case 0:
-+ break;
-+ default:
-+ dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
-+ rotation);
-+ }
-+ }
-+
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
-+ NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
-+ fwnode_handle_put(endpoint);
-+ if (ret) {
-+ dev_err(dev, "Could not parse endpoint\n");
-+ return ret;
-+ }
-+
-+ if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL) {
-+ dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
-+ return -EINVAL;
-+ }
-+
-+ /* get system clock (xclk) */
-+ sensor->xclk = devm_clk_get(dev, "xclk");
-+ if (IS_ERR(sensor->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(sensor->xclk);
-+ }
-+
-+ sensor->xclk_freq = clk_get_rate(sensor->xclk);
-+ if (sensor->xclk_freq < SC2235_XCLK_MIN ||
-+ sensor->xclk_freq > SC2235_XCLK_MAX) {
-+ dev_err(dev, "xclk frequency out of range: %d Hz\n",
-+ sensor->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->pwdn_gpio))
-+ return PTR_ERR(sensor->pwdn_gpio);
-+
-+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
-+ GPIOD_OUT_HIGH);
-+ if (IS_ERR(sensor->reset_gpio))
-+ return PTR_ERR(sensor->reset_gpio);
-+
-+ v4l2_i2c_subdev_init(&sensor->sd, client, &sc2235_subdev_ops);
-+
-+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
-+ V4L2_SUBDEV_FL_HAS_EVENTS;
-+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
-+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
-+ if (ret)
-+ return ret;
-+
-+ ret = sc2235_get_regulators(sensor);
-+ if (ret)
-+ return ret;
-+ mutex_init(&sensor->lock);
-+
-+ ret = sc2235_set_power_on(dev);
-+ if (ret) {
-+ dev_err(dev, "failed to power on\n");
-+ goto entity_cleanup;
-+ }
-+
-+ ret = sc2235_check_chip_id(sensor);
-+ if (ret)
-+ goto entity_power_off;
-+
-+ ret = sc2235_init_controls(sensor);
-+ if (ret)
-+ goto entity_power_off;
-+
-+ ret = v4l2_async_register_subdev_sensor(&sensor->sd);
-+ if (ret)
-+ goto free_ctrls;
-+
-+ pm_runtime_set_active(dev);
-+ pm_runtime_enable(dev);
-+
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+entity_power_off:
-+ sc2235_set_power_off(dev);
-+entity_cleanup:
-+ media_entity_cleanup(&sensor->sd.entity);
-+ mutex_destroy(&sensor->lock);
-+ return ret;
-+}
-+
-+static void sc2235_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct sc2235_dev *sensor = to_sc2235_dev(sd);
-+
-+ v4l2_async_unregister_subdev(&sensor->sd);
-+ media_entity_cleanup(&sensor->sd.entity);
-+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
-+ mutex_destroy(&sensor->lock);
-+
-+ pm_runtime_disable(&client->dev);
-+ if (!pm_runtime_status_suspended(&client->dev))
-+ sc2235_set_power_off(&client->dev);
-+ pm_runtime_set_suspended(&client->dev);
-+}
-+
-+static const struct i2c_device_id sc2235_id[] = {
-+ { "sc2235", 0 },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(i2c, sc2235_id);
-+
-+static const struct of_device_id sc2235_dt_ids[] = {
-+ { .compatible = "smartsens,sc2235" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, sc2235_dt_ids);
-+
-+static const struct dev_pm_ops sc2235_pm_ops = {
-+ SET_RUNTIME_PM_OPS(sc2235_set_power_off, sc2235_set_power_on, NULL)
-+};
-+
-+static struct i2c_driver sc2235_i2c_driver = {
-+ .driver = {
-+ .name = "sc2235",
-+ .of_match_table = sc2235_dt_ids,
-+ .pm = &sc2235_pm_ops,
-+ },
-+ .id_table = sc2235_id,
-+ .probe = sc2235_probe,
-+ .remove = sc2235_remove,
-+};
-+
-+module_i2c_driver(sc2235_i2c_driver);
-+
-+MODULE_DESCRIPTION("SC2235 Camera Subdev Driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_common.h
-@@ -0,0 +1,185 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_COMMON_H
-+#define STF_COMMON_H
-+
-+#include <linux/kern_levels.h>
-+
-+// #define STF_DEBUG
-+
-+// #define USE_CSIDPHY_ONE_CLK_MODE 1
-+
-+enum {
-+ ST_DVP = 0x0001,
-+ ST_CSIPHY = 0x0002,
-+ ST_CSI = 0x0004,
-+ ST_ISP = 0x0008,
-+ ST_VIN = 0x0010,
-+ ST_VIDEO = 0x0020,
-+ ST_CAMSS = 0x0040,
-+ ST_SENSOR = 0x0080,
-+};
-+
-+enum {
-+ ST_NONE = 0x00,
-+ ST_ERR = 0x01,
-+ ST_WARN = 0x02,
-+ ST_INFO = 0x03,
-+ ST_DEBUG = 0x04,
-+};
-+
-+extern unsigned int stdbg_level;
-+extern unsigned int stdbg_mask;
-+
-+#define ST_MODULE2STRING(__module) ({ \
-+ char *__str; \
-+ \
-+ switch (__module) { \
-+ case ST_DVP: \
-+ __str = "st_dvp"; \
-+ break; \
-+ case ST_CSIPHY: \
-+ __str = "st_csiphy"; \
-+ break; \
-+ case ST_CSI: \
-+ __str = "st_csi"; \
-+ break; \
-+ case ST_ISP: \
-+ __str = "st_isp"; \
-+ break; \
-+ case ST_VIN: \
-+ __str = "st_vin"; \
-+ break; \
-+ case ST_VIDEO: \
-+ __str = "st_video"; \
-+ break; \
-+ case ST_CAMSS: \
-+ __str = "st_camss"; \
-+ break; \
-+ case ST_SENSOR: \
-+ __str = "st_sensor"; \
-+ break; \
-+ default: \
-+ __str = "unknow"; \
-+ break; \
-+ } \
-+ \
-+ __str; \
-+ })
-+
-+#define st_debug(module, __fmt, arg...) \
-+ do { \
-+ if (stdbg_level > ST_INFO) { \
-+ if (stdbg_mask & module) \
-+ pr_err("[%s] debug: " __fmt, \
-+ ST_MODULE2STRING(module), \
-+ ## arg); \
-+ } \
-+ } while (0)
-+
-+#define st_info(module, __fmt, arg...) \
-+ do { \
-+ if (stdbg_level > ST_WARN) { \
-+ if (stdbg_mask & module) \
-+ pr_err("[%s] info: " __fmt, \
-+ ST_MODULE2STRING(module), \
-+ ## arg); \
-+ } \
-+ } while (0)
-+
-+#define st_warn(module, __fmt, arg...) \
-+ do { \
-+ if (stdbg_level > ST_ERR) { \
-+ if (stdbg_mask & module) \
-+ pr_err("[%s] warn: " __fmt, \
-+ ST_MODULE2STRING(module), \
-+ ## arg); \
-+ } \
-+ } while (0)
-+
-+#define st_err(module, __fmt, arg...) \
-+ do { \
-+ if (stdbg_level > ST_NONE) { \
-+ if (stdbg_mask & module) \
-+ pr_err("[%s] error: " __fmt, \
-+ ST_MODULE2STRING(module), \
-+ ## arg); \
-+ } \
-+ } while (0)
-+
-+#define st_err_ratelimited(module, fmt, ...) \
-+ do { \
-+ static DEFINE_RATELIMIT_STATE(_rs, \
-+ DEFAULT_RATELIMIT_INTERVAL, \
-+ DEFAULT_RATELIMIT_BURST); \
-+ if (__ratelimit(&_rs) && (stdbg_level > ST_NONE)) { \
-+ if (stdbg_mask & module) \
-+ pr_err("[%s] error: " fmt, \
-+ ST_MODULE2STRING(module), \
-+ ##__VA_ARGS__); \
-+ } \
-+ } while (0)
-+
-+#define set_bits(p, v, b, m) (((p) & ~(m)) | ((v) << (b)))
-+
-+static inline u32 reg_read(void __iomem *base, u32 reg)
-+{
-+ return ioread32(base + reg);
-+}
-+
-+static inline void reg_write(void __iomem *base, u32 reg, u32 val)
-+{
-+ iowrite32(val, base + reg);
-+}
-+
-+static inline void reg_set_bit(void __iomem *base, u32 reg, u32 mask, u32 val)
-+{
-+ u32 value;
-+
-+ value = ioread32(base + reg) & ~mask;
-+ val &= mask;
-+ val |= value;
-+ iowrite32(val, base + reg);
-+}
-+
-+static inline void reg_set(void __iomem *base, u32 reg, u32 mask)
-+{
-+ iowrite32(ioread32(base + reg) | mask, base + reg);
-+}
-+
-+static inline void reg_clear(void __iomem *base, u32 reg, u32 mask)
-+{
-+ iowrite32(ioread32(base + reg) & ~mask, base + reg);
-+}
-+
-+static inline void reg_set_highest_bit(void __iomem *base, u32 reg)
-+{
-+ u32 val;
-+
-+ val = ioread32(base + reg);
-+ val &= ~(0x1 << 31);
-+ val |= (0x1 & 0x1) << 31;
-+ iowrite32(val, base + reg);
-+}
-+
-+static inline void reg_clr_highest_bit(void __iomem *base, u32 reg)
-+{
-+ u32 val;
-+
-+ val = ioread32(base + reg);
-+ val &= ~(0x1 << 31);
-+ val |= (0x0 & 0x1) << 31;
-+ iowrite32(val, base + reg);
-+}
-+
-+static inline void print_reg(unsigned int module, void __iomem *base, u32 reg)
-+{
-+ //st_debug(module, "REG 0x%x = 0x%x\n",
-+ // base + reg, ioread32(base + reg));
-+}
-+
-+#endif /* STF_COMMON_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_csi.c
-@@ -0,0 +1,465 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+
-+static const struct csi_format csi_formats_sink[] = {
-+ { MEDIA_BUS_FMT_UYVY8_2X8, 16},
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
-+};
-+
-+/* this bpp need see csi controllor */
-+static const struct csi_format csi_formats_src[] = {
-+ { MEDIA_BUS_FMT_AYUV8_1X32, 32},
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 16},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 16},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 16},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 16},
-+};
-+
-+static int csi_find_format(u32 code,
-+ const struct csi_format *formats,
-+ unsigned int nformats)
-+{
-+ int i;
-+
-+ for (i = 0; i < nformats; i++)
-+ if (formats[i].code == code)
-+ return i;
-+ return -EINVAL;
-+}
-+
-+int stf_csi_subdev_init(struct stfcamss *stfcamss)
-+{
-+ struct stf_csi_dev *csi_dev = stfcamss->csi_dev;
-+
-+ csi_dev->s_type = SENSOR_VIN;
-+ csi_dev->hw_ops = &csi_ops;
-+ csi_dev->stfcamss = stfcamss;
-+ csi_dev->formats_sink = csi_formats_sink;
-+ csi_dev->nformats_sink = ARRAY_SIZE(csi_formats_sink);
-+ csi_dev->formats_src = csi_formats_src;
-+ csi_dev->nformats_src = ARRAY_SIZE(csi_formats_src);
-+ mutex_init(&csi_dev->stream_lock);
-+ return 0;
-+}
-+
-+static int csi_set_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct stf_csi_dev *csi_dev = v4l2_get_subdevdata(sd);
-+
-+ csi_dev->hw_ops->csi_power_on(csi_dev, (u8)on);
-+ return 0;
-+}
-+
-+static struct v4l2_mbus_framefmt *
-+__csi_get_format(struct stf_csi_dev *csi_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_format(&csi_dev->subdev, state, pad);
-+
-+ return &csi_dev->fmt[pad];
-+}
-+
-+static u32 code_to_data_type(int code)
-+{
-+ switch (code) {
-+ case MEDIA_BUS_FMT_SRGGB10_1X10:
-+ case MEDIA_BUS_FMT_SGRBG10_1X10:
-+ case MEDIA_BUS_FMT_SGBRG10_1X10:
-+ case MEDIA_BUS_FMT_SBGGR10_1X10:
-+ return 0x2b;
-+ case MEDIA_BUS_FMT_UYVY8_2X8:
-+ return 0x1E;
-+ default:
-+ return 0x2b;
-+ }
-+}
-+
-+static int csi_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct stf_csi_dev *csi_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+ int ret = 0;
-+ u32 code, width, dt;
-+ u8 bpp;
-+
-+ format = __csi_get_format(csi_dev, NULL, STF_CSI_PAD_SINK,
-+ V4L2_SUBDEV_FORMAT_ACTIVE);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ width = format->width;
-+
-+ ret = csi_find_format(format->code,
-+ csi_dev->formats_sink,
-+ csi_dev->nformats_sink);
-+ if (ret < 0)
-+ return ret;
-+
-+ code = csi_dev->formats_sink[ret].code;
-+ bpp = csi_dev->formats_src[ret].bpp;
-+ dt = code_to_data_type(code);
-+
-+ mutex_lock(&csi_dev->stream_lock);
-+ if (enable) {
-+ if (csi_dev->stream_count == 0) {
-+ csi_dev->hw_ops->csi_clk_enable(csi_dev);
-+ csi_dev->hw_ops->csi_stream_set(csi_dev, enable, dt, width, bpp);
-+ }
-+ csi_dev->stream_count++;
-+ } else {
-+ if (csi_dev->stream_count == 0)
-+ goto exit;
-+ if (csi_dev->stream_count == 1) {
-+ csi_dev->hw_ops->csi_stream_set(csi_dev, enable, dt, width, bpp);
-+ csi_dev->hw_ops->csi_clk_disable(csi_dev);
-+ }
-+ csi_dev->stream_count--;
-+ }
-+exit:
-+ mutex_unlock(&csi_dev->stream_lock);
-+ return 0;
-+}
-+
-+static void csi_try_format(struct stf_csi_dev *csi_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ unsigned int i;
-+
-+ switch (pad) {
-+ case STF_CSI_PAD_SINK:
-+ /* Set format on sink pad */
-+
-+ for (i = 0; i < csi_dev->nformats_sink; i++)
-+ if (fmt->code == csi_dev->formats_sink[i].code)
-+ break;
-+
-+ if (i >= csi_dev->nformats_sink)
-+ fmt->code = csi_dev->formats_sink[0].code;
-+
-+ fmt->width = clamp_t(u32,
-+ fmt->width,
-+ STFCAMSS_FRAME_MIN_WIDTH,
-+ STFCAMSS_FRAME_MAX_WIDTH);
-+ fmt->height = clamp_t(u32,
-+ fmt->height,
-+ STFCAMSS_FRAME_MIN_HEIGHT,
-+ STFCAMSS_FRAME_MAX_HEIGHT);
-+
-+
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->flags = 0;
-+
-+ break;
-+
-+ case STF_CSI_PAD_SRC:
-+ /* Set format on src pad */
-+
-+ for (i = 0; i < csi_dev->nformats_src; i++)
-+ if (fmt->code == csi_dev->formats_src[i].code)
-+ break;
-+
-+ if (i >= csi_dev->nformats_src)
-+ fmt->code = csi_dev->formats_src[0].code;
-+
-+ fmt->width = clamp_t(u32,
-+ fmt->width,
-+ STFCAMSS_FRAME_MIN_WIDTH,
-+ STFCAMSS_FRAME_MAX_WIDTH);
-+ fmt->height = clamp_t(u32,
-+ fmt->height,
-+ STFCAMSS_FRAME_MIN_HEIGHT,
-+ STFCAMSS_FRAME_MAX_HEIGHT);
-+
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->flags = 0;
-+
-+ break;
-+ }
-+}
-+
-+static int csi_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ struct stf_csi_dev *csi_dev = v4l2_get_subdevdata(sd);
-+
-+ if (code->index >= csi_dev->nformats_sink)
-+ return -EINVAL;
-+ if (code->pad == STF_CSI_PAD_SINK) {
-+ code->code = csi_dev->formats_sink[code->index].code;
-+ } else {
-+ struct v4l2_mbus_framefmt *sink_fmt;
-+
-+ sink_fmt = __csi_get_format(csi_dev, state, STF_CSI_PAD_SINK,
-+ code->which);
-+
-+ code->code = sink_fmt->code;
-+ if (!code->code)
-+ return -EINVAL;
-+ }
-+ code->flags = 0;
-+
-+ return 0;
-+}
-+
-+static int csi_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ struct stf_csi_dev *csi_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt format;
-+
-+ if (fse->index != 0)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = 1;
-+ format.height = 1;
-+ csi_try_format(csi_dev, state, fse->pad, &format, fse->which);
-+ fse->min_width = format.width;
-+ fse->min_height = format.height;
-+
-+ if (format.code != fse->code)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = -1;
-+ format.height = -1;
-+ csi_try_format(csi_dev, state, fse->pad, &format, fse->which);
-+ fse->max_width = format.width;
-+ fse->max_height = format.height;
-+
-+ return 0;
-+}
-+
-+static int csi_get_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_csi_dev *csi_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ format = __csi_get_format(csi_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ fmt->format = *format;
-+
-+ return 0;
-+}
-+
-+static int csi_set_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_csi_dev *csi_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+ struct v4l2_mbus_framefmt *format_src;
-+ int ret;
-+
-+ format = __csi_get_format(csi_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&csi_dev->stream_lock);
-+ if (csi_dev->stream_count) {
-+ fmt->format = *format;
-+ mutex_unlock(&csi_dev->stream_lock);
-+ goto out;
-+ } else {
-+ csi_try_format(csi_dev, state, fmt->pad, &fmt->format, fmt->which);
-+ *format = fmt->format;
-+ }
-+ mutex_unlock(&csi_dev->stream_lock);
-+
-+ if (fmt->pad == STF_CSI_PAD_SINK) {
-+ format_src = __csi_get_format(csi_dev, state, STF_DVP_PAD_SRC,
-+ fmt->which);
-+
-+ ret = csi_find_format(format->code, csi_dev->formats_sink,
-+ csi_dev->nformats_sink);
-+ if (ret < 0)
-+ return ret;
-+
-+ format_src->code = csi_dev->formats_src[ret].code;
-+ csi_try_format(csi_dev, state, STF_DVP_PAD_SRC, format_src,
-+ fmt->which);
-+ }
-+out:
-+ return 0;
-+}
-+
-+static int csi_init_formats(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_subdev_format format = {
-+ .pad = STF_CSI_PAD_SINK,
-+ .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
-+ V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .format = {
-+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
-+ .width = 1920,
-+ .height = 1080
-+ }
-+ };
-+
-+ return csi_set_format(sd, fh ? fh->state : NULL, &format);
-+}
-+
-+static int csi_link_setup(struct media_entity *entity,
-+ const struct media_pad *local,
-+ const struct media_pad *remote, u32 flags)
-+{
-+ if ((local->flags & MEDIA_PAD_FL_SOURCE) &&
-+ (flags & MEDIA_LNK_FL_ENABLED)) {
-+ struct v4l2_subdev *sd;
-+ struct stf_csi_dev *csi_dev;
-+ struct vin_line *line;
-+
-+ if (media_pad_remote_pad_first(local))
-+ return -EBUSY;
-+
-+ sd = media_entity_to_v4l2_subdev(entity);
-+ csi_dev = v4l2_get_subdevdata(sd);
-+
-+ sd = media_entity_to_v4l2_subdev(remote->entity);
-+ line = v4l2_get_subdevdata(sd);
-+ if (line->sdev_type == VIN_DEV_TYPE)
-+ csi_dev->s_type = SENSOR_VIN;
-+ if (line->sdev_type == ISP_DEV_TYPE)
-+ csi_dev->s_type = SENSOR_ISP;
-+ st_info(ST_CSI, "CSI device sensor type: %d\n", csi_dev->s_type);
-+ }
-+
-+ if ((local->flags & MEDIA_PAD_FL_SINK) &&
-+ (flags & MEDIA_LNK_FL_ENABLED)) {
-+ struct v4l2_subdev *sd;
-+ struct stf_csi_dev *csi_dev;
-+ struct stf_csiphy_dev *csiphy_dev;
-+
-+ if (media_pad_remote_pad_first(local))
-+ return -EBUSY;
-+
-+ sd = media_entity_to_v4l2_subdev(entity);
-+ csi_dev = v4l2_get_subdevdata(sd);
-+
-+ sd = media_entity_to_v4l2_subdev(remote->entity);
-+ csiphy_dev = v4l2_get_subdevdata(sd);
-+
-+ st_info(ST_CSI, "CSI0 link to csiphy0\n");
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_core_ops csi_core_ops = {
-+ .s_power = csi_set_power,
-+};
-+
-+static const struct v4l2_subdev_video_ops csi_video_ops = {
-+ .s_stream = csi_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops csi_pad_ops = {
-+ .enum_mbus_code = csi_enum_mbus_code,
-+ .enum_frame_size = csi_enum_frame_size,
-+ .get_fmt = csi_get_format,
-+ .set_fmt = csi_set_format,
-+};
-+
-+static const struct v4l2_subdev_ops csi_v4l2_ops = {
-+ .core = &csi_core_ops,
-+ .video = &csi_video_ops,
-+ .pad = &csi_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops csi_v4l2_internal_ops = {
-+ .open = csi_init_formats,
-+};
-+
-+static const struct media_entity_operations csi_media_ops = {
-+ .link_setup = csi_link_setup,
-+ .link_validate = v4l2_subdev_link_validate,
-+};
-+
-+int stf_csi_register(struct stf_csi_dev *csi_dev, struct v4l2_device *v4l2_dev)
-+{
-+ struct v4l2_subdev *sd = &csi_dev->subdev;
-+ struct device *dev = csi_dev->stfcamss->dev;
-+ struct media_pad *pads = csi_dev->pads;
-+ int ret;
-+
-+ csi_dev->mipirx_1p8 = devm_regulator_get(dev, "mipirx_1p8");
-+ if (IS_ERR(csi_dev->mipirx_1p8))
-+ return PTR_ERR(csi_dev->mipirx_1p8);
-+
-+ csi_dev->mipirx_0p9 = devm_regulator_get(dev, "mipirx_0p9");
-+ if (IS_ERR(csi_dev->mipirx_0p9))
-+ return PTR_ERR(csi_dev->mipirx_0p9);
-+
-+ v4l2_subdev_init(sd, &csi_v4l2_ops);
-+ sd->internal_ops = &csi_v4l2_internal_ops;
-+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
-+ STF_CSI_NAME, 0);
-+ v4l2_set_subdevdata(sd, csi_dev);
-+
-+ ret = csi_init_formats(sd, NULL);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to init format: %d\n", ret);
-+ return ret;
-+ }
-+
-+ pads[STF_CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-+ pads[STF_CSI_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
-+
-+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
-+ sd->entity.ops = &csi_media_ops;
-+ ret = media_entity_pads_init(&sd->entity, STF_CSI_PADS_NUM, pads);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to init media entity: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to register subdev: %d\n", ret);
-+ goto err_sreg;
-+ }
-+
-+ return 0;
-+
-+err_sreg:
-+ media_entity_cleanup(&sd->entity);
-+ return ret;
-+}
-+
-+int stf_csi_unregister(struct stf_csi_dev *csi_dev)
-+{
-+ v4l2_device_unregister_subdev(&csi_dev->subdev);
-+ media_entity_cleanup(&csi_dev->subdev.entity);
-+ mutex_destroy(&csi_dev->stream_lock);
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_csi.h
-@@ -0,0 +1,61 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_CSI_H
-+#define STF_CSI_H
-+
-+#include <linux/regulator/consumer.h>
-+#include <media/v4l2-subdev.h>
-+#include <media/v4l2-device.h>
-+#include <media/media-entity.h>
-+#include <video/stf-vin.h>
-+
-+#define STF_CSI_NAME "stf_csi"
-+
-+#define STF_CSI_PAD_SINK 0
-+#define STF_CSI_PAD_SRC 1
-+#define STF_CSI_PADS_NUM 2
-+
-+struct csi_format {
-+ u32 code;
-+ u8 bpp;
-+};
-+
-+struct stf_csi_dev;
-+
-+struct csi_hw_ops {
-+ int (*csi_power_on)(struct stf_csi_dev *csi_dev, u8 on);
-+ int (*csi_clk_enable)(struct stf_csi_dev *csi_dev);
-+ int (*csi_clk_disable)(struct stf_csi_dev *csi_dev);
-+ int (*csi_stream_set)(struct stf_csi_dev *csi_dev, int on,
-+ u32 dt, u32 width, u8 bpp);
-+};
-+
-+struct stf_csi_dev {
-+ struct stfcamss *stfcamss;
-+ enum sensor_type s_type;
-+ struct v4l2_subdev subdev;
-+ struct media_pad pads[STF_CSI_PADS_NUM];
-+ struct v4l2_mbus_framefmt fmt[STF_CSI_PADS_NUM];
-+ const struct csi_format *formats_sink;
-+ unsigned int nformats_sink;
-+ const struct csi_format *formats_src;
-+ unsigned int nformats_src;
-+ struct csi_hw_ops *hw_ops;
-+ struct mutex stream_lock;
-+ int stream_count;
-+ struct regulator *mipirx_1p8;
-+ struct regulator *mipirx_0p9;
-+};
-+
-+extern int stf_csi_subdev_init(struct stfcamss *stfcamss);
-+extern int stf_csi_register(struct stf_csi_dev *csi_dev,
-+ struct v4l2_device *v4l2_dev);
-+extern int stf_csi_unregister(struct stf_csi_dev *csi_dev);
-+extern struct csi_hw_ops csi_ops;
-+extern void dump_csi_reg(void *__iomem csibase);
-+
-+#endif /* STF_CSI_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_csi_hw_ops.c
-@@ -0,0 +1,310 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <linux/regmap.h>
-+
-+#define CSI2RX_DEVICE_CFG_REG 0x000
-+
-+#define CSI2RX_SOFT_RESET_REG 0x004
-+#define CSI2RX_SOFT_RESET_PROTOCOL BIT(1)
-+#define CSI2RX_SOFT_RESET_FRONT BIT(0)
-+
-+#define CSI2RX_DPHY_LANE_CONTROL 0x040
-+
-+#define CSI2RX_STATIC_CFG_REG 0x008
-+#define CSI2RX_STATIC_CFG_DLANE_MAP(llane, plane) \
-+ ((plane) << (16 + (llane) * 4))
-+#define CSI2RX_STATIC_CFG_LANES_MASK GENMASK(11, 8)
-+
-+#define CSI2RX_STREAM_BASE(n) (((n) + 1) * 0x100)
-+
-+#define CSI2RX_STREAM_CTRL_REG(n) (CSI2RX_STREAM_BASE(n) + 0x000)
-+#define CSI2RX_STREAM_CTRL_START BIT(0)
-+
-+#define CSI2RX_STREAM_DATA_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x008)
-+#define CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT BIT(31)
-+#define CSI2RX_STREAM_DATA_CFG_EN_DATA_TYPE_0 BIT(7)
-+#define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16)
-+
-+#define CSI2RX_STREAM_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x00c)
-+#define CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF (1 << 8)
-+
-+#define CSI2RX_LANES_MAX 4
-+#define CSI2RX_STREAMS_MAX 4
-+
-+static int stf_csi_power_on(struct stf_csi_dev *csi_dev, u8 on)
-+{
-+ struct stfcamss *stfcamss = csi_dev->stfcamss;
-+ int ret;
-+
-+ if (on) {
-+ ret = regulator_enable(csi_dev->mipirx_1p8);
-+ if (ret) {
-+ st_err(ST_CSI, "Cannot enable mipirx_1p8 regulator\n");
-+ goto err_1p8;
-+ }
-+
-+ ret = regulator_enable(csi_dev->mipirx_0p9);
-+ if (ret) {
-+ st_err(ST_CSI, "Cannot enable mipirx_0p9 regulator\n");
-+ goto err_0p9;
-+ }
-+ } else {
-+ regulator_disable(csi_dev->mipirx_1p8);
-+ regulator_disable(csi_dev->mipirx_0p9);
-+ }
-+
-+ regmap_update_bits(stfcamss->stf_aon_syscon, stfcamss->aon_gp_reg,
-+ BIT(31), BIT(31));
-+
-+ return 0;
-+
-+err_0p9:
-+ regulator_disable(csi_dev->mipirx_1p8);
-+err_1p8:
-+ return ret;
-+
-+}
-+
-+static int stf_csi_clk_enable(struct stf_csi_dev *csi_dev)
-+{
-+ struct stfcamss *stfcamss = csi_dev->stfcamss;
-+
-+ clk_set_rate(stfcamss->sys_clk[STFCLK_MIPI_RX0_PXL].clk, 198000000);
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF0].clk);
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF1].clk);
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF2].clk);
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF3].clk);
-+
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF0].rstc);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF1].rstc);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF2].rstc);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF3].rstc);
-+
-+ switch (csi_dev->s_type) {
-+ case SENSOR_VIN:
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_AXIWR].rstc);
-+ clk_set_parent(stfcamss->sys_clk[STFCLK_AXIWR].clk,
-+ stfcamss->sys_clk[STFCLK_MIPI_RX0_PXL].clk);
-+ break;
-+ case SENSOR_ISP:
-+ clk_set_parent(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk,
-+ stfcamss->sys_clk[STFCLK_MIPI_RX0_PXL].clk);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int stf_csi_clk_disable(struct stf_csi_dev *csi_dev)
-+{
-+ struct stfcamss *stfcamss = csi_dev->stfcamss;
-+
-+ switch (csi_dev->s_type) {
-+ case SENSOR_VIN:
-+ reset_control_assert(stfcamss->sys_rst[STFRST_AXIWR].rstc);
-+ break;
-+ case SENSOR_ISP:
-+ break;
-+ }
-+
-+ reset_control_assert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF3].rstc);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF2].rstc);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF1].rstc);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_PIXEL_CLK_IF0].rstc);
-+
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF3].clk);
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF2].clk);
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF1].clk);
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_PIXEL_CLK_IF0].clk);
-+
-+ return 0;
-+}
-+
-+static void csi2rx_reset(void *reg_base)
-+{
-+ writel(CSI2RX_SOFT_RESET_PROTOCOL | CSI2RX_SOFT_RESET_FRONT,
-+ reg_base + CSI2RX_SOFT_RESET_REG);
-+
-+ udelay(10);
-+
-+ writel(0, reg_base + CSI2RX_SOFT_RESET_REG);
-+}
-+
-+static int csi2rx_start(struct stf_csi_dev *csi_dev, void *reg_base, u32 dt)
-+{
-+ struct stfcamss *stfcamss = csi_dev->stfcamss;
-+ struct csi2phy_cfg *csiphy =
-+ stfcamss->csiphy_dev->csiphy;
-+ unsigned int i;
-+ unsigned long lanes_used = 0;
-+ u32 reg;
-+
-+ if (!csiphy) {
-+ st_err(ST_CSI, "csiphy0 config not exist\n");
-+ return -EINVAL;
-+ }
-+
-+ csi2rx_reset(reg_base);
-+
-+ reg = csiphy->num_data_lanes << 8;
-+ for (i = 0; i < csiphy->num_data_lanes; i++) {
-+#ifndef USE_CSIDPHY_ONE_CLK_MODE
-+ reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, csiphy->data_lanes[i]);
-+ set_bit(csiphy->data_lanes[i] - 1, &lanes_used);
-+#else
-+ reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, i + 1);
-+ set_bit(i, &lanes_used);
-+#endif
-+ }
-+
-+ /*
-+ * Even the unused lanes need to be mapped. In order to avoid
-+ * to map twice to the same physical lane, keep the lanes used
-+ * in the previous loop, and only map unused physical lanes to
-+ * the rest of our logical lanes.
-+ */
-+ for (i = csiphy->num_data_lanes; i < CSI2RX_LANES_MAX; i++) {
-+ unsigned int idx = find_first_zero_bit(&lanes_used,
-+ CSI2RX_LANES_MAX);
-+
-+ set_bit(idx, &lanes_used);
-+ reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, idx + 1);
-+ }
-+
-+ writel(reg, reg_base + CSI2RX_STATIC_CFG_REG);
-+
-+ // 0x40 DPHY_LANE_CONTROL
-+ reg = 0;
-+#ifndef USE_CSIDPHY_ONE_CLK_MODE
-+ for (i = 0; i < csiphy->num_data_lanes; i++)
-+ reg |= 1 << (csiphy->data_lanes[i] - 1)
-+ | 1 << (csiphy->data_lanes[i] + 11);
-+#else
-+ for (i = 0; i < csiphy->num_data_lanes; i++)
-+ reg |= 1 << i | 1 << (i + 12); //data_clane
-+#endif
-+
-+ reg |= 1 << 4 | 1 << 16; //clk_lane
-+ writel(reg, reg_base + CSI2RX_DPHY_LANE_CONTROL);
-+
-+ /*
-+ * Create a static mapping between the CSI virtual channels
-+ * and the output stream.
-+ *
-+ * This should be enhanced, but v4l2 lacks the support for
-+ * changing that mapping dynamically.
-+ *
-+ * We also cannot enable and disable independent streams here,
-+ * hence the reference counting.
-+ */
-+ for (i = 0; i < CSI2RX_STREAMS_MAX; i++) {
-+ writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF,
-+ reg_base + CSI2RX_STREAM_CFG_REG(i));
-+
-+ writel(CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT |
-+ CSI2RX_STREAM_DATA_CFG_VC_SELECT(i) |
-+ CSI2RX_STREAM_DATA_CFG_EN_DATA_TYPE_0 | dt,
-+ reg_base + CSI2RX_STREAM_DATA_CFG_REG(i));
-+
-+ writel(CSI2RX_STREAM_CTRL_START,
-+ reg_base + CSI2RX_STREAM_CTRL_REG(i));
-+ }
-+
-+ return 0;
-+}
-+
-+static void csi2rx_stop(struct stf_csi_dev *csi_dev, void *reg_base)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < CSI2RX_STREAMS_MAX; i++)
-+ writel(0, reg_base + CSI2RX_STREAM_CTRL_REG(i));
-+}
-+
-+static void csi_set_vin_axiwr_pix(struct stf_csi_dev *csi_dev, u32 width, u8 bpp)
-+{
-+ struct stf_vin_dev *vin = csi_dev->stfcamss->vin;
-+ u32 value = 0;
-+ int cnfg_axiwr_pix_ct = 64 / bpp;
-+
-+ if (cnfg_axiwr_pix_ct == 2)
-+ value = 0;
-+ else if (cnfg_axiwr_pix_ct == 4)
-+ value = 1;
-+ else if (cnfg_axiwr_pix_ct == 8)
-+ value = 2;
-+
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ BIT(14)|BIT(13), value << 13); //u0_vin_cnfg_axiwr0_pix_ct
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ BIT(12)|BIT(11)|BIT(10)|BIT(9)|BIT(8)|BIT(7)|BIT(6)|BIT(5)|BIT(4)|BIT(3)|BIT(2),
-+ (width / cnfg_axiwr_pix_ct - 1)<<2); //u0_vin_cnfg_axiwr0_pix_cnt_end
-+}
-+
-+static int stf_csi_stream_set(struct stf_csi_dev *csi_dev,
-+ int on, u32 dt, u32 width, u8 bpp)
-+{
-+ struct stf_vin_dev *vin = csi_dev->stfcamss->vin;
-+ void __iomem *reg_base = vin->csi2rx_base;
-+
-+ switch (csi_dev->s_type) {
-+ case SENSOR_VIN:
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_20,
-+ BIT(3)|BIT(2)|BIT(1)|BIT(0),
-+ 0<<0); //u0_vin_cnfg_axiwr0_channel_sel
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ BIT(16)|BIT(15),
-+ 0<<15); //u0_vin_cnfg_axiwr0_pixel_high_bit_sel
-+ csi_set_vin_axiwr_pix(csi_dev, width, bpp);
-+ break;
-+ case SENSOR_ISP:
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ BIT(7)|BIT(6),
-+ 0<<6); //u0_vin_cnfg_mipi_byte_en_isp
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ BIT(11)|BIT(10)|BIT(9)|BIT(8),
-+ 0<<8); //u0_vin_cnfg_mipi_channel_sel0
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ BIT(16)|BIT(15)|BIT(14)|BIT(13),
-+ 0<<13); //u0_vin_cnfg_pix_num
-+
-+ if (dt == 0x2b)
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ BIT(12),
-+ 1<<12); //u0_vin_cnfg_p_i_mipi_header_en0
-+ break;
-+ }
-+
-+ if (on)
-+ csi2rx_start(csi_dev, reg_base, dt);
-+ else
-+ csi2rx_stop(csi_dev, reg_base);
-+
-+ return 0;
-+}
-+
-+void dump_csi_reg(void *__iomem csibase)
-+{
-+ st_info(ST_CSI, "DUMP CSI register:\n");
-+ print_reg(ST_CSI, csibase, 0x00);
-+ print_reg(ST_CSI, csibase, 0x04);
-+ print_reg(ST_CSI, csibase, 0x08);
-+ print_reg(ST_CSI, csibase, 0x10);
-+
-+ print_reg(ST_CSI, csibase, 0x40);
-+ print_reg(ST_CSI, csibase, 0x48);
-+ print_reg(ST_CSI, csibase, 0x4c);
-+ print_reg(ST_CSI, csibase, 0x50);
-+}
-+
-+struct csi_hw_ops csi_ops = {
-+ .csi_power_on = stf_csi_power_on,
-+ .csi_clk_enable = stf_csi_clk_enable,
-+ .csi_clk_disable = stf_csi_clk_disable,
-+ .csi_stream_set = stf_csi_stream_set,
-+};
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_csiphy.c
-@@ -0,0 +1,357 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+
-+static const struct csiphy_format csiphy_formats_st7110[] = {
-+ { MEDIA_BUS_FMT_UYVY8_2X8, 16},
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
-+};
-+
-+int stf_csiphy_subdev_init(struct stfcamss *stfcamss)
-+{
-+ struct stf_csiphy_dev *csiphy_dev = stfcamss->csiphy_dev;
-+
-+ csiphy_dev->hw_ops = &csiphy_ops;
-+ csiphy_dev->stfcamss = stfcamss;
-+ csiphy_dev->formats = csiphy_formats_st7110;
-+ csiphy_dev->nformats = ARRAY_SIZE(csiphy_formats_st7110);
-+ mutex_init(&csiphy_dev->stream_lock);
-+ return 0;
-+}
-+
-+static int csiphy_set_power(struct v4l2_subdev *sd, int on)
-+{
-+ return 0;
-+}
-+
-+static int csiphy_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct stf_csiphy_dev *csiphy_dev = v4l2_get_subdevdata(sd);
-+
-+ mutex_lock(&csiphy_dev->stream_lock);
-+ if (enable) {
-+ if (csiphy_dev->stream_count == 0) {
-+ csiphy_dev->hw_ops->csiphy_clk_enable(csiphy_dev);
-+ csiphy_dev->hw_ops->csiphy_config_set(csiphy_dev);
-+ csiphy_dev->hw_ops->csiphy_stream_set(csiphy_dev, 1);
-+ }
-+ csiphy_dev->stream_count++;
-+ } else {
-+ if (csiphy_dev->stream_count == 0)
-+ goto exit;
-+ if (csiphy_dev->stream_count == 1) {
-+ csiphy_dev->hw_ops->csiphy_clk_disable(csiphy_dev);
-+ csiphy_dev->hw_ops->csiphy_stream_set(csiphy_dev, 0);
-+ }
-+ csiphy_dev->stream_count--;
-+ }
-+exit:
-+ mutex_unlock(&csiphy_dev->stream_lock);
-+
-+ return 0;
-+}
-+
-+static struct v4l2_mbus_framefmt *
-+__csiphy_get_format(struct stf_csiphy_dev *csiphy_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_format(
-+ &csiphy_dev->subdev,
-+ state,
-+ pad);
-+
-+ return &csiphy_dev->fmt[pad];
-+}
-+
-+static void csiphy_try_format(struct stf_csiphy_dev *csiphy_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ unsigned int i;
-+
-+ switch (pad) {
-+ case STF_CSIPHY_PAD_SINK:
-+ /* Set format on sink pad */
-+
-+ for (i = 0; i < csiphy_dev->nformats; i++)
-+ if (fmt->code == csiphy_dev->formats[i].code)
-+ break;
-+
-+ if (i >= csiphy_dev->nformats)
-+ fmt->code = csiphy_dev->formats[0].code;
-+
-+ fmt->width = clamp_t(u32,
-+ fmt->width,
-+ STFCAMSS_FRAME_MIN_WIDTH,
-+ STFCAMSS_FRAME_MAX_WIDTH);
-+ fmt->height = clamp_t(u32,
-+ fmt->height,
-+ STFCAMSS_FRAME_MIN_HEIGHT,
-+ STFCAMSS_FRAME_MAX_HEIGHT);
-+
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->flags = 0;
-+
-+ break;
-+
-+ case STF_CSIPHY_PAD_SRC:
-+
-+ *fmt = *__csiphy_get_format(csiphy_dev,
-+ state,
-+ STF_CSIPHY_PAD_SINK, which);
-+
-+ break;
-+ }
-+}
-+
-+static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ struct stf_csiphy_dev *csiphy_dev = v4l2_get_subdevdata(sd);
-+
-+ if (code->index >= csiphy_dev->nformats)
-+ return -EINVAL;
-+
-+ if (code->pad == STF_CSIPHY_PAD_SINK) {
-+ code->code = csiphy_dev->formats[code->index].code;
-+ } else {
-+ struct v4l2_mbus_framefmt *sink_fmt;
-+
-+ sink_fmt = __csiphy_get_format(csiphy_dev, state,
-+ STF_CSIPHY_PAD_SINK,
-+ code->which);
-+
-+ code->code = sink_fmt->code;
-+ if (!code->code)
-+ return -EINVAL;
-+ }
-+ code->flags = 0;
-+ return 0;
-+}
-+
-+static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ struct stf_csiphy_dev *csiphy_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt format;
-+
-+ if (fse->index != 0)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = 1;
-+ format.height = 1;
-+ csiphy_try_format(csiphy_dev, state, fse->pad, &format, fse->which);
-+ fse->min_width = format.width;
-+ fse->min_height = format.height;
-+
-+ if (format.code != fse->code)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = -1;
-+ format.height = -1;
-+ csiphy_try_format(csiphy_dev, state, fse->pad, &format, fse->which);
-+ fse->max_width = format.width;
-+ fse->max_height = format.height;
-+
-+ return 0;
-+}
-+
-+static int csiphy_get_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_csiphy_dev *csiphy_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ format = __csiphy_get_format(csiphy_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ fmt->format = *format;
-+
-+ return 0;
-+}
-+
-+static int csiphy_set_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_csiphy_dev *csiphy_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ format = __csiphy_get_format(csiphy_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&csiphy_dev->stream_lock);
-+ if (csiphy_dev->stream_count) {
-+ fmt->format = *format;
-+ mutex_unlock(&csiphy_dev->stream_lock);
-+ goto out;
-+ } else {
-+ csiphy_try_format(csiphy_dev, state, fmt->pad, &fmt->format, fmt->which);
-+ *format = fmt->format;
-+ }
-+ mutex_unlock(&csiphy_dev->stream_lock);
-+
-+ /* Propagate the format from sink to source */
-+ if (fmt->pad == STF_CSIPHY_PAD_SINK) {
-+ format = __csiphy_get_format(csiphy_dev,
-+ state,
-+ STF_CSIPHY_PAD_SRC,
-+ fmt->which);
-+
-+ *format = fmt->format;
-+ csiphy_try_format(csiphy_dev, state, STF_CSIPHY_PAD_SRC, format,
-+ fmt->which);
-+ }
-+out:
-+ return 0;
-+}
-+
-+static int csiphy_init_formats(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_subdev_format format = {
-+ .pad = STF_CSIPHY_PAD_SINK,
-+ .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
-+ V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .format = {
-+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
-+ .width = 1920,
-+ .height = 1080
-+ }
-+ };
-+
-+ return csiphy_set_format(sd, fh ? fh->state : NULL, &format);
-+}
-+
-+static int csiphy_link_setup(struct media_entity *entity,
-+ const struct media_pad *local,
-+ const struct media_pad *remote, u32 flags)
-+{
-+ if ((local->flags & MEDIA_PAD_FL_SOURCE) &&
-+ (flags & MEDIA_LNK_FL_ENABLED)) {
-+ struct v4l2_subdev *sd;
-+ struct stf_csiphy_dev *csiphy_dev;
-+ struct stf_csi_dev *csi_dev;
-+
-+ if (media_pad_remote_pad_first(local))
-+ return -EBUSY;
-+
-+ sd = media_entity_to_v4l2_subdev(entity);
-+ csiphy_dev = v4l2_get_subdevdata(sd);
-+
-+ sd = media_entity_to_v4l2_subdev(remote->entity);
-+ csi_dev = v4l2_get_subdevdata(sd);
-+ st_info(ST_CSIPHY, "CSIPHY0 link to CSI0\n");
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_core_ops csiphy_core_ops = {
-+ .s_power = csiphy_set_power,
-+};
-+
-+static const struct v4l2_subdev_video_ops csiphy_video_ops = {
-+ .s_stream = csiphy_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops csiphy_pad_ops = {
-+ .enum_mbus_code = csiphy_enum_mbus_code,
-+ .enum_frame_size = csiphy_enum_frame_size,
-+ .get_fmt = csiphy_get_format,
-+ .set_fmt = csiphy_set_format,
-+};
-+
-+static const struct v4l2_subdev_ops csiphy_v4l2_ops = {
-+ .core = &csiphy_core_ops,
-+ .video = &csiphy_video_ops,
-+ .pad = &csiphy_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops csiphy_v4l2_internal_ops = {
-+ .open = csiphy_init_formats,
-+};
-+
-+static const struct media_entity_operations csiphy_media_ops = {
-+ .link_setup = csiphy_link_setup,
-+ .link_validate = v4l2_subdev_link_validate,
-+};
-+
-+int stf_csiphy_register(struct stf_csiphy_dev *csiphy_dev,
-+ struct v4l2_device *v4l2_dev)
-+{
-+ struct v4l2_subdev *sd = &csiphy_dev->subdev;
-+ struct device *dev = csiphy_dev->stfcamss->dev;
-+ struct media_pad *pads = csiphy_dev->pads;
-+ int ret;
-+
-+ v4l2_subdev_init(sd, &csiphy_v4l2_ops);
-+ sd->internal_ops = &csiphy_v4l2_internal_ops;
-+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
-+ STF_CSIPHY_NAME, 0);
-+ v4l2_set_subdevdata(sd, csiphy_dev);
-+
-+ ret = csiphy_init_formats(sd, NULL);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to init format: %d\n", ret);
-+ return ret;
-+ }
-+
-+ pads[STF_CSIPHY_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-+ pads[STF_CSIPHY_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
-+
-+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
-+ sd->entity.ops = &csiphy_media_ops;
-+ ret = media_entity_pads_init(&sd->entity, STF_CSIPHY_PADS_NUM, pads);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to init media entity: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
-+ if (ret < 0) {
-+ dev_err(dev, "Failed to register subdev: %d\n", ret);
-+ goto err_sreg;
-+ }
-+
-+ return 0;
-+
-+err_sreg:
-+ media_entity_cleanup(&sd->entity);
-+ return ret;
-+}
-+
-+int stf_csiphy_unregister(struct stf_csiphy_dev *csiphy_dev)
-+{
-+ v4l2_device_unregister_subdev(&csiphy_dev->subdev);
-+ media_entity_cleanup(&csiphy_dev->subdev.entity);
-+ mutex_destroy(&csiphy_dev->stream_lock);
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_csiphy.h
-@@ -0,0 +1,188 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_CSIPHY_H
-+#define STF_CSIPHY_H
-+
-+#include <media/v4l2-subdev.h>
-+#include <media/v4l2-device.h>
-+#include <media/media-entity.h>
-+#include <video/stf-vin.h>
-+
-+#define STF_CSIPHY_NAME "stf_csiphy"
-+
-+#define STF_CSIPHY_PAD_SINK 0
-+#define STF_CSIPHY_PAD_SRC 1
-+#define STF_CSIPHY_PADS_NUM 2
-+
-+#define STF_CSI2_MAX_DATA_LANES 4
-+
-+union static_config {
-+ u32 raw;
-+ struct {
-+ u32 sel : 2;
-+ u32 rsvd_6 : 2;
-+ u32 v2p0_support_enable : 1;
-+ u32 rsvd_5 : 3;
-+ u32 lane_nb : 3;
-+ u32 rsvd_4 : 5;
-+ u32 dl0_map : 3;
-+ u32 rsvd_3 : 1;
-+ u32 dl1_map : 3;
-+ u32 rsvd_2 : 1;
-+ u32 dl2_map : 3;
-+ u32 rsvd_1 : 1;
-+ u32 dl3_map : 3;
-+ u32 rsvd_0 : 1;
-+ } bits;
-+};
-+
-+union error_bypass_cfg {
-+ u32 value;
-+ struct {
-+ u32 crc : 1;
-+ u32 ecc : 1;
-+ u32 data_id : 1;
-+ u32 rsvd_0 : 29;
-+ };
-+};
-+
-+union stream_monitor_ctrl {
-+ u32 value;
-+ struct {
-+ u32 lb_vc : 4;
-+ u32 lb_en : 1;
-+ u32 timer_vc : 4;
-+ u32 timer_en : 1;
-+ u32 timer_eof : 1;
-+ u32 frame_mon_vc : 4;
-+ u32 frame_mon_en : 1;
-+ u32 frame_length : 16;
-+ };
-+};
-+
-+union stream_cfg {
-+ u32 value;
-+ struct {
-+ u32 interface_mode : 1;
-+ u32 ls_le_mode : 1;
-+ u32 rsvd_3 : 2;
-+ u32 num_pixels : 2;
-+ u32 rsvd_2 : 2;
-+ u32 fifo_mode : 2;
-+ u32 rsvd_1 : 2;
-+ u32 bpp_bypass : 3;
-+ u32 rsvd_0 : 1;
-+ u32 fifo_fill : 16;
-+ };
-+};
-+
-+union dphy_lane_ctrl {
-+ u32 raw;
-+ struct {
-+ u32 dl0_en : 1;
-+ u32 dl1_en : 1;
-+ u32 dl2_en : 1;
-+ u32 dl3_en : 1;
-+ u32 cl_en : 1;
-+ u32 rsvd_1 : 7;
-+ u32 dl0_reset : 1;
-+ u32 dl1_reset : 1;
-+ u32 dl2_reset : 1;
-+ u32 dl3_reset : 1;
-+ u32 cl_reset : 1;
-+ u32 rsvd_0 : 15;
-+ } bits;
-+};
-+
-+union dphy_lane_swap {
-+ u32 raw;
-+ struct {
-+ u32 rx_1c2c_sel : 1;
-+ u32 lane_swap_clk : 3;
-+ u32 lane_swap_clk1 : 3;
-+ u32 lane_swap_lan0 : 3;
-+ u32 lane_swap_lan1 : 3;
-+ u32 lane_swap_lan2 : 3;
-+ u32 lane_swap_lan3 : 3;
-+ u32 dpdn_swap_clk : 1;
-+ u32 dpdn_swap_clk1 : 1;
-+ u32 dpdn_swap_lan0 : 1;
-+ u32 dpdn_swap_lan1 : 1;
-+ u32 dpdn_swap_lan2 : 1;
-+ u32 dpdn_swap_lan3 : 1;
-+ u32 hs_freq_chang_clk0 : 1;
-+ u32 hs_freq_chang_clk1 : 1;
-+ u32 reserved : 5;
-+ } bits;
-+};
-+
-+union dphy_lane_en {
-+ u32 raw;
-+ struct {
-+ u32 gpio_en : 6;
-+ u32 mp_test_mode_sel : 5;
-+ u32 mp_test_en : 1;
-+ u32 dphy_enable_lan0 : 1;
-+ u32 dphy_enable_lan1 : 1;
-+ u32 dphy_enable_lan2 : 1;
-+ u32 dphy_enable_lan3 : 1;
-+ u32 rsvd_0 : 16;
-+ } bits;
-+};
-+
-+struct csiphy_format {
-+ u32 code;
-+ u8 bpp;
-+};
-+
-+struct csi2phy_cfg {
-+ unsigned int flags;
-+ unsigned char data_lanes[STF_CSI2_MAX_DATA_LANES];
-+ unsigned char clock_lane;
-+ unsigned char num_data_lanes;
-+ bool lane_polarities[1 + STF_CSI2_MAX_DATA_LANES];
-+};
-+
-+struct csi2phy_cfg2 {
-+ unsigned char data_lanes[STF_CSI2_MAX_DATA_LANES];
-+ unsigned char num_data_lanes;
-+ unsigned char num_clks;
-+ unsigned char clock_lane;
-+ unsigned char clock1_lane;
-+ bool lane_polarities[2 + STF_CSI2_MAX_DATA_LANES];
-+};
-+
-+struct stf_csiphy_dev;
-+
-+struct csiphy_hw_ops {
-+ int (*csiphy_clk_enable)(struct stf_csiphy_dev *csiphy_dev);
-+ int (*csiphy_clk_disable)(struct stf_csiphy_dev *csiphy_dev);
-+ int (*csiphy_config_set)(struct stf_csiphy_dev *csiphy_dev);
-+ int (*csiphy_stream_set)(struct stf_csiphy_dev *csiphy_dev, int on);
-+};
-+
-+struct stf_csiphy_dev {
-+ struct stfcamss *stfcamss;
-+ struct csi2phy_cfg *csiphy;
-+ struct v4l2_subdev subdev;
-+ struct media_pad pads[STF_CSIPHY_PADS_NUM];
-+ struct v4l2_mbus_framefmt fmt[STF_CSIPHY_PADS_NUM];
-+ const struct csiphy_format *formats;
-+ unsigned int nformats;
-+ struct csiphy_hw_ops *hw_ops;
-+ struct mutex stream_lock;
-+ int stream_count;
-+};
-+
-+extern int stf_csiphy_subdev_init(struct stfcamss *stfcamss);
-+extern int stf_csiphy_register(struct stf_csiphy_dev *csiphy_dev,
-+ struct v4l2_device *v4l2_dev);
-+extern int stf_csiphy_unregister(struct stf_csiphy_dev *csiphy_dev);
-+
-+extern struct csiphy_hw_ops csiphy_ops;
-+
-+#endif /* STF_CSIPHY_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_csiphy_hw_ops.c
-@@ -0,0 +1,335 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <linux/sort.h>
-+
-+static int stf_csiphy_clk_set(struct stf_csiphy_dev *csiphy_dev, int on)
-+{
-+ struct stfcamss *stfcamss = csiphy_dev->stfcamss;
-+ static int init_flag;
-+ static struct mutex count_lock;
-+ static int count;
-+
-+ if (!init_flag) {
-+ init_flag = 1;
-+ mutex_init(&count_lock);
-+ }
-+ mutex_lock(&count_lock);
-+ if (on) {
-+ clk_set_rate(stfcamss->sys_clk[STFCLK_M31DPHY_CFGCLK_IN].clk,
-+ 99000000);
-+ clk_set_rate(stfcamss->sys_clk[STFCLK_M31DPHY_REFCLK_IN].clk,
-+ 49500000);
-+ clk_set_rate(stfcamss->sys_clk[STFCLK_M31DPHY_TXCLKESC_LAN0].clk,
-+ 19800000);
-+
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_M31DPHY_HW].rstc);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_M31DPHY_B09_ALWAYS_ON].rstc);
-+
-+ count++;
-+ } else {
-+ if (count == 0)
-+ goto exit;
-+ if (count == 1) {
-+ reset_control_assert(stfcamss->sys_rst[STFRST_M31DPHY_HW].rstc);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_M31DPHY_B09_ALWAYS_ON].rstc);
-+ }
-+ count--;
-+ }
-+exit:
-+ mutex_unlock(&count_lock);
-+ return 0;
-+}
-+
-+static int stf_csiphy_clk_enable(struct stf_csiphy_dev *csiphy_dev)
-+{
-+ return stf_csiphy_clk_set(csiphy_dev, 1);
-+}
-+
-+static int stf_csiphy_clk_disable(struct stf_csiphy_dev *csiphy_dev)
-+{
-+ return stf_csiphy_clk_set(csiphy_dev, 0);
-+}
-+
-+#ifndef USE_CSIDPHY_ONE_CLK_MODE
-+static int cmp_func(const void *x1, const void *x2)
-+{
-+ return *((unsigned char *)x1) - *((unsigned char *)x2);
-+}
-+#endif
-+
-+int try_cfg(struct csi2phy_cfg2 *cfg, struct csi2phy_cfg *cfg0,
-+ struct csi2phy_cfg *cfg1)
-+{
-+ int i = 0;
-+
-+ cfg->clock_lane = 0;
-+ cfg->clock1_lane = 5;
-+ cfg->data_lanes[0] = 1;
-+ cfg->data_lanes[1] = 2;
-+ cfg->data_lanes[2] = 3;
-+ cfg->data_lanes[3] = 4;
-+
-+ if (cfg0 && cfg1) {
-+ st_debug(ST_CSIPHY, "CSIPHY use 2 clk mode\n");
-+ cfg->num_clks = 2;
-+ cfg->num_data_lanes =
-+ cfg1->num_data_lanes + cfg0->num_data_lanes;
-+ if (cfg->num_data_lanes > STF_CSI2_MAX_DATA_LANES)
-+ return -EINVAL;
-+ cfg->clock_lane = cfg0->clock_lane;
-+ cfg->lane_polarities[0] = cfg0->lane_polarities[0];
-+ cfg->clock1_lane = cfg1->clock_lane;
-+ cfg->lane_polarities[1] = cfg1->lane_polarities[0];
-+ for (i = 0; i < cfg0->num_data_lanes; i++) {
-+ cfg->data_lanes[i] = cfg0->data_lanes[i];
-+ cfg->lane_polarities[i + 2] =
-+ cfg0->lane_polarities[i + 1];
-+ }
-+
-+ for (i = cfg0->num_data_lanes; i < cfg->num_data_lanes; i++) {
-+ cfg->data_lanes[i] =
-+ cfg1->data_lanes[i - cfg0->num_data_lanes];
-+ cfg->lane_polarities[i + 2] =
-+ cfg1->lane_polarities[i - cfg0->num_data_lanes + 1];
-+ }
-+ } else if (cfg0 && !cfg1) {
-+ st_debug(ST_CSIPHY, "CSIPHY cfg0 use 1 clk mode\n");
-+ cfg->num_clks = 1;
-+ cfg->num_data_lanes = cfg0->num_data_lanes;
-+ cfg->clock_lane = cfg->clock1_lane = cfg0->clock_lane;
-+ cfg->lane_polarities[0] = cfg->lane_polarities[1] =
-+ cfg0->lane_polarities[0];
-+ for (i = 0; i < cfg0->num_data_lanes; i++) {
-+ cfg->data_lanes[i] = cfg0->data_lanes[i];
-+ cfg->lane_polarities[i + 2] = cfg0->lane_polarities[i + 1];
-+ }
-+ } else if (!cfg0 && cfg1) {
-+ st_debug(ST_CSIPHY, "CSIPHY cfg1 use 1 clk mode\n");
-+ cfg->num_clks = 1;
-+ cfg->num_data_lanes = cfg1->num_data_lanes;
-+ cfg->clock_lane = cfg->clock1_lane = cfg1->clock_lane;
-+ cfg->lane_polarities[0] = cfg->lane_polarities[1] =
-+ cfg1->lane_polarities[0];
-+ for (i = 0; i < cfg1->num_data_lanes; i++) {
-+ cfg->data_lanes[i] = cfg1->data_lanes[i];
-+ cfg->lane_polarities[i + 2] = cfg1->lane_polarities[i + 1];
-+ }
-+ } else {
-+ return -EINVAL;
-+ }
-+
-+#ifndef USE_CSIDPHY_ONE_CLK_MODE
-+ sort(cfg->data_lanes, cfg->num_data_lanes,
-+ sizeof(cfg->data_lanes[0]), cmp_func, NULL);
-+#endif
-+ for (i = 0; i < cfg->num_data_lanes; i++)
-+ st_debug(ST_CSIPHY, "%d: %d\n", i, cfg->data_lanes[i]);
-+ return 0;
-+}
-+
-+static int csi2rx_dphy_config(struct stf_vin_dev *vin,
-+ struct stf_csiphy_dev *csiphy_dev)
-+{
-+ struct csi2phy_cfg2 cfg2 = {0};
-+ struct csi2phy_cfg2 *cfg = &cfg2;
-+ struct csi2phy_cfg *phycfg = csiphy_dev->csiphy;
-+
-+ if (!phycfg)
-+ return -EINVAL;
-+
-+ if (try_cfg(cfg, phycfg, NULL))
-+ return -EINVAL;
-+
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_4, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_8, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_12, 0xfff0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_16, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_20, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_24, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_28, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_32, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_36, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_40, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_44, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_48, 0x24000000);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_52, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_56, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_60, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_64, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_68, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_72, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_76, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_80, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_84, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_88, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_92, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_96, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_100, 0x02000000);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_104, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_108, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_112, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_116, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_120, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_124, 0xc);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_128, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_132, 0xcc500000);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_136, 0xcc);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_140, 0x0);
-+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_144, 0x0);
-+
-+ reg_set_bit(vin->rstgen_base, //r100_ctrl0_2d1c_efuse_en
-+ M31DPHY_APBCFGSAIF__SYSCFG_0,
-+ BIT(6), 1<<6);
-+ reg_set_bit(vin->rstgen_base, //r100_ctrl0_2d1c_efuse_in
-+ M31DPHY_APBCFGSAIF__SYSCFG_0,
-+ BIT(12)|BIT(11)|BIT(10)|BIT(9)|BIT(8)|BIT(7), 0x1b<<7);
-+ reg_set_bit(vin->rstgen_base, //r100_ctrl1_2d1c_efuse_en
-+ M31DPHY_APBCFGSAIF__SYSCFG_0,
-+ BIT(13), 1<<13);
-+ reg_set_bit(vin->rstgen_base, //r100_ctrl1_2d1c_efuse_in
-+ M31DPHY_APBCFGSAIF__SYSCFG_0,
-+ BIT(19)|BIT(18)|BIT(17)|BIT(16)|BIT(15)|BIT(14), 0x1b<<14);
-+
-+ reg_set_bit(vin->rstgen_base, //data_bus16_8
-+ M31DPHY_APBCFGSAIF__SYSCFG_184,
-+ BIT(8), 0<<8);
-+
-+ reg_set_bit(vin->rstgen_base, //debug_mode_sel
-+ M31DPHY_APBCFGSAIF__SYSCFG_184,
-+ BIT(15)|BIT(14)|BIT(13)|BIT(12)|BIT(11)|BIT(10)|BIT(9), 0x5a<<9);
-+
-+ reg_set_bit(vin->rstgen_base, //dpdn_swap_clk0
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(0), cfg->lane_polarities[0]<<0);
-+ reg_set_bit(vin->rstgen_base, //dpdn_swap_clk1
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(1), cfg->lane_polarities[1]<<1);
-+ reg_set_bit(vin->rstgen_base, //dpdn_swap_lan0
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(2), cfg->lane_polarities[2]<<2);
-+ reg_set_bit(vin->rstgen_base, //dpdn_swap_lan1
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(3), cfg->lane_polarities[3]<<3);
-+ reg_set_bit(vin->rstgen_base, //dpdn_swap_lan2
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(4), cfg->lane_polarities[4]<<4);
-+ reg_set_bit(vin->rstgen_base, //dpdn_swap_lan3
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(5), cfg->lane_polarities[5]<<5);
-+ reg_set_bit(vin->rstgen_base, //enable clk0
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(6), 1<<6);
-+ reg_set_bit(vin->rstgen_base, //enable clk1
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(7), 1<<7);
-+ reg_set_bit(vin->rstgen_base, //enable lan0
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(8), 1<<8);
-+ reg_set_bit(vin->rstgen_base, //enable lan1
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(9), 1<<9);
-+ reg_set_bit(vin->rstgen_base, //enable lan2
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(10), 1<<10);
-+ reg_set_bit(vin->rstgen_base, //enable lan3
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(11), 1<<11);
-+ reg_set_bit(vin->rstgen_base, //gpi_en
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(17)|BIT(16)|BIT(15)|BIT(14)|BIT(13)|BIT(12),
-+ 0<<12);
-+ reg_set_bit(vin->rstgen_base, //hs_freq_change_clk0
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(18), 0<<18);
-+ reg_set_bit(vin->rstgen_base, //hs_freq_change_clk1
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(19), 0<<19);
-+
-+ reg_set_bit(vin->rstgen_base,
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(22)|BIT(21)|BIT(20), cfg->clock_lane<<20); //clock lane 0
-+ reg_set_bit(vin->rstgen_base,
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(25)|BIT(24)|BIT(23), cfg->clock1_lane<<23); //clock lane 1
-+
-+ reg_set_bit(vin->rstgen_base,
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(28)|BIT(27)|BIT(26), cfg->data_lanes[0]<<26); //data lane 0
-+ reg_set_bit(vin->rstgen_base,
-+ M31DPHY_APBCFGSAIF__SYSCFG_188,
-+ BIT(31)|BIT(30)|BIT(29), cfg->data_lanes[1]<<29); //data lane 1
-+ reg_set_bit(vin->rstgen_base,
-+ M31DPHY_APBCFGSAIF__SYSCFG_192,
-+ BIT(2)|BIT(1)|BIT(0), cfg->data_lanes[2]<<0); //data lane 2
-+ reg_set_bit(vin->rstgen_base,
-+ M31DPHY_APBCFGSAIF__SYSCFG_192,
-+ BIT(5)|BIT(4)|BIT(3), cfg->data_lanes[3]<<3); //data lane 3
-+
-+ reg_set_bit(vin->rstgen_base, //mp_test_en
-+ M31DPHY_APBCFGSAIF__SYSCFG_192,
-+ BIT(6), 0<<6);
-+ reg_set_bit(vin->rstgen_base, //mp_test_mode_sel
-+ M31DPHY_APBCFGSAIF__SYSCFG_192,
-+ BIT(11)|BIT(10)|BIT(9)|BIT(8)|BIT(7), 0<<7);
-+
-+ reg_set_bit(vin->rstgen_base, //pll_clk_sel
-+ M31DPHY_APBCFGSAIF__SYSCFG_192,
-+ BIT(20)|BIT(19)|BIT(18)|BIT(17)|BIT(16)|BIT(15)|BIT(14)|BIT(13)|BIT(12),
-+ 0x37c<<12);
-+
-+ reg_set_bit(vin->rstgen_base, //rx_1c2c_sel
-+ M31DPHY_APBCFGSAIF__SYSCFG_200,
-+ BIT(8), 0<<8);
-+
-+ reg_set_bit(vin->rstgen_base, //precounter in clk0
-+ M31DPHY_APBCFGSAIF__SYSCFG_192,
-+ BIT(29)|BIT(28)|BIT(27)|BIT(26)|BIT(25)|BIT(24)|BIT(23)|BIT(22),
-+ 8<<22);
-+ reg_set_bit(vin->rstgen_base, //precounter in clk1
-+ M31DPHY_APBCFGSAIF__SYSCFG_196,
-+ BIT(7)|BIT(6)|BIT(5)|BIT(4)|BIT(3)|BIT(2)|BIT(1)|BIT(0),
-+ 8<<0);
-+ reg_set_bit(vin->rstgen_base, //precounter in lan0
-+ M31DPHY_APBCFGSAIF__SYSCFG_196,
-+ BIT(15)|BIT(14)|BIT(13)|BIT(12)|BIT(11)|BIT(10)|BIT(9)|BIT(8),
-+ 7<<8);
-+ reg_set_bit(vin->rstgen_base, //precounter in lan1
-+ M31DPHY_APBCFGSAIF__SYSCFG_196,
-+ BIT(23)|BIT(22)|BIT(21)|BIT(20)|BIT(19)|BIT(18)|BIT(17)|BIT(16),
-+ 7<<16);
-+ reg_set_bit(vin->rstgen_base, //precounter in lan2
-+ M31DPHY_APBCFGSAIF__SYSCFG_196,
-+ BIT(31)|BIT(30)|BIT(29)|BIT(28)|BIT(27)|BIT(26)|BIT(25)|BIT(24),
-+ 7<<24);
-+ reg_set_bit(vin->rstgen_base, //precounter in lan3
-+ M31DPHY_APBCFGSAIF__SYSCFG_200,
-+ BIT(7)|BIT(6)|BIT(5)|BIT(4)|BIT(3)|BIT(2)|BIT(1)|BIT(0),
-+ 7<<0);
-+
-+ return 0;
-+}
-+
-+static int stf_csiphy_config_set(struct stf_csiphy_dev *csiphy_dev)
-+{
-+ struct stf_vin_dev *vin = csiphy_dev->stfcamss->vin;
-+
-+ csi2rx_dphy_config(vin, csiphy_dev);
-+ return 0;
-+}
-+
-+static int stf_csiphy_stream_set(struct stf_csiphy_dev *csiphy_dev, int on)
-+{
-+ return 0;
-+}
-+
-+struct csiphy_hw_ops csiphy_ops = {
-+ .csiphy_clk_enable = stf_csiphy_clk_enable,
-+ .csiphy_clk_disable = stf_csiphy_clk_disable,
-+ .csiphy_config_set = stf_csiphy_config_set,
-+ .csiphy_stream_set = stf_csiphy_stream_set,
-+};
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_dmabuf.c
-@@ -0,0 +1,123 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/dma-buf.h>
-+#include <media/v4l2-subdev.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "stf_isp_ioctl.h"
-+#include "stf_dmabuf.h"
-+
-+#define TOTAL_SIZE_LIMIT (64 * 1024 * 1024)
-+
-+static size_t total_size;
-+static struct vb2_queue vb2_queue = {
-+ .dma_attrs = 0,
-+ .gfp_flags = 0,
-+ .dma_dir = DMA_TO_DEVICE,
-+};
-+static struct vb2_buffer vb = {
-+ .vb2_queue = &vb2_queue,
-+};
-+
-+static int dmabuf_create(struct device *dev,
-+ struct dmabuf_create *head)
-+{
-+ struct dma_buf *dmabuf = NULL;
-+ void *mem_priv = NULL;
-+ dma_addr_t *paddr = NULL;
-+ int ret = 0;
-+
-+ mem_priv = vb2_dma_contig_memops.alloc(&vb, dev, head->size);
-+ if (IS_ERR_OR_NULL(mem_priv)) {
-+ if (mem_priv)
-+ ret = PTR_ERR(mem_priv);
-+ goto exit;
-+ }
-+
-+ dmabuf = vb2_dma_contig_memops.get_dmabuf(&vb, mem_priv, O_RDWR);
-+ if (IS_ERR(dmabuf)) {
-+ ret = PTR_ERR(dmabuf);
-+ goto free;
-+ }
-+
-+ head->fd = dma_buf_fd(dmabuf, O_CLOEXEC);
-+ if (head->fd < 0) {
-+ dma_buf_put(dmabuf);
-+ ret = head->fd;
-+ goto free;
-+ }
-+
-+ paddr = vb2_dma_contig_memops.cookie(&vb, mem_priv);
-+ head->paddr = *paddr;
-+ return 0;
-+free:
-+ vb2_dma_contig_memops.put(mem_priv);
-+exit:
-+ return ret;
-+}
-+
-+int stf_dmabuf_ioctl_alloc(struct device *dev, void *arg)
-+{
-+ struct dmabuf_create *head = arg;
-+ int ret = -EINVAL;
-+
-+ if (IS_ERR_OR_NULL(head))
-+ return -EFAULT;
-+
-+ head->size = PAGE_ALIGN(head->size);
-+ if (!head->size)
-+ return -EINVAL;
-+ if ((head->size + total_size) > TOTAL_SIZE_LIMIT)
-+ return -ENOMEM;
-+
-+ ret = dmabuf_create(dev, head);
-+ if (ret)
-+ return -EFAULT;
-+
-+ total_size += head->size;
-+ return ret;
-+}
-+
-+int stf_dmabuf_ioctl_free(struct device *dev, void *arg)
-+{
-+ struct dmabuf_create *head = arg;
-+ struct dma_buf *dmabuf = NULL;
-+ int ret = 0;
-+
-+ if (IS_ERR_OR_NULL(head))
-+ return -EFAULT;
-+ if (head->size != PAGE_ALIGN(head->size))
-+ return -EINVAL;
-+ if (head->size > total_size)
-+ return -EINVAL;
-+
-+ dmabuf = dma_buf_get(head->fd);
-+ if (IS_ERR_OR_NULL(dmabuf))
-+ return -EINVAL;
-+
-+ dma_buf_put(dmabuf);
-+ vb2_dma_contig_memops.put(dmabuf->priv);
-+ total_size -= head->size;
-+ return ret;
-+}
-+
-+int stf_dmabuf_ioctl(struct device *dev, unsigned int cmd, void *arg)
-+{
-+ int ret = -ENOIOCTLCMD;
-+
-+ switch (cmd) {
-+ case VIDIOC_STF_DMABUF_ALLOC:
-+ ret = stf_dmabuf_ioctl_alloc(dev, arg);
-+ break;
-+ case VIDIOC_STF_DMABUF_FREE:
-+ ret = stf_dmabuf_ioctl_free(dev, arg);
-+ break;
-+ default:
-+ break;
-+ }
-+ return ret;
-+}
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_dmabuf.h
-@@ -0,0 +1,12 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_DMABUF_H
-+#define STF_DMABUF_H
-+
-+extern int stf_dmabuf_ioctl(struct device *dev, unsigned int cmd, void *arg);
-+
-+#endif /* STF_DMABUF_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_dvp.c
-@@ -0,0 +1,385 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+
-+static const struct dvp_format dvp_formats_st7110[] = {
-+ { MEDIA_BUS_FMT_YUYV8_2X8, 8},
-+ { MEDIA_BUS_FMT_RGB565_2X8_LE, 8},
-+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8},
-+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8},
-+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8},
-+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8},
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 8},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 8},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 8},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 8},
-+};
-+
-+static int dvp_find_format(u32 code,
-+ const struct dvp_format *formats,
-+ unsigned int nformats)
-+{
-+ int i;
-+
-+ for (i = 0; i < nformats; i++)
-+ if (formats[i].code == code)
-+ return i;
-+ return -EINVAL;
-+}
-+
-+int stf_dvp_subdev_init(struct stfcamss *stfcamss)
-+{
-+ struct stf_dvp_dev *dvp_dev = stfcamss->dvp_dev;
-+
-+ dvp_dev->s_type = SENSOR_VIN;
-+ dvp_dev->hw_ops = &dvp_ops;
-+ dvp_dev->stfcamss = stfcamss;
-+ dvp_dev->formats = dvp_formats_st7110;
-+ dvp_dev->nformats = ARRAY_SIZE(dvp_formats_st7110);
-+ mutex_init(&dvp_dev->stream_lock);
-+ dvp_dev->stream_count = 0;
-+ return 0;
-+}
-+
-+static int dvp_set_power(struct v4l2_subdev *sd, int on)
-+{
-+ return 0;
-+}
-+
-+static struct v4l2_mbus_framefmt *
-+__dvp_get_format(struct stf_dvp_dev *dvp_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ enum v4l2_subdev_format_whence which)
-+{
-+
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_format(
-+ &dvp_dev->subdev, state, pad);
-+ return &dvp_dev->fmt[pad];
-+}
-+
-+static int dvp_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct stf_dvp_dev *dvp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+ int ret = 0;
-+
-+ format = __dvp_get_format(dvp_dev, NULL, STF_DVP_PAD_SRC,
-+ V4L2_SUBDEV_FORMAT_ACTIVE);
-+ if (format == NULL)
-+ return -EINVAL;
-+ ret = dvp_find_format(format->code,
-+ dvp_dev->formats,
-+ dvp_dev->nformats);
-+ if (ret < 0)
-+ return ret;
-+
-+ mutex_lock(&dvp_dev->stream_lock);
-+ if (enable) {
-+ if (dvp_dev->stream_count == 0) {
-+ dvp_dev->hw_ops->dvp_clk_enable(dvp_dev);
-+ dvp_dev->hw_ops->dvp_config_set(dvp_dev);
-+ dvp_dev->hw_ops->dvp_set_format(dvp_dev,
-+ format->width, dvp_dev->formats[ret].bpp);
-+ dvp_dev->hw_ops->dvp_stream_set(dvp_dev, 1);
-+ }
-+ dvp_dev->stream_count++;
-+ } else {
-+ if (dvp_dev->stream_count == 0)
-+ goto exit;
-+ if (dvp_dev->stream_count == 1) {
-+ dvp_dev->hw_ops->dvp_stream_set(dvp_dev, 0);
-+ dvp_dev->hw_ops->dvp_clk_disable(dvp_dev);
-+ }
-+ dvp_dev->stream_count--;
-+ }
-+exit:
-+ mutex_unlock(&dvp_dev->stream_lock);
-+ return 0;
-+}
-+
-+static void dvp_try_format(struct stf_dvp_dev *dvp_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ unsigned int i;
-+
-+ switch (pad) {
-+ case STF_DVP_PAD_SINK:
-+ /* Set format on sink pad */
-+
-+ for (i = 0; i < dvp_dev->nformats; i++)
-+ if (fmt->code == dvp_dev->formats[i].code)
-+ break;
-+
-+ if (i >= dvp_dev->nformats)
-+ fmt->code = dvp_dev->formats[0].code;
-+
-+ fmt->width = clamp_t(u32,
-+ fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
-+ STFCAMSS_FRAME_MAX_WIDTH);
-+ fmt->height = clamp_t(u32,
-+ fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
-+ STFCAMSS_FRAME_MAX_HEIGHT);
-+
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->flags = 0;
-+
-+ break;
-+
-+ case STF_DVP_PAD_SRC:
-+
-+ *fmt = *__dvp_get_format(dvp_dev, state, STF_DVP_PAD_SINK, which);
-+
-+ break;
-+ }
-+}
-+
-+static int dvp_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ struct stf_dvp_dev *dvp_dev = v4l2_get_subdevdata(sd);
-+
-+ if (code->index >= dvp_dev->nformats)
-+ return -EINVAL;
-+
-+ if (code->pad == STF_DVP_PAD_SINK) {
-+ code->code = dvp_dev->formats[code->index].code;
-+ } else {
-+ struct v4l2_mbus_framefmt *sink_fmt;
-+
-+ sink_fmt = __dvp_get_format(dvp_dev, state, STF_DVP_PAD_SINK,
-+ code->which);
-+
-+ code->code = sink_fmt->code;
-+ if (!code->code)
-+ return -EINVAL;
-+ }
-+ code->flags = 0;
-+
-+ return 0;
-+}
-+
-+static int dvp_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ struct stf_dvp_dev *dvp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt format;
-+
-+ if (fse->index != 0)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = 1;
-+ format.height = 1;
-+ dvp_try_format(dvp_dev, state, fse->pad, &format, fse->which);
-+ fse->min_width = format.width;
-+ fse->min_height = format.height;
-+
-+ if (format.code != fse->code)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = -1;
-+ format.height = -1;
-+ dvp_try_format(dvp_dev, state, fse->pad, &format, fse->which);
-+ fse->max_width = format.width;
-+ fse->max_height = format.height;
-+
-+ return 0;
-+}
-+
-+static int dvp_get_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_dvp_dev *dvp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ format = __dvp_get_format(dvp_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ fmt->format = *format;
-+
-+ return 0;
-+}
-+
-+static int dvp_set_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_dvp_dev *dvp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ format = __dvp_get_format(dvp_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&dvp_dev->stream_lock);
-+ if (dvp_dev->stream_count) {
-+ fmt->format = *format;
-+ mutex_unlock(&dvp_dev->stream_lock);
-+ goto out;
-+ } else {
-+ dvp_try_format(dvp_dev, state, fmt->pad, &fmt->format, fmt->which);
-+ *format = fmt->format;
-+ }
-+ mutex_unlock(&dvp_dev->stream_lock);
-+
-+ /* Propagate the format from sink to source */
-+ if (fmt->pad == STF_DVP_PAD_SINK) {
-+ format = __dvp_get_format(dvp_dev, state, STF_DVP_PAD_SRC,
-+ fmt->which);
-+
-+ *format = fmt->format;
-+ dvp_try_format(dvp_dev, state, STF_DVP_PAD_SRC, format,
-+ fmt->which);
-+ }
-+
-+out:
-+ return 0;
-+}
-+
-+static int dvp_init_formats(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_subdev_format format = {
-+ .pad = STF_DVP_PAD_SINK,
-+ .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
-+ V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .format = {
-+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
-+ .width = 1920,
-+ .height = 1080
-+ }
-+ };
-+
-+ return dvp_set_format(sd, fh ? fh->state : NULL, &format);
-+}
-+
-+static int dvp_link_setup(struct media_entity *entity,
-+ const struct media_pad *local,
-+ const struct media_pad *remote, u32 flags)
-+{
-+ if ((local->flags & MEDIA_PAD_FL_SOURCE) &&
-+ (flags & MEDIA_LNK_FL_ENABLED)) {
-+ struct v4l2_subdev *sd;
-+ struct stf_dvp_dev *dvp_dev;
-+ struct vin_line *line;
-+
-+ if (media_pad_remote_pad_first(local))
-+ return -EBUSY;
-+
-+ sd = media_entity_to_v4l2_subdev(entity);
-+ dvp_dev = v4l2_get_subdevdata(sd);
-+
-+ sd = media_entity_to_v4l2_subdev(remote->entity);
-+ line = v4l2_get_subdevdata(sd);
-+ if (line->sdev_type == VIN_DEV_TYPE)
-+ dvp_dev->s_type = SENSOR_VIN;
-+ if (line->sdev_type == ISP_DEV_TYPE)
-+ dvp_dev->s_type = SENSOR_ISP;
-+ st_info(ST_DVP, "DVP device sensor type: %d\n", dvp_dev->s_type);
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_core_ops dvp_core_ops = {
-+ .s_power = dvp_set_power,
-+};
-+
-+static const struct v4l2_subdev_video_ops dvp_video_ops = {
-+ .s_stream = dvp_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops dvp_pad_ops = {
-+ .enum_mbus_code = dvp_enum_mbus_code,
-+ .enum_frame_size = dvp_enum_frame_size,
-+ .get_fmt = dvp_get_format,
-+ .set_fmt = dvp_set_format,
-+};
-+
-+static const struct v4l2_subdev_ops dvp_v4l2_ops = {
-+ .core = &dvp_core_ops,
-+ .video = &dvp_video_ops,
-+ .pad = &dvp_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops dvp_v4l2_internal_ops = {
-+ .open = dvp_init_formats,
-+};
-+
-+static const struct media_entity_operations dvp_media_ops = {
-+ .link_setup = dvp_link_setup,
-+ .link_validate = v4l2_subdev_link_validate,
-+};
-+
-+int stf_dvp_register(struct stf_dvp_dev *dvp_dev,
-+ struct v4l2_device *v4l2_dev)
-+{
-+ struct v4l2_subdev *sd = &dvp_dev->subdev;
-+ struct media_pad *pads = dvp_dev->pads;
-+ int ret;
-+
-+ v4l2_subdev_init(sd, &dvp_v4l2_ops);
-+ sd->internal_ops = &dvp_v4l2_internal_ops;
-+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
-+ STF_DVP_NAME, 0);
-+ v4l2_set_subdevdata(sd, dvp_dev);
-+
-+ ret = dvp_init_formats(sd, NULL);
-+ if (ret < 0) {
-+ st_err(ST_DVP, "Failed to init format: %d\n", ret);
-+ return ret;
-+ }
-+
-+ pads[STF_DVP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-+ pads[STF_DVP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
-+
-+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
-+ sd->entity.ops = &dvp_media_ops;
-+ ret = media_entity_pads_init(&sd->entity, STF_DVP_PADS_NUM, pads);
-+ if (ret < 0) {
-+ st_err(ST_DVP, "Failed to init media entity: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
-+ if (ret < 0) {
-+ st_err(ST_DVP, "Failed to register subdev: %d\n", ret);
-+ goto err_sreg;
-+ }
-+
-+ return 0;
-+
-+err_sreg:
-+ media_entity_cleanup(&sd->entity);
-+ return ret;
-+}
-+
-+int stf_dvp_unregister(struct stf_dvp_dev *dvp_dev)
-+{
-+ v4l2_device_unregister_subdev(&dvp_dev->subdev);
-+ media_entity_cleanup(&dvp_dev->subdev.entity);
-+ mutex_destroy(&dvp_dev->stream_lock);
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_dvp.h
-@@ -0,0 +1,67 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_DVP_H
-+#define STF_DVP_H
-+
-+#include <media/v4l2-subdev.h>
-+#include <media/v4l2-device.h>
-+#include <media/media-entity.h>
-+#include <video/stf-vin.h>
-+
-+#define STF_DVP_NAME "stf_dvp"
-+
-+#define STF_DVP_PAD_SINK 0
-+#define STF_DVP_PAD_SRC 1
-+#define STF_DVP_PADS_NUM 2
-+
-+struct dvp_format {
-+ u32 code;
-+ u8 bpp;
-+};
-+
-+enum sensor_type;
-+enum subdev_type;
-+
-+struct dvp_cfg {
-+ unsigned int flags;
-+ unsigned char bus_width;
-+ unsigned char data_shift;
-+};
-+
-+struct stf_dvp_dev;
-+
-+struct dvp_hw_ops {
-+ int (*dvp_clk_enable)(struct stf_dvp_dev *dvp_dev);
-+ int (*dvp_clk_disable)(struct stf_dvp_dev *dvp_dev);
-+ int (*dvp_config_set)(struct stf_dvp_dev *dvp_dev);
-+ int (*dvp_set_format)(struct stf_dvp_dev *dvp_dev,
-+ u32 pix_width, u8 bpp);
-+ int (*dvp_stream_set)(struct stf_dvp_dev *dvp_dev, int on);
-+};
-+
-+struct stf_dvp_dev {
-+ struct stfcamss *stfcamss;
-+ struct dvp_cfg *dvp;
-+ enum sensor_type s_type;
-+ struct v4l2_subdev subdev;
-+ struct media_pad pads[STF_DVP_PADS_NUM];
-+ struct v4l2_mbus_framefmt fmt[STF_DVP_PADS_NUM];
-+ const struct dvp_format *formats;
-+ unsigned int nformats;
-+ struct dvp_hw_ops *hw_ops;
-+ struct mutex stream_lock;
-+ int stream_count;
-+};
-+
-+extern int stf_dvp_subdev_init(struct stfcamss *stfcamss);
-+extern int stf_dvp_register(struct stf_dvp_dev *dvp_dev,
-+ struct v4l2_device *v4l2_dev);
-+extern int stf_dvp_unregister(struct stf_dvp_dev *dvp_dev);
-+
-+extern struct dvp_hw_ops dvp_ops;
-+
-+#endif /* STF_DVP_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_dvp_hw_ops.c
-@@ -0,0 +1,187 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+
-+static int stf_dvp_clk_enable(struct stf_dvp_dev *dvp_dev)
-+{
-+ struct stfcamss *stfcamss = dvp_dev->stfcamss;
-+
-+ switch (dvp_dev->s_type) {
-+ case SENSOR_VIN:
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_AXIWR].rstc);
-+ clk_set_phase(stfcamss->sys_clk[STFCLK_DVP_INV].clk, 0);
-+ clk_set_parent(stfcamss->sys_clk[STFCLK_AXIWR].clk,
-+ stfcamss->sys_clk[STFCLK_DVP_INV].clk);
-+ break;
-+ case SENSOR_ISP:
-+ clk_set_phase(stfcamss->sys_clk[STFCLK_DVP_INV].clk, 0);
-+ clk_set_parent(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk,
-+ stfcamss->sys_clk[STFCLK_DVP_INV].clk);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int stf_dvp_clk_disable(struct stf_dvp_dev *dvp_dev)
-+{
-+ struct stfcamss *stfcamss = dvp_dev->stfcamss;
-+
-+ switch (dvp_dev->s_type) {
-+ case SENSOR_VIN:
-+ clk_set_parent(stfcamss->sys_clk[STFCLK_AXIWR].clk,
-+ stfcamss->sys_clk[STFCLK_MIPI_RX0_PXL].clk);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_AXIWR].rstc);
-+ break;
-+ case SENSOR_ISP:
-+ clk_set_parent(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk,
-+ stfcamss->sys_clk[STFCLK_MIPI_RX0_PXL].clk);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int stf_dvp_config_set(struct stf_dvp_dev *dvp_dev)
-+{
-+
-+ struct stf_vin_dev *vin = dvp_dev->stfcamss->vin;
-+ unsigned int flags = 0;
-+ unsigned char data_shift = 0;
-+ u32 polarities = 0;
-+
-+ if (!dvp_dev->dvp)
-+ return -EINVAL;
-+
-+ flags = dvp_dev->dvp->flags;
-+ data_shift = dvp_dev->dvp->data_shift;
-+ st_info(ST_DVP, "%s, polarities = 0x%x, flags = 0x%x\n",
-+ __func__, polarities, flags);
-+
-+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
-+ polarities |= BIT(1);
-+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
-+ polarities |= BIT(3);
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCONSAIF_SYSCFG_36);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ U0_VIN_CNFG_DVP_HS_POS
-+ | U0_VIN_CNFG_DVP_VS_POS,
-+ polarities);
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCONSAIF_SYSCFG_36);
-+
-+ switch (data_shift) {
-+ case 0:
-+ data_shift = 0;
-+ break;
-+ case 2:
-+ data_shift = 1;
-+ break;
-+ case 4:
-+ data_shift = 2;
-+ break;
-+ case 6:
-+ data_shift = 3;
-+ break;
-+ default:
-+ data_shift = 0;
-+ break;
-+ };
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCONSAIF_SYSCFG_28);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ UO_VIN_CNFG_AXIWR0_PIXEL_HEIGH_BIT_SEL,
-+ data_shift << 15);
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCONSAIF_SYSCFG_28);
-+
-+ return 0;
-+}
-+
-+static int set_vin_axiwr_pix_ct(struct stf_vin_dev *vin, u8 bpp)
-+{
-+ u32 value = 0;
-+ int cnfg_axiwr_pix_ct = 64 / bpp;
-+
-+ // need check
-+ if (cnfg_axiwr_pix_ct == 2)
-+ value = 1;
-+ else if (cnfg_axiwr_pix_ct == 4)
-+ value = 1;
-+ else if (cnfg_axiwr_pix_ct == 8)
-+ value = 0;
-+ else
-+ return 0;
-+
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCONSAIF_SYSCFG_28);
-+ reg_set_bit(vin->sysctrl_base,
-+ SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_PIX_CT,
-+ value<<13);
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCONSAIF_SYSCFG_28);
-+
-+ return cnfg_axiwr_pix_ct;
-+
-+}
-+
-+static int stf_dvp_set_format(struct stf_dvp_dev *dvp_dev,
-+ u32 pix_width, u8 bpp)
-+{
-+ struct stf_vin_dev *vin = dvp_dev->stfcamss->vin;
-+ int val, pix_ct;
-+
-+ if (dvp_dev->s_type == SENSOR_VIN) {
-+ pix_ct = set_vin_axiwr_pix_ct(vin, bpp);
-+ val = (pix_width / pix_ct) - 1;
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCTRL_VIN_WR_PIX_TOTAL);
-+ reg_set_bit(vin->sysctrl_base,
-+ SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_PIX_CNT_END,
-+ val << 2);
-+ print_reg(ST_DVP, vin->sysctrl_base, SYSCTRL_VIN_WR_PIX_TOTAL);
-+
-+ }
-+
-+ return 0;
-+}
-+
-+static int stf_dvp_stream_set(struct stf_dvp_dev *dvp_dev, int on)
-+{
-+ struct stf_vin_dev *vin = dvp_dev->stfcamss->vin;
-+
-+ switch (dvp_dev->s_type) {
-+ case SENSOR_VIN:
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ U0_VIN_CNFG_ISP_DVP_EN0,
-+ 0);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_0,
-+ U0_VIN_CNFG_AXI_DVP_EN,
-+ !!on<<2);
-+ break;
-+ case SENSOR_ISP:
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ U0_VIN_CNFG_ISP_DVP_EN0,
-+ !!on<<5);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_0,
-+ U0_VIN_CNFG_AXI_DVP_EN,
-+ 0);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ U0_VIN_CNFG_DVP_SWAP_EN,
-+ 0);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
-+ U0_VIN_CNFG_GEN_EN_AXIRD,
-+ 0);
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+struct dvp_hw_ops dvp_ops = {
-+ .dvp_clk_enable = stf_dvp_clk_enable,
-+ .dvp_clk_disable = stf_dvp_clk_disable,
-+ .dvp_config_set = stf_dvp_config_set,
-+ .dvp_set_format = stf_dvp_set_format,
-+ .dvp_stream_set = stf_dvp_stream_set,
-+};
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_event.c
-@@ -0,0 +1,36 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/notifier.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/fs.h>
-+
-+static ATOMIC_NOTIFIER_HEAD(vin_notifier_list);
-+
-+int vin_notifier_register(struct notifier_block *nb)
-+{
-+ return atomic_notifier_chain_register(&vin_notifier_list, nb);
-+}
-+EXPORT_SYMBOL_GPL(vin_notifier_register);
-+
-+void vin_notifier_unregister(struct notifier_block *nb)
-+{
-+ atomic_notifier_chain_unregister(&vin_notifier_list, nb);
-+}
-+EXPORT_SYMBOL_GPL(vin_notifier_unregister);
-+
-+int vin_notifier_call(unsigned long e, void *v)
-+{
-+ return atomic_notifier_call_chain(&vin_notifier_list, e, v);
-+}
-+EXPORT_SYMBOL_GPL(vin_notifier_call);
-+
-+MODULE_AUTHOR("StarFive Technology Co., Ltd.");
-+MODULE_DESCRIPTION("Starfive VIC video in notifier");
-+MODULE_LICENSE("GPL");
-+//MODULE_SUPPORTED_DEVICE("video");
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-@@ -0,0 +1,1521 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+#include <linux/firmware.h>
-+#include <linux/jh7110-isp.h>
-+#include "stf_isp_ioctl.h"
-+#include "stf_dmabuf.h"
-+
-+static int user_config_isp;
-+static int isp_set_selection(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_selection *sel);
-+
-+static struct v4l2_rect *
-+__isp_get_compose(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ enum v4l2_subdev_format_whence which);
-+
-+static struct v4l2_rect *
-+__isp_get_crop(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ enum v4l2_subdev_format_whence which);
-+
-+static struct v4l2_rect *
-+__isp_get_scale(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_selection *sel);
-+
-+static struct v4l2_rect *
-+__isp_get_itiws(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ enum v4l2_subdev_format_whence which);
-+
-+// sink format and raw format must one by one
-+static const struct isp_format isp_formats_st7110_sink[] = {
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
-+};
-+
-+static const struct isp_format isp_formats_st7110_raw[] = {
-+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
-+};
-+
-+static const struct isp_format isp_formats_st7110_compat_10bit_raw[] = {
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
-+};
-+
-+static const struct isp_format isp_formats_st7110_compat_8bit_raw[] = {
-+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8},
-+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8},
-+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8},
-+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8},
-+};
-+
-+static const struct isp_format isp_formats_st7110_uo[] = {
-+ { MEDIA_BUS_FMT_Y12_1X12, 8},
-+};
-+
-+static const struct isp_format isp_formats_st7110_iti[] = {
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
-+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
-+ { MEDIA_BUS_FMT_Y12_1X12, 8},
-+ { MEDIA_BUS_FMT_YUV8_1X24, 8},
-+};
-+
-+static const struct isp_format_table isp_formats_st7110[] = {
-+ { isp_formats_st7110_sink, ARRAY_SIZE(isp_formats_st7110_sink) }, /* pad 0 */
-+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, /* pad 1 */
-+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, /* pad 2 */
-+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, /* pad 3 */
-+ { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) }, /* pad 4 */
-+ { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) }, /* pad 5 */
-+ { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) }, /* pad 6 */
-+ { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) }, /* pad 7 */
-+};
-+
-+int stf_isp_subdev_init(struct stfcamss *stfcamss)
-+{
-+ struct stf_isp_dev *isp_dev = stfcamss->isp_dev;
-+
-+ isp_dev->sdev_type = ISP_DEV_TYPE;
-+ isp_dev->hw_ops = &isp_ops;
-+ isp_dev->stfcamss = stfcamss;
-+ isp_dev->formats = isp_formats_st7110;
-+ isp_dev->nformats = ARRAY_SIZE(isp_formats_st7110);
-+ mutex_init(&isp_dev->stream_lock);
-+ mutex_init(&isp_dev->power_lock);
-+ mutex_init(&isp_dev->setfile_lock);
-+ atomic_set(&isp_dev->shadow_count, 0);
-+ return 0;
-+}
-+
-+/*
-+ * ISP Controls.
-+ */
-+
-+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
-+{
-+ return &container_of(ctrl->handler, struct stf_isp_dev,
-+ ctrls.handler)->subdev;
-+}
-+
-+static u64 isp_calc_pixel_rate(struct stf_isp_dev *isp_dev)
-+{
-+ u64 rate = 0;
-+
-+ return rate;
-+}
-+
-+static int isp_set_ctrl_hue(struct stf_isp_dev *isp_dev, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_contrast(struct stf_isp_dev *isp_dev, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_saturation(struct stf_isp_dev *isp_dev, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_white_balance(struct stf_isp_dev *isp_dev, int awb)
-+{
-+ struct isp_ctrls *ctrls = &isp_dev->ctrls;
-+ int ret = 0;
-+
-+ if (!awb && (ctrls->red_balance->is_new
-+ || ctrls->blue_balance->is_new)) {
-+ u16 red = (u16)ctrls->red_balance->val;
-+ u16 blue = (u16)ctrls->blue_balance->val;
-+
-+ st_debug(ST_ISP, "red = 0x%x, blue = 0x%x\n", red, blue);
-+ //isp_dev->hw_ops->isp_set_awb_r_gain(isp_dev, red);
-+ //if (ret)
-+ // return ret;
-+ //isp_dev->hw_ops->isp_set_awb_b_gain(isp_dev, blue);
-+ }
-+
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_exposure(struct stf_isp_dev *isp_dev,
-+ enum v4l2_exposure_auto_type auto_exposure)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_gain(struct stf_isp_dev *isp_dev, bool auto_gain)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static const char * const test_pattern_menu[] = {
-+ "Disabled",
-+ "Color bars",
-+ "Color bars w/ rolling bar",
-+ "Color squares",
-+ "Color squares w/ rolling bar",
-+};
-+
-+#define ISP_TEST_ENABLE BIT(7)
-+#define ISP_TEST_ROLLING BIT(6) /* rolling horizontal bar */
-+#define ISP_TEST_TRANSPARENT BIT(5)
-+#define ISP_TEST_SQUARE_BW BIT(4) /* black & white squares */
-+#define ISP_TEST_BAR_STANDARD (0 << 2)
-+#define ISP_TEST_BAR_VERT_CHANGE_1 (1 << 2)
-+#define ISP_TEST_BAR_HOR_CHANGE (2 << 2)
-+#define ISP_TEST_BAR_VERT_CHANGE_2 (3 << 2)
-+#define ISP_TEST_BAR (0 << 0)
-+#define ISP_TEST_RANDOM (1 << 0)
-+#define ISP_TEST_SQUARE (2 << 0)
-+#define ISP_TEST_BLACK (3 << 0)
-+
-+static const u8 test_pattern_val[] = {
-+ 0,
-+ ISP_TEST_ENABLE | ISP_TEST_BAR_VERT_CHANGE_1 |
-+ ISP_TEST_BAR,
-+ ISP_TEST_ENABLE | ISP_TEST_ROLLING |
-+ ISP_TEST_BAR_VERT_CHANGE_1 | ISP_TEST_BAR,
-+ ISP_TEST_ENABLE | ISP_TEST_SQUARE,
-+ ISP_TEST_ENABLE | ISP_TEST_ROLLING | ISP_TEST_SQUARE,
-+};
-+
-+static int isp_set_ctrl_test_pattern(struct stf_isp_dev *isp_dev, int value)
-+{
-+ int ret = 0;
-+
-+ // return isp_write_reg(isp_dev, ISP_REG_PRE_ISP_TEST_SET1,
-+ // test_pattern_val[value]);
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_light_freq(struct stf_isp_dev *isp_dev, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_hflip(struct stf_isp_dev *isp_dev, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int isp_set_ctrl_vflip(struct stf_isp_dev *isp_dev, int value)
-+{
-+ int ret = 0;
-+
-+ return ret;
-+}
-+
-+static int isp_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ switch (ctrl->id) {
-+ case V4L2_CID_AUTOGAIN:
-+ break;
-+ case V4L2_CID_EXPOSURE_AUTO:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static int isp_s_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ int ret = 0;
-+
-+ /*
-+ * If the device is not powered up by the host driver do
-+ * not apply any controls to H/W at this time. Instead
-+ * the controls will be restored right after power-up.
-+ */
-+ mutex_lock(&isp_dev->power_lock);
-+ if (isp_dev->power_count == 0) {
-+ mutex_unlock(&isp_dev->power_lock);
-+ return 0;
-+ }
-+ mutex_unlock(&isp_dev->power_lock);
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_AUTOGAIN:
-+ ret = isp_set_ctrl_gain(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE_AUTO:
-+ ret = isp_set_ctrl_exposure(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_AUTO_WHITE_BALANCE:
-+ ret = isp_set_ctrl_white_balance(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_HUE:
-+ ret = isp_set_ctrl_hue(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_CONTRAST:
-+ ret = isp_set_ctrl_contrast(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_SATURATION:
-+ ret = isp_set_ctrl_saturation(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = isp_set_ctrl_test_pattern(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_POWER_LINE_FREQUENCY:
-+ ret = isp_set_ctrl_light_freq(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_HFLIP:
-+ ret = isp_set_ctrl_hflip(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_VFLIP:
-+ ret = isp_set_ctrl_vflip(isp_dev, ctrl->val);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_WB_SETTING:
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_CAR_SETTING:
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_CCM_SETTING:
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops isp_ctrl_ops = {
-+ .g_volatile_ctrl = isp_g_volatile_ctrl,
-+ .s_ctrl = isp_s_ctrl,
-+};
-+
-+struct v4l2_ctrl_config isp_ctrl[] = {
-+ [0] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "WB Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_WB_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_wb_setting),
-+ .flags = 0,
-+ },
-+ [1] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "Car Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_CAR_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_car_setting),
-+ .flags = 0,
-+ },
-+ [2] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "CCM Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_CCM_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_ccm_setting),
-+ .flags = 0,
-+ },
-+};
-+
-+static int isp_init_controls(struct stf_isp_dev *isp_dev)
-+{
-+ const struct v4l2_ctrl_ops *ops = &isp_ctrl_ops;
-+ struct isp_ctrls *ctrls = &isp_dev->ctrls;
-+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
-+ int ret;
-+ int i;
-+
-+ v4l2_ctrl_handler_init(hdl, 32);
-+
-+ /* Clock related controls */
-+ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
-+ 0, INT_MAX, 1,
-+ isp_calc_pixel_rate(isp_dev));
-+
-+ /* Auto/manual white balance */
-+ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
-+ V4L2_CID_AUTO_WHITE_BALANCE,
-+ 0, 1, 1, 1);
-+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
-+ 0, 4095, 1, 0);
-+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
-+ 0, 4095, 1, 0);
-+ /* Auto/manual exposure */
-+ ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_EXPOSURE_AUTO,
-+ V4L2_EXPOSURE_MANUAL, 0,
-+ V4L2_EXPOSURE_AUTO);
-+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
-+ 0, 65535, 1, 0);
-+ /* Auto/manual gain */
-+ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
-+ 0, 1, 1, 1);
-+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
-+ 0, 1023, 1, 0);
-+
-+ ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
-+ 0, 255, 1, 64);
-+ ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
-+ 0, 359, 1, 0);
-+ ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
-+ 0, 255, 1, 0);
-+ ctrls->test_pattern =
-+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(test_pattern_menu) - 1,
-+ 0, 0, test_pattern_menu);
-+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
-+ 0, 1, 1, 0);
-+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
-+ 0, 1, 1, 0);
-+
-+ ctrls->light_freq =
-+ v4l2_ctrl_new_std_menu(hdl, ops,
-+ V4L2_CID_POWER_LINE_FREQUENCY,
-+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
-+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
-+
-+ for (i = 0; i < ARRAY_SIZE(isp_ctrl); i++)
-+ v4l2_ctrl_new_custom(hdl, &isp_ctrl[i], NULL);
-+
-+
-+ if (hdl->error) {
-+ ret = hdl->error;
-+ goto free_ctrls;
-+ }
-+
-+ ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+ ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
-+
-+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
-+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
-+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
-+
-+ isp_dev->subdev.ctrl_handler = hdl;
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(hdl);
-+ return ret;
-+}
-+
-+static int isp_set_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+
-+ st_debug(ST_ISP, "%s, %d\n", __func__, __LINE__);
-+ mutex_lock(&isp_dev->power_lock);
-+ if (on) {
-+ if (isp_dev->power_count == 0)
-+ st_debug(ST_ISP, "turn on isp\n");
-+ isp_dev->power_count++;
-+ } else {
-+ if (isp_dev->power_count == 0)
-+ goto exit;
-+ isp_dev->power_count--;
-+ }
-+exit:
-+ mutex_unlock(&isp_dev->power_lock);
-+
-+ return 0;
-+}
-+
-+static struct v4l2_mbus_framefmt *
-+__isp_get_format(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ enum v4l2_subdev_format_whence which)
-+{
-+
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_format(&isp_dev->subdev, state, pad);
-+
-+ return &isp_dev->fmt[pad];
-+}
-+
-+static int isp_get_interface_type(struct media_entity *entity)
-+{
-+ struct v4l2_subdev *subdev;
-+ struct media_pad *pad = &entity->pads[0];
-+
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ return -EINVAL;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ return -EINVAL;
-+
-+ subdev = media_entity_to_v4l2_subdev(pad->entity);
-+
-+ st_debug(ST_ISP, "interface subdev name %s\n", subdev->name);
-+ if (!strncmp(subdev->name, STF_CSI_NAME, strlen(STF_CSI_NAME)))
-+ return CSI_SENSOR;
-+ if (!strncmp(subdev->name, STF_DVP_NAME, strlen(STF_DVP_NAME)))
-+ return DVP_SENSOR;
-+ return -EINVAL;
-+}
-+
-+static int isp_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ int ret = 0, interface_type;
-+ struct v4l2_mbus_framefmt *fmt;
-+ struct v4l2_event src_ch = { 0 };
-+
-+ fmt = __isp_get_format(isp_dev, NULL, STF_ISP_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE);
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (enable) {
-+ if (isp_dev->stream_count == 0) {
-+ isp_dev->hw_ops->isp_clk_enable(isp_dev);
-+ if (!user_config_isp)
-+ isp_dev->hw_ops->isp_config_set(isp_dev);
-+ interface_type = isp_get_interface_type(&sd->entity);
-+ if (interface_type < 0) {
-+ st_err(ST_ISP, "%s, pipeline not config\n", __func__);
-+ goto exit;
-+ }
-+ isp_dev->hw_ops->isp_set_format(isp_dev,
-+ isp_dev->rect, fmt->code, interface_type);
-+ isp_dev->hw_ops->isp_reset(isp_dev);
-+ isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
-+ user_config_isp = 0;
-+ }
-+ isp_dev->stream_count++;
-+ } else {
-+ if (isp_dev->stream_count == 0)
-+ goto exit;
-+ if (isp_dev->stream_count == 1) {
-+ isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
-+ isp_dev->hw_ops->isp_clk_disable(isp_dev);
-+ }
-+ isp_dev->stream_count--;
-+ }
-+ src_ch.type = V4L2_EVENT_SOURCE_CHANGE,
-+ src_ch.u.src_change.changes = isp_dev->stream_count,
-+
-+ v4l2_subdev_notify_event(sd, &src_ch);
-+exit:
-+ mutex_unlock(&isp_dev->stream_lock);
-+
-+ mutex_lock(&isp_dev->power_lock);
-+ /* restore controls */
-+ if (enable && isp_dev->power_count == 1) {
-+ mutex_unlock(&isp_dev->power_lock);
-+ ret = v4l2_ctrl_handler_setup(&isp_dev->ctrls.handler);
-+ } else
-+ mutex_unlock(&isp_dev->power_lock);
-+
-+ return ret;
-+}
-+
-+/*Try to match sensor format with sink, and then get the index as default.*/
-+static int isp_match_sensor_format_get_index(struct stf_isp_dev *isp_dev)
-+{
-+ int ret, idx;
-+ struct media_entity *sensor;
-+ struct v4l2_subdev *subdev;
-+ struct v4l2_subdev_format fmt;
-+ const struct isp_format_table *formats;
-+
-+ if (!isp_dev)
-+ return -EINVAL;
-+
-+ sensor = stfcamss_find_sensor(&isp_dev->subdev.entity);
-+ if (!sensor)
-+ return -EINVAL;
-+
-+ subdev = media_entity_to_v4l2_subdev(sensor);
-+ st_debug(ST_ISP, "Found sensor = %s\n", sensor->name);
-+
-+ fmt.pad = 0;
-+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
-+ if (ret) {
-+ st_warn(ST_ISP, "Sonser get format failed !!\n");
-+ return -EINVAL;
-+ }
-+
-+ st_debug(ST_ISP, "Got sensor format 0x%x !!\n", fmt.format.code);
-+
-+ formats = &isp_dev->formats[0]; /* isp sink format */
-+ for (idx = 0; idx < formats->nfmts; idx++) {
-+ if (formats->fmts[idx].code == fmt.format.code) {
-+ st_info(ST_ISP,
-+ "Match sensor format to isp_formats_st7110_sink index %d !!\n",
-+ idx);
-+ return idx;
-+ }
-+ }
-+ return -ERANGE;
-+}
-+
-+static int isp_match_format_get_index(const struct isp_format_table *f_table,
-+ __u32 mbus_code,
-+ unsigned int pad)
-+{
-+ int i;
-+
-+ for (i = 0; i < f_table->nfmts; i++) {
-+ if (mbus_code == f_table->fmts[i].code) {
-+ break;
-+ } else {
-+ if (pad == STF_ISP_PAD_SRC_RAW || pad == STF_ISP_PAD_SRC_SCD_Y) {
-+ if (mbus_code == (isp_formats_st7110_compat_10bit_raw[i].code ||
-+ isp_formats_st7110_compat_8bit_raw[i].code))
-+ break;
-+ }
-+ }
-+ }
-+
-+ return i;
-+}
-+
-+static void isp_try_format(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ const struct isp_format_table *formats;
-+ unsigned int i;
-+ u32 code = fmt->code;
-+ u32 bpp;
-+
-+ if (pad == STF_ISP_PAD_SINK) {
-+ /* Set format on sink pad */
-+
-+ formats = &isp_dev->formats[pad];
-+ fmt->width = clamp_t(u32,
-+ fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
-+ STFCAMSS_FRAME_MAX_WIDTH);
-+ fmt->height = clamp_t(u32,
-+ fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
-+ STFCAMSS_FRAME_MAX_HEIGHT);
-+ fmt->height &= ~0x1;
-+
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->flags = 0;
-+ } else {
-+ formats = &isp_dev->formats[pad];
-+ }
-+
-+ i = isp_match_format_get_index(formats, fmt->code, pad);
-+ st_debug(ST_ISP, "%s pad=%d, code=%x isp_match_format_get_index = %d\n",
-+ __func__, pad, code, i);
-+
-+ if (i >= formats->nfmts &&
-+ (pad == STF_ISP_PAD_SRC_RAW || pad == STF_ISP_PAD_SRC_SCD_Y)) {
-+ int sensor_idx;
-+
-+ sensor_idx = isp_match_sensor_format_get_index(isp_dev);
-+ if (sensor_idx)
-+ i = sensor_idx;
-+ }
-+
-+ if (pad != STF_ISP_PAD_SINK)
-+ *fmt = *__isp_get_format(isp_dev, state, STF_ISP_PAD_SINK, which);
-+
-+ if (i >= formats->nfmts) {
-+ fmt->code = formats->fmts[0].code;
-+ bpp = formats->fmts[0].bpp;
-+ st_info(ST_ISP, "Use default index 0 format = 0x%x\n", fmt->code);
-+ } else {
-+ // sink format and raw format must one by one
-+ if (pad == STF_ISP_PAD_SRC_RAW || pad == STF_ISP_PAD_SRC_SCD_Y) {
-+ fmt->code = formats->fmts[i].code;
-+ bpp = formats->fmts[i].bpp;
-+ st_info(ST_ISP, "Use mapping format from sink index %d = 0x%x\n",
-+ i, fmt->code);
-+ } else {
-+ fmt->code = code;
-+ bpp = formats->fmts[i].bpp;
-+ st_info(ST_ISP, "Use input format = 0x%x\n", fmt->code);
-+ }
-+ }
-+
-+ switch (pad) {
-+ case STF_ISP_PAD_SINK:
-+ break;
-+ case STF_ISP_PAD_SRC:
-+ isp_dev->rect[ISP_COMPOSE].bpp = bpp;
-+ break;
-+ case STF_ISP_PAD_SRC_SS0:
-+ isp_dev->rect[ISP_SCALE_SS0].bpp = bpp;
-+ break;
-+ case STF_ISP_PAD_SRC_SS1:
-+ isp_dev->rect[ISP_SCALE_SS1].bpp = bpp;
-+ break;
-+ case STF_ISP_PAD_SRC_ITIW:
-+ case STF_ISP_PAD_SRC_ITIR:
-+ isp_dev->rect[ISP_ITIWS].bpp = bpp;
-+ break;
-+ case STF_ISP_PAD_SRC_RAW:
-+ isp_dev->rect[ISP_CROP].bpp = bpp;
-+ break;
-+ case STF_ISP_PAD_SRC_SCD_Y:
-+ break;
-+ }
-+}
-+
-+static int isp_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ const struct isp_format_table *formats;
-+
-+ if (code->index >= isp_dev->formats[code->pad].nfmts)
-+ return -EINVAL;
-+
-+ formats = &isp_dev->formats[code->pad];
-+ code->code = formats->fmts[code->index].code;
-+ code->flags = 0;
-+
-+ return 0;
-+}
-+
-+static int isp_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt format;
-+
-+ if (fse->index != 0)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = 1;
-+ format.height = 1;
-+ isp_try_format(isp_dev, state, fse->pad, &format, fse->which);
-+ fse->min_width = format.width;
-+ fse->min_height = format.height;
-+
-+ if (format.code != fse->code)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = -1;
-+ format.height = -1;
-+ isp_try_format(isp_dev, state, fse->pad, &format, fse->which);
-+ fse->max_width = format.width;
-+ fse->max_height = format.height;
-+
-+ return 0;
-+}
-+
-+static int isp_get_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ format = __isp_get_format(isp_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ fmt->format = *format;
-+
-+ return 0;
-+}
-+
-+static int isp_set_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+ struct v4l2_subdev_selection sel = { 0 };
-+ struct v4l2_rect *rect = NULL;
-+ int ret;
-+
-+ st_debug(ST_ISP, "%s pad=%d, code=%x, which=%d\n",
-+ __func__, fmt->reserved[0], fmt->format.code, fmt->which);
-+ format = __isp_get_format(isp_dev, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (isp_dev->stream_count) {
-+ fmt->format = *format;
-+ if (fmt->reserved[0] != 0) {
-+ sel.which = fmt->which;
-+ sel.pad = fmt->reserved[0];
-+
-+ switch (fmt->reserved[0]) {
-+ case STF_ISP_PAD_SRC:
-+ rect = __isp_get_compose(isp_dev, state, fmt->which);
-+ break;
-+ case STF_ISP_PAD_SRC_SS0:
-+ case STF_ISP_PAD_SRC_SS1:
-+ rect = __isp_get_scale(isp_dev, state, &sel);
-+ break;
-+ case STF_ISP_PAD_SRC_ITIW:
-+ case STF_ISP_PAD_SRC_ITIR:
-+ rect = __isp_get_itiws(isp_dev, state, fmt->which);
-+ break;
-+ case STF_ISP_PAD_SRC_RAW:
-+ case STF_ISP_PAD_SRC_SCD_Y:
-+ rect = __isp_get_crop(isp_dev, state, fmt->which);
-+ break;
-+ default:
-+ break;
-+ }
-+ if (rect != NULL) {
-+ fmt->format.width = rect->width;
-+ fmt->format.height = rect->height;
-+ }
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+ goto out;
-+ } else {
-+ isp_try_format(isp_dev, state, fmt->pad, &fmt->format, fmt->which);
-+ *format = fmt->format;
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+
-+ /* Propagate the format from sink to source */
-+ if (fmt->pad == STF_ISP_PAD_SINK) {
-+ /* Reset sink pad compose selection */
-+ sel.which = fmt->which;
-+ sel.pad = STF_ISP_PAD_SINK;
-+ sel.target = V4L2_SEL_TGT_CROP;
-+ sel.r.width = fmt->format.width;
-+ sel.r.height = fmt->format.height;
-+ ret = isp_set_selection(sd, state, &sel);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+out:
-+ return 0;
-+}
-+
-+static struct v4l2_rect *
-+__isp_get_compose(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_compose(&isp_dev->subdev, state,
-+ STF_ISP_PAD_SINK);
-+
-+
-+ return &isp_dev->rect[ISP_COMPOSE].rect;
-+}
-+
-+static struct v4l2_rect *
-+__isp_get_crop(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_crop(&isp_dev->subdev, state,
-+ STF_ISP_PAD_SINK);
-+
-+ return &isp_dev->rect[ISP_CROP].rect;
-+}
-+
-+static struct v4l2_rect *
-+__isp_get_scale(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_selection *sel)
-+{
-+ int pad;
-+
-+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_compose(&isp_dev->subdev, state,
-+ STF_ISP_PAD_SINK);
-+ if (sel->pad != STF_ISP_PAD_SRC_SS0 && sel->pad != STF_ISP_PAD_SRC_SS1)
-+ return NULL;
-+
-+ pad = sel->pad == STF_ISP_PAD_SRC_SS0 ? ISP_SCALE_SS0 : ISP_SCALE_SS1;
-+ return &isp_dev->rect[pad].rect;
-+}
-+
-+static struct v4l2_rect *
-+__isp_get_itiws(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_crop(&isp_dev->subdev, state, STF_ISP_PAD_SINK);
-+
-+ return &isp_dev->rect[ISP_ITIWS].rect;
-+}
-+
-+static void isp_try_crop(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_rect *rect,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ struct v4l2_mbus_framefmt *fmt;
-+
-+ fmt = __isp_get_format(isp_dev, state, STF_ISP_PAD_SINK, which);
-+
-+ if (rect->width > fmt->width)
-+ rect->width = fmt->width;
-+
-+ if (rect->width + rect->left > fmt->width)
-+ rect->left = fmt->width - rect->width;
-+
-+ if (rect->height > fmt->height)
-+ rect->height = fmt->height;
-+
-+ if (rect->height + rect->top > fmt->height)
-+ rect->top = fmt->height - rect->height;
-+
-+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
-+ rect->left = 0;
-+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
-+ }
-+
-+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
-+ rect->top = 0;
-+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
-+ }
-+ rect->height &= ~0x1;
-+}
-+
-+static void isp_try_compose(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_rect *rect,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ struct v4l2_rect *crop;
-+
-+ crop = __isp_get_crop(isp_dev, state, which);
-+
-+ if (rect->width > crop->width)
-+ rect->width = crop->width;
-+
-+ if (rect->height > crop->height)
-+ rect->height = crop->height;
-+
-+ if (crop->width > rect->width * SCALER_RATIO_MAX)
-+ rect->width = (crop->width + SCALER_RATIO_MAX - 1) /
-+ SCALER_RATIO_MAX;
-+
-+ if (crop->height > rect->height * SCALER_RATIO_MAX)
-+ rect->height = (crop->height + SCALER_RATIO_MAX - 1) /
-+ SCALER_RATIO_MAX;
-+
-+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH)
-+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
-+
-+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT)
-+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
-+ rect->height &= ~0x1;
-+}
-+
-+static void isp_try_scale(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_rect *rect,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ struct v4l2_rect *compose;
-+
-+ compose = __isp_get_compose(isp_dev, state, which);
-+
-+ if (rect->width > compose->width)
-+ rect->width = compose->width;
-+
-+ if (rect->width + rect->left > compose->width)
-+ rect->left = compose->width - rect->width;
-+
-+ if (rect->height > compose->height)
-+ rect->height = compose->height;
-+
-+ if (rect->height + rect->top > compose->height)
-+ rect->top = compose->height - rect->height;
-+
-+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
-+ rect->left = 0;
-+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
-+ }
-+
-+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
-+ rect->top = 0;
-+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
-+ }
-+ rect->height &= ~0x1;
-+}
-+
-+static void isp_try_itiws(struct stf_isp_dev *isp_dev,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_rect *rect,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ struct v4l2_rect *crop;
-+
-+ crop = __isp_get_crop(isp_dev, state, which);
-+
-+ if (rect->width > crop->width)
-+ rect->width = crop->width;
-+
-+ if (rect->width + rect->left > crop->width)
-+ rect->left = crop->width - rect->width;
-+
-+ if (rect->height > crop->height)
-+ rect->height = crop->height;
-+
-+ if (rect->height + rect->top > crop->height)
-+ rect->top = crop->height - rect->height;
-+
-+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
-+ rect->left = 0;
-+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
-+ }
-+
-+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
-+ rect->top = 0;
-+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
-+ }
-+ rect->height &= ~0x1;
-+}
-+
-+static int isp_get_selection(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_selection *sel)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_subdev_format fmt = { 0 };
-+ struct v4l2_rect *rect;
-+ int ret;
-+
-+ switch (sel->target) {
-+ case V4L2_SEL_TGT_CROP_BOUNDS:
-+ case V4L2_SEL_TGT_CROP_DEFAULT:
-+ fmt.pad = sel->pad;
-+ fmt.which = sel->which;
-+ ret = isp_get_format(sd, state, &fmt);
-+ if (ret < 0)
-+ return ret;
-+
-+ sel->r.left = 0;
-+ sel->r.top = 0;
-+ sel->r.width = fmt.format.width;
-+ sel->r.height = fmt.format.height;
-+ break;
-+ case V4L2_SEL_TGT_CROP:
-+ rect = __isp_get_crop(isp_dev, state, sel->which);
-+ if (rect == NULL)
-+ return -EINVAL;
-+
-+ sel->r = *rect;
-+ break;
-+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-+ if (sel->pad > STF_ISP_PAD_SRC_ITIR)
-+ return -EINVAL;
-+ rect = __isp_get_crop(isp_dev, state, sel->which);
-+ if (rect == NULL)
-+ return -EINVAL;
-+
-+ sel->r.left = rect->left;
-+ sel->r.top = rect->top;
-+ sel->r.width = rect->width;
-+ sel->r.height = rect->height;
-+ break;
-+ case V4L2_SEL_TGT_COMPOSE:
-+ if (sel->pad > STF_ISP_PAD_SRC_ITIR)
-+ return -EINVAL;
-+ if (sel->pad == STF_ISP_PAD_SRC_SS0
-+ || sel->pad == STF_ISP_PAD_SRC_SS1) {
-+ rect = __isp_get_scale(isp_dev, state, sel);
-+ if (rect == NULL)
-+ return -EINVAL;
-+ } else if (sel->pad == STF_ISP_PAD_SRC_ITIW
-+ || sel->pad == STF_ISP_PAD_SRC_ITIR) {
-+ rect = __isp_get_itiws(isp_dev, state, sel->which);
-+ if (rect == NULL)
-+ return -EINVAL;
-+ } else {
-+ rect = __isp_get_compose(isp_dev, state, sel->which);
-+ if (rect == NULL)
-+ return -EINVAL;
-+ }
-+ sel->r = *rect;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ st_info(ST_ISP, "%s pad = %d, left = %d, %d, %d, %d\n",
-+ __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
-+ return 0;
-+}
-+
-+static int isp_set_selection(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_selection *sel)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ struct v4l2_rect *rect;
-+ int ret = 0;
-+
-+ if (sel->target == V4L2_SEL_TGT_COMPOSE &&
-+ ((sel->pad == STF_ISP_PAD_SINK)
-+ || (sel->pad == STF_ISP_PAD_SRC))) {
-+ struct v4l2_subdev_format fmt = { 0 };
-+ int i;
-+
-+ rect = __isp_get_compose(isp_dev, state, sel->which);
-+ if (rect == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (isp_dev->stream_count) {
-+ sel->r = *rect;
-+ mutex_unlock(&isp_dev->stream_lock);
-+ ret = 0;
-+ goto out;
-+ } else {
-+ isp_try_compose(isp_dev, state, &sel->r, sel->which);
-+ *rect = sel->r;
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+
-+ /* Reset source pad format width and height */
-+ fmt.which = sel->which;
-+ fmt.pad = STF_ISP_PAD_SRC;
-+ ret = isp_get_format(sd, state, &fmt);
-+ if (ret < 0)
-+ return ret;
-+
-+ fmt.format.width = rect->width;
-+ fmt.format.height = rect->height;
-+ ret = isp_set_format(sd, state, &fmt);
-+
-+ /* Reset scale */
-+ for (i = STF_ISP_PAD_SRC_SS0; i <= STF_ISP_PAD_SRC_ITIR; i++) {
-+ struct v4l2_subdev_selection scale = { 0 };
-+
-+ scale.which = sel->which;
-+ scale.target = V4L2_SEL_TGT_COMPOSE;
-+ scale.r = *rect;
-+ scale.pad = i;
-+ ret = isp_set_selection(sd, state, &scale);
-+ }
-+ } else if (sel->target == V4L2_SEL_TGT_COMPOSE
-+ && ((sel->pad == STF_ISP_PAD_SRC_SS0)
-+ || (sel->pad == STF_ISP_PAD_SRC_SS1))) {
-+ struct v4l2_subdev_format fmt = { 0 };
-+
-+ rect = __isp_get_scale(isp_dev, state, sel);
-+ if (rect == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (isp_dev->stream_count) {
-+ sel->r = *rect;
-+ mutex_unlock(&isp_dev->stream_lock);
-+ ret = 0;
-+ goto out;
-+ } else {
-+ isp_try_scale(isp_dev, state, &sel->r, sel->which);
-+ *rect = sel->r;
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+
-+ /* Reset source pad format width and height */
-+ fmt.which = sel->which;
-+ fmt.pad = sel->pad;
-+ ret = isp_get_format(sd, state, &fmt);
-+ if (ret < 0)
-+ return ret;
-+
-+ fmt.format.width = rect->width;
-+ fmt.format.height = rect->height;
-+ ret = isp_set_format(sd, state, &fmt);
-+ } else if (sel->target == V4L2_SEL_TGT_COMPOSE
-+ && ((sel->pad == STF_ISP_PAD_SRC_ITIW)
-+ || (sel->pad == STF_ISP_PAD_SRC_ITIR))) {
-+ struct v4l2_subdev_format fmt = { 0 };
-+
-+ rect = __isp_get_itiws(isp_dev, state, sel->which);
-+ if (rect == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (isp_dev->stream_count) {
-+ sel->r = *rect;
-+ mutex_unlock(&isp_dev->stream_lock);
-+ ret = 0;
-+ goto out;
-+ } else {
-+ isp_try_itiws(isp_dev, state, &sel->r, sel->which);
-+ *rect = sel->r;
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+
-+ /* Reset source pad format width and height */
-+ fmt.which = sel->which;
-+ fmt.pad = sel->pad;
-+ ret = isp_get_format(sd, state, &fmt);
-+ if (ret < 0)
-+ return ret;
-+
-+ fmt.format.width = rect->width;
-+ fmt.format.height = rect->height;
-+ ret = isp_set_format(sd, state, &fmt);
-+ } else if (sel->target == V4L2_SEL_TGT_CROP) {
-+ struct v4l2_subdev_selection compose = { 0 };
-+ int i;
-+
-+ rect = __isp_get_crop(isp_dev, state, sel->which);
-+ if (rect == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (isp_dev->stream_count) {
-+ sel->r = *rect;
-+ mutex_unlock(&isp_dev->stream_lock);
-+ ret = 0;
-+ goto out;
-+ } else {
-+ isp_try_crop(isp_dev, state, &sel->r, sel->which);
-+ *rect = sel->r;
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+
-+ /* Reset source compose selection */
-+ compose.which = sel->which;
-+ compose.target = V4L2_SEL_TGT_COMPOSE;
-+ compose.r.width = rect->width;
-+ compose.r.height = rect->height;
-+ compose.pad = STF_ISP_PAD_SINK;
-+ ret = isp_set_selection(sd, state, &compose);
-+
-+ /* Reset source pad format width and height */
-+ for (i = STF_ISP_PAD_SRC_RAW; i < STF_ISP_PAD_MAX; i++) {
-+ struct v4l2_subdev_format fmt = { 0 };
-+
-+ fmt.which = sel->which;
-+ fmt.pad = i;
-+ ret = isp_get_format(sd, state, &fmt);
-+ if (ret < 0)
-+ return ret;
-+
-+ fmt.format.width = rect->width;
-+ fmt.format.height = rect->height;
-+ ret = isp_set_format(sd, state, &fmt);
-+ }
-+ } else {
-+ ret = -EINVAL;
-+ }
-+
-+ st_info(ST_ISP, "%s pad = %d, left = %d, %d, %d, %d\n",
-+ __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
-+out:
-+ return ret;
-+}
-+
-+static int isp_init_formats(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_subdev_format format = {
-+ .pad = STF_ISP_PAD_SINK,
-+ .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
-+ V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .format = {
-+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
-+ .width = 1920,
-+ .height = 1080
-+ }
-+ };
-+
-+ return isp_set_format(sd, fh ? fh->state : NULL, &format);
-+}
-+
-+static int isp_link_setup(struct media_entity *entity,
-+ const struct media_pad *local,
-+ const struct media_pad *remote, u32 flags)
-+{
-+ if (flags & MEDIA_LNK_FL_ENABLED)
-+ if (media_pad_remote_pad_first(local))
-+ return -EBUSY;
-+ return 0;
-+}
-+
-+static int stf_isp_load_setfile(struct stf_isp_dev *isp_dev, char *file_name)
-+{
-+ struct device *dev = isp_dev->stfcamss->dev;
-+ const struct firmware *fw;
-+ u8 *buf = NULL;
-+ int *regval_num;
-+ int ret;
-+
-+ st_debug(ST_ISP, "%s, file_name %s\n", __func__, file_name);
-+ ret = request_firmware(&fw, file_name, dev);
-+ if (ret < 0) {
-+ st_err(ST_ISP, "firmware request failed (%d)\n", ret);
-+ return ret;
-+ }
-+ buf = devm_kzalloc(dev, fw->size, GFP_KERNEL);
-+ if (!buf)
-+ return -ENOMEM;
-+ memcpy(buf, fw->data, fw->size);
-+
-+ mutex_lock(&isp_dev->setfile_lock);
-+ if (isp_dev->setfile.state == 1)
-+ devm_kfree(dev, isp_dev->setfile.data);
-+ isp_dev->setfile.data = buf;
-+ isp_dev->setfile.size = fw->size;
-+ isp_dev->setfile.state = 1;
-+ regval_num = (int *)&buf[fw->size - sizeof(unsigned int)];
-+ isp_dev->setfile.settings.regval_num = *regval_num;
-+ isp_dev->setfile.settings.regval = (struct regval_t *)buf;
-+ mutex_unlock(&isp_dev->setfile_lock);
-+
-+ st_debug(ST_ISP, "stf_isp setfile loaded size: %zu B, reg_nul: %d\n",
-+ fw->size, isp_dev->setfile.settings.regval_num);
-+
-+ release_firmware(fw);
-+ return ret;
-+}
-+
-+static long stf_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+ struct device *dev = isp_dev->stfcamss->dev;
-+ int ret = -ENOIOCTLCMD;
-+
-+ switch (cmd) {
-+ case VIDIOC_STFISP_LOAD_FW: {
-+ struct stfisp_fw_info *fw_info = arg;
-+
-+ if (IS_ERR(fw_info)) {
-+ st_err(ST_ISP, "fw_info failed, params invaild\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = stf_isp_load_setfile(isp_dev, fw_info->filename);
-+ break;
-+ }
-+ case VIDIOC_STF_DMABUF_ALLOC:
-+ case VIDIOC_STF_DMABUF_FREE:
-+ ret = stf_dmabuf_ioctl(dev, cmd, arg);
-+ break;
-+ case VIDIOC_STFISP_GET_REG:
-+ ret = isp_dev->hw_ops->isp_reg_read(isp_dev, arg);
-+ break;
-+ case VIDIOC_STFISP_SET_REG:
-+ ret = isp_dev->hw_ops->isp_reg_write(isp_dev, arg);
-+ break;
-+ case VIDIOC_STFISP_SHADOW_LOCK:
-+ if (atomic_add_unless(&isp_dev->shadow_count, 1, 1))
-+ ret = 0;
-+ else
-+ ret = -EBUSY;
-+ st_debug(ST_ISP, "%s, %d, ret = %d\n", __func__, __LINE__, ret);
-+ break;
-+ case VIDIOC_STFISP_SHADOW_UNLOCK:
-+ if (atomic_dec_if_positive(&isp_dev->shadow_count) < 0)
-+ ret = -EINVAL;
-+ else
-+ ret = 0;
-+ st_debug(ST_ISP, "%s, %d, ret = %d\n", __func__, __LINE__, ret);
-+ break;
-+ case VIDIOC_STFISP_SHADOW_UNLOCK_N_TRIGGER:
-+ {
-+ isp_dev->hw_ops->isp_shadow_trigger(isp_dev);
-+ if (atomic_dec_if_positive(&isp_dev->shadow_count) < 0)
-+ ret = -EINVAL;
-+ else
-+ ret = 0;
-+ st_debug(ST_ISP, "%s, %d, ret = %d\n", __func__, __LINE__, ret);
-+ }
-+ break;
-+ case VIDIOC_STFISP_SET_USER_CONFIG_ISP:
-+ st_debug(ST_ISP, "%s, %d set user_config_isp\n", __func__, __LINE__);
-+ user_config_isp = 1;
-+ break;
-+ default:
-+ break;
-+ }
-+ return ret;
-+}
-+
-+int isp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-+{
-+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-+
-+ st_debug(ST_ISP, "%s, %d\n", __func__, __LINE__);
-+ while (atomic_dec_if_positive(&isp_dev->shadow_count) > 0)
-+ st_warn(ST_ISP, "user not unlocked the shadow lock, driver unlock it!\n");
-+
-+ return 0;
-+}
-+
-+static int stf_isp_subscribe_event(struct v4l2_subdev *sd,
-+ struct v4l2_fh *fh,
-+ struct v4l2_event_subscription *sub)
-+{
-+ switch (sub->type) {
-+ case V4L2_EVENT_SOURCE_CHANGE:
-+ return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
-+ case V4L2_EVENT_CTRL:
-+ return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
-+ default:
-+ st_debug(ST_ISP, "unspport subscribe_event\n");
-+ return -EINVAL;
-+ }
-+}
-+
-+static const struct v4l2_subdev_core_ops isp_core_ops = {
-+ .s_power = isp_set_power,
-+ .ioctl = stf_isp_ioctl,
-+ .log_status = v4l2_ctrl_subdev_log_status,
-+ // .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
-+ .subscribe_event = stf_isp_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops isp_video_ops = {
-+ .s_stream = isp_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops isp_pad_ops = {
-+ .enum_mbus_code = isp_enum_mbus_code,
-+ .enum_frame_size = isp_enum_frame_size,
-+ .get_fmt = isp_get_format,
-+ .set_fmt = isp_set_format,
-+ .get_selection = isp_get_selection,
-+ .set_selection = isp_set_selection,
-+};
-+
-+static const struct v4l2_subdev_ops isp_v4l2_ops = {
-+ .core = &isp_core_ops,
-+ .video = &isp_video_ops,
-+ .pad = &isp_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops isp_v4l2_internal_ops = {
-+ .open = isp_init_formats,
-+ .close = isp_close,
-+};
-+
-+static const struct media_entity_operations isp_media_ops = {
-+ .link_setup = isp_link_setup,
-+ .link_validate = v4l2_subdev_link_validate,
-+};
-+
-+int stf_isp_register(struct stf_isp_dev *isp_dev,
-+ struct v4l2_device *v4l2_dev)
-+{
-+ struct v4l2_subdev *sd = &isp_dev->subdev;
-+ struct media_pad *pads = isp_dev->pads;
-+ int ret;
-+
-+ v4l2_subdev_init(sd, &isp_v4l2_ops);
-+ sd->internal_ops = &isp_v4l2_internal_ops;
-+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
-+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
-+ STF_ISP_NAME, 0);
-+ v4l2_set_subdevdata(sd, isp_dev);
-+
-+ ret = isp_init_formats(sd, NULL);
-+ if (ret < 0) {
-+ st_err(ST_ISP, "Failed to init format: %d\n", ret);
-+ return ret;
-+ }
-+
-+ pads[STF_ISP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-+ pads[STF_ISP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
-+ pads[STF_ISP_PAD_SRC_SS0].flags = MEDIA_PAD_FL_SOURCE;
-+ pads[STF_ISP_PAD_SRC_SS1].flags = MEDIA_PAD_FL_SOURCE;
-+ pads[STF_ISP_PAD_SRC_ITIW].flags = MEDIA_PAD_FL_SOURCE;
-+ pads[STF_ISP_PAD_SRC_ITIR].flags = MEDIA_PAD_FL_SOURCE;
-+ pads[STF_ISP_PAD_SRC_RAW].flags = MEDIA_PAD_FL_SOURCE;
-+ pads[STF_ISP_PAD_SRC_SCD_Y].flags = MEDIA_PAD_FL_SOURCE;
-+
-+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
-+ sd->entity.ops = &isp_media_ops;
-+ ret = media_entity_pads_init(&sd->entity, STF_ISP_PAD_MAX, pads);
-+ if (ret < 0) {
-+ st_err(ST_ISP, "Failed to init media entity: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = isp_init_controls(isp_dev);
-+ if (ret)
-+ goto err_sreg;
-+
-+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
-+ if (ret < 0) {
-+ st_err(ST_ISP, "Failed to register subdev: %d\n", ret);
-+ goto free_ctrls;
-+ }
-+
-+ return 0;
-+
-+free_ctrls:
-+ v4l2_ctrl_handler_free(&isp_dev->ctrls.handler);
-+err_sreg:
-+ media_entity_cleanup(&sd->entity);
-+ return ret;
-+}
-+
-+int stf_isp_unregister(struct stf_isp_dev *isp_dev)
-+{
-+ v4l2_device_unregister_subdev(&isp_dev->subdev);
-+ media_entity_cleanup(&isp_dev->subdev.entity);
-+ v4l2_ctrl_handler_free(&isp_dev->ctrls.handler);
-+ mutex_destroy(&isp_dev->stream_lock);
-+ mutex_destroy(&isp_dev->power_lock);
-+ mutex_destroy(&isp_dev->setfile_lock);
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.h
-@@ -0,0 +1,222 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_ISP_H
-+#define STF_ISP_H
-+
-+#include <media/v4l2-subdev.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/media-entity.h>
-+#include <video/stf-vin.h>
-+
-+#define STF_ISP_NAME "stf_isp"
-+#define STF_ISP_SETFILE "stf_isp0_fw.bin"
-+
-+#define ISP_SCD_BUFFER_SIZE (19 * 256 * 4) // align 128
-+#define ISP_YHIST_BUFFER_SIZE (64 * 4)
-+#define ISP_SCD_Y_BUFFER_SIZE (ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)
-+#define ISP_RAW_DATA_BITS 12
-+#define SCALER_RATIO_MAX 1 // no compose function
-+#define STF_ISP_REG_OFFSET_MAX 0x0FFF
-+#define STF_ISP_REG_DELAY_MAX 100
-+
-+#define ISP_REG_CSIINTS_ADDR 0x00000008
-+#define ISP_REG_SENSOR 0x00000014
-+#define ISP_REG_DUMP_CFG_0 0x00000024
-+#define ISP_REG_DUMP_CFG_1 0x00000028
-+#define ISP_REG_SCD_CFG_0 0x00000098
-+#define ISP_REG_SCD_CFG_1 0x0000009C
-+#define ISP_REG_SC_CFG_1 0x000000BC
-+#define ISP_REG_IESHD_ADDR 0x00000A50
-+#define ISP_REG_SS0AY 0x00000A94
-+#define ISP_REG_SS0AUV 0x00000A98
-+#define ISP_REG_SS0S 0x00000A9C
-+#define ISP_REG_SS0IW 0x00000AA8
-+#define ISP_REG_SS1AY 0x00000AAC
-+#define ISP_REG_SS1AUV 0x00000AB0
-+#define ISP_REG_SS1S 0x00000AB4
-+#define ISP_REG_SS1IW 0x00000AC0
-+#define ISP_REG_YHIST_CFG_4 0x00000CD8
-+#define ISP_REG_ITIIWSR 0x00000B20
-+#define ISP_REG_ITIDWLSR 0x00000B24
-+#define ISP_REG_ITIDWYSAR 0x00000B28
-+#define ISP_REG_ITIDWUSAR 0x00000B2C
-+#define ISP_REG_ITIDRYSAR 0x00000B30
-+#define ISP_REG_ITIDRUSAR 0x00000B34
-+#define ISP_REG_ITIPDFR 0x00000B38
-+#define ISP_REG_ITIDRLSR 0x00000B3C
-+#define ISP_REG_ITIBSR 0x00000B40
-+#define ISP_REG_ITIAIR 0x00000B44
-+#define ISP_REG_ITIDPSR 0x00000B48
-+
-+/* The output line of a isp controller */
-+enum isp_line_id {
-+ STF_ISP_LINE_INVALID = -1,
-+ STF_ISP_LINE_SRC = 1,
-+ STF_ISP_LINE_SRC_SS0 = 2,
-+ STF_ISP_LINE_SRC_SS1 = 3,
-+ STF_ISP_LINE_SRC_ITIW = 4,
-+ STF_ISP_LINE_SRC_ITIR = 5,
-+ STF_ISP_LINE_SRC_RAW = 6,
-+ STF_ISP_LINE_SRC_SCD_Y = 7,
-+ STF_ISP_LINE_MAX = STF_ISP_LINE_SRC_SCD_Y
-+};
-+
-+/* pad id for media framework */
-+enum isp_pad_id {
-+ STF_ISP_PAD_SINK = 0,
-+ STF_ISP_PAD_SRC = 1,
-+ STF_ISP_PAD_SRC_SS0 = 2,
-+ STF_ISP_PAD_SRC_SS1 = 3,
-+ STF_ISP_PAD_SRC_ITIW = 4,
-+ STF_ISP_PAD_SRC_ITIR = 5,
-+ STF_ISP_PAD_SRC_RAW = 6,
-+ STF_ISP_PAD_SRC_SCD_Y = 7,
-+ STF_ISP_PAD_MAX = 8
-+};
-+
-+enum {
-+ EN_INT_NONE = 0,
-+ EN_INT_ISP_DONE = (0x1 << 24),
-+ EN_INT_CSI_DONE = (0x1 << 25),
-+ EN_INT_SC_DONE = (0x1 << 26),
-+ EN_INT_LINE_INT = (0x1 << 27),
-+ EN_INT_ALL = (0xF << 24),
-+};
-+
-+enum {
-+ DVP_SENSOR = 0,
-+ CSI_SENSOR,
-+};
-+
-+#define ISP_AWB_OECF_SKIP_FRAME 0
-+// 0x0BC [31:30] SEL - sc0 input mux for sc awb
-+// 00 : after DEC, 01 : after OBC, 10 : after OECF, 11 : after AWB
-+enum scd_type {
-+ DEC_TYPE = 0,
-+ OBC_TYPE,
-+ OECF_TYPE,
-+ AWB_TYPE
-+};
-+
-+struct isp_format {
-+ u32 code;
-+ u8 bpp;
-+};
-+
-+struct isp_format_table {
-+ const struct isp_format *fmts;
-+ int nfmts;
-+};
-+
-+struct regval_t {
-+ u32 addr;
-+ u32 val;
-+ u32 mask;
-+ u32 delay_ms;
-+};
-+
-+struct reg_table {
-+ struct regval_t *regval;
-+ int regval_num;
-+};
-+
-+struct isp_stream_format {
-+ struct v4l2_rect rect;
-+ u32 bpp;
-+};
-+
-+struct stf_isp_dev;
-+enum subdev_type;
-+
-+struct isp_hw_ops {
-+ int (*isp_clk_enable)(struct stf_isp_dev *isp_dev);
-+ int (*isp_clk_disable)(struct stf_isp_dev *isp_dev);
-+ int (*isp_reset)(struct stf_isp_dev *isp_dev);
-+ int (*isp_config_set)(struct stf_isp_dev *isp_dev);
-+ int (*isp_set_format)(struct stf_isp_dev *isp_dev,
-+ struct isp_stream_format *crop, u32 mcode,
-+ int type);
-+ // u32 width, u32 height);
-+ int (*isp_stream_set)(struct stf_isp_dev *isp_dev, int on);
-+ int (*isp_reg_read)(struct stf_isp_dev *isp_dev, void *arg);
-+ int (*isp_reg_write)(struct stf_isp_dev *isp_dev, void *arg);
-+ int (*isp_shadow_trigger)(struct stf_isp_dev *isp_dev);
-+};
-+
-+struct isp_ctrls {
-+ struct v4l2_ctrl_handler handler;
-+ struct v4l2_ctrl *pixel_rate;
-+ struct {
-+ struct v4l2_ctrl *auto_exp;
-+ struct v4l2_ctrl *exposure;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_wb;
-+ struct v4l2_ctrl *blue_balance;
-+ struct v4l2_ctrl *red_balance;
-+ };
-+ struct {
-+ struct v4l2_ctrl *auto_gain;
-+ struct v4l2_ctrl *gain;
-+ };
-+ struct v4l2_ctrl *brightness;
-+ struct v4l2_ctrl *light_freq;
-+ struct v4l2_ctrl *saturation;
-+ struct v4l2_ctrl *contrast;
-+ struct v4l2_ctrl *hue;
-+ struct v4l2_ctrl *test_pattern;
-+ struct v4l2_ctrl *hflip;
-+ struct v4l2_ctrl *vflip;
-+};
-+
-+struct isp_setfile {
-+ struct reg_table settings;
-+ const u8 *data;
-+ unsigned int size;
-+ unsigned int state;
-+};
-+
-+enum {
-+ ISP_CROP = 0,
-+ ISP_COMPOSE,
-+ ISP_SCALE_SS0,
-+ ISP_SCALE_SS1,
-+ ISP_ITIWS,
-+ ISP_RECT_MAX
-+};
-+
-+struct stf_isp_dev {
-+ enum subdev_type sdev_type; // must be frist
-+ struct stfcamss *stfcamss;
-+ struct v4l2_subdev subdev;
-+ struct media_pad pads[STF_ISP_PAD_MAX];
-+ struct v4l2_mbus_framefmt fmt[STF_ISP_PAD_MAX];
-+ struct isp_stream_format rect[ISP_RECT_MAX];
-+ const struct isp_format_table *formats;
-+ unsigned int nformats;
-+ struct isp_hw_ops *hw_ops;
-+ struct mutex power_lock;
-+ int power_count;
-+ struct mutex stream_lock;
-+ int stream_count;
-+ atomic_t shadow_count;
-+
-+ struct isp_ctrls ctrls;
-+ struct mutex setfile_lock;
-+ struct isp_setfile setfile;
-+ struct reg_table *context_regs;
-+};
-+
-+extern int stf_isp_subdev_init(struct stfcamss *stfcamss);
-+extern int stf_isp_register(struct stf_isp_dev *isp_dev,
-+ struct v4l2_device *v4l2_dev);
-+extern int stf_isp_unregister(struct stf_isp_dev *isp_dev);
-+extern struct isp_hw_ops isp_ops;
-+extern void dump_isp_reg(void *__iomem ispbase);
-+
-+#endif /* STF_ISP_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp_hw_ops.c
-@@ -0,0 +1,1550 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <linux/io.h>
-+#include <linux/fb.h>
-+#include <linux/module.h>
-+#include <video/stf-vin.h>
-+#include "stf_isp_ioctl.h"
-+#include "stf_isp.h"
-+#include <linux/delay.h>
-+#include <linux/clk.h>
-+#define USE_NEW_CONFIG_SETTING
-+
-+static struct regval_t isp_reg_init_config_list[] = {
-+ /* config DC(0040H~0044H) */
-+ {0x00000044, 0x00000000, 0, 0},
-+ /* config DEC(0030H) */
-+ {0x00000030, 0x00000000, 0, 0},
-+ /* config OBC(0034H, 02E0H~02FCH) */
-+ {0x00000034, 0x000000BB, 0, 0},
-+ {0x000002E0, 0x40404040, 0, 0},
-+ {0x000002E4, 0x40404040, 0, 0},
-+ {0x000002E8, 0x40404040, 0, 0},
-+ {0x000002EC, 0x40404040, 0, 0},
-+ {0x000002F0, 0x00000000, 0, 0},
-+ {0x000002F4, 0x00000000, 0, 0},
-+ {0x000002F8, 0x00000000, 0, 0},
-+ {0x000002FC, 0x00000000, 0, 0},
-+ /* config LCBQ(0074H, 007CH, 0300H~039FH, and 0400H~049FH) */
-+ {0x00000074, 0x00009900, 0, 0},
-+ {0x0000007C, 0x01E40040, 0, 0},
-+ {0x00000300, 0x01000100, 0, 0},
-+ {0x00000304, 0x01000100, 0, 0},
-+ {0x00000308, 0x01000100, 0, 0},
-+ {0x0000030C, 0x01000100, 0, 0},
-+ {0x00000310, 0x01000100, 0, 0},
-+ {0x00000314, 0x01000100, 0, 0},
-+ {0x00000318, 0x01000100, 0, 0},
-+ {0x0000031C, 0x01000100, 0, 0},
-+ {0x00000320, 0x01000100, 0, 0},
-+ {0x00000324, 0x01000100, 0, 0},
-+ {0x00000328, 0x01000100, 0, 0},
-+ {0x0000032C, 0x01000100, 0, 0},
-+ {0x00000330, 0x00000100, 0, 0},
-+ {0x00000334, 0x01000100, 0, 0},
-+ {0x00000338, 0x01000100, 0, 0},
-+ {0x0000033C, 0x01000100, 0, 0},
-+ {0x00000340, 0x01000100, 0, 0},
-+ {0x00000344, 0x01000100, 0, 0},
-+ {0x00000348, 0x01000100, 0, 0},
-+ {0x0000034C, 0x01000100, 0, 0},
-+ {0x00000350, 0x01000100, 0, 0},
-+ {0x00000354, 0x01000100, 0, 0},
-+ {0x00000358, 0x01000100, 0, 0},
-+ {0x0000035C, 0x01000100, 0, 0},
-+ {0x00000360, 0x01000100, 0, 0},
-+ {0x00000364, 0x00000100, 0, 0},
-+ {0x00000368, 0x01000100, 0, 0},
-+ {0x0000036C, 0x01000100, 0, 0},
-+ {0x00000370, 0x01000100, 0, 0},
-+ {0x00000374, 0x01000100, 0, 0},
-+ {0x00000378, 0x01000100, 0, 0},
-+ {0x0000037C, 0x01000100, 0, 0},
-+ {0x00000380, 0x01000100, 0, 0},
-+ {0x00000384, 0x01000100, 0, 0},
-+ {0x00000388, 0x01000100, 0, 0},
-+ {0x0000038C, 0x01000100, 0, 0},
-+ {0x00000390, 0x01000100, 0, 0},
-+ {0x00000394, 0x01000100, 0, 0},
-+ {0x00000398, 0x00000100, 0, 0},
-+ {0x0000039C, 0x01000100, 0, 0},
-+ {0x000003A0, 0x01000100, 0, 0},
-+ {0x000003A4, 0x01000100, 0, 0},
-+ {0x000003A8, 0x01000100, 0, 0},
-+ {0x000003AC, 0x01000100, 0, 0},
-+ {0x000003B0, 0x01000100, 0, 0},
-+ {0x000003B4, 0x01000100, 0, 0},
-+ {0x000003B8, 0x01000100, 0, 0},
-+ {0x000003BC, 0x01000100, 0, 0},
-+ {0x000003C0, 0x01000100, 0, 0},
-+ {0x000003C4, 0x01000100, 0, 0},
-+ {0x000003C8, 0x01000100, 0, 0},
-+ {0x000003CC, 0x00000100, 0, 0},
-+ {0x00000400, 0x00000000, 0, 0},
-+ {0x00000404, 0x00000000, 0, 0},
-+ {0x00000408, 0x00000000, 0, 0},
-+ {0x0000040C, 0x00000000, 0, 0},
-+ {0x00000410, 0x00000000, 0, 0},
-+ {0x00000414, 0x00000000, 0, 0},
-+ {0x00000418, 0x00000000, 0, 0},
-+ {0x0000041C, 0x00000000, 0, 0},
-+ {0x00000420, 0x00000000, 0, 0},
-+ {0x00000424, 0x00000000, 0, 0},
-+ {0x00000428, 0x00000000, 0, 0},
-+ {0x0000042C, 0x00000000, 0, 0},
-+ {0x00000430, 0x00000000, 0, 0},
-+ {0x00000434, 0x00000000, 0, 0},
-+ {0x00000438, 0x00000000, 0, 0},
-+ {0x0000043C, 0x00000000, 0, 0},
-+ {0x00000440, 0x00000000, 0, 0},
-+ {0x00000444, 0x00000000, 0, 0},
-+ {0x00000448, 0x00000000, 0, 0},
-+ {0x0000044C, 0x00000000, 0, 0},
-+ {0x00000450, 0x00000000, 0, 0},
-+ {0x00000454, 0x00000000, 0, 0},
-+ {0x00000458, 0x00000000, 0, 0},
-+ {0x0000045C, 0x00000000, 0, 0},
-+ {0x00000460, 0x00000000, 0, 0},
-+ {0x00000464, 0x00000000, 0, 0},
-+ {0x00000468, 0x00000000, 0, 0},
-+ {0x0000046C, 0x00000000, 0, 0},
-+ {0x00000470, 0x00000000, 0, 0},
-+ {0x00000474, 0x00000000, 0, 0},
-+ {0x00000478, 0x00000000, 0, 0},
-+ {0x0000047C, 0x00000000, 0, 0},
-+ {0x00000480, 0x00000000, 0, 0},
-+ {0x00000484, 0x00000000, 0, 0},
-+ {0x00000488, 0x00000000, 0, 0},
-+ {0x0000048C, 0x00000000, 0, 0},
-+ {0x00000490, 0x00000000, 0, 0},
-+ {0x00000494, 0x00000000, 0, 0},
-+ {0x00000498, 0x00000000, 0, 0},
-+ {0x0000049C, 0x00000000, 0, 0},
-+ {0x000004A0, 0x00000000, 0, 0},
-+ {0x000004A4, 0x00000000, 0, 0},
-+ {0x000004A8, 0x00000000, 0, 0},
-+ {0x000004AC, 0x00000000, 0, 0},
-+ {0x000004B0, 0x00000000, 0, 0},
-+ {0x000004B4, 0x00000000, 0, 0},
-+ {0x000004B8, 0x00000000, 0, 0},
-+ {0x000004BC, 0x00000000, 0, 0},
-+ {0x000004C0, 0x00000000, 0, 0},
-+ {0x000004C4, 0x00000000, 0, 0},
-+ {0x000004C8, 0x00000000, 0, 0},
-+ {0x000004CC, 0x00000000, 0, 0},
-+ /* config OECF(0100H~027CH) */
-+ {0x00000100, 0x00100000, 0, 0},
-+ {0x00000104, 0x00400020, 0, 0},
-+ {0x00000108, 0x00800060, 0, 0},
-+ {0x0000010C, 0x00C000A0, 0, 0},
-+ {0x00000110, 0x010000E0, 0, 0},
-+ {0x00000114, 0x02000180, 0, 0},
-+ {0x00000118, 0x03000280, 0, 0},
-+ {0x0000011C, 0x03FE0380, 0, 0},
-+ {0x00000120, 0x00100000, 0, 0},
-+ {0x00000124, 0x00400020, 0, 0},
-+ {0x00000128, 0x00800060, 0, 0},
-+ {0x0000012C, 0x00C000A0, 0, 0},
-+ {0x00000130, 0x010000E0, 0, 0},
-+ {0x00000134, 0x02000180, 0, 0},
-+ {0x00000138, 0x03000280, 0, 0},
-+ {0x0000013C, 0x03FE0380, 0, 0},
-+ {0x00000140, 0x00100000, 0, 0},
-+ {0x00000144, 0x00400020, 0, 0},
-+ {0x00000148, 0x00800060, 0, 0},
-+ {0x0000014C, 0x00C000A0, 0, 0},
-+ {0x00000150, 0x010000E0, 0, 0},
-+ {0x00000154, 0x02000180, 0, 0},
-+ {0x00000158, 0x03000280, 0, 0},
-+ {0x0000015C, 0x03FE0380, 0, 0},
-+ {0x00000160, 0x00100000, 0, 0},
-+ {0x00000164, 0x00400020, 0, 0},
-+ {0x00000168, 0x00800060, 0, 0},
-+ {0x0000016C, 0x00C000A0, 0, 0},
-+ {0x00000170, 0x010000E0, 0, 0},
-+ {0x00000174, 0x02000180, 0, 0},
-+ {0x00000178, 0x03000280, 0, 0},
-+ {0x0000017C, 0x03FE0380, 0, 0},
-+ {0x00000180, 0x00100000, 0, 0},
-+ {0x00000184, 0x00400020, 0, 0},
-+ {0x00000188, 0x00800060, 0, 0},
-+ {0x0000018C, 0x00C000A0, 0, 0},
-+ {0x00000190, 0x010000E0, 0, 0},
-+ {0x00000194, 0x02000180, 0, 0},
-+ {0x00000198, 0x03000280, 0, 0},
-+ {0x0000019C, 0x03FE0380, 0, 0},
-+ {0x000001A0, 0x00100000, 0, 0},
-+ {0x000001A4, 0x00400020, 0, 0},
-+ {0x000001A8, 0x00800060, 0, 0},
-+ {0x000001AC, 0x00C000A0, 0, 0},
-+ {0x000001B0, 0x010000E0, 0, 0},
-+ {0x000001B4, 0x02000180, 0, 0},
-+ {0x000001B8, 0x03000280, 0, 0},
-+ {0x000001BC, 0x03FE0380, 0, 0},
-+ {0x000001C0, 0x00100000, 0, 0},
-+ {0x000001C4, 0x00400020, 0, 0},
-+ {0x000001C8, 0x00800060, 0, 0},
-+ {0x000001CC, 0x00C000A0, 0, 0},
-+ {0x000001D0, 0x010000E0, 0, 0},
-+ {0x000001D4, 0x02000180, 0, 0},
-+ {0x000001D8, 0x03000280, 0, 0},
-+ {0x000001DC, 0x03FE0380, 0, 0},
-+ {0x000001E0, 0x00100000, 0, 0},
-+ {0x000001E4, 0x00400020, 0, 0},
-+ {0x000001E8, 0x00800060, 0, 0},
-+ {0x000001EC, 0x00C000A0, 0, 0},
-+ {0x000001F0, 0x010000E0, 0, 0},
-+ {0x000001F4, 0x02000180, 0, 0},
-+ {0x000001F8, 0x03000280, 0, 0},
-+ {0x000001FC, 0x03FE0380, 0, 0},
-+ {0x00000200, 0x00800080, 0, 0},
-+ {0x00000204, 0x00800080, 0, 0},
-+ {0x00000208, 0x00800080, 0, 0},
-+ {0x0000020C, 0x00800080, 0, 0},
-+ {0x00000210, 0x00800080, 0, 0},
-+ {0x00000214, 0x00800080, 0, 0},
-+ {0x00000218, 0x00800080, 0, 0},
-+ {0x0000021C, 0x00800080, 0, 0},
-+ {0x00000220, 0x00800080, 0, 0},
-+ {0x00000224, 0x00800080, 0, 0},
-+ {0x00000228, 0x00800080, 0, 0},
-+ {0x0000022C, 0x00800080, 0, 0},
-+ {0x00000230, 0x00800080, 0, 0},
-+ {0x00000234, 0x00800080, 0, 0},
-+ {0x00000238, 0x00800080, 0, 0},
-+ {0x0000023C, 0x00800080, 0, 0},
-+ {0x00000240, 0x00800080, 0, 0},
-+ {0x00000244, 0x00800080, 0, 0},
-+ {0x00000248, 0x00800080, 0, 0},
-+ {0x0000024C, 0x00800080, 0, 0},
-+ {0x00000250, 0x00800080, 0, 0},
-+ {0x00000254, 0x00800080, 0, 0},
-+ {0x00000258, 0x00800080, 0, 0},
-+ {0x0000025C, 0x00800080, 0, 0},
-+ {0x00000260, 0x00800080, 0, 0},
-+ {0x00000264, 0x00800080, 0, 0},
-+ {0x00000268, 0x00800080, 0, 0},
-+ {0x0000026C, 0x00800080, 0, 0},
-+ {0x00000270, 0x00800080, 0, 0},
-+ {0x00000274, 0x00800080, 0, 0},
-+ {0x00000278, 0x00800080, 0, 0},
-+ {0x0000027C, 0x00800080, 0, 0},
-+ /* config OECFHM(03D0H~03E4H) */
-+ {0x000003D0, 0x04000000, 0, 0},
-+ {0x000003D4, 0x0C000800, 0, 0},
-+ {0x000003D8, 0x00000FFF, 0, 0},
-+ {0x000003DC, 0x08000800, 0, 0},
-+ {0x000003E0, 0x08000800, 0, 0},
-+ {0x000003E4, 0x00000800, 0, 0},
-+ /* config LCCF(0050H, 0058H, 00E0H~00ECH) */
-+ {0x00000050, 0x021C03C0, 0, 0},
-+ {0x00000058, 0x0000000B, 0, 0},
-+ {0x000000E0, 0x00000000, 0, 0},
-+ {0x000000E4, 0x00000000, 0, 0},
-+ {0x000000E8, 0x00000000, 0, 0},
-+ {0x000000EC, 0x00000000, 0, 0},
-+ /* config AWB(0280H~02DCH) */
-+ {0x00000280, 0x00000000, 0, 0},
-+ {0x00000284, 0x00000000, 0, 0},
-+ {0x00000288, 0x00000000, 0, 0},
-+ {0x0000028C, 0x00000000, 0, 0},
-+ {0x00000290, 0x00000000, 0, 0},
-+ {0x00000294, 0x00000000, 0, 0},
-+ {0x00000298, 0x00000000, 0, 0},
-+ {0x0000029C, 0x00000000, 0, 0},
-+ {0x000002A0, 0x00000000, 0, 0},
-+ {0x000002A4, 0x00000000, 0, 0},
-+ {0x000002A8, 0x00000000, 0, 0},
-+ {0x000002AC, 0x00000000, 0, 0},
-+ {0x000002B0, 0x00000000, 0, 0},
-+ {0x000002B4, 0x00000000, 0, 0},
-+ {0x000002B8, 0x00000000, 0, 0},
-+ {0x000002BC, 0x00000000, 0, 0},
-+ {0x000002C0, 0x00800080, 0, 0},
-+ {0x000002C4, 0x00800080, 0, 0},
-+ {0x000002C8, 0x00800080, 0, 0},
-+ {0x000002CC, 0x00800080, 0, 0},
-+ {0x000002D0, 0x00800080, 0, 0},
-+ {0x000002D4, 0x00800080, 0, 0},
-+ {0x000002D8, 0x00800080, 0, 0},
-+ {0x000002DC, 0x00800080, 0, 0},
-+ /* config CTC(0A10H) and DBC(0A14H) filter */
-+ {0x00000A10, 0x41400040, 0, 0},
-+ {0x00000A14, 0x02000200, 0, 0},
-+ /* config CFA(0018H, 0A1CH) */
-+ {0x00000018, 0x000011BB, 0, 0},
-+ {0x00000A1C, 0x00000032, 0, 0},
-+ /* config CCM(0C40H~0CA4H) */
-+ {0x00000C40, 0x00060000, 0, 0},
-+ {0x00000C44, 0x00000000, 0, 0},
-+ {0x00000C48, 0x00000000, 0, 0},
-+ {0x00000C4C, 0x00000000, 0, 0},
-+ {0x00000C50, 0x00000000, 0, 0},
-+ {0x00000C54, 0x00000000, 0, 0},
-+ {0x00000C58, 0x00000000, 0, 0},
-+ {0x00000C5C, 0x00000000, 0, 0},
-+ {0x00000C60, 0x00000000, 0, 0},
-+ {0x00000C64, 0x00000000, 0, 0},
-+ {0x00000C68, 0x00000000, 0, 0},
-+ {0x00000C6C, 0x00000000, 0, 0},
-+ {0x00000C70, 0x00000080, 0, 0},
-+ {0x00000C74, 0x00000000, 0, 0},
-+ {0x00000C78, 0x00000000, 0, 0},
-+ {0x00000C7C, 0x00000000, 0, 0},
-+ {0x00000C80, 0x00000080, 0, 0},
-+ {0x00000C84, 0x00000000, 0, 0},
-+ {0x00000C88, 0x00000000, 0, 0},
-+ {0x00000C8C, 0x00000000, 0, 0},
-+ {0x00000C90, 0x00000080, 0, 0},
-+ {0x00000C94, 0x00000000, 0, 0},
-+ {0x00000C98, 0x00000000, 0, 0},
-+ {0x00000C9C, 0x00000000, 0, 0},
-+ {0x00000CA0, 0x00000700, 0, 0},
-+ {0x00000CA4, 0x00000200, 0, 0},
-+ /* config GMARGB(0E00H~0E38H) */
-+ {0x00000E00, 0x24000000, 0, 0},
-+ {0x00000E04, 0x08000020, 0, 0},
-+ {0x00000E08, 0x08000040, 0, 0},
-+ {0x00000E0C, 0x08000060, 0, 0},
-+ {0x00000E10, 0x08000080, 0, 0},
-+ {0x00000E14, 0x080000A0, 0, 0},
-+ {0x00000E18, 0x080000C0, 0, 0},
-+ {0x00000E1C, 0x080000E0, 0, 0},
-+ {0x00000E20, 0x08000100, 0, 0},
-+ {0x00000E24, 0x08000180, 0, 0},
-+ {0x00000E28, 0x08000200, 0, 0},
-+ {0x00000E2C, 0x08000280, 0, 0},
-+ {0x00000E30, 0x08000300, 0, 0},
-+ {0x00000E34, 0x08000380, 0, 0},
-+ {0x00000E38, 0x080003FE, 0, 0},
-+ /* config R2Y(0E40H~0E60H) */
-+ {0x00000E40, 0x0000004C, 0, 0},
-+ {0x00000E44, 0x00000097, 0, 0},
-+ {0x00000E48, 0x0000001D, 0, 0},
-+ {0x00000E4C, 0x000001D5, 0, 0},
-+ {0x00000E50, 0x000001AC, 0, 0},
-+ {0x00000E54, 0x00000080, 0, 0},
-+ {0x00000E58, 0x00000080, 0, 0},
-+ {0x00000E5C, 0x00000194, 0, 0},
-+ {0x00000E60, 0x000001EC, 0, 0},
-+ /* config YCRV(0F00H~0FFCH) */
-+ {0x00000F00, 0x00000000, 0, 0},
-+ {0x00000F04, 0x00000010, 0, 0},
-+ {0x00000F08, 0x00000020, 0, 0},
-+ {0x00000F0C, 0x00000030, 0, 0},
-+ {0x00000F10, 0x00000040, 0, 0},
-+ {0x00000F14, 0x00000050, 0, 0},
-+ {0x00000F18, 0x00000060, 0, 0},
-+ {0x00000F1C, 0x00000070, 0, 0},
-+ {0x00000F20, 0x00000080, 0, 0},
-+ {0x00000F24, 0x00000090, 0, 0},
-+ {0x00000F28, 0x000000A0, 0, 0},
-+ {0x00000F2C, 0x000000B0, 0, 0},
-+ {0x00000F30, 0x000000C0, 0, 0},
-+ {0x00000F34, 0x000000D0, 0, 0},
-+ {0x00000F38, 0x000000E0, 0, 0},
-+ {0x00000F3C, 0x000000F0, 0, 0},
-+ {0x00000F40, 0x00000100, 0, 0},
-+ {0x00000F44, 0x00000110, 0, 0},
-+ {0x00000F48, 0x00000120, 0, 0},
-+ {0x00000F4C, 0x00000130, 0, 0},
-+ {0x00000F50, 0x00000140, 0, 0},
-+ {0x00000F54, 0x00000150, 0, 0},
-+ {0x00000F58, 0x00000160, 0, 0},
-+ {0x00000F5C, 0x00000170, 0, 0},
-+ {0x00000F60, 0x00000180, 0, 0},
-+ {0x00000F64, 0x00000190, 0, 0},
-+ {0x00000F68, 0x000001A0, 0, 0},
-+ {0x00000F6C, 0x000001B0, 0, 0},
-+ {0x00000F70, 0x000001C0, 0, 0},
-+ {0x00000F74, 0x000001D0, 0, 0},
-+ {0x00000F78, 0x000001E0, 0, 0},
-+ {0x00000F7C, 0x000001F0, 0, 0},
-+ {0x00000F80, 0x00000200, 0, 0},
-+ {0x00000F84, 0x00000210, 0, 0},
-+ {0x00000F88, 0x00000220, 0, 0},
-+ {0x00000F8C, 0x00000230, 0, 0},
-+ {0x00000F90, 0x00000240, 0, 0},
-+ {0x00000F94, 0x00000250, 0, 0},
-+ {0x00000F98, 0x00000260, 0, 0},
-+ {0x00000F9C, 0x00000270, 0, 0},
-+ {0x00000FA0, 0x00000280, 0, 0},
-+ {0x00000FA4, 0x00000290, 0, 0},
-+ {0x00000FA8, 0x000002A0, 0, 0},
-+ {0x00000FAC, 0x000002B0, 0, 0},
-+ {0x00000FB0, 0x000002C0, 0, 0},
-+ {0x00000FB4, 0x000002D0, 0, 0},
-+ {0x00000FB8, 0x000002E0, 0, 0},
-+ {0x00000FBC, 0x000002F0, 0, 0},
-+ {0x00000FC0, 0x00000300, 0, 0},
-+ {0x00000FC4, 0x00000310, 0, 0},
-+ {0x00000FC8, 0x00000320, 0, 0},
-+ {0x00000FCC, 0x00000330, 0, 0},
-+ {0x00000FD0, 0x00000340, 0, 0},
-+ {0x00000FD4, 0x00000350, 0, 0},
-+ {0x00000FD8, 0x00000360, 0, 0},
-+ {0x00000FDC, 0x00000370, 0, 0},
-+ {0x00000FE0, 0x00000380, 0, 0},
-+ {0x00000FE4, 0x00000390, 0, 0},
-+ {0x00000FE8, 0x000003A0, 0, 0},
-+ {0x00000FEC, 0x000003B0, 0, 0},
-+ {0x00000FF0, 0x000003C0, 0, 0},
-+ {0x00000FF4, 0x000003D0, 0, 0},
-+ {0x00000FF8, 0x000003E0, 0, 0},
-+ {0x00000FFC, 0x000003F0, 0, 0},
-+ /* config Shrp(0E80H~0EE8H) */
-+ {0x00000E80, 0x00070F00, 0, 0},
-+ {0x00000E84, 0x00180F00, 0, 0},
-+ {0x00000E88, 0x00800F00, 0, 0},
-+ {0x00000E8C, 0x01000F00, 0, 0},
-+ {0x00000E90, 0x00100F00, 0, 0},
-+ {0x00000E94, 0x00600F00, 0, 0},
-+ {0x00000E98, 0x01000F00, 0, 0},
-+ {0x00000E9C, 0x01900F00, 0, 0},
-+ {0x00000EA0, 0x00000F00, 0, 0},
-+ {0x00000EA4, 0x00000F00, 0, 0},
-+ {0x00000EA8, 0x00000F00, 0, 0},
-+ {0x00000EAC, 0x00000F00, 0, 0},
-+ {0x00000EB0, 0x00000F00, 0, 0},
-+ {0x00000EB4, 0x00000F00, 0, 0},
-+ {0x00000EB8, 0x00000F00, 0, 0},
-+ {0x00000EBC, 0x10000000, 0, 0},
-+ {0x00000EC0, 0x10000000, 0, 0},
-+ {0x00000EC4, 0x10000000, 0, 0},
-+ {0x00000EC8, 0x10000000, 0, 0},
-+ {0x00000ECC, 0x10000000, 0, 0},
-+ {0x00000ED0, 0x10000000, 0, 0},
-+ {0x00000ED4, 0x88000D7C, 0, 0},
-+ {0x00000ED8, 0x00C00040, 0, 0},
-+ {0x00000EDC, 0xFF000000, 0, 0},
-+ {0x00000EE0, 0x00A00040, 0, 0},
-+ {0x00000EE4, 0x00000000, 0, 0},
-+ {0x00000EE8, 0x00000000, 0, 0},
-+ /* config DNYUV(0C00H~0C24H) */
-+ {0x00000C00, 0x00777777, 0, 0},
-+ {0x00000C04, 0x00007777, 0, 0},
-+ {0x00000C08, 0x00777777, 0, 0},
-+ {0x00000C0C, 0x00007777, 0, 0},
-+ {0x00000C10, 0x00600040, 0, 0},
-+ {0x00000C14, 0x00D80090, 0, 0},
-+ {0x00000C18, 0x01E60144, 0, 0},
-+ {0x00000C1C, 0x00600040, 0, 0},
-+ {0x00000C20, 0x00D80090, 0, 0},
-+ {0x00000C24, 0x01E60144, 0, 0},
-+ /* config SAT(0A30H~0A40H, 0A54H~0A58H) */
-+ {0x00000A30, 0x00000100, 0, 0},
-+ {0x00000A34, 0x001F0001, 0, 0},
-+ {0x00000A38, 0x00000000, 0, 0},
-+ {0x00000A3C, 0x00000100, 0, 0},
-+ {0x00000A40, 0x00000008, 0, 0},
-+ {0x00000A54, 0x04010001, 0, 0},
-+ {0x00000A58, 0x03FF0001, 0, 0},
-+ /* config OBA(0090H~0094H) */
-+ {0x00000090, 0x04380000, 0, 0},
-+ {0x00000094, 0x04390780, 0, 0},
-+ /* config SC(0098H~009CH, 00B8H~00BCH,
-+ * 00C0H, 0C4H~0D4H, 04D0H~054CH, 5D0H~5D4H)
-+ */
-+ {0x0000009C, 0x01000000, 0, 0},
-+ {0x000000B8, 0x000C0000, 0, 0},
-+ {0x000000BC, 0xC010151D, 0, 0},
-+ {0x000000C0, 0x01F1BF08, 0, 0},
-+ {0x000000C4, 0xFF00FF00, 0, 0},
-+ {0x000000C8, 0xFF00FF00, 0, 0},
-+ {0x000000CC, 0xFFFF0000, 0, 0},
-+ {0x000000D0, 0xFFFF0000, 0, 0},
-+ {0x000000D4, 0xFFFF0000, 0, 0},
-+ {0x000000D8, 0x01050107, 0, 0},
-+ {0x000004D0, 0x00000000, 0, 0},
-+ {0x000004D4, 0x00000000, 0, 0},
-+ {0x000004D8, 0x00000000, 0, 0},
-+ {0x000004DC, 0x00000000, 0, 0},
-+ {0x000004E0, 0x00000000, 0, 0},
-+ {0x000004E4, 0x00000000, 0, 0},
-+ {0x000004E8, 0x00000000, 0, 0},
-+ {0x000004EC, 0x00000000, 0, 0},
-+ {0x000004F0, 0x00100000, 0, 0},
-+ {0x000004F4, 0x00000000, 0, 0},
-+ {0x000004F8, 0x03D20000, 0, 0},
-+ {0x000004FC, 0x00000000, 0, 0},
-+ {0x00000500, 0x00950000, 0, 0},
-+ {0x00000504, 0x00000000, 0, 0},
-+ {0x00000508, 0x00253000, 0, 0},
-+ {0x0000050C, 0x00000000, 0, 0},
-+ {0x00000510, 0x00000000, 0, 0},
-+ {0x00000514, 0x00000000, 0, 0},
-+ {0x00000518, 0x00000000, 0, 0},
-+ {0x0000051C, 0x00000000, 0, 0},
-+ {0x00000520, 0x00000000, 0, 0},
-+ {0x00000524, 0x00000000, 0, 0},
-+ {0x00000528, 0x00000000, 0, 0},
-+ {0x0000052C, 0x00000000, 0, 0},
-+ {0x00000530, 0x00000000, 0, 0},
-+ {0x00000534, 0x00000000, 0, 0},
-+ {0x00000538, 0xFFFFFFF0, 0, 0},
-+ {0x0000053C, 0x8FFFFFFF, 0, 0},
-+ {0x00000540, 0x0000001E, 0, 0},
-+ {0x00000544, 0x00000000, 0, 0},
-+ {0x00000548, 0x00000000, 0, 0},
-+ {0x0000054C, 0xF0F20000, 0, 0},
-+ {0x000005D0, 0xFF00FF00, 0, 0},
-+ {0x000005D4, 0xFF00FF00, 0, 0},
-+ /* config YHIST(0CC8H~0CD8H) */
-+ {0x00000CC8, 0x00000000, 0, 0},
-+ {0x00000CCC, 0x0437077F, 0, 0},
-+ {0x00000CD0, 0x00010002, 0, 0},
-+ {0x00000CD4, 0x00000000, 0, 0},
-+ /* config CBAR(0600H-0653H) */
-+ {0x00000600, 0x043E0782, 0, 0},
-+ {0x00000604, 0x00000000, 0, 0},
-+ {0x00000608, 0x0437077F, 0, 0},
-+ {0x0000060C, 0x00443150, 0, 0},
-+ {0x00000610, 0x00000000, 0, 0},
-+ {0x00000614, 0x08880888, 0, 0},
-+ {0x00000618, 0x02220222, 0, 0},
-+ {0x0000061C, 0x04440444, 0, 0},
-+ {0x00000620, 0x08880888, 0, 0},
-+ {0x00000624, 0x0AAA0AAA, 0, 0},
-+ {0x00000628, 0x0CCC0CCC, 0, 0},
-+ {0x0000062C, 0x0EEE0EEE, 0, 0},
-+ {0x00000630, 0x0FFF0FFF, 0, 0},
-+ {0x00000634, 0x08880888, 0, 0},
-+ {0x00000638, 0x02220222, 0, 0},
-+ {0x0000063C, 0x04440444, 0, 0},
-+ {0x00000640, 0x08880888, 0, 0},
-+ {0x00000644, 0x0AAA0AAA, 0, 0},
-+ {0x00000648, 0x0CCC0CCC, 0, 0},
-+ {0x0000064C, 0x0EEE0EEE, 0, 0},
-+ {0x00000650, 0x0FFF0FFF, 0, 0},
-+ /* config sensor(0014H) */
-+ {0x00000014, 0x0000000c, 0, 0},
-+ /* config CROP(001CH, 0020H) */
-+ {0x0000001C, 0x00000000, 0, 0},
-+ {0x00000020, 0x0437077F, 0, 0},
-+ /* config isp pileline X/Y size(A0CH) */
-+ {0x00000A0C, 0x04380780, 0, 0},
-+ /* config CSI dump (24H/28H) */
-+ {0x00000028, 0x00030B80, 0, 0},
-+ /* Video Output */
-+ /* config UO(0A80H~0A90H) */
-+ {0x00000A88, 0x00000780, 0, 0},
-+ /* NV12 */
-+ {0x00000A8C, 0x00000000, 0, 0},
-+ /* NV21
-+ *{0x00000A8C, 0x00000020, 0, 0},
-+ */
-+ {0x00000A90, 0x00000000, 0, 0},
-+ {0x00000A9C, 0x00000780, 0, 0},
-+ {0x00000AA0, 0x00000002, 0, 0},
-+ {0x00000AA4, 0x00000002, 0, 0},
-+ {0x00000AA8, 0x07800438, 0, 0},
-+ {0x00000AB4, 0x00000780, 0, 0},
-+ {0x00000AB8, 0x00000002, 0, 0},
-+ {0x00000ABC, 0x00000002, 0, 0},
-+ {0x00000AC0, 0x07800438, 0, 0},
-+ {0x00000AC4, 0x00000000, 0, 0},
-+ /* config TIL(0B20H~0B48H) */
-+ {0x00000B20, 0x04380780, 0, 0},
-+ {0x00000B24, 0x00000960, 0, 0},
-+ {0x00000B38, 0x00030003, 0, 0},
-+ {0x00000B3C, 0x00000960, 0, 0},
-+ {0x00000B44, 0x00000000, 0, 0},
-+ {0x00000B48, 0x00000000, 0, 0},
-+ /* Enable DEC/OBC/OECF/LCCF/AWB/SC/DUMP */
-+ {0x00000010, 0x000A00D6, 0x00000000, 0x00},
-+ /* Enable CFA/CAR/CCM/GMARGB/R2Y/SHRP/SAT/DNYUV/YCRV/YHIST/CTC/DBC */
-+ {0x00000A08, 0x107A01BE, 0x00000000, 0x00},
-+};
-+
-+const struct reg_table isp_reg_init_settings[] = {
-+ {isp_reg_init_config_list,
-+ ARRAY_SIZE(isp_reg_init_config_list)},
-+};
-+
-+static struct regval_t isp_reg_start_config_list[] = {
-+#if defined(ENABLE_SS0_SS1)
-+ /* ENABLE UO/SS0/SS1/Multi-Frame and Reset ISP */
-+ {0x00000A00, 0x00121802, 0x00000000, 0x0A},
-+ /* ENABLE UO/SS0/SS1/Multi-Frame and Leave ISP reset */
-+ {0x00000A00, 0x00121800, 0x00000000, 0x0A},
-+#else
-+ /* ENABLE UO/Multi-Frame and Reset ISP */
-+ {0x00000A00, 0x00120002, 0x00000000, 0x0A},
-+ /* ENABLE UO/Multi-Frame and Leave ISP reset */
-+ {0x00000A00, 0x00120000, 0x00000000, 0x0A},
-+#endif
-+ /* Config ISP shadow mode as next-vsync */
-+ {0x00000A50, 0x00000002, 0x00000000, 0x00},
-+#if defined(ENABLE_SS0_SS1)
-+ /* ENABLE UO/SS0/SS1/Multi-Frame and Enable ISP */
-+ {0x00000A00, 0x00121801, 0x00000000, 0x0A},
-+#else
-+ /* ENABLE UO/Multi-Frame and Enable ISP */
-+ {0x00000A00, 0x00120001, 0x00000000, 0x0A},
-+#endif
-+ /* Config CSI shadow mode as immediate to fetch current setting */
-+ {0x00000008, 0x00010004, 0x00000000, 0x0A},
-+ /* Config CSI shadow mode as next-vsync */
-+ {0x00000008, 0x00020004, 0x00000000, 0x00},
-+ /* Enable CSI */
-+ {0x00000000, 0x00000001, 0x00000000, 0x0A},
-+};
-+
-+const struct reg_table isp_reg_start_settings[] = {
-+ {isp_reg_start_config_list,
-+ ARRAY_SIZE(isp_reg_start_config_list)},
-+};
-+
-+static struct regval_t isp_imx_219_reg_config_list[] = {
-+ /* MIPI sensor */
-+ {0x00000014, 0x0000000D, 0, 0},
-+ /* config CFA(0018H, 0A1CH) */
-+ {0x00000A1C, 0x00000032, 0, 0},
-+ {0x00000A8C, 0x00000000, 0, 0},
-+ {0x00000A90, 0x00000000, 0, 0},
-+ /* config R2Y(0E40H~0E60H) */
-+ {0x00000E40, 0x0000004C, 0, 0},
-+ {0x00000E44, 0x00000097, 0, 0},
-+ {0x00000E48, 0x0000001D, 0, 0},
-+ {0x00000E4C, 0x000001D5, 0, 0},
-+ {0x00000E50, 0x000001AC, 0, 0},
-+ {0x00000E54, 0x00000080, 0, 0},
-+ {0x00000E58, 0x00000080, 0, 0},
-+ {0x00000E5C, 0x00000194, 0, 0},
-+ {0x00000E60, 0x000001EC, 0, 0},
-+ /* Config AWB(0280H~02DCH). Fixed WB gain for IMX-219 sensor. */
-+ {0x00000280, 0x00000000, 0, 0},
-+ {0x00000284, 0x00000000, 0, 0},
-+ {0x00000288, 0x00000000, 0, 0},
-+ {0x0000028C, 0x00000000, 0, 0},
-+ {0x00000290, 0x00000000, 0, 0},
-+ {0x00000294, 0x00000000, 0, 0},
-+ {0x00000298, 0x00000000, 0, 0},
-+ {0x0000029C, 0x00000000, 0, 0},
-+ {0x000002A0, 0x00000000, 0, 0},
-+ {0x000002A4, 0x00000000, 0, 0},
-+ {0x000002A8, 0x00000000, 0, 0},
-+ {0x000002AC, 0x00000000, 0, 0},
-+ {0x000002B0, 0x00000000, 0, 0},
-+ {0x000002B4, 0x00000000, 0, 0},
-+ {0x000002B8, 0x00000000, 0, 0},
-+ {0x000002BC, 0x00000000, 0, 0},
-+ {0x000002C0, 0x00F000F0, 0, 0},
-+ {0x000002C4, 0x00F000F0, 0, 0},
-+ {0x000002C8, 0x00800080, 0, 0},
-+ {0x000002CC, 0x00800080, 0, 0},
-+ {0x000002D0, 0x00800080, 0, 0},
-+ {0x000002D4, 0x00800080, 0, 0},
-+ {0x000002D8, 0x00B000B0, 0, 0},
-+ {0x000002DC, 0x00B000B0, 0, 0},
-+ /* config GMARGB(0E00H~0E38H)
-+ * Gamma RGB 1.9 for IMX-219 sensor
-+ */
-+ {0x00000E00, 0x24000000, 0, 0},
-+ {0x00000E04, 0x159500A5, 0, 0},
-+ {0x00000E08, 0x0F9900EE, 0, 0},
-+ {0x00000E0C, 0x0CE40127, 0, 0},
-+ {0x00000E10, 0x0B410157, 0, 0},
-+ {0x00000E14, 0x0A210181, 0, 0},
-+ {0x00000E18, 0x094B01A8, 0, 0},
-+ {0x00000E1C, 0x08A401CC, 0, 0},
-+ {0x00000E20, 0x081D01EE, 0, 0},
-+ {0x00000E24, 0x06B20263, 0, 0},
-+ {0x00000E28, 0x05D802C7, 0, 0},
-+ {0x00000E2C, 0x05420320, 0, 0},
-+ {0x00000E30, 0x04D30370, 0, 0},
-+ {0x00000E34, 0x047C03BB, 0, 0},
-+ {0x00000E38, 0x043703FF, 0, 0},
-+ {0x00000010, 0x00000080, 0, 0},
-+ /* Enable CFA/GMARGB/R2Y */
-+ {0x00000A08, 0x10000032, 0x0FFFFFFF, 0x00},
-+ {0x00000A00, 0x00120002, 0, 0},
-+ {0x00000A00, 0x00120000, 0, 0},
-+ {0x00000A50, 0x00000002, 0, 0},
-+ {0x00000008, 0x00010000, 0, 0},
-+ {0x00000008, 0x0002000A, 0, 0},
-+ {0x00000000, 0x00000001, 0, 0},
-+};
-+
-+const struct reg_table isp_imx_219_settings[] = {
-+ {isp_imx_219_reg_config_list,
-+ ARRAY_SIZE(isp_imx_219_reg_config_list)},
-+};
-+
-+static struct regval_t isp_format_reg_list[] = {
-+ {0x0000001C, 0x00000000, 0x00000000, 0},
-+ {0x00000020, 0x0437077F, 0x00000000, 0},
-+ {0x00000A0C, 0x04380780, 0x00000000, 0},
-+ {0x00000A88, 0x00000780, 0x00000000, 0},
-+ {0x00000018, 0x000011BB, 0x00000000, 0},
-+ {0x00000A08, 0x10000000, 0xF0000000, 0},
-+ {0x00000028, 0x00030B80, 0x0003FFFF, 0},
-+ {0x00000AA8, 0x07800438, 0x00000000, 0},
-+ {0x00000A9C, 0x00000780, 0x00000000, 0},
-+ {0x00000AC0, 0x07800438, 0x00000000, 0},
-+ {0x00000AB4, 0x00000780, 0x00000000, 0},
-+ {0x00000B20, 0x04380780, 0x00000000, 0},
-+ {0x00000B24, 0x00000960, 0x00000000, 0},
-+ {0x00000B3C, 0x00000960, 0x00000000, 0},
-+ {0x00000014, 0x00000008, 0x00000000, 0},
-+};
-+
-+const struct reg_table isp_format_settings[] = {
-+ {isp_format_reg_list,
-+ ARRAY_SIZE(isp_format_reg_list)},
-+};
-+
-+#if defined(USE_NEW_CONFIG_SETTING)
-+#else
-+static struct reg_table *isp_settings = (struct reg_table *)isp_imx_219_settings;
-+#endif
-+
-+static void isp_load_regs(void __iomem *ispbase, const struct reg_table *table)
-+{
-+ int j;
-+ u32 delay_ms, reg_addr, mask, val;
-+
-+ for (j = 0; j < table->regval_num; j++) {
-+ delay_ms = table->regval[j].delay_ms;
-+ reg_addr = table->regval[j].addr;
-+ val = table->regval[j].val;
-+ mask = table->regval[j].mask;
-+
-+ if (reg_addr % 4
-+ || reg_addr > STF_ISP_REG_OFFSET_MAX
-+ || delay_ms > STF_ISP_REG_DELAY_MAX)
-+ continue;
-+
-+ if (mask)
-+ reg_set_bit(ispbase, reg_addr, mask, val);
-+ else
-+ reg_write(ispbase, reg_addr, val);
-+ if (delay_ms)
-+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
-+ }
-+}
-+
-+static void isp_load_regs_exclude_csi_isp_enable(
-+ void __iomem *ispbase,
-+ const struct reg_table *table)
-+{
-+ int j;
-+ u32 delay_ms, reg_addr, mask, val;
-+
-+ for (j = 0; j < table->regval_num; j++) {
-+ delay_ms = table->regval[j].delay_ms;
-+ reg_addr = table->regval[j].addr;
-+ val = table->regval[j].val;
-+ mask = table->regval[j].mask;
-+
-+ if (reg_addr % 4
-+ || reg_addr > STF_ISP_REG_OFFSET_MAX
-+ || delay_ms > STF_ISP_REG_DELAY_MAX
-+ || ((reg_addr == ISP_REG_CSI_INPUT_EN_AND_STATUS) && (val & 0x01))
-+ || ((reg_addr == ISP_REG_ISP_CTRL_0) && (val & 0x01)))
-+ continue;
-+
-+ if (mask)
-+ reg_set_bit(ispbase, reg_addr, mask, val);
-+ else
-+ reg_write(ispbase, reg_addr, val);
-+ if (delay_ms)
-+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
-+ }
-+}
-+
-+static int stf_isp_clk_enable(struct stf_isp_dev *isp_dev)
-+{
-+ struct stfcamss *stfcamss = isp_dev->stfcamss;
-+
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_C].rstc);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_P].rstc);
-+
-+ return 0;
-+}
-+
-+static int stf_isp_clk_disable(struct stf_isp_dev *isp_dev)
-+{
-+ struct stfcamss *stfcamss = isp_dev->stfcamss;
-+
-+ reset_control_assert(stfcamss->sys_rst[STFRST_WRAPPER_C].rstc);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_WRAPPER_P].rstc);
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk);
-+
-+ return 0;
-+}
-+
-+static void __iomem *stf_isp_get_ispbase(struct stf_vin_dev *vin)
-+{
-+ void __iomem *base = vin->isp_base;
-+
-+ return base;
-+}
-+
-+static int stf_isp_save_ctx_regs(struct stf_isp_dev *isp_dev)
-+{
-+ int j;
-+ u32 addr, val;
-+ void __iomem *ispbase;
-+ struct device *dev = isp_dev->stfcamss->dev;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ if (!isp_dev->context_regs) {
-+ int regs_size =
-+ sizeof(struct regval_t) * isp_reg_init_settings->regval_num;
-+ isp_dev->context_regs =
-+ devm_kzalloc(dev, sizeof(struct reg_table), GFP_KERNEL);
-+ isp_dev->context_regs->regval =
-+ devm_kzalloc(dev, regs_size, GFP_KERNEL);
-+ isp_dev->context_regs->regval_num = isp_reg_init_settings->regval_num;
-+ }
-+
-+ if (!isp_dev->context_regs || !isp_dev->context_regs->regval)
-+ return -ENOMEM;
-+
-+ st_debug(ST_ISP, "Saving ISP context registers\n");
-+ for (j = 0; j < isp_reg_init_settings->regval_num; j++) {
-+ addr = isp_reg_init_settings->regval[j].addr;
-+ val = ioread32(ispbase + addr);
-+ isp_dev->context_regs->regval[j].addr = addr;
-+ isp_dev->context_regs->regval[j].val = val;
-+ }
-+ st_debug(ST_ISP, "ISP context registers have been saved\n");
-+
-+ return 0;
-+};
-+
-+static int stf_isp_restore_ctx_regs(struct stf_isp_dev *isp_dev)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ if (isp_dev->context_regs) {
-+ isp_load_regs(ispbase, isp_dev->context_regs);
-+ st_debug(ST_ISP, "Restored ISP register: isp_reg_init_settings.\n");
-+ }
-+
-+ return 0;
-+}
-+
-+static int stf_isp_reset(struct stf_isp_dev *isp_dev)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(1), BIT(1));
-+ reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(1), 0);
-+
-+ return 0;
-+}
-+
-+static int stf_isp_config_set(struct stf_isp_dev *isp_dev)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ st_debug(ST_ISP, "%s\n", __func__);
-+
-+#if defined(USE_NEW_CONFIG_SETTING)
-+ mutex_lock(&isp_dev->setfile_lock);
-+
-+ if (isp_dev->context_regs) {
-+ stf_isp_restore_ctx_regs(isp_dev);
-+ st_debug(ST_ISP, "%s context regs restore done\n", __func__);
-+ } else {
-+ isp_load_regs(ispbase, isp_reg_init_settings);
-+ st_debug(ST_ISP, "%s isp_reg_init_settings done\n", __func__);
-+ }
-+ if (isp_dev->setfile.state) {
-+ st_info(ST_ISP, "%s, Program extra ISP setting!\n", __func__);
-+ isp_load_regs_exclude_csi_isp_enable(ispbase,
-+ &isp_dev->setfile.settings);
-+ }
-+
-+ mutex_unlock(&isp_dev->setfile_lock);
-+#else
-+ mutex_lock(&isp_dev->setfile_lock);
-+ if (isp_dev->setfile.state)
-+ isp_load_regs(ispbase, &isp_dev->setfile.settings);
-+ else
-+ isp_load_regs(ispbase, isp_settings);
-+ mutex_unlock(&isp_dev->setfile_lock);
-+
-+ st_debug(ST_ISP, "config 0x%x = 0x%x\n",
-+ isp_format_reg_list[0].addr,
-+ isp_format_reg_list[0].val);
-+ st_debug(ST_ISP, "config 0x%x = 0x%x\n",
-+ isp_format_reg_list[1].addr,
-+ isp_format_reg_list[1].val);
-+ st_debug(ST_ISP, "config 0x%x = 0x%x\n",
-+ isp_format_reg_list[2].addr,
-+ isp_format_reg_list[2].val);
-+ st_debug(ST_ISP, "config 0x%x = 0x%x\n",
-+ isp_format_reg_list[3].addr,
-+ isp_format_reg_list[3].val);
-+#endif
-+
-+ return 0;
-+}
-+
-+static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
-+ struct isp_stream_format *crop_array, u32 mcode,
-+ int type)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ struct stf_dvp_dev *dvp_dev = isp_dev->stfcamss->dvp_dev;
-+ struct v4l2_rect *crop = &crop_array[ISP_COMPOSE].rect;
-+ u32 bpp = crop_array[ISP_COMPOSE].bpp;
-+ void __iomem *ispbase;
-+ u32 val, val1;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ st_debug(ST_ISP, "interface type is %d(%s)\n",
-+ type, type == CSI_SENSOR ? "CSI" : "DVP");
-+
-+ if (type == DVP_SENSOR) {
-+ unsigned int flags = dvp_dev->dvp->flags;
-+
-+ st_debug(ST_ISP, "dvp flags = 0x%x, hsync active is %s, vsync active is %s\n",
-+ flags, flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH ? "high" : "low",
-+ flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? "high" : "low");
-+ }
-+
-+ val = crop->left + (crop->top << 16);
-+ isp_format_reg_list[0].addr = ISP_REG_PIC_CAPTURE_START_CFG;
-+ isp_format_reg_list[0].val = val;
-+
-+ val = (crop->width + crop->left - 1)
-+ + ((crop->height + crop->top - 1) << 16);
-+ isp_format_reg_list[1].addr = ISP_REG_PIC_CAPTURE_END_CFG;
-+ isp_format_reg_list[1].val = val;
-+
-+ val = crop->width + (crop->height << 16);
-+ isp_format_reg_list[2].addr = ISP_REG_PIPELINE_XY_SIZE;
-+ isp_format_reg_list[2].val = val;
-+
-+ isp_format_reg_list[3].addr = ISP_REG_STRIDE;
-+ isp_format_reg_list[3].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+
-+ switch (mcode) {
-+ case MEDIA_BUS_FMT_SRGGB10_1X10:
-+ case MEDIA_BUS_FMT_SRGGB8_1X8:
-+ // 3 2 3 2 1 0 1 0 B Gb B Gb Gr R Gr R
-+ val = 0x0000EE44;
-+ val1 = 0x00000000;
-+ break;
-+ case MEDIA_BUS_FMT_SGRBG10_1X10:
-+ case MEDIA_BUS_FMT_SGRBG8_1X8:
-+ // 2 3 2 3 0 1 0 1, Gb B Gb B R Gr R Gr
-+ val = 0x0000BB11;
-+ val1 = 0x20000000;
-+ break;
-+ case MEDIA_BUS_FMT_SGBRG10_1X10:
-+ case MEDIA_BUS_FMT_SGBRG8_1X8:
-+ // 1 0 1 0 3 2 3 2, Gr R Gr R B Gb B Gb
-+ val = 0x000044EE;
-+ val1 = 0x30000000;
-+ break;
-+ case MEDIA_BUS_FMT_SBGGR10_1X10:
-+ case MEDIA_BUS_FMT_SBGGR8_1X8:
-+ // 0 1 0 1 2 3 2 3 R Gr R Gr Gb B Gb B
-+ val = 0x000011BB;
-+ val1 = 0x10000000;
-+ break;
-+ default:
-+ st_err(ST_ISP, "UNKNOW format\n");
-+ val = 0x000011BB;
-+ val1 = 0x10000000;
-+ break;
-+ }
-+
-+ isp_format_reg_list[4].addr = ISP_REG_RAW_FORMAT_CFG;
-+ isp_format_reg_list[4].val = val;
-+
-+ isp_format_reg_list[5].addr = ISP_REG_ISP_CTRL_1;
-+ isp_format_reg_list[5].val = val1;
-+ isp_format_reg_list[5].mask = 0xF0000000;
-+
-+ st_info(ST_ISP, "src left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
-+ crop->left, crop->top, crop->width, crop->height, bpp);
-+
-+ crop = &crop_array[ISP_CROP].rect;
-+ bpp = crop_array[ISP_CROP].bpp;
-+ val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_128);
-+ isp_format_reg_list[6].addr = ISP_REG_DUMP_CFG_1;
-+ isp_format_reg_list[6].val = val | 3 << 16;
-+ isp_format_reg_list[6].mask = 0x0003FFFF;
-+
-+ st_info(ST_ISP, "raw left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
-+ crop->left, crop->top, crop->width, crop->height, bpp);
-+
-+ crop = &crop_array[ISP_SCALE_SS0].rect;
-+ bpp = crop_array[ISP_SCALE_SS0].bpp;
-+ isp_format_reg_list[7].addr = ISP_REG_SS0IW;
-+ isp_format_reg_list[7].val = (crop->width << 16) + crop->height;
-+ isp_format_reg_list[8].addr = ISP_REG_SS0S;
-+ isp_format_reg_list[8].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+
-+ st_info(ST_ISP, "ss0 left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
-+ crop->left, crop->top, crop->width, crop->height, bpp);
-+
-+ crop = &crop_array[ISP_SCALE_SS1].rect;
-+ bpp = crop_array[ISP_SCALE_SS1].bpp;
-+ isp_format_reg_list[9].addr = ISP_REG_SS1IW;
-+ isp_format_reg_list[9].val = (crop->width << 16) + crop->height;
-+ isp_format_reg_list[10].addr = ISP_REG_SS1S;
-+ isp_format_reg_list[10].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+
-+ crop = &crop_array[ISP_ITIWS].rect;
-+ bpp = crop_array[ISP_ITIWS].bpp;
-+ isp_format_reg_list[11].addr = ISP_REG_ITIIWSR;
-+ isp_format_reg_list[11].val = (crop->height << 16) + crop->width;
-+ isp_format_reg_list[12].addr = ISP_REG_ITIDWLSR;
-+ isp_format_reg_list[12].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+ isp_format_reg_list[13].addr = ISP_REG_ITIDRLSR;
-+ isp_format_reg_list[13].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+
-+ st_info(ST_ISP, "iti left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
-+ crop->left, crop->top, crop->width, crop->height, bpp);
-+
-+ isp_format_reg_list[14].addr = ISP_REG_SENSOR;
-+ isp_format_reg_list[14].val = 0x00000000;
-+ if (type == DVP_SENSOR) {
-+ unsigned int flags = dvp_dev->dvp->flags;
-+
-+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
-+ isp_format_reg_list[14].val |= 0x08;
-+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
-+ isp_format_reg_list[14].val |= 0x04;
-+ } else {
-+ isp_format_reg_list[14].val |= 0x01;
-+ }
-+
-+ isp_load_regs(ispbase, isp_format_settings);
-+ return 0;
-+}
-+
-+static int stf_isp_stream_set(struct stf_isp_dev *isp_dev, int on)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+
-+ void __iomem *ispbase;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ if (on) {
-+#if defined(USE_NEW_CONFIG_SETTING)
-+ isp_load_regs(ispbase, isp_reg_start_settings);
-+#else
-+ reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x3FFFF, 0x3000a);
-+ reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3);
-+ reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 1);
-+#endif //#if defined(USE_NEW_CONFIG_SETTING)
-+ } else {
-+ /* NOTE: Clear bit 0 of ISP_REG_ISP_CTRL_0 here will get crash. */
-+ stf_isp_save_ctx_regs(isp_dev);
-+ }
-+
-+ return 0;
-+}
-+
-+static union reg_buf reg_buf;
-+static int stf_isp_reg_read(struct stf_isp_dev *isp_dev, void *arg)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+ struct isp_reg_param *reg_param = arg;
-+ u32 size;
-+ unsigned long r;
-+
-+ if (reg_param->reg_buf == NULL) {
-+ st_err(ST_ISP, "Failed to access register. The pointer is NULL!!!\n");
-+ return -EINVAL;
-+ }
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ size = 0;
-+ switch (reg_param->reg_info.method) {
-+ case STF_ISP_REG_METHOD_ONE_REG:
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SERIES:
-+ if (reg_param->reg_info.length > STF_ISP_REG_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ break;
-+
-+ case STF_ISP_REG_METHOD_MODULE:
-+ /* This mode is not supported in the V4L2 version. */
-+ st_err(ST_ISP, "Reg Read - Failed to access register. The method = \
-+ STF_ISP_REG_METHOD_MODULE is not supported!!!\n");
-+ return -ENOTTY;
-+
-+ case STF_ISP_REG_METHOD_TABLE:
-+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_TBL_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 2;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_2:
-+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_2_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_TBL_2_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 3;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_3:
-+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_3_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_TBL_3_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 4;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SMPL_PACK:
-+ st_err(ST_ISP, "Reg Read - Failed to access register. The method = \
-+ STF_ISP_REG_METHOD_SMPL_PACK is not supported!!!\n");
-+ return -ENOTTY;
-+
-+ case STF_ISP_REG_METHOD_SOFT_RDMA:
-+ // This mode is not supported in the V4L2 version.
-+ st_err(ST_ISP, "Reg Read - Failed to access register. The method = \
-+ STF_ISP_REG_METHOD_SOFT_RDMA is not supported!!!\n");
-+ return -ENOTTY;
-+
-+ default:
-+ st_err(ST_ISP, "Failed to access register. The method=%d \
-+ is not supported!!!\n", reg_param->reg_info.method);
-+ return -ENOTTY;
-+ }
-+
-+ memset(®_buf, 0, sizeof(union reg_buf));
-+ if (size) {
-+ r = copy_from_user((u8 *)reg_buf.buffer,
-+ (u8 *)reg_param->reg_buf->buffer, size);
-+ if (r) {
-+ st_err(ST_ISP, "Failed to call copy_from_user for the \
-+ reg_param->reg_buf value\n");
-+ return -EIO;
-+ }
-+ }
-+
-+ size = 0;
-+ switch (reg_param->reg_info.method) {
-+ case STF_ISP_REG_METHOD_ONE_REG:
-+ reg_buf.buffer[0] = reg_read(ispbase, reg_param->reg_info.offset);
-+ size = sizeof(u32);
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SERIES:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ reg_buf.buffer[r] = reg_read(ispbase,
-+ reg_param->reg_info.offset + (r * 4));
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_MODULE:
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ reg_buf.reg_tbl[r].value = reg_read(ispbase,
-+ reg_buf.reg_tbl[r].offset);
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 2;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_2:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ if (reg_buf.reg_tbl2[r].mask) {
-+ reg_buf.reg_tbl2[r].value = (reg_read(ispbase,
-+ reg_buf.reg_tbl2[r].offset)
-+ & reg_buf.reg_tbl2[r].mask);
-+ } else {
-+ reg_buf.reg_tbl2[r].value = reg_read(ispbase,
-+ reg_buf.reg_tbl2[r].offset);
-+ }
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 3;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_3:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ if (reg_buf.reg_tbl3[r].mask) {
-+ reg_buf.reg_tbl3[r].value = (reg_read(ispbase,
-+ reg_buf.reg_tbl3[r].offset)
-+ & reg_buf.reg_tbl3[r].mask);
-+ } else {
-+ reg_buf.reg_tbl3[r].value = reg_read(ispbase,
-+ reg_buf.reg_tbl3[r].offset);
-+ }
-+ if (reg_buf.reg_tbl3[r].delay_ms) {
-+ usleep_range(1000 * reg_buf.reg_tbl3[r].delay_ms,
-+ 1000 * reg_buf.reg_tbl3[r].delay_ms + 100);
-+ }
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 4;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SMPL_PACK:
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SOFT_RDMA:
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ r = copy_to_user((u8 *)reg_param->reg_buf->buffer, (u8 *)reg_buf.buffer,
-+ size);
-+ if (r) {
-+ st_err(ST_ISP, "Failed to call copy_to_user for the \
-+ reg_param->buffer value\n");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int stf_isp_soft_rdma(struct stf_isp_dev *isp_dev, u32 rdma_addr)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+ struct isp_rdma_info *rdma_info = NULL;
-+ s32 len;
-+ u32 offset;
-+ int ret = 0;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ rdma_info = phys_to_virt(rdma_addr);
-+ while (1) {
-+ if (rdma_info->tag == RDMA_WR_ONE) {
-+ reg_write(ispbase, rdma_info->offset, rdma_info->param);
-+ rdma_info++;
-+ } else if (rdma_info->tag == RDMA_WR_SRL) {
-+ offset = rdma_info->offset;
-+ len = rdma_info->param;
-+ rdma_info++;
-+ while (len > 0) {
-+ reg_write(ispbase, offset, rdma_info->param);
-+ offset += 4;
-+ len--;
-+ if (len > 0) {
-+ reg_write(ispbase, offset, rdma_info->value);
-+ len--;
-+ }
-+ offset += 4;
-+ rdma_info++;
-+ }
-+ } else if (rdma_info->tag == RDMA_LINK) {
-+ rdma_info = phys_to_virt(rdma_info->param);
-+ } else if (rdma_info->tag == RDMA_SINT) {
-+ /* Software not support this command. */
-+ rdma_info++;
-+ } else if (rdma_info->tag == RDMA_END) {
-+ break;
-+ } else
-+ rdma_info++;
-+ }
-+
-+ return ret;
-+}
-+
-+static int stf_isp_reg_write(struct stf_isp_dev *isp_dev, void *arg)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+ struct isp_reg_param *reg_param = arg;
-+ struct isp_rdma_info *rdma_info = NULL;
-+ s32 len;
-+ u32 offset;
-+ u32 size;
-+ unsigned long r;
-+ int ret = 0;
-+
-+ if ((reg_param->reg_buf == NULL)
-+ && (reg_param->reg_info.method != STF_ISP_REG_METHOD_SOFT_RDMA)) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The register buffer pointer is NULL!!!\n");
-+ return -EINVAL;
-+ }
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ size = 0;
-+ switch (reg_param->reg_info.method) {
-+ case STF_ISP_REG_METHOD_ONE_REG:
-+ size = sizeof(u32);
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SERIES:
-+ if (reg_param->reg_info.length > STF_ISP_REG_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_MODULE:
-+ // This mode is not supported in the V4L2 version.
-+ st_err(ST_ISP, "Reg Write - Failed to access register. \
-+ The method = STF_ISP_REG_METHOD_MODULE is not supported!!!\n");
-+ return -ENOTTY;
-+
-+ case STF_ISP_REG_METHOD_TABLE:
-+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_TBL_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 2;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_2:
-+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_2_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_TBL_2_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 3;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_3:
-+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_3_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_TBL_3_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 4;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SMPL_PACK:
-+ if (reg_param->reg_info.length > STF_ISP_REG_SMPL_PACK_BUF_SIZE) {
-+ st_err(ST_ISP, "Failed to access register. \
-+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
-+ reg_param->reg_info.length, STF_ISP_REG_SMPL_PACK_BUF_SIZE);
-+ return -EINVAL;
-+ }
-+ size = sizeof(u32) * reg_param->reg_info.length * 2;
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SOFT_RDMA:
-+ break;
-+
-+ default:
-+ st_err(ST_ISP, "Failed to access register. The method=%d \
-+ is not supported!!!\n", reg_param->reg_info.method);
-+ return -ENOTTY;
-+ }
-+
-+ memset(®_buf, 0, sizeof(union reg_buf));
-+ if (size) {
-+ r = copy_from_user((u8 *)reg_buf.buffer,
-+ (u8 *)reg_param->reg_buf->buffer, size);
-+ if (r) {
-+ st_err(ST_ISP, "Failed to call copy_from_user for the \
-+ reg_param->reg_buf value\n");
-+ return -EIO;
-+ }
-+ }
-+
-+ switch (reg_param->reg_info.method) {
-+ case STF_ISP_REG_METHOD_ONE_REG:
-+ reg_write(ispbase, reg_param->reg_info.offset, reg_buf.buffer[0]);
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SERIES:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ reg_write(ispbase, reg_param->reg_info.offset + (r * 4),
-+ reg_buf.buffer[r]);
-+ }
-+ break;
-+
-+ case STF_ISP_REG_METHOD_MODULE:
-+ /* This mode is not supported in the V4L2 version. */
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ reg_write(ispbase, reg_buf.reg_tbl[r].offset,
-+ reg_buf.reg_tbl[r].value);
-+ }
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_2:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ if (reg_buf.reg_tbl2[r].mask) {
-+ reg_set_bit(ispbase, reg_buf.reg_tbl2[r].offset,
-+ reg_buf.reg_tbl2[r].mask, reg_buf.reg_tbl2[r].value);
-+ } else {
-+ reg_write(ispbase, reg_buf.reg_tbl2[r].offset,
-+ reg_buf.reg_tbl2[r].value);
-+ }
-+ }
-+ break;
-+
-+ case STF_ISP_REG_METHOD_TABLE_3:
-+ for (r = 0; r < reg_param->reg_info.length; r++) {
-+ if (reg_buf.reg_tbl3[r].mask) {
-+ reg_set_bit(ispbase, reg_buf.reg_tbl3[r].offset,
-+ reg_buf.reg_tbl3[r].mask, reg_buf.reg_tbl3[r].value);
-+ } else {
-+ reg_write(ispbase, reg_buf.reg_tbl3[r].offset,
-+ reg_buf.reg_tbl3[r].value);
-+ }
-+ if (reg_buf.reg_tbl3[r].delay_ms) {
-+ usleep_range(1000 * reg_buf.reg_tbl3[r].delay_ms,
-+ 1000 * reg_buf.reg_tbl3[r].delay_ms + 100);
-+ }
-+ }
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SMPL_PACK:
-+ size = reg_param->reg_info.length;
-+ rdma_info = ®_buf.rdma_cmd[0];
-+ while (size) {
-+ if (rdma_info->tag == RDMA_WR_ONE) {
-+ reg_write(ispbase, rdma_info->offset, rdma_info->param);
-+ rdma_info++;
-+ size--;
-+ } else if (rdma_info->tag == RDMA_WR_SRL) {
-+ offset = rdma_info->offset;
-+ len = rdma_info->param;
-+ rdma_info++;
-+ size--;
-+ while (size && (len > 0)) {
-+ reg_write(ispbase, offset, rdma_info->param);
-+ offset += 4;
-+ len--;
-+ if (len > 0) {
-+ reg_write(ispbase, offset, rdma_info->value);
-+ len--;
-+ }
-+ offset += 4;
-+ rdma_info++;
-+ size--;
-+ }
-+ } else if (rdma_info->tag == RDMA_END) {
-+ break;
-+ } else {
-+ rdma_info++;
-+ size--;
-+ }
-+ }
-+ break;
-+
-+ case STF_ISP_REG_METHOD_SOFT_RDMA:
-+ /*
-+ * Simulation the hardware RDMA behavior to debug and verify
-+ * the RDMA chain.
-+ */
-+ ret = stf_isp_soft_rdma(isp_dev, reg_param->reg_info.offset);
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int stf_isp_shadow_trigger(struct stf_isp_dev *isp_dev)
-+{
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+
-+ ispbase = stf_isp_get_ispbase(vin);
-+
-+ // shadow update
-+ reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, (BIT(17) | BIT(16)), 0x30000);
-+ reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, (BIT(1) | BIT(0)), 0x3);
-+ return 0;
-+}
-+
-+void dump_isp_reg(void *__iomem ispbase)
-+{
-+ int j;
-+ u32 addr, val;
-+
-+ st_debug(ST_ISP, "DUMP ISP register:\n -- isp_reg_init_settings --\n");
-+ for (j = 0; j < isp_reg_init_settings->regval_num; j++) {
-+ addr = isp_reg_init_settings->regval[j].addr;
-+ val = ioread32(ispbase + addr);
-+ st_debug(ST_ISP, "{0x%08x, 0x%08x}\n", addr, val);
-+ }
-+
-+ st_debug(ST_ISP, " --- isp_format_settings ---\n");
-+ for (j = 0; j < isp_format_settings->regval_num; j++) {
-+ addr = isp_format_settings->regval[j].addr;
-+ val = ioread32(ispbase + addr);
-+ st_debug(ST_ISP, "{0x%08x, 0x%08x}\n", addr, val);
-+ }
-+
-+ val = ioread32(ispbase + ISP_REG_Y_PLANE_START_ADDR);
-+ st_debug(ST_ISP, "-- ISP_REG_Y_PLANE_START_ADDR --\n {0x%08x, 0x%08x}\n",
-+ ISP_REG_Y_PLANE_START_ADDR, val);
-+ val = ioread32(ispbase + ISP_REG_UV_PLANE_START_ADDR);
-+ st_debug(ST_ISP, "-- ISP_REG_UV_PLANE_START_ADDR --\n {0x%08x, 0x%08x}\n",
-+ ISP_REG_UV_PLANE_START_ADDR, val);
-+ val = ioread32(ispbase + ISP_REG_DUMP_CFG_0);
-+ st_debug(ST_ISP, "-- ISP_REG_DUMP_CFG_0 --\n {0x%08x, 0x%08x}\n",
-+ ISP_REG_DUMP_CFG_0, val);
-+ val = ioread32(ispbase + ISP_REG_DUMP_CFG_1);
-+ st_debug(ST_ISP, " --- ISP_REG_DUMP_CFG_1 ---\n {0x%08x, 0x%08x}\n",
-+ ISP_REG_DUMP_CFG_1, val);
-+
-+ st_debug(ST_ISP, " --- isp_reg_start_settings ---\n");
-+ for (j = 0; j < isp_reg_start_settings->regval_num; j++) {
-+ addr = isp_reg_start_settings->regval[j].addr;
-+ val = ioread32(ispbase + addr);
-+ st_debug(ST_ISP, "{0x%08x, 0x%08x}\n", addr, val);
-+ }
-+}
-+
-+struct isp_hw_ops isp_ops = {
-+ .isp_clk_enable = stf_isp_clk_enable,
-+ .isp_clk_disable = stf_isp_clk_disable,
-+ .isp_reset = stf_isp_reset,
-+ .isp_config_set = stf_isp_config_set,
-+ .isp_set_format = stf_isp_set_format,
-+ .isp_stream_set = stf_isp_stream_set,
-+ .isp_reg_read = stf_isp_reg_read,
-+ .isp_reg_write = stf_isp_reg_write,
-+ .isp_shadow_trigger = stf_isp_shadow_trigger,
-+};
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp_ioctl.h
-@@ -0,0 +1,133 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_ISP_IOCTL_H
-+#define STF_ISP_IOCTL_H
-+
-+
-+#include <media/v4l2-ctrls.h>
-+
-+
-+#define FILENAME_MAX_LEN 30
-+
-+#define ISP_IOC ('V')
-+#define STF_ISP_REG_BUF_SIZE (768)
-+#define STF_ISP_REG_TBL_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 2)
-+#define STF_ISP_REG_TBL_2_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 3)
-+#define STF_ISP_REG_TBL_3_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 4)
-+#define STF_ISP_REG_SMPL_PACK_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 2)
-+#define RDMA_WR_ONE (0xA0)
-+#define RDMA_WR_SRL (0xA1)
-+#define RDMA_LINK (0xA2)
-+#define RDMA_SINT (0xA3)
-+#define RDMA_END (0xAF)
-+#define ENABLE_SS0_SS1
-+
-+enum _STF_ISP_IOCTL {
-+ STF_ISP_IOCTL_LOAD_FW = BASE_VIDIOC_PRIVATE + 1,
-+ STF_ISP_IOCTL_DMABUF_ALLOC,
-+ STF_ISP_IOCTL_DMABUF_FREE,
-+ STF_ISP_IOCTL_GET_HW_VER,
-+ STF_ISP_IOCTL_REG,
-+ STF_ISP_IOCTL_SHADOW_LOCK,
-+ STF_ISP_IOCTL_SHADOW_UNLOCK,
-+ STF_ISP_IOCTL_SHADOW_UNLOCK_N_TRIGGER,
-+ STF_ISP_IOCTL_SET_USER_CONFIG_ISP,
-+ STF_ISP_IOCTL_MAX
-+};
-+
-+enum _STF_ISP_REG_METHOD {
-+ STF_ISP_REG_METHOD_ONE_REG = 0,
-+ STF_ISP_REG_METHOD_SERIES,
-+ STF_ISP_REG_METHOD_MODULE,
-+ STF_ISP_REG_METHOD_TABLE,
-+ STF_ISP_REG_METHOD_TABLE_2,
-+ STF_ISP_REG_METHOD_TABLE_3,
-+ STF_ISP_REG_METHOD_SMPL_PACK,
-+ STF_ISP_REG_METHOD_SOFT_RDMA,
-+ STF_ISP_REG_METHOD_MAX
-+};
-+
-+
-+struct stfisp_fw_info {
-+ char __user filename[FILENAME_MAX_LEN];
-+};
-+
-+struct dmabuf_create {
-+ __u32 fd;
-+ __u32 size;
-+ __u32 paddr;
-+};
-+
-+struct isp_rdma_info {
-+ u32 param;
-+ union {
-+ u32 value;
-+ struct {
-+ u32 offset : 24;
-+ u32 tag : 8;
-+ };
-+ };
-+};
-+
-+struct isp_reg_info {
-+ /** @brief [in] access method of register */
-+ u8 method;
-+ /** @brief [in] offset indicated which register will be read/write */
-+ u32 offset;
-+ /** @brief [in] length for indicated how much register will be read/write */
-+ u32 length;
-+};
-+
-+union reg_buf {
-+ u32 buffer[STF_ISP_REG_BUF_SIZE];
-+ struct {
-+ u32 offset;
-+ u32 value;
-+ } reg_tbl[STF_ISP_REG_TBL_BUF_SIZE];
-+ struct {
-+ u32 offset;
-+ u32 value;
-+ u32 mask;
-+ } reg_tbl2[STF_ISP_REG_TBL_2_BUF_SIZE];
-+ struct {
-+ u32 offset;
-+ u32 value;
-+ u32 mask;
-+ u32 delay_ms;
-+ } reg_tbl3[STF_ISP_REG_TBL_3_BUF_SIZE];
-+ struct isp_rdma_info rdma_cmd[STF_ISP_REG_SMPL_PACK_BUF_SIZE];
-+};
-+
-+struct isp_reg_param {
-+ /** @brief [in, out] register read/write information */
-+ struct isp_reg_info reg_info;
-+ /** @brief [in, out] buffer */
-+ union reg_buf *reg_buf;
-+};
-+
-+
-+#define VIDIOC_STFISP_LOAD_FW \
-+ _IOW(ISP_IOC, STF_ISP_IOCTL_LOAD_FW, struct stfisp_fw_info)
-+#define VIDIOC_STF_DMABUF_ALLOC \
-+ _IOWR(ISP_IOC, STF_ISP_IOCTL_DMABUF_ALLOC, struct dmabuf_create)
-+#define VIDIOC_STF_DMABUF_FREE \
-+ _IOWR(ISP_IOC, STF_ISP_IOCTL_DMABUF_FREE, struct dmabuf_create)
-+#define VIDIOC_STFISP_GET_REG \
-+ _IOWR(ISP_IOC, STF_ISP_IOCTL_REG, struct isp_reg_param)
-+#define VIDIOC_STFISP_SET_REG \
-+ _IOW(ISP_IOC, STF_ISP_IOCTL_REG, struct isp_reg_param)
-+#define VIDIOC_STFISP_SHADOW_LOCK \
-+ _IO(ISP_IOC, STF_ISP_IOCTL_SHADOW_LOCK)
-+#define VIDIOC_STFISP_SHADOW_UNLOCK \
-+ _IO(ISP_IOC, STF_ISP_IOCTL_SHADOW_UNLOCK)
-+#define VIDIOC_STFISP_SHADOW_UNLOCK_N_TRIGGER \
-+ _IO(ISP_IOC, STF_ISP_IOCTL_SHADOW_UNLOCK_N_TRIGGER)
-+#define VIDIOC_STFISP_SET_USER_CONFIG_ISP \
-+ _IO(ISP_IOC, STF_ISP_IOCTL_SET_USER_CONFIG_ISP)
-+
-+
-+#endif /* STF_ISP_IOCTL_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.c
-@@ -0,0 +1,1552 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include "stf_video.h"
-+#include <media/media-entity.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-mc.h>
-+#include <media/videobuf2-dma-sg.h>
-+#include <media/videobuf2-vmalloc.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+static const struct stfcamss_format_info formats_pix_st7110_wr[] = {
-+ { MEDIA_BUS_FMT_AYUV8_1X32, V4L2_PIX_FMT_AYUV32, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 32 } },
-+ { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 16 } },
-+ { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_PIX_FMT_RGB565, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 16 } },
-+ { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
-+ { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
-+ { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
-+ { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+};
-+
-+static const struct stfcamss_format_info formats_raw_st7110_isp[] = {
-+ { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+ { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+ { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+ { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+};
-+
-+static const struct stfcamss_format_info formats_pix_st7110_isp[] = {
-+ // { MEDIA_BUS_FMT_YUYV12_2X12, V4L2_PIX_FMT_NV12M, 2,
-+ // { { 1, 1 }, { 1, 1 } }, { { 1, 1 }, { 1, 1 } }, { 8 , 4 } },
-+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1,
-+ { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV21, 1,
-+ { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-+};
-+
-+static const struct stfcamss_format_info formats_st7110_isp_iti[] = {
-+ // raw format
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-+ { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+ { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+ { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+ { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 1,
-+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
-+
-+ // YUV420
-+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1,
-+ { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV21, 1,
-+ { { 1, 1 } }, { { 2, 3 } }, { 8 } },
-+
-+ // YUV444
-+ { MEDIA_BUS_FMT_YUV8_1X24, V4L2_PIX_FMT_NV24, 1,
-+ { { 1, 1 } }, { { 1, 3 } }, { 8 } },
-+ { MEDIA_BUS_FMT_VUY8_1X24, V4L2_PIX_FMT_NV42, 1,
-+ { { 1, 1 } }, { { 1, 3 } }, { 8 } },
-+};
-+
-+static int video_find_format(u32 code, u32 pixelformat,
-+ const struct stfcamss_format_info *formats,
-+ unsigned int nformats)
-+{
-+ int i;
-+
-+ for (i = 0; i < nformats; i++) {
-+ if (formats[i].code == code &&
-+ formats[i].pixelformat == pixelformat)
-+ return i;
-+ }
-+
-+ for (i = 0; i < nformats; i++)
-+ if (formats[i].code == code)
-+ return i;
-+
-+ for (i = 0; i < nformats; i++)
-+ if (formats[i].pixelformat == pixelformat)
-+ return i;
-+
-+ return -EINVAL;
-+}
-+
-+static int __video_try_fmt(struct stfcamss_video *video,
-+ struct v4l2_format *f, int is_mp)
-+{
-+ struct v4l2_pix_format *pix;
-+ struct v4l2_pix_format_mplane *pix_mp;
-+ const struct stfcamss_format_info *fi;
-+ u32 width, height;
-+ u32 bpl;
-+ int i, j;
-+
-+ st_debug(ST_VIDEO, "%s, fmt.type = 0x%x\n", __func__, f->type);
-+ pix = &f->fmt.pix;
-+ pix_mp = &f->fmt.pix_mp;
-+
-+ if (is_mp) {
-+ for (i = 0; i < video->nformats; i++)
-+ if (pix_mp->pixelformat
-+ == video->formats[i].pixelformat)
-+ break;
-+
-+ if (i == video->nformats)
-+ i = 0; /* default format */
-+
-+ fi = &video->formats[i];
-+ width = pix_mp->width;
-+ height = pix_mp->height;
-+
-+ memset(pix_mp, 0, sizeof(*pix_mp));
-+
-+ pix_mp->pixelformat = fi->pixelformat;
-+ pix_mp->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
-+ STFCAMSS_FRAME_MAX_WIDTH);
-+ pix_mp->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
-+ STFCAMSS_FRAME_MAX_HEIGHT);
-+ pix_mp->num_planes = fi->planes;
-+ for (j = 0; j < pix_mp->num_planes; j++) {
-+ bpl = pix_mp->width / fi->hsub[j].numerator *
-+ fi->hsub[j].denominator * fi->bpp[j] / 8;
-+ bpl = ALIGN(bpl, video->bpl_alignment);
-+ pix_mp->plane_fmt[j].bytesperline = bpl;
-+ pix_mp->plane_fmt[j].sizeimage = pix_mp->height /
-+ fi->vsub[j].numerator
-+ * fi->vsub[j].denominator * bpl;
-+ }
-+
-+ pix_mp->field = V4L2_FIELD_NONE;
-+ pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
-+ pix_mp->flags = 0;
-+ pix_mp->ycbcr_enc =
-+ V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace);
-+ pix_mp->quantization =
-+ V4L2_MAP_QUANTIZATION_DEFAULT(true,
-+ pix_mp->colorspace, pix_mp->ycbcr_enc);
-+ pix_mp->xfer_func =
-+ V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace);
-+
-+ st_info(ST_VIDEO, "w, h = %d, %d, bpp = %d\n", pix_mp->width,
-+ pix_mp->height, fi->bpp[0]);
-+ st_info(ST_VIDEO, "i = %d, p = %d, s = 0x%x\n", i,
-+ pix_mp->num_planes, pix_mp->plane_fmt[0].sizeimage);
-+
-+ } else {
-+ for (i = 0; i < video->nformats; i++)
-+ if (pix->pixelformat == video->formats[i].pixelformat)
-+ break;
-+
-+ if (i == video->nformats)
-+ i = 0; /* default format */
-+
-+ fi = &video->formats[i];
-+ width = pix->width;
-+ height = pix->height;
-+
-+ memset(pix, 0, sizeof(*pix));
-+
-+ pix->pixelformat = fi->pixelformat;
-+ pix->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
-+ STFCAMSS_FRAME_MAX_WIDTH);
-+ pix->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
-+ STFCAMSS_FRAME_MAX_HEIGHT);
-+ bpl = pix->width / fi->hsub[0].numerator *
-+ fi->hsub[0].denominator * fi->bpp[0] / 8;
-+ bpl = ALIGN(bpl, video->bpl_alignment);
-+ pix->bytesperline = bpl;
-+ pix->sizeimage = pix->height /
-+ fi->vsub[0].numerator
-+ * fi->vsub[0].denominator * bpl;
-+
-+ pix->field = V4L2_FIELD_NONE;
-+ pix->colorspace = V4L2_COLORSPACE_SRGB;
-+ pix->flags = 0;
-+ pix->ycbcr_enc =
-+ V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
-+ pix->quantization =
-+ V4L2_MAP_QUANTIZATION_DEFAULT(true,
-+ pix->colorspace, pix->ycbcr_enc);
-+ pix->xfer_func =
-+ V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
-+
-+ st_info(ST_VIDEO, "w, h = %d, %d, bpp = %d\n", pix->width,
-+ pix->height, fi->bpp[0]);
-+ st_info(ST_VIDEO, "i = %d, s = 0x%x\n", i, pix->sizeimage);
-+ }
-+ return 0;
-+}
-+
-+static int stf_video_init_format(struct stfcamss_video *video, int is_mp)
-+{
-+ int ret;
-+ struct v4l2_format format = {
-+ .type = video->type,
-+ .fmt.pix = {
-+ .width = 1920,
-+ .height = 1080,
-+ .pixelformat = V4L2_PIX_FMT_RGB565,
-+ },
-+ };
-+
-+ ret = __video_try_fmt(video, &format, is_mp);
-+
-+ if (ret < 0)
-+ return ret;
-+
-+ video->active_fmt = format;
-+
-+ return 0;
-+}
-+
-+static int video_queue_setup(struct vb2_queue *q,
-+ unsigned int *num_buffers, unsigned int *num_planes,
-+ unsigned int sizes[], struct device *alloc_devs[])
-+{
-+ struct stfcamss_video *video = vb2_get_drv_priv(q);
-+ const struct v4l2_pix_format *format =
-+ &video->active_fmt.fmt.pix;
-+ const struct v4l2_pix_format_mplane *format_mp =
-+ &video->active_fmt.fmt.pix_mp;
-+ unsigned int i;
-+
-+ st_debug(ST_VIDEO, "%s, planes = %d\n", __func__, *num_planes);
-+
-+ if (video->is_mp) {
-+ if (*num_planes) {
-+ if (*num_planes != format_mp->num_planes)
-+ return -EINVAL;
-+
-+ for (i = 0; i < *num_planes; i++)
-+ if (sizes[i] <
-+ format_mp->plane_fmt[i].sizeimage)
-+ return -EINVAL;
-+
-+ return 0;
-+ }
-+
-+ *num_planes = format_mp->num_planes;
-+
-+ for (i = 0; i < *num_planes; i++)
-+ sizes[i] = format_mp->plane_fmt[i].sizeimage;
-+ } else {
-+ if (*num_planes) {
-+ if (*num_planes != 1)
-+ return -EINVAL;
-+
-+ if (sizes[0] < format->sizeimage)
-+ return -EINVAL;
-+ }
-+
-+ *num_planes = 1;
-+ sizes[0] = format->sizeimage;
-+ if (!sizes[0])
-+ st_err(ST_VIDEO, "%s: error size is zero!!!\n", __func__);
-+ }
-+ if ((stf_vin_map_isp_pad(video->id, STF_ISP_PAD_SRC)
-+ == STF_ISP_PAD_SRC_SCD_Y) &&
-+ sizes[0] < ISP_SCD_Y_BUFFER_SIZE) {
-+ sizes[0] = ISP_SCD_Y_BUFFER_SIZE;
-+ }
-+
-+ st_info(ST_VIDEO, "%s, planes = %d, size = %d\n",
-+ __func__, *num_planes, sizes[0]);
-+ return 0;
-+}
-+
-+static int video_buf_init(struct vb2_buffer *vb)
-+{
-+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-+ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
-+ struct stfcamss_buffer *buffer =
-+ container_of(vbuf, struct stfcamss_buffer, vb);
-+ const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix;
-+ const struct v4l2_pix_format_mplane *fmt_mp =
-+ &video->active_fmt.fmt.pix_mp;
-+ //struct sg_table *sgt;
-+ dma_addr_t *paddr;
-+ unsigned int i;
-+
-+ buffer->sizeimage = 0;
-+
-+ if (video->is_mp) {
-+ for (i = 0; i < fmt_mp->num_planes; i++) {
-+ paddr = vb2_plane_cookie(vb, i);
-+ buffer->addr[i] = *paddr;
-+ buffer->sizeimage += vb2_plane_size(vb, i);
-+ }
-+
-+ if (fmt_mp->num_planes == 1
-+ && (fmt_mp->pixelformat == V4L2_PIX_FMT_NV12
-+ || fmt_mp->pixelformat == V4L2_PIX_FMT_NV21
-+ || fmt_mp->pixelformat == V4L2_PIX_FMT_NV16
-+ || fmt_mp->pixelformat == V4L2_PIX_FMT_NV61))
-+ buffer->addr[1] = buffer->addr[0] +
-+ fmt_mp->plane_fmt[0].bytesperline *
-+ fmt_mp->height;
-+ } else {
-+ paddr = vb2_plane_cookie(vb, 0);
-+ buffer->sizeimage = vb2_plane_size(vb, 0);
-+ buffer->addr[0] = *paddr;
-+ if (fmt->pixelformat == V4L2_PIX_FMT_NV12
-+ || fmt->pixelformat == V4L2_PIX_FMT_NV21
-+ || fmt->pixelformat == V4L2_PIX_FMT_NV16
-+ || fmt->pixelformat == V4L2_PIX_FMT_NV61)
-+ buffer->addr[1] = buffer->addr[0] +
-+ fmt->bytesperline *
-+ fmt->height;
-+ }
-+
-+ if (stf_vin_map_isp_pad(video->id, STF_ISP_PAD_SRC)
-+ == STF_ISP_PAD_SRC_SCD_Y) {
-+ buffer->addr[1] = buffer->addr[0] + ISP_YHIST_BUFFER_SIZE;
-+ buffer->vaddr_sc = vb2_plane_vaddr(vb, 0);
-+ }
-+
-+ return 0;
-+}
-+
-+static int video_buf_prepare(struct vb2_buffer *vb)
-+{
-+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-+ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
-+ const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix;
-+ const struct v4l2_pix_format_mplane *fmt_mp =
-+ &video->active_fmt.fmt.pix_mp;
-+ unsigned int i;
-+
-+ if (video->is_mp) {
-+ for (i = 0; i < fmt_mp->num_planes; i++) {
-+ if (fmt_mp->plane_fmt[i].sizeimage
-+ > vb2_plane_size(vb, i))
-+ return -EINVAL;
-+
-+ vb2_set_plane_payload(vb, i,
-+ fmt_mp->plane_fmt[i].sizeimage);
-+ }
-+ } else {
-+ if (fmt->sizeimage > vb2_plane_size(vb, 0)) {
-+ st_err(ST_VIDEO, "sizeimage = %d, plane size = %d\n",
-+ fmt->sizeimage, (unsigned int)vb2_plane_size(vb, 0));
-+ return -EINVAL;
-+ }
-+ vb2_set_plane_payload(vb, 0, fmt->sizeimage);
-+ }
-+
-+ vbuf->field = V4L2_FIELD_NONE;
-+
-+ return 0;
-+}
-+
-+static void video_buf_queue(struct vb2_buffer *vb)
-+{
-+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-+ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
-+ struct stfcamss_buffer *buffer =
-+ container_of(vbuf, struct stfcamss_buffer, vb);
-+
-+ video->ops->queue_buffer(video, buffer);
-+}
-+
-+static int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus,
-+ struct v4l2_pix_format_mplane *pix,
-+ const struct stfcamss_format_info *f,
-+ unsigned int alignment)
-+{
-+ unsigned int i;
-+ u32 bytesperline;
-+
-+ memset(pix, 0, sizeof(*pix));
-+ v4l2_fill_pix_format_mplane(pix, mbus);
-+ pix->pixelformat = f->pixelformat;
-+ pix->num_planes = f->planes;
-+ for (i = 0; i < pix->num_planes; i++) {
-+ bytesperline = pix->width / f->hsub[i].numerator *
-+ f->hsub[i].denominator * f->bpp[i] / 8;
-+ bytesperline = ALIGN(bytesperline, alignment);
-+ pix->plane_fmt[i].bytesperline = bytesperline;
-+ pix->plane_fmt[i].sizeimage = pix->height /
-+ f->vsub[i].numerator * f->vsub[i].denominator *
-+ bytesperline;
-+ }
-+
-+ return 0;
-+}
-+
-+static int video_mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
-+ struct v4l2_pix_format *pix,
-+ const struct stfcamss_format_info *f,
-+ unsigned int alignment)
-+{
-+ u32 bytesperline;
-+
-+ memset(pix, 0, sizeof(*pix));
-+ v4l2_fill_pix_format(pix, mbus);
-+ pix->pixelformat = f->pixelformat;
-+ bytesperline = pix->width / f->hsub[0].numerator *
-+ f->hsub[0].denominator * f->bpp[0] / 8;
-+ bytesperline = ALIGN(bytesperline, alignment);
-+ pix->bytesperline = bytesperline;
-+ pix->sizeimage = pix->height /
-+ f->vsub[0].numerator * f->vsub[0].denominator *
-+ bytesperline;
-+ return 0;
-+}
-+
-+static struct v4l2_subdev *video_remote_subdev(
-+ struct stfcamss_video *video, u32 *pad)
-+{
-+ struct media_pad *remote;
-+
-+ remote = media_pad_remote_pad_first(&video->pad);
-+
-+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
-+ return NULL;
-+
-+ if (pad)
-+ *pad = remote->index;
-+
-+ return media_entity_to_v4l2_subdev(remote->entity);
-+}
-+
-+static int video_get_subdev_format(struct stfcamss_video *video,
-+ struct v4l2_format *format)
-+{
-+ struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix;
-+ struct v4l2_pix_format_mplane *pix_mp =
-+ &video->active_fmt.fmt.pix_mp;
-+ struct v4l2_subdev_format fmt;
-+ struct v4l2_subdev *subdev;
-+ u32 pixelformat;
-+ u32 pad;
-+ int ret;
-+
-+ subdev = video_remote_subdev(video, &pad);
-+ if (subdev == NULL)
-+ return -EPIPE;
-+
-+ fmt.pad = pad;
-+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+
-+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
-+ if (ret)
-+ return ret;
-+
-+ if (video->is_mp)
-+ pixelformat = pix_mp->pixelformat;
-+ else
-+ pixelformat = pix->pixelformat;
-+ ret = video_find_format(fmt.format.code, pixelformat,
-+ video->formats, video->nformats);
-+ if (ret < 0)
-+ return ret;
-+
-+ format->type = video->type;
-+
-+ if (video->is_mp)
-+ return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp,
-+ &video->formats[ret], video->bpl_alignment);
-+ else
-+ return video_mbus_to_pix(&fmt.format, &format->fmt.pix,
-+ &video->formats[ret], video->bpl_alignment);
-+}
-+
-+static int video_check_format(struct stfcamss_video *video)
-+{
-+ struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix;
-+ struct v4l2_pix_format_mplane *pix_mp =
-+ &video->active_fmt.fmt.pix_mp;
-+ struct v4l2_format format;
-+ struct v4l2_pix_format *sd_pix = &format.fmt.pix;
-+ struct v4l2_pix_format_mplane *sd_pix_mp = &format.fmt.pix_mp;
-+ int ret;
-+
-+ if (video->is_mp) {
-+ sd_pix_mp->pixelformat = pix_mp->pixelformat;
-+ ret = video_get_subdev_format(video, &format);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (pix_mp->pixelformat != sd_pix_mp->pixelformat ||
-+ pix_mp->height > sd_pix_mp->height ||
-+ pix_mp->width > sd_pix_mp->width ||
-+ pix_mp->num_planes != sd_pix_mp->num_planes ||
-+ pix_mp->field != format.fmt.pix_mp.field) {
-+ st_err(ST_VIDEO,
-+ "%s, not match:\n"
-+ "0x%x 0x%x\n0x%x 0x%x\n0x%x 0x%x\n",
-+ __func__,
-+ pix_mp->pixelformat, sd_pix_mp->pixelformat,
-+ pix_mp->height, sd_pix_mp->height,
-+ pix_mp->field, format.fmt.pix_mp.field);
-+ return -EPIPE;
-+ }
-+
-+ } else {
-+ sd_pix->pixelformat = pix->pixelformat;
-+ ret = video_get_subdev_format(video, &format);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (pix->pixelformat != sd_pix->pixelformat ||
-+ pix->height > sd_pix->height ||
-+ pix->width > sd_pix->width ||
-+ pix->field != format.fmt.pix.field) {
-+ st_err(ST_VIDEO,
-+ "%s, not match:\n"
-+ "0x%x 0x%x\n0x%x 0x%x\n0x%x 0x%x\n",
-+ __func__,
-+ pix->pixelformat, sd_pix->pixelformat,
-+ pix->height, sd_pix->height,
-+ pix->field, format.fmt.pix.field);
-+ return -EPIPE;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int video_start_streaming(struct vb2_queue *q, unsigned int count)
-+{
-+ struct stfcamss_video *video = vb2_get_drv_priv(q);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity;
-+ struct media_pad *pad;
-+ struct v4l2_subdev *subdev;
-+ int ret;
-+
-+ ret = video_device_pipeline_start(vdev, &video->stfcamss->pipe);
-+ if (ret < 0) {
-+ st_err(ST_VIDEO,
-+ "Failed to video_device_pipeline_start: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = video_check_format(video);
-+ if (ret < 0)
-+ goto error;
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ ret = v4l2_subdev_call(subdev, video, s_stream, 1);
-+ if (ret < 0 && ret != -ENOIOCTLCMD)
-+ goto error;
-+ }
-+ return 0;
-+
-+error:
-+ video_device_pipeline_stop(vdev);
-+ video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
-+ return ret;
-+}
-+
-+static void video_stop_streaming(struct vb2_queue *q)
-+{
-+ struct stfcamss_video *video = vb2_get_drv_priv(q);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity;
-+ struct media_pad *pad;
-+ struct v4l2_subdev *subdev;
-+
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ v4l2_subdev_call(subdev, video, s_stream, 0);
-+ }
-+
-+ video_device_pipeline_stop(vdev);
-+ video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
-+}
-+
-+static const struct vb2_ops stf_video_vb2_q_ops = {
-+ .queue_setup = video_queue_setup,
-+ .wait_prepare = vb2_ops_wait_prepare,
-+ .wait_finish = vb2_ops_wait_finish,
-+ .buf_init = video_buf_init,
-+ .buf_prepare = video_buf_prepare,
-+ .buf_queue = video_buf_queue,
-+ .start_streaming = video_start_streaming,
-+ .stop_streaming = video_stop_streaming,
-+};
-+
-+/* -----------------------------------------------------
-+ * V4L2 ioctls
-+ */
-+
-+static int getcrop_pad_id(int video_id)
-+{
-+ return stf_vin_map_isp_pad(video_id, STF_ISP_PAD_SRC);
-+}
-+
-+static int video_querycap(struct file *file, void *fh,
-+ struct v4l2_capability *cap)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+
-+ strscpy(cap->driver, "stf camss", sizeof(cap->driver));
-+ strscpy(cap->card, "Starfive Camera Subsystem", sizeof(cap->card));
-+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
-+ dev_name(video->stfcamss->dev));
-+ return 0;
-+}
-+
-+static int video_get_unique_pixelformat_by_index(struct stfcamss_video *video,
-+ int ndx)
-+{
-+ int i, j, k;
-+
-+ /* find index "i" of "k"th unique pixelformat in formats array */
-+ k = -1;
-+ for (i = 0; i < video->nformats; i++) {
-+ for (j = 0; j < i; j++) {
-+ if (video->formats[i].pixelformat ==
-+ video->formats[j].pixelformat)
-+ break;
-+ }
-+
-+ if (j == i)
-+ k++;
-+
-+ if (k == ndx)
-+ return i;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static int video_get_pixelformat_by_mbus_code(struct stfcamss_video *video,
-+ u32 mcode)
-+{
-+ int i;
-+
-+ for (i = 0; i < video->nformats; i++) {
-+ if (video->formats[i].code == mcode)
-+ return i;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+ int i;
-+
-+ st_debug(ST_VIDEO, "%s:\n0x%x 0x%x\n 0x%x, 0x%x\n0x%x\n",
-+ __func__,
-+ f->type, video->type,
-+ f->index, video->nformats,
-+ f->mbus_code);
-+
-+ if (f->type != video->type)
-+ return -EINVAL;
-+ if (f->index >= video->nformats)
-+ return -EINVAL;
-+
-+ if (f->mbus_code) {
-+ /* Each entry in formats[] table has unique mbus_code */
-+ if (f->index > 0)
-+ return -EINVAL;
-+
-+ i = video_get_pixelformat_by_mbus_code(video, f->mbus_code);
-+ } else {
-+ i = video_get_unique_pixelformat_by_index(video, f->index);
-+ }
-+
-+ if (i < 0)
-+ return -EINVAL;
-+
-+ f->pixelformat = video->formats[i].pixelformat;
-+
-+ return 0;
-+}
-+
-+static int video_enum_framesizes(struct file *file, void *fh,
-+ struct v4l2_frmsizeenum *fsize)
-+{
-+ struct v4l2_subdev_frame_size_enum fse = {0};
-+ struct v4l2_subdev_mbus_code_enum code = {0};
-+ struct stfcamss_video *video = video_drvdata(file);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity = &vdev->entity;
-+ struct media_entity *sensor;
-+ struct v4l2_subdev *subdev;
-+ struct media_pad *pad;
-+ bool support_selection = false;
-+ int i;
-+ int ret;
-+
-+ for (i = 0; i < video->nformats; i++) {
-+ if (video->formats[i].pixelformat == fsize->pixel_format)
-+ break;
-+ }
-+
-+ if (i == video->nformats)
-+ return -EINVAL;
-+
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ if (subdev->ops->pad->set_selection) {
-+ support_selection = true;
-+ break;
-+ }
-+ }
-+
-+ if (support_selection) {
-+ if (fsize->index)
-+ return -EINVAL;
-+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
-+ fsize->stepwise.min_width = STFCAMSS_FRAME_MIN_WIDTH;
-+ fsize->stepwise.max_width = STFCAMSS_FRAME_MAX_WIDTH;
-+ fsize->stepwise.min_height = STFCAMSS_FRAME_MIN_HEIGHT;
-+ fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT;
-+ fsize->stepwise.step_width = 1;
-+ fsize->stepwise.step_height = 1;
-+ } else {
-+ entity = &vdev->entity;
-+ sensor = stfcamss_find_sensor(entity);
-+ if (!sensor)
-+ return -ENOTTY;
-+
-+ subdev = media_entity_to_v4l2_subdev(sensor);
-+ code.index = 0;
-+ code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+ ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code);
-+ if (ret < 0)
-+ return -EINVAL;
-+ fse.index = fsize->index;
-+ fse.code = code.code;
-+ fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+ ret = v4l2_subdev_call(subdev, pad, enum_frame_size, NULL, &fse);
-+ if (ret < 0)
-+ return -EINVAL;
-+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-+ fsize->discrete.width = fse.min_width;
-+ fsize->discrete.height = fse.min_height;
-+ }
-+
-+ return 0;
-+}
-+
-+static int video_enum_frameintervals(struct file *file, void *fh,
-+ struct v4l2_frmivalenum *fival)
-+{
-+ int ret = 0;
-+ struct stfcamss_video *video = video_drvdata(file);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity = &vdev->entity;
-+ struct media_entity *sensor;
-+ struct v4l2_subdev *subdev;
-+ struct v4l2_subdev_mbus_code_enum code = {0};
-+ struct v4l2_subdev_frame_interval_enum fie = {0};
-+
-+ sensor = stfcamss_find_sensor(entity);
-+ if (!sensor)
-+ return -ENOTTY;
-+ fie.index = fival->index;
-+ fie.width = fival->width;
-+ fie.height = fival->height;
-+ fie.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+ subdev = media_entity_to_v4l2_subdev(sensor);
-+
-+ code.index = 0;
-+ code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-+
-+ /* Don't care about the code, just find by pixelformat */
-+ ret = video_find_format(0, fival->pixel_format,
-+ video->formats, video->nformats);
-+ if (ret < 0)
-+ return -EINVAL;
-+
-+ ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code);
-+ if (ret < 0)
-+ return -EINVAL;
-+
-+ fie.code = code.code;
-+ ret = v4l2_subdev_call(subdev, pad, enum_frame_interval, NULL, &fie);
-+ if (ret < 0)
-+ return ret;
-+
-+ fival->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-+ fival->discrete = fie.interval;
-+
-+ return 0;
-+}
-+
-+static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+
-+ st_debug(ST_VIDEO, "%s, fmt.type = 0x%x\n", __func__, f->type);
-+ st_debug(ST_VIDEO, "%s, active_fmt.type = 0x%x,0x%x\n",
-+ __func__, video->active_fmt.type,
-+ video->active_fmt.fmt.pix.pixelformat);
-+ *f = video->active_fmt;
-+ return 0;
-+}
-+
-+static int video_g_fmt_mp(struct file *file, void *fh, struct v4l2_format *f)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+
-+ st_debug(ST_VIDEO, "%s, fmt.type = 0x%x\n", __func__, f->type);
-+ st_debug(ST_VIDEO, "%s, active_fmt.type = 0x%x\n",
-+ __func__, video->active_fmt.type);
-+ *f = video->active_fmt;
-+ return 0;
-+}
-+
-+static int video_entity_s_fmt(struct stfcamss_video *video,
-+ struct media_entity *entity,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct v4l2_subdev *subdev;
-+ struct media_pad *pad;
-+ struct v4l2_mbus_framefmt *mf = &fmt->format;
-+ struct v4l2_subdev_format fmt_src = {
-+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-+ };
-+ u32 width, height, code;
-+ int ret, index = 0;
-+
-+ code = mf->code;
-+ width = mf->width;
-+ height = mf->height;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+ while (1) {
-+ if (index >= entity->num_pads)
-+ break;
-+ pad = &entity->pads[index];
-+ pad = media_pad_remote_pad_first(pad);
-+ if (pad && is_media_entity_v4l2_subdev(pad->entity)) {
-+ fmt->pad = index;
-+ ret = v4l2_subdev_call(subdev, pad, set_fmt, state, fmt);
-+ if (mf->code != code ||
-+ mf->width != width || mf->height != height) {
-+ st_warn(ST_VIDEO,
-+ "\"%s\":%d pad fmt has been"
-+ " changed to 0x%x %ux%u\n",
-+ subdev->name, fmt->pad, mf->code,
-+ mf->width, mf->height);
-+ }
-+ if (index) {
-+ fmt_src.pad = index;
-+ ret = v4l2_subdev_call(subdev, pad, get_fmt, state, &fmt_src);
-+ if (ret)
-+ return ret;
-+
-+ fmt->format.code = fmt_src.format.code;
-+ ret = video_entity_s_fmt(video, pad->entity, state, fmt);
-+ }
-+ }
-+
-+ if (ret < 0 && ret != -ENOIOCTLCMD)
-+ break;
-+ index++;
-+ }
-+ return ret;
-+}
-+
-+static int video_pipeline_s_fmt(struct stfcamss_video *video,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_format *f)
-+{
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity = &vdev->entity;
-+ struct v4l2_subdev *subdev;
-+ int ret, index;
-+ struct v4l2_subdev_format fmt = {
-+ .pad = 0,
-+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .reserved = {getcrop_pad_id(video->id)}
-+ };
-+ struct v4l2_mbus_framefmt *mf = &fmt.format;
-+ struct v4l2_pix_format *pix = &f->fmt.pix;
-+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
-+ struct media_entity *sensor;
-+ u32 width, height;
-+ struct media_pad *pad;
-+
-+ /* pix to mbus format */
-+ if (video->is_mp) {
-+ index = video_find_format(mf->code,
-+ pix_mp->pixelformat,
-+ video->formats, video->nformats);
-+ if (index < 0)
-+ return index;
-+ v4l2_fill_mbus_format_mplane(mf, pix_mp);
-+ mf->code = video->formats[index].code;
-+ } else {
-+ index = video_find_format(mf->code,
-+ pix->pixelformat,
-+ video->formats, video->nformats);
-+ if (index < 0)
-+ return index;
-+ v4l2_fill_mbus_format(mf, pix, video->formats[index].code);
-+ }
-+
-+ width = mf->width;
-+ height = mf->height;
-+
-+ sensor = stfcamss_find_sensor(entity);
-+ if (!sensor) {
-+ st_err(ST_VIDEO, "Can't find sensor\n");
-+ return -ENOTTY;
-+ }
-+
-+ subdev = media_entity_to_v4l2_subdev(sensor);
-+ ret = v4l2_subdev_call(subdev, pad, get_fmt, state, &fmt);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * Starting from sensor subdevice, walk within
-+ * pipeline and set format on each subdevice
-+ */
-+ pad = media_pad_remote_pad_first(&sensor->pads[0]);
-+ ret = video_entity_s_fmt(video, pad->entity, state, &fmt);
-+ if (ret < 0 && ret != -ENOIOCTLCMD)
-+ return ret;
-+
-+ index = video_find_format(mf->code,
-+ video->formats[index].pixelformat,
-+ video->formats, video->nformats);
-+ st_debug(ST_VIDEO, "%s, code=%x, index=%d\n",
-+ __func__, mf->code, index);
-+
-+ if (index < 0)
-+ return index;
-+
-+ if (video->is_mp)
-+ video_mbus_to_pix_mp(mf, pix_mp,
-+ &video->formats[index], video->bpl_alignment);
-+ else
-+ video_mbus_to_pix(mf, pix,
-+ &video->formats[index], video->bpl_alignment);
-+
-+ ret = __video_try_fmt(video, f, video->is_mp);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+ int ret;
-+
-+ st_debug(ST_VIDEO, "%s, fmt.type = 0x%x, v4l2fmt=%x\n",
-+ __func__, f->type, f->fmt.pix.pixelformat);
-+
-+ if (vb2_is_busy(&video->vb2_q))
-+ return -EBUSY;
-+
-+ ret = __video_try_fmt(video, f, false);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = video_pipeline_s_fmt(video, NULL, f);
-+
-+ st_debug(ST_VIDEO, "%s, pixelformat=0x%x, ret=%d\n",
-+ __func__, f->fmt.pix.pixelformat, ret);
-+ if (ret < 0)
-+ return ret;
-+
-+ video->active_fmt = *f;
-+
-+ return 0;
-+}
-+
-+static int video_s_fmt_mp(struct file *file, void *fh, struct v4l2_format *f)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+ int ret;
-+
-+ st_debug(ST_VIDEO, "%s, fmt.type = 0x%x\n", __func__, f->type);
-+ if (vb2_is_busy(&video->vb2_q))
-+ return -EBUSY;
-+
-+ ret = __video_try_fmt(video, f, true);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = video_pipeline_s_fmt(video, NULL, f);
-+ if (ret < 0)
-+ return ret;
-+
-+ video->active_fmt = *f;
-+
-+ return 0;
-+}
-+
-+static int video_try_fmt(struct file *file,
-+ void *fh, struct v4l2_format *f)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+
-+ return __video_try_fmt(video, f, false);
-+}
-+
-+static int video_try_fmt_mp(struct file *file,
-+ void *fh, struct v4l2_format *f)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+
-+ return __video_try_fmt(video, f, true);
-+}
-+
-+static int video_enum_input(struct file *file, void *fh,
-+ struct v4l2_input *input)
-+{
-+ if (input->index > 0)
-+ return -EINVAL;
-+
-+ strscpy(input->name, "camera", sizeof(input->name));
-+ input->type = V4L2_INPUT_TYPE_CAMERA;
-+
-+ return 0;
-+}
-+
-+static int video_g_input(struct file *file, void *fh, unsigned int *input)
-+{
-+ *input = 0;
-+
-+ return 0;
-+}
-+
-+static int video_s_input(struct file *file, void *fh, unsigned int input)
-+{
-+ return input == 0 ? 0 : -EINVAL;
-+}
-+
-+static int video_g_parm(struct file *file, void *priv,
-+ struct v4l2_streamparm *p)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity;
-+ struct v4l2_subdev *subdev;
-+ struct media_pad *pad;
-+ int ret, is_support = 0;
-+
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ ret = v4l2_g_parm_cap(vdev, subdev, p);
-+ if (ret < 0 && ret != -ENOIOCTLCMD)
-+ break;
-+ if (!ret)
-+ is_support = 1;
-+ }
-+
-+ return is_support ? 0 : ret;
-+}
-+
-+static int video_s_parm(struct file *file, void *priv,
-+ struct v4l2_streamparm *p)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity;
-+ struct v4l2_subdev *subdev;
-+ struct media_pad *pad;
-+ struct v4l2_streamparm tmp_p;
-+ int ret, is_support = 0;
-+
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ tmp_p = *p;
-+ ret = v4l2_s_parm_cap(vdev, subdev, &tmp_p);
-+ if (ret < 0 && ret != -ENOIOCTLCMD)
-+ break;
-+ if (!ret) {
-+ is_support = 1;
-+ *p = tmp_p;
-+ }
-+ }
-+
-+ return is_support ? 0 : ret;
-+}
-+
-+/* Crop ioctls */
-+int video_g_pixelaspect(struct file *file, void *fh,
-+ int buf_type, struct v4l2_fract *aspect)
-+{
-+ return 0;
-+}
-+
-+int video_g_selection(struct file *file, void *fh,
-+ struct v4l2_selection *s)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity;
-+ struct v4l2_subdev *subdev;
-+ struct media_pad *pad;
-+ struct v4l2_subdev_selection sel = {
-+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .pad = getcrop_pad_id(video->id),
-+ .target = s->target,
-+ .r = s->r,
-+ .flags = s->flags,
-+ };
-+ int ret;
-+
-+ st_debug(ST_VIDEO, "%s, target = 0x%x, 0x%x\n",
-+ __func__, sel.target, s->target);
-+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-+ && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-+ return -EINVAL;
-+
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sel);
-+ if (!ret) {
-+ s->r = sel.r;
-+ s->flags = sel.flags;
-+ break;
-+ }
-+ if (ret != -ENOIOCTLCMD)
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+int video_s_selection(struct file *file, void *fh,
-+ struct v4l2_selection *s)
-+{
-+ struct stfcamss_video *video = video_drvdata(file);
-+ struct video_device *vdev = &video->vdev;
-+ struct media_entity *entity;
-+ struct v4l2_subdev *subdev;
-+ struct media_pad *pad;
-+ struct v4l2_subdev_selection sel = {
-+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .pad = getcrop_pad_id(video->id),
-+ .target = s->target,
-+ .r = s->r,
-+ .flags = s->flags,
-+ };
-+ struct v4l2_pix_format *format = &video->active_fmt.fmt.pix;
-+ struct v4l2_pix_format_mplane *format_mp =
-+ &video->active_fmt.fmt.pix_mp;
-+ int ret;
-+
-+ st_debug(ST_VIDEO, "%s, target = 0x%x, 0x%x\n",
-+ __func__, sel.target, s->target);
-+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-+ && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-+ return -EINVAL;
-+
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sel);
-+ if (!ret) {
-+ s->r = sel.r;
-+ s->flags = sel.flags;
-+ format->width = s->r.width;
-+ format->height = s->r.height;
-+ format_mp->width = s->r.width;
-+ format_mp->height = s->r.height;
-+ ret = __video_try_fmt(video, &video->active_fmt,
-+ video->is_mp);
-+ if (ret < 0)
-+ return ret;
-+ break;
-+ }
-+ if (ret != -ENOIOCTLCMD)
-+ break;
-+ }
-+
-+ st_debug(ST_VIDEO, "ret = 0x%x, -EINVAL = 0x%x\n", ret, -EINVAL);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ioctl_ops stf_vid_ioctl_ops = {
-+ .vidioc_querycap = video_querycap,
-+ .vidioc_enum_fmt_vid_cap = video_enum_fmt,
-+ .vidioc_enum_framesizes = video_enum_framesizes,
-+ .vidioc_enum_frameintervals = video_enum_frameintervals,
-+ .vidioc_g_fmt_vid_cap = video_g_fmt,
-+ .vidioc_s_fmt_vid_cap = video_s_fmt,
-+ .vidioc_try_fmt_vid_cap = video_try_fmt,
-+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
-+ .vidioc_querybuf = vb2_ioctl_querybuf,
-+ .vidioc_qbuf = vb2_ioctl_qbuf,
-+ .vidioc_expbuf = vb2_ioctl_expbuf,
-+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
-+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
-+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
-+ .vidioc_streamon = vb2_ioctl_streamon,
-+ .vidioc_streamoff = vb2_ioctl_streamoff,
-+ .vidioc_enum_input = video_enum_input,
-+ .vidioc_g_input = video_g_input,
-+ .vidioc_s_input = video_s_input,
-+ .vidioc_g_parm = video_g_parm,
-+ .vidioc_s_parm = video_s_parm,
-+ .vidioc_s_selection = video_s_selection,
-+ .vidioc_g_selection = video_g_selection,
-+};
-+
-+static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_mp = {
-+ .vidioc_querycap = video_querycap,
-+ .vidioc_enum_fmt_vid_cap = video_enum_fmt,
-+ .vidioc_enum_framesizes = video_enum_framesizes,
-+ .vidioc_enum_frameintervals = video_enum_frameintervals,
-+ .vidioc_g_fmt_vid_cap_mplane = video_g_fmt_mp,
-+ .vidioc_s_fmt_vid_cap_mplane = video_s_fmt_mp,
-+ .vidioc_try_fmt_vid_cap_mplane = video_try_fmt_mp,
-+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
-+ .vidioc_querybuf = vb2_ioctl_querybuf,
-+ .vidioc_qbuf = vb2_ioctl_qbuf,
-+ .vidioc_expbuf = vb2_ioctl_expbuf,
-+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
-+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
-+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
-+ .vidioc_streamon = vb2_ioctl_streamon,
-+ .vidioc_streamoff = vb2_ioctl_streamoff,
-+ .vidioc_enum_input = video_enum_input,
-+ .vidioc_g_input = video_g_input,
-+ .vidioc_s_input = video_s_input,
-+ .vidioc_g_parm = video_g_parm,
-+ .vidioc_s_parm = video_s_parm,
-+ .vidioc_s_selection = video_s_selection,
-+ .vidioc_g_selection = video_g_selection,
-+};
-+
-+static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_out = {
-+ .vidioc_querycap = video_querycap,
-+ .vidioc_enum_fmt_vid_out = video_enum_fmt,
-+ .vidioc_enum_framesizes = video_enum_framesizes,
-+ .vidioc_enum_frameintervals = video_enum_frameintervals,
-+ .vidioc_g_fmt_vid_out = video_g_fmt,
-+ .vidioc_s_fmt_vid_out = video_s_fmt,
-+ .vidioc_try_fmt_vid_out = video_try_fmt,
-+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
-+ .vidioc_querybuf = vb2_ioctl_querybuf,
-+ .vidioc_qbuf = vb2_ioctl_qbuf,
-+ .vidioc_expbuf = vb2_ioctl_expbuf,
-+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
-+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
-+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
-+ .vidioc_streamon = vb2_ioctl_streamon,
-+ .vidioc_streamoff = vb2_ioctl_streamoff,
-+};
-+
-+static int video_open(struct file *file)
-+{
-+ struct video_device *vdev = video_devdata(file);
-+ struct stfcamss_video *video = video_drvdata(file);
-+ struct v4l2_fh *vfh;
-+ int ret;
-+
-+ mutex_lock(&video->lock);
-+
-+ vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
-+ if (vfh == NULL) {
-+ ret = -ENOMEM;
-+ goto error_alloc;
-+ }
-+
-+ v4l2_fh_init(vfh, vdev);
-+ v4l2_fh_add(vfh);
-+
-+ file->private_data = vfh;
-+
-+ if (!video->pm_count) {
-+ ret = v4l2_pipeline_pm_get(&vdev->entity);
-+ if (ret < 0) {
-+ st_err(ST_VIDEO,
-+ "Failed to power up pipeline: %d\n", ret);
-+ goto error_pm_use;
-+ }
-+ }
-+
-+ video->pm_count++;
-+
-+ mutex_unlock(&video->lock);
-+
-+ return 0;
-+
-+error_pm_use:
-+ v4l2_fh_release(file);
-+error_alloc:
-+ mutex_unlock(&video->lock);
-+ return ret;
-+}
-+
-+static int video_release(struct file *file)
-+{
-+ struct video_device *vdev = video_devdata(file);
-+ struct stfcamss_video *video = video_drvdata(file);
-+
-+ vb2_fop_release(file);
-+
-+ video->pm_count--;
-+
-+ if (!video->pm_count)
-+ v4l2_pipeline_pm_put(&vdev->entity);
-+
-+ file->private_data = NULL;
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_file_operations stf_vid_fops = {
-+ .owner = THIS_MODULE,
-+ .unlocked_ioctl = video_ioctl2,
-+ .open = video_open,
-+ .release = video_release,
-+ .poll = vb2_fop_poll,
-+ .mmap = vb2_fop_mmap,
-+ .read = vb2_fop_read,
-+};
-+
-+static void stf_video_release(struct video_device *vdev)
-+{
-+ struct stfcamss_video *video = video_get_drvdata(vdev);
-+
-+ media_entity_cleanup(&vdev->entity);
-+
-+ mutex_destroy(&video->q_lock);
-+ mutex_destroy(&video->lock);
-+}
-+
-+int stf_video_register(struct stfcamss_video *video,
-+ struct v4l2_device *v4l2_dev,
-+ const char *name, int is_mp)
-+{
-+ struct video_device *vdev;
-+ struct vb2_queue *q;
-+ struct media_pad *pad = &video->pad;
-+ int ret;
-+ enum isp_pad_id isp_pad;
-+
-+ vdev = &video->vdev;
-+
-+ mutex_init(&video->q_lock);
-+
-+ q = &video->vb2_q;
-+ q->drv_priv = video;
-+ q->mem_ops = &vb2_dma_contig_memops;
-+ q->ops = &stf_video_vb2_q_ops;
-+ //q->type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
-+ // V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ q->type = video->type;
-+ q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
-+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-+ q->buf_struct_size = sizeof(struct stfcamss_buffer);
-+ q->dev = video->stfcamss->dev;
-+ q->lock = &video->q_lock;
-+ q->min_buffers_needed = STFCAMSS_MIN_BUFFERS;
-+ ret = vb2_queue_init(q);
-+ if (ret < 0) {
-+ st_err(ST_VIDEO,
-+ "Failed to init vb2 queue: %d\n", ret);
-+ goto err_vb2_init;
-+ }
-+
-+ pad->flags = MEDIA_PAD_FL_SINK;
-+ ret = media_entity_pads_init(&vdev->entity, 1, pad);
-+ if (ret < 0) {
-+ st_err(ST_VIDEO,
-+ "Failed to init video entity: %d\n",
-+ ret);
-+ goto err_vb2_init;
-+ }
-+
-+ mutex_init(&video->lock);
-+
-+ isp_pad = stf_vin_map_isp_pad(video->id, STF_ISP_PAD_SRC);
-+ if (video->id == VIN_LINE_WR) {
-+ video->formats = formats_pix_st7110_wr;
-+ video->nformats = ARRAY_SIZE(formats_pix_st7110_wr);
-+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
-+ } else if (isp_pad == STF_ISP_PAD_SRC
-+ || isp_pad == STF_ISP_PAD_SRC_SS0
-+ || isp_pad == STF_ISP_PAD_SRC_SS1) {
-+ video->formats = formats_pix_st7110_isp;
-+ video->nformats = ARRAY_SIZE(formats_pix_st7110_isp);
-+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
-+ } else if (isp_pad == STF_ISP_PAD_SRC_ITIW
-+ || isp_pad == STF_ISP_PAD_SRC_ITIR) {
-+ video->formats = formats_st7110_isp_iti;
-+ video->nformats = ARRAY_SIZE(formats_st7110_isp_iti);
-+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
-+ } else { // raw/scdump/yhist
-+ video->formats = formats_raw_st7110_isp;
-+ video->nformats = ARRAY_SIZE(formats_raw_st7110_isp);
-+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_128;
-+ }
-+ video->is_mp = is_mp;
-+
-+ ret = stf_video_init_format(video, is_mp);
-+ if (ret < 0) {
-+ st_err(ST_VIDEO, "Failed to init format: %d\n", ret);
-+ goto err_vid_init_format;
-+ }
-+
-+ vdev->fops = &stf_vid_fops;
-+ if (isp_pad == STF_ISP_PAD_SRC_ITIR) {
-+ vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT;
-+ vdev->vfl_dir = VFL_DIR_TX;
-+ } else {
-+ vdev->device_caps = is_mp ? V4L2_CAP_VIDEO_CAPTURE_MPLANE :
-+ V4L2_CAP_VIDEO_CAPTURE;
-+ vdev->vfl_dir = VFL_DIR_RX;
-+ }
-+ vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC;
-+ if (video->type == V4L2_CAP_VIDEO_OUTPUT)
-+ vdev->ioctl_ops = &stf_vid_ioctl_ops_out;
-+ else
-+ vdev->ioctl_ops = is_mp ? &stf_vid_ioctl_ops_mp : &stf_vid_ioctl_ops;
-+ vdev->release = stf_video_release;
-+ vdev->v4l2_dev = v4l2_dev;
-+ vdev->queue = &video->vb2_q;
-+ vdev->lock = &video->lock;
-+ //strlcpy(vdev->name, name, sizeof(vdev->name));
-+ strscpy(vdev->name, name, sizeof(vdev->name));
-+
-+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, video->id);
-+ if (ret < 0) {
-+ st_err(ST_VIDEO,
-+ "Failed to register video device: %d\n",
-+ ret);
-+ goto err_vid_reg;
-+ }
-+
-+ video_set_drvdata(vdev, video);
-+ return 0;
-+
-+err_vid_reg:
-+err_vid_init_format:
-+ media_entity_cleanup(&vdev->entity);
-+ mutex_destroy(&video->lock);
-+err_vb2_init:
-+ mutex_destroy(&video->q_lock);
-+ return ret;
-+}
-+
-+void stf_video_unregister(struct stfcamss_video *video)
-+{
-+ vb2_video_unregister_device(&video->vdev);
-+}
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.h
-@@ -0,0 +1,83 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_VIDEO_H
-+#define STF_VIDEO_H
-+
-+#include <linux/mutex.h>
-+#include <media/videobuf2-v4l2.h>
-+#include <linux/videodev2.h>
-+#include <media/v4l2-dev.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-fh.h>
-+#include <media/v4l2-ioctl.h>
-+
-+#define STFCAMSS_FRAME_MIN_WIDTH 64
-+#define STFCAMSS_FRAME_MAX_WIDTH 1920
-+#define STFCAMSS_FRAME_MIN_HEIGHT 64
-+#define STFCAMSS_FRAME_MAX_HEIGHT 1080
-+#define STFCAMSS_FRAME_WIDTH_ALIGN_8 8
-+#define STFCAMSS_FRAME_WIDTH_ALIGN_128 128
-+#define STFCAMSS_MIN_BUFFERS 2
-+
-+#define STFCAMSS_MAX_ENTITY_NAME_LEN 27
-+
-+struct stfcamss_buffer {
-+ struct vb2_v4l2_buffer vb;
-+ dma_addr_t addr[3];
-+ void *vaddr_sc; /* Use for isp sc data */
-+ struct list_head queue;
-+ int sizeimage;
-+};
-+
-+struct stfcamss_video;
-+
-+struct stfcamss_video_ops {
-+ int (*queue_buffer)(struct stfcamss_video *vid,
-+ struct stfcamss_buffer *buf);
-+ int (*flush_buffers)(struct stfcamss_video *vid,
-+ enum vb2_buffer_state state);
-+};
-+
-+struct fract {
-+ u8 numerator;
-+ u8 denominator;
-+};
-+
-+struct stfcamss_format_info {
-+ u32 code;
-+ u32 pixelformat;
-+ u8 planes;
-+ struct fract hsub[3];
-+ struct fract vsub[3];
-+ u8 bpp[3];
-+};
-+
-+struct stfcamss_video {
-+ struct stfcamss *stfcamss;
-+ u8 id;
-+ struct vb2_queue vb2_q;
-+ struct video_device vdev;
-+ struct media_pad pad;
-+ struct media_pipeline pipe;
-+ struct v4l2_format active_fmt;
-+ enum v4l2_buf_type type;
-+ const struct stfcamss_video_ops *ops;
-+ struct mutex lock;
-+ struct mutex q_lock;
-+ unsigned int bpl_alignment;
-+ const struct stfcamss_format_info *formats;
-+ unsigned int nformats;
-+ unsigned int is_mp;
-+ unsigned int pm_count;
-+};
-+
-+int stf_video_register(struct stfcamss_video *video,
-+ struct v4l2_device *v4l2_dev, const char *name, int is_mp);
-+
-+void stf_video_unregister(struct stfcamss_video *video);
-+
-+#endif /* STF_VIDEO_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c
-@@ -0,0 +1,1515 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/pm_runtime.h>
-+#include <media/v4l2-event.h>
-+
-+#include "stfcamss.h"
-+
-+#define vin_line_array(ptr_line) \
-+ ((const struct vin_line (*)[]) &(ptr_line[-(ptr_line->id)]))
-+
-+#define line_to_vin2_dev(ptr_line) \
-+ container_of(vin_line_array(ptr_line), struct stf_vin2_dev, line)
-+
-+#define VIN_FRAME_DROP_MAX_VAL 90
-+#define VIN_FRAME_DROP_MIN_VAL 4
-+#define VIN_FRAME_PER_SEC_MAX_VAL 90
-+
-+/* ISP ctrl need 1 sec to let frames become stable. */
-+#define VIN_FRAME_DROP_SEC_FOR_ISP_CTRL 1
-+
-+
-+// #define VIN_TWO_BUFFER
-+
-+static const struct vin2_format vin2_formats_st7110[] = {
-+ { MEDIA_BUS_FMT_YUYV8_2X8, 16},
-+ { MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
-+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8},
-+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8},
-+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8},
-+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8},
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
-+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
-+ { MEDIA_BUS_FMT_Y12_1X12, 8},
-+ { MEDIA_BUS_FMT_YUV8_1X24, 8},
-+ { MEDIA_BUS_FMT_AYUV8_1X32, 32},
-+};
-+
-+static const struct vin2_format isp_formats_st7110_raw[] = {
-+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
-+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
-+};
-+
-+static const struct vin2_format isp_formats_st7110_uo[] = {
-+ { MEDIA_BUS_FMT_Y12_1X12, 8},
-+};
-+
-+static const struct vin2_format isp_formats_st7110_iti[] = {
-+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
-+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
-+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
-+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
-+ { MEDIA_BUS_FMT_Y12_1X12, 8},
-+ { MEDIA_BUS_FMT_YUV8_1X24, 8},
-+};
-+
-+static const struct vin2_format_table vin2_formats_table[] = {
-+ /* VIN_LINE_WR */
-+ { vin2_formats_st7110, ARRAY_SIZE(vin2_formats_st7110) },
-+ /* VIN_LINE_ISP */
-+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },
-+ /* VIN_LINE_ISP_SS0 */
-+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },
-+ /* VIN_LINE_ISP_SS1 */
-+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },
-+ /* VIN_LINE_ISP_ITIW */
-+ { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },
-+ /* VIN_LINE_ISP_ITIR */
-+ { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },
-+ /* VIN_LINE_ISP_RAW */
-+ { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },
-+ /* VIN_LINE_ISP_SCD_Y */
-+ { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },
-+};
-+
-+static void vin_buffer_done(struct vin_line *line, struct vin_params *params);
-+static void vin_change_buffer(struct vin_line *line);
-+static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output);
-+static void vin_output_init_addrs(struct vin_line *line);
-+static void vin_init_outputs(struct vin_line *line);
-+static struct v4l2_mbus_framefmt *
-+__vin_get_format(struct vin_line *line,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ enum v4l2_subdev_format_whence which);
-+
-+static char *get_line_subdevname(int line_id)
-+{
-+ char *name = NULL;
-+
-+ switch (line_id) {
-+ case VIN_LINE_WR:
-+ name = "wr";
-+ break;
-+ case VIN_LINE_ISP:
-+ name = "isp0";
-+ break;
-+ case VIN_LINE_ISP_SS0:
-+ name = "isp0_ss0";
-+ break;
-+ case VIN_LINE_ISP_SS1:
-+ name = "isp0_ss1";
-+ break;
-+ case VIN_LINE_ISP_ITIW:
-+ name = "isp0_itiw";
-+ break;
-+ case VIN_LINE_ISP_ITIR:
-+ name = "isp0_itir";
-+ break;
-+ case VIN_LINE_ISP_RAW:
-+ name = "isp0_raw";
-+ break;
-+ case VIN_LINE_ISP_SCD_Y:
-+ name = "isp0_scd_y";
-+ break;
-+ default:
-+ name = "unknow";
-+ break;
-+ }
-+ return name;
-+}
-+
-+static enum isp_line_id stf_vin_map_isp_line(enum vin_line_id line)
-+{
-+ enum isp_line_id line_id;
-+
-+ if ((line > VIN_LINE_WR) && (line < VIN_LINE_MAX)) {
-+ line_id = line % STF_ISP_LINE_MAX;
-+ if (line_id == 0)
-+ line_id = STF_ISP_LINE_SRC_SCD_Y;
-+ } else
-+ line_id = STF_ISP_LINE_INVALID;
-+
-+ return line_id;
-+}
-+
-+enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line, enum isp_pad_id def)
-+{
-+ enum isp_pad_id pad_id;
-+
-+ if (line == VIN_LINE_WR)
-+ pad_id = STF_ISP_PAD_SINK;
-+ else if ((line > VIN_LINE_WR) && (line < VIN_LINE_MAX))
-+ pad_id = stf_vin_map_isp_line(line);
-+ else
-+ pad_id = def;
-+
-+ return pad_id;
-+}
-+
-+int stf_vin_subdev_init(struct stfcamss *stfcamss)
-+{
-+ struct stf_vin_dev *vin;
-+ struct device *dev = stfcamss->dev;
-+ struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
-+ int i, ret = 0;
-+
-+ vin_dev->stfcamss = stfcamss;
-+ vin_dev->hw_ops = &vin_ops;
-+ vin_dev->hw_ops->isr_buffer_done = vin_buffer_done;
-+ vin_dev->hw_ops->isr_change_buffer = vin_change_buffer;
-+
-+ vin = stfcamss->vin;
-+ atomic_set(&vin_dev->ref_count, 0);
-+
-+ ret = devm_request_irq(dev,
-+ vin->irq, vin_dev->hw_ops->vin_wr_irq_handler,
-+ 0, "vin_axiwr_irq", vin_dev);
-+ if (ret) {
-+ st_err(ST_VIN, "failed to request irq\n");
-+ goto out;
-+ }
-+
-+ ret = devm_request_irq(dev,
-+ vin->isp_irq, vin_dev->hw_ops->vin_isp_irq_handler,
-+ 0, "vin_isp_irq", vin_dev);
-+ if (ret) {
-+ st_err(ST_VIN, "failed to request isp irq\n");
-+ goto out;
-+ }
-+
-+ st_info(ST_CAMSS, "%s, %d!\n", __func__, __LINE__);
-+#ifdef ISP_USE_CSI_AND_SC_DONE_INTERRUPT
-+ ret = devm_request_irq(dev,
-+ vin->isp_csi_irq, vin_dev->hw_ops->vin_isp_csi_irq_handler,
-+ 0, "vin_isp_csi_irq", vin_dev);
-+ if (ret) {
-+ st_err(ST_VIN, "failed to request isp raw irq\n");
-+ goto out;
-+ }
-+
-+ ret = devm_request_irq(dev,
-+ vin->isp_scd_irq, vin_dev->hw_ops->vin_isp_scd_irq_handler,
-+ 0, "vin_isp_scd_irq", vin_dev);
-+ if (ret) {
-+ st_err(ST_VIN, "failed to request isp scd irq\n");
-+ goto out;
-+ }
-+#endif
-+
-+ ret = devm_request_irq(dev,
-+ vin->isp_irq_csiline, vin_dev->hw_ops->vin_isp_irq_csiline_handler,
-+ 0, "vin_isp_irq_csiline", vin_dev);
-+ if (ret) {
-+ st_err(ST_VIN, "failed to request isp irq csiline\n");
-+ goto out;
-+ }
-+
-+ mutex_init(&vin_dev->power_lock);
-+ vin_dev->power_count = 0;
-+
-+ for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++) {
-+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[i];
-+
-+ mutex_init(&dummy_buffer->stream_lock);
-+ dummy_buffer->nums = i == 0 ? VIN_DUMMY_BUFFER_NUMS : ISP_DUMMY_BUFFER_NUMS;
-+ dummy_buffer->stream_count = 0;
-+ dummy_buffer->buffer = devm_kzalloc(dev,
-+ dummy_buffer->nums * sizeof(struct vin_dummy_buffer), GFP_KERNEL);
-+ atomic_set(&dummy_buffer->frame_skip, 0);
-+ }
-+
-+ for (i = VIN_LINE_WR;
-+ i < STF_ISP_LINE_MAX + 1; i++) {
-+ struct vin_line *l = &vin_dev->line[i];
-+ int is_mp;
-+
-+ is_mp = i == VIN_LINE_WR ? false : true;
-+ is_mp = false;
-+ if (stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC_ITIR)
-+ l->video_out.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-+ else
-+ l->video_out.type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
-+ V4L2_BUF_TYPE_VIDEO_CAPTURE;
-+ l->video_out.stfcamss = stfcamss;
-+ l->id = i;
-+ l->sdev_type = VIN_DEV_TYPE;
-+ l->formats = vin2_formats_table[i].fmts;
-+ l->nformats = vin2_formats_table[i].nfmts;
-+ spin_lock_init(&l->output_lock);
-+
-+ mutex_init(&l->stream_lock);
-+ l->stream_count = 0;
-+ mutex_init(&l->power_lock);
-+ l->power_count = 0;
-+ }
-+
-+ return 0;
-+out:
-+ return ret;
-+}
-+
-+static int vin_set_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct vin_line *line = v4l2_get_subdevdata(sd);
-+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
-+ struct stfcamss *stfcamss = vin_dev->stfcamss;
-+
-+ mutex_lock(&line->power_lock);
-+ if (on) {
-+ if (line->power_count == 0)
-+ vin_init_outputs(line);
-+ line->power_count++;
-+ } else {
-+ if (line->power_count == 0) {
-+ st_err(ST_VIN,
-+ "line power off on power_count == 0\n");
-+ goto exit_line;
-+ }
-+ line->power_count--;
-+ }
-+exit_line:
-+ mutex_unlock(&line->power_lock);
-+
-+ mutex_lock(&vin_dev->power_lock);
-+ if (on) {
-+ if (vin_dev->power_count == 0) {
-+ pm_runtime_get_sync(stfcamss->dev);
-+ vin_dev->hw_ops->vin_clk_enable(vin_dev);
-+ vin_dev->hw_ops->vin_config_set(vin_dev);
-+ }
-+ vin_dev->power_count++;
-+ } else {
-+ if (vin_dev->power_count == 0) {
-+ st_err(ST_VIN,
-+ "vin_dev power off on power_count == 0\n");
-+ goto exit;
-+ }
-+ if (vin_dev->power_count == 1) {
-+ vin_dev->hw_ops->vin_clk_disable(vin_dev);
-+ pm_runtime_put_sync(stfcamss->dev);
-+ }
-+ vin_dev->power_count--;
-+ }
-+exit:
-+
-+ mutex_unlock(&vin_dev->power_lock);
-+
-+ return 0;
-+}
-+
-+static unsigned int get_frame_skip(struct vin_line *line)
-+{
-+ unsigned int frame_skip = 0;
-+ unsigned int isp_ctrl_skip_frames = 0;
-+ struct media_entity *sensor;
-+ struct v4l2_subdev_frame_interval fi;
-+
-+ sensor = stfcamss_find_sensor(&line->subdev.entity);
-+ if (sensor) {
-+ int fps = 0;
-+ struct v4l2_subdev *subdev =
-+ media_entity_to_v4l2_subdev(sensor);
-+
-+ if (subdev->ops->video->g_frame_interval) {
-+ if (!subdev->ops->video->g_frame_interval(subdev, &fi))
-+ fps = fi.interval.denominator;
-+
-+ if (fps > 0 && fps <= 90)
-+ isp_ctrl_skip_frames = fps * VIN_FRAME_DROP_SEC_FOR_ISP_CTRL;
-+ }
-+ if (!fps)
-+ st_debug(ST_VIN, "%s, Failed to get sensor fps !\n", __func__);
-+
-+ if (isp_ctrl_skip_frames <= VIN_FRAME_DROP_MIN_VAL)
-+ isp_ctrl_skip_frames = VIN_FRAME_DROP_MIN_VAL;
-+
-+ v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
-+
-+ frame_skip += isp_ctrl_skip_frames;
-+
-+ if (frame_skip > VIN_FRAME_DROP_MAX_VAL)
-+ frame_skip = VIN_FRAME_DROP_MAX_VAL;
-+ st_debug(ST_VIN, "%s, frame_skip %d\n", __func__, frame_skip);
-+ }
-+
-+ return frame_skip;
-+}
-+
-+static void vin_buf_l2cache_flush(struct vin_output *output)
-+{
-+ struct stfcamss_buffer *buffer = NULL;
-+
-+ if (!list_empty(&output->pending_bufs)) {
-+ list_for_each_entry(buffer, &output->pending_bufs, queue) {
-+ sifive_l2_flush64_range(buffer->addr[0], buffer->sizeimage);
-+ }
-+ }
-+}
-+
-+static int vin_enable_output(struct vin_line *line)
-+{
-+ struct vin_output *output = &line->output;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&line->output_lock, flags);
-+
-+ output->state = VIN_OUTPUT_IDLE;
-+
-+ vin_buf_l2cache_flush(output);
-+
-+ output->buf[0] = vin_buf_get_pending(output);
-+#ifdef VIN_TWO_BUFFER
-+ if (line->id == VIN_LINE_WR)
-+ output->buf[1] = vin_buf_get_pending(output);
-+#endif
-+ if (!output->buf[0] && output->buf[1]) {
-+ output->buf[0] = output->buf[1];
-+ output->buf[1] = NULL;
-+ }
-+
-+ if (output->buf[0])
-+ output->state = VIN_OUTPUT_SINGLE;
-+
-+#ifdef VIN_TWO_BUFFER
-+ if (output->buf[1] && line->id == VIN_LINE_WR)
-+ output->state = VIN_OUTPUT_CONTINUOUS;
-+#endif
-+ output->sequence = 0;
-+
-+ vin_output_init_addrs(line);
-+ spin_unlock_irqrestore(&line->output_lock, flags);
-+ return 0;
-+}
-+
-+static int vin_disable_output(struct vin_line *line)
-+{
-+ struct vin_output *output = &line->output;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&line->output_lock, flags);
-+
-+ output->state = VIN_OUTPUT_OFF;
-+
-+ spin_unlock_irqrestore(&line->output_lock, flags);
-+ return 0;
-+}
-+
-+static u32 line_to_dummy_module(struct vin_line *line)
-+{
-+ u32 dummy_module = 0;
-+
-+ switch (line->id) {
-+ case VIN_LINE_WR:
-+ dummy_module = STF_DUMMY_VIN;
-+ break;
-+ case VIN_LINE_ISP:
-+ case VIN_LINE_ISP_SS0:
-+ case VIN_LINE_ISP_SS1:
-+ case VIN_LINE_ISP_ITIW:
-+ case VIN_LINE_ISP_ITIR:
-+ case VIN_LINE_ISP_RAW:
-+ case VIN_LINE_ISP_SCD_Y:
-+ dummy_module = STF_DUMMY_ISP;
-+ break;
-+ default:
-+ dummy_module = STF_DUMMY_VIN;
-+ break;
-+ }
-+
-+ return dummy_module;
-+}
-+
-+static int vin_alloc_dummy_buffer(struct stf_vin2_dev *vin_dev,
-+ struct v4l2_mbus_framefmt *fmt, int dummy_module)
-+{
-+ struct device *dev = vin_dev->stfcamss->dev;
-+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
-+ struct vin_dummy_buffer *buffer = NULL;
-+ int ret = 0, i;
-+ u32 aligns;
-+
-+ for (i = 0; i < dummy_buffer->nums; i++) {
-+ buffer = &vin_dev->dummy_buffer[dummy_module].buffer[i];
-+ buffer->width = fmt->width;
-+ buffer->height = fmt->height;
-+ buffer->mcode = fmt->code;
-+ if (i == STF_VIN_PAD_SINK) {
-+ aligns = ALIGN(fmt->width * 4, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height);
-+ } else if (i == STF_ISP_PAD_SRC
-+ || i == STF_ISP_PAD_SRC_SS0
-+ || i == STF_ISP_PAD_SRC_SS1) {
-+ aligns = ALIGN(fmt->width, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height * 3 / 2);
-+ } else if (i == STF_ISP_PAD_SRC_ITIW
-+ || i == STF_ISP_PAD_SRC_ITIR) {
-+ aligns = ALIGN(fmt->width, STFCAMSS_FRAME_WIDTH_ALIGN_8);
-+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height * 3);
-+ } else if (i == STF_ISP_PAD_SRC_RAW) {
-+ aligns = ALIGN(fmt->width * ISP_RAW_DATA_BITS / 8,
-+ STFCAMSS_FRAME_WIDTH_ALIGN_128);
-+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height);
-+ } else if (i == STF_ISP_PAD_SRC_SCD_Y)
-+ buffer->buffer_size = PAGE_ALIGN(ISP_SCD_Y_BUFFER_SIZE);
-+ else
-+ continue;
-+
-+ buffer->vaddr = dma_alloc_coherent(dev, buffer->buffer_size,
-+ &buffer->paddr[0], GFP_DMA | GFP_KERNEL);
-+
-+ if (buffer->vaddr) {
-+ if (i == STF_ISP_PAD_SRC
-+ || i == STF_ISP_PAD_SRC_SS0
-+ || i == STF_ISP_PAD_SRC_SS1
-+ || i == STF_ISP_PAD_SRC_ITIW
-+ || i == STF_ISP_PAD_SRC_ITIR)
-+ buffer->paddr[1] = (dma_addr_t)(buffer->paddr[0] +
-+ aligns * fmt->height);
-+ else if (i == STF_ISP_PAD_SRC_SCD_Y)
-+ buffer->paddr[1] = (dma_addr_t)(buffer->paddr[0] +
-+ ISP_YHIST_BUFFER_SIZE);
-+ else
-+ st_debug(ST_VIN, "signal plane\n");
-+ }
-+ {
-+ char szPadName[][32] = {
-+ "VIN_PAD_SINK",
-+ "ISP_PAD_SRC",
-+ "ISP_PAD_SRC_SS0",
-+ "ISP_PAD_SRC_SS1",
-+ "ISP_PAD_SRC_ITIW",
-+ "ISP_PAD_SRC_ITIR",
-+ "ISP_PAD_SRC_RAW",
-+ "ISP_PAD_SRC_SCD_Y",
-+ "Unknown Pad"
-+ };
-+
-+ st_debug(ST_VIN, "%s: i = %d(%s) addr[0] = %llx, addr[1] = %llx, size = %u bytes\n",
-+ __func__,
-+ i,
-+ szPadName[i],
-+ buffer->paddr[0],
-+ buffer->paddr[1],
-+ buffer->buffer_size
-+ );
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static void vin_free_dummy_buffer(struct stf_vin2_dev *vin_dev, int dummy_module)
-+{
-+ struct device *dev = vin_dev->stfcamss->dev;
-+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
-+ struct vin_dummy_buffer *buffer = NULL;
-+ int i;
-+
-+ for (i = 0; i < dummy_buffer->nums; i++) {
-+ buffer = &dummy_buffer->buffer[i];
-+ if (buffer->vaddr)
-+ dma_free_coherent(dev, buffer->buffer_size,
-+ buffer->vaddr, buffer->paddr[0]);
-+ memset(buffer, 0, sizeof(struct vin_dummy_buffer));
-+ }
-+}
-+
-+static void vin_set_dummy_buffer(struct vin_line *line, u32 pad)
-+{
-+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
-+ int dummy_module = line_to_dummy_module(line);
-+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
-+ struct vin_dummy_buffer *buffer = NULL;
-+
-+ switch (pad) {
-+ case STF_VIN_PAD_SINK:
-+ if (line->id == VIN_LINE_WR) {
-+ buffer = &dummy_buffer->buffer[STF_VIN_PAD_SINK];
-+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev, buffer->paddr[0]);
-+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, buffer->paddr[0]);
-+ } else {
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC];
-+ vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS0];
-+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS1];
-+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIW];
-+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIR];
-+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_RAW];
-+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, buffer->paddr[0]);
-+
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SCD_Y];
-+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1], AWB_TYPE);
-+ }
-+ break;
-+ case STF_ISP_PAD_SRC:
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC];
-+ vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+ break;
-+ case STF_ISP_PAD_SRC_SS0:
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS0];
-+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+ break;
-+ case STF_ISP_PAD_SRC_SS1:
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS1];
-+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+ break;
-+ case STF_ISP_PAD_SRC_ITIW:
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIW];
-+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+ break;
-+ case STF_ISP_PAD_SRC_ITIR:
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIR];
-+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1]);
-+ break;
-+ case STF_ISP_PAD_SRC_RAW:
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_RAW];
-+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, buffer->paddr[0]);
-+ break;
-+ case STF_ISP_PAD_SRC_SCD_Y:
-+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SCD_Y];
-+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
-+ buffer->paddr[0], buffer->paddr[1], AWB_TYPE);
-+ break;
-+ default:
-+ break;
-+ }
-+}
-+
-+static int vin_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct vin_line *line = v4l2_get_subdevdata(sd);
-+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
-+ int dummy_module = line_to_dummy_module(line);
-+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
-+ struct v4l2_mbus_framefmt *fmt;
-+
-+ st_debug(ST_VIN, "%s, %d\n", __func__, __LINE__);
-+ fmt = __vin_get_format(line, NULL, STF_VIN_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE);
-+ mutex_lock(&dummy_buffer->stream_lock);
-+ if (enable) {
-+ if (dummy_buffer->stream_count == 0) {
-+ vin_alloc_dummy_buffer(vin_dev, fmt, dummy_module);
-+ vin_set_dummy_buffer(line, STF_VIN_PAD_SINK);
-+ atomic_set(&dummy_buffer->frame_skip, get_frame_skip(line));
-+ }
-+ dummy_buffer->stream_count++;
-+ } else {
-+ if (dummy_buffer->stream_count == 1) {
-+ vin_free_dummy_buffer(vin_dev, dummy_module);
-+ // set buffer addr to zero
-+ vin_set_dummy_buffer(line, STF_VIN_PAD_SINK);
-+ } else
-+ vin_set_dummy_buffer(line,
-+ stf_vin_map_isp_pad(line->id, STF_ISP_PAD_SINK));
-+
-+ dummy_buffer->stream_count--;
-+ }
-+ mutex_unlock(&dummy_buffer->stream_lock);
-+
-+ mutex_lock(&line->stream_lock);
-+ if (enable) {
-+ if (line->stream_count == 0) {
-+ if (line->id == VIN_LINE_WR) {
-+ vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 1);
-+ vin_dev->hw_ops->vin_wr_stream_set(vin_dev, 1);
-+ }
-+ }
-+ line->stream_count++;
-+ } else {
-+ if (line->stream_count == 1) {
-+ if (line->id == VIN_LINE_WR) {
-+ vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 0);
-+ vin_dev->hw_ops->vin_wr_stream_set(vin_dev, 0);
-+ }
-+ }
-+ line->stream_count--;
-+ }
-+ mutex_unlock(&line->stream_lock);
-+
-+ if (enable)
-+ vin_enable_output(line);
-+ else
-+ vin_disable_output(line);
-+
-+ return 0;
-+}
-+
-+static struct v4l2_mbus_framefmt *
-+__vin_get_format(struct vin_line *line,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ if (which == V4L2_SUBDEV_FORMAT_TRY)
-+ return v4l2_subdev_get_try_format(&line->subdev, state, pad);
-+ return &line->fmt[pad];
-+}
-+
-+static void vin_try_format(struct vin_line *line,
-+ struct v4l2_subdev_state *state,
-+ unsigned int pad,
-+ struct v4l2_mbus_framefmt *fmt,
-+ enum v4l2_subdev_format_whence which)
-+{
-+ unsigned int i;
-+
-+ switch (pad) {
-+ case STF_VIN_PAD_SINK:
-+ /* Set format on sink pad */
-+
-+ for (i = 0; i < line->nformats; i++)
-+ if (fmt->code == line->formats[i].code)
-+ break;
-+
-+ /* If not found, use UYVY as default */
-+ if (i >= line->nformats)
-+ fmt->code = line->formats[0].code;
-+
-+ fmt->width = clamp_t(u32,
-+ fmt->width, STFCAMSS_FRAME_MIN_WIDTH, STFCAMSS_FRAME_MAX_WIDTH);
-+ fmt->height = clamp_t(u32,
-+ fmt->height, STFCAMSS_FRAME_MIN_HEIGHT, STFCAMSS_FRAME_MAX_HEIGHT);
-+
-+ fmt->field = V4L2_FIELD_NONE;
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+ fmt->flags = 0;
-+
-+ break;
-+
-+ case STF_VIN_PAD_SRC:
-+ /* Set and return a format same as sink pad */
-+ *fmt = *__vin_get_format(line, state, STF_VIN_PAD_SINK, which);
-+ break;
-+ }
-+
-+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
-+}
-+
-+static int vin_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ struct vin_line *line = v4l2_get_subdevdata(sd);
-+
-+ if (code->index >= line->nformats)
-+ return -EINVAL;
-+ if (code->pad == STF_VIN_PAD_SINK) {
-+ code->code = line->formats[code->index].code;
-+ } else {
-+ struct v4l2_mbus_framefmt *sink_fmt;
-+
-+ sink_fmt = __vin_get_format(line, state, STF_VIN_PAD_SINK,
-+ code->which);
-+
-+ code->code = sink_fmt->code;
-+ if (!code->code)
-+ return -EINVAL;
-+ }
-+ code->flags = 0;
-+
-+ return 0;
-+}
-+
-+static int vin_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ struct vin_line *line = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt format;
-+
-+ if (fse->index != 0)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = 1;
-+ format.height = 1;
-+ vin_try_format(line, state, fse->pad, &format, fse->which);
-+ fse->min_width = format.width;
-+ fse->min_height = format.height;
-+
-+ if (format.code != fse->code)
-+ return -EINVAL;
-+
-+ format.code = fse->code;
-+ format.width = -1;
-+ format.height = -1;
-+ vin_try_format(line, state, fse->pad, &format, fse->which);
-+ fse->max_width = format.width;
-+ fse->max_height = format.height;
-+
-+ return 0;
-+}
-+
-+static int vin_get_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct vin_line *line = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ format = __vin_get_format(line, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ fmt->format = *format;
-+
-+ return 0;
-+}
-+
-+static int vin_set_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct vin_line *line = v4l2_get_subdevdata(sd);
-+ struct v4l2_mbus_framefmt *format;
-+
-+ st_debug(ST_VIDEO, "%s, pad %d, fmt code %x\n",
-+ __func__, fmt->pad, fmt->format.code);
-+
-+ format = __vin_get_format(line, state, fmt->pad, fmt->which);
-+ if (format == NULL)
-+ return -EINVAL;
-+
-+ mutex_lock(&line->stream_lock);
-+ if (line->stream_count) {
-+ fmt->format = *format;
-+ mutex_unlock(&line->stream_lock);
-+ goto out;
-+ } else {
-+ vin_try_format(line, state, fmt->pad, &fmt->format, fmt->which);
-+ *format = fmt->format;
-+ }
-+ mutex_unlock(&line->stream_lock);
-+
-+ if (fmt->pad == STF_VIN_PAD_SINK) {
-+ /* Propagate the format from sink to source */
-+ format = __vin_get_format(line, state, STF_VIN_PAD_SRC,
-+ fmt->which);
-+
-+ *format = fmt->format;
-+ vin_try_format(line, state, STF_VIN_PAD_SRC, format,
-+ fmt->which);
-+ }
-+
-+out:
-+ return 0;
-+}
-+
-+static int vin_init_formats(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_fh *fh)
-+{
-+ struct v4l2_subdev_format format = {
-+ .pad = STF_VIN_PAD_SINK,
-+ .which = fh ? V4L2_SUBDEV_FORMAT_TRY :
-+ V4L2_SUBDEV_FORMAT_ACTIVE,
-+ .format = {
-+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
-+ .width = 1920,
-+ .height = 1080
-+ }
-+ };
-+
-+ return vin_set_format(sd, fh ? fh->state : NULL, &format);
-+}
-+
-+static void vin_output_init_addrs(struct vin_line *line)
-+{
-+ struct vin_output *output = &line->output;
-+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
-+ dma_addr_t ping_addr;
-+ dma_addr_t pong_addr;
-+ dma_addr_t y_addr, uv_addr;
-+
-+ output->active_buf = 0;
-+
-+ if (output->buf[0]) {
-+ ping_addr = output->buf[0]->addr[0];
-+ y_addr = output->buf[0]->addr[0];
-+ uv_addr = output->buf[0]->addr[1];
-+ } else
-+ return;
-+
-+ if (output->buf[1])
-+ pong_addr = output->buf[1]->addr[0];
-+ else
-+ pong_addr = ping_addr;
-+
-+ switch (stf_vin_map_isp_line(line->id)) {
-+ case STF_ISP_LINE_SRC:
-+ vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
-+ y_addr, uv_addr);
-+ break;
-+ case STF_ISP_LINE_SRC_SS0:
-+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
-+ y_addr, uv_addr);
-+ break;
-+ case STF_ISP_LINE_SRC_SS1:
-+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
-+ y_addr, uv_addr);
-+ break;
-+ case STF_ISP_LINE_SRC_ITIW:
-+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
-+ y_addr, uv_addr);
-+ break;
-+ case STF_ISP_LINE_SRC_ITIR:
-+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
-+ y_addr, uv_addr);
-+ break;
-+ case STF_ISP_LINE_SRC_RAW:
-+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, y_addr);
-+ break;
-+ case STF_ISP_LINE_SRC_SCD_Y:
-+ output->frame_skip = ISP_AWB_OECF_SKIP_FRAME;
-+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
-+ y_addr, uv_addr, AWB_TYPE);
-+ break;
-+ default:
-+ if (line->id == VIN_LINE_WR) {
-+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev, ping_addr);
-+#ifdef VIN_TWO_BUFFER
-+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, pong_addr);
-+#else
-+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, ping_addr);
-+#endif
-+ }
-+ break;
-+ }
-+}
-+
-+static void vin_init_outputs(struct vin_line *line)
-+{
-+ struct vin_output *output = &line->output;
-+
-+ output->state = VIN_OUTPUT_OFF;
-+ output->buf[0] = NULL;
-+ output->buf[1] = NULL;
-+ output->active_buf = 0;
-+ INIT_LIST_HEAD(&output->pending_bufs);
-+ INIT_LIST_HEAD(&output->ready_bufs);
-+}
-+
-+static void vin_buf_add_ready(struct vin_output *output,
-+ struct stfcamss_buffer *buffer)
-+{
-+ INIT_LIST_HEAD(&buffer->queue);
-+ list_add_tail(&buffer->queue, &output->ready_bufs);
-+}
-+
-+static struct stfcamss_buffer *vin_buf_get_ready(struct vin_output *output)
-+{
-+ struct stfcamss_buffer *buffer = NULL;
-+
-+ if (!list_empty(&output->ready_bufs)) {
-+ buffer = list_first_entry(&output->ready_bufs,
-+ struct stfcamss_buffer,
-+ queue);
-+ list_del(&buffer->queue);
-+ }
-+
-+ return buffer;
-+}
-+
-+static void vin_buf_add_pending(struct vin_output *output,
-+ struct stfcamss_buffer *buffer)
-+{
-+ INIT_LIST_HEAD(&buffer->queue);
-+ list_add_tail(&buffer->queue, &output->pending_bufs);
-+}
-+
-+static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output)
-+{
-+ struct stfcamss_buffer *buffer = NULL;
-+
-+ if (!list_empty(&output->pending_bufs)) {
-+ buffer = list_first_entry(&output->pending_bufs,
-+ struct stfcamss_buffer,
-+ queue);
-+ list_del(&buffer->queue);
-+ }
-+
-+ return buffer;
-+}
-+
-+#ifdef UNUSED_CODE
-+static void vin_output_checkpending(struct vin_line *line)
-+{
-+ struct vin_output *output = &line->output;
-+
-+ if (output->state == VIN_OUTPUT_STOPPING) {
-+ /* Release last buffer when hw is idle */
-+ if (output->last_buffer) {
-+ // vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
-+ // VB2_BUF_STATE_DONE);
-+ vin_buf_add_pending(output, output->last_buffer);
-+ output->last_buffer = NULL;
-+ }
-+ output->state = VIN_OUTPUT_IDLE;
-+
-+ /* Buffers received in stopping state are queued in */
-+ /* dma pending queue, start next capture here */
-+ output->buf[0] = vin_buf_get_pending(output);
-+#ifdef VIN_TWO_BUFFER
-+ if (line->id == VIN_LINE_WR)
-+ output->buf[1] = vin_buf_get_pending(output);
-+#endif
-+
-+ if (!output->buf[0] && output->buf[1]) {
-+ output->buf[0] = output->buf[1];
-+ output->buf[1] = NULL;
-+ }
-+
-+ if (output->buf[0])
-+ output->state = VIN_OUTPUT_SINGLE;
-+
-+#ifdef VIN_TWO_BUFFER
-+ if (output->buf[1] && line->id == VIN_LINE_WR)
-+ output->state = VIN_OUTPUT_CONTINUOUS;
-+#endif
-+ vin_output_init_addrs(line);
-+ }
-+}
-+#endif
-+
-+static void vin_buf_update_on_last(struct vin_line *line)
-+{
-+ struct vin_output *output = &line->output;
-+
-+ switch (output->state) {
-+ case VIN_OUTPUT_CONTINUOUS:
-+ output->state = VIN_OUTPUT_SINGLE;
-+ output->active_buf = !output->active_buf;
-+ break;
-+ case VIN_OUTPUT_SINGLE:
-+ output->state = VIN_OUTPUT_STOPPING;
-+ break;
-+ default:
-+ st_err_ratelimited(ST_VIN,
-+ "Last buff in wrong state! %d\n",
-+ output->state);
-+ break;
-+ }
-+}
-+
-+static void vin_buf_update_on_next(struct vin_line *line)
-+{
-+ struct vin_output *output = &line->output;
-+
-+ switch (output->state) {
-+ case VIN_OUTPUT_CONTINUOUS:
-+ output->active_buf = !output->active_buf;
-+ break;
-+ case VIN_OUTPUT_SINGLE:
-+ default:
-+#ifdef VIN_TWO_BUFFER
-+ if (line->id == VIN_LINE_WR)
-+ st_err_ratelimited(ST_VIN,
-+ "Next buf in wrong state! %d\n",
-+ output->state);
-+#endif
-+ break;
-+ }
-+}
-+
-+static void vin_buf_update_on_new(struct vin_line *line,
-+ struct vin_output *output,
-+ struct stfcamss_buffer *new_buf)
-+{
-+#ifdef VIN_TWO_BUFFER
-+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
-+ int inactive_idx;
-+#endif
-+
-+ switch (output->state) {
-+ case VIN_OUTPUT_SINGLE:
-+#ifdef VIN_TWO_BUFFER
-+ int inactive_idx = !output->active_buf;
-+
-+ if (!output->buf[inactive_idx] && line->id == VIN_LINE_WR) {
-+ output->buf[inactive_idx] = new_buf;
-+ if (inactive_idx)
-+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
-+ output->buf[1]->addr[0]);
-+ else
-+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev,
-+ output->buf[0]->addr[0]);
-+ output->state = VIN_OUTPUT_CONTINUOUS;
-+
-+ } else {
-+ vin_buf_add_pending(output, new_buf);
-+ if (line->id == VIN_LINE_WR)
-+ st_warn(ST_VIN, "Inactive buffer is busy\n");
-+ }
-+#else
-+ vin_buf_add_pending(output, new_buf);
-+#endif
-+ break;
-+ case VIN_OUTPUT_IDLE:
-+ st_warn(ST_VIN, "Output idle buffer set!\n");
-+ if (!output->buf[0]) {
-+ output->buf[0] = new_buf;
-+ vin_output_init_addrs(line);
-+ output->state = VIN_OUTPUT_SINGLE;
-+ } else {
-+ vin_buf_add_pending(output, new_buf);
-+ st_warn(ST_VIN, "Output idle with buffer set!\n");
-+ }
-+ break;
-+ case VIN_OUTPUT_STOPPING:
-+ if (output->last_buffer) {
-+ output->buf[output->active_buf] = output->last_buffer;
-+ output->last_buffer = NULL;
-+ } else
-+ st_err(ST_VIN, "stop state lost lastbuffer!\n");
-+ output->state = VIN_OUTPUT_SINGLE;
-+ // vin_output_checkpending(line);
-+ vin_buf_add_pending(output, new_buf);
-+ break;
-+ case VIN_OUTPUT_CONTINUOUS:
-+ default:
-+ vin_buf_add_pending(output, new_buf);
-+ break;
-+ }
-+}
-+
-+static void vin_buf_flush(struct vin_output *output,
-+ enum vb2_buffer_state state)
-+{
-+ struct stfcamss_buffer *buf;
-+ struct stfcamss_buffer *t;
-+
-+ list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) {
-+ vb2_buffer_done(&buf->vb.vb2_buf, state);
-+ list_del(&buf->queue);
-+ }
-+ list_for_each_entry_safe(buf, t, &output->ready_bufs, queue) {
-+ vb2_buffer_done(&buf->vb.vb2_buf, state);
-+ list_del(&buf->queue);
-+ }
-+}
-+
-+static void vin_buffer_done(struct vin_line *line, struct vin_params *params)
-+{
-+ struct stfcamss_buffer *ready_buf;
-+ struct vin_output *output = &line->output;
-+ unsigned long flags;
-+ u64 ts = ktime_get_ns();
-+ struct v4l2_event event = {
-+ .type = V4L2_EVENT_FRAME_SYNC,
-+ };
-+
-+ if (output->state == VIN_OUTPUT_OFF
-+ || output->state == VIN_OUTPUT_RESERVED)
-+ return;
-+
-+ spin_lock_irqsave(&line->output_lock, flags);
-+
-+ while ((ready_buf = vin_buf_get_ready(output))) {
-+ if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) {
-+ event.u.frame_sync.frame_sequence = output->sequence;
-+ v4l2_event_queue(line->subdev.devnode, &event);
-+ }
-+
-+ ready_buf->vb.vb2_buf.timestamp = ts;
-+ ready_buf->vb.sequence = output->sequence++;
-+
-+ /* The stf_isp_ctrl currently buffered with mmap,
-+ * which will not update cache by default.
-+ * Flush L2 cache to make sure data is updated.
-+ */
-+ if (ready_buf->vb.vb2_buf.memory == VB2_MEMORY_MMAP)
-+ sifive_l2_flush64_range(ready_buf->addr[0], ready_buf->sizeimage);
-+
-+ vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
-+ }
-+
-+ spin_unlock_irqrestore(&line->output_lock, flags);
-+}
-+
-+static void vin_change_buffer(struct vin_line *line)
-+{
-+ struct stfcamss_buffer *ready_buf;
-+ struct vin_output *output = &line->output;
-+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
-+ dma_addr_t *new_addr;
-+ unsigned long flags;
-+ u32 active_index;
-+ int scd_type;
-+
-+ if (output->state == VIN_OUTPUT_OFF
-+ || output->state == VIN_OUTPUT_STOPPING
-+ || output->state == VIN_OUTPUT_RESERVED
-+ || output->state == VIN_OUTPUT_IDLE)
-+ return;
-+
-+ spin_lock_irqsave(&line->output_lock, flags);
-+
-+ active_index = output->active_buf;
-+
-+ ready_buf = output->buf[active_index];
-+ if (!ready_buf) {
-+ st_err_ratelimited(ST_VIN,
-+ "Missing ready buf %d %d!\n",
-+ active_index, output->state);
-+ active_index = !active_index;
-+ ready_buf = output->buf[active_index];
-+ if (!ready_buf) {
-+ st_err_ratelimited(ST_VIN,
-+ "Missing ready buf 2 %d %d!\n",
-+ active_index, output->state);
-+ goto out_unlock;
-+ }
-+ }
-+
-+ /* Get next buffer */
-+ output->buf[active_index] = vin_buf_get_pending(output);
-+ if (!output->buf[active_index]) {
-+ /* No next buffer - set same address */
-+ new_addr = ready_buf->addr;
-+ vin_buf_update_on_last(line);
-+ } else {
-+ new_addr = output->buf[active_index]->addr;
-+ vin_buf_update_on_next(line);
-+ }
-+
-+ if (output->state == VIN_OUTPUT_STOPPING)
-+ output->last_buffer = ready_buf;
-+ else {
-+ switch (stf_vin_map_isp_line(line->id)) {
-+ case STF_ISP_LINE_SRC:
-+ vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
-+ new_addr[0], new_addr[1]);
-+ break;
-+ case STF_ISP_LINE_SRC_SS0:
-+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
-+ new_addr[0], new_addr[1]);
-+ break;
-+ case STF_ISP_LINE_SRC_SS1:
-+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
-+ new_addr[0], new_addr[1]);
-+ break;
-+ case STF_ISP_LINE_SRC_ITIW:
-+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
-+ new_addr[0], new_addr[1]);
-+ break;
-+ case STF_ISP_LINE_SRC_ITIR:
-+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
-+ new_addr[0], new_addr[1]);
-+ break;
-+ case STF_ISP_LINE_SRC_RAW:
-+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, new_addr[0]);
-+ break;
-+ case STF_ISP_LINE_SRC_SCD_Y:
-+ scd_type = vin_dev->hw_ops->vin_isp_get_scd_type(vin_dev);
-+ ready_buf->vb.flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME);
-+ if (scd_type == AWB_TYPE)
-+ ready_buf->vb.flags |= V4L2_BUF_FLAG_PFRAME;
-+ else
-+ ready_buf->vb.flags |= V4L2_BUF_FLAG_BFRAME;
-+ if (!output->frame_skip) {
-+ output->frame_skip = ISP_AWB_OECF_SKIP_FRAME;
-+ scd_type = scd_type == AWB_TYPE ? OECF_TYPE : AWB_TYPE;
-+ } else {
-+ output->frame_skip--;
-+ scd_type = scd_type == AWB_TYPE ? AWB_TYPE : OECF_TYPE;
-+ }
-+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
-+ new_addr[0], new_addr[1], scd_type);
-+ break;
-+ default:
-+ if (line->id == VIN_LINE_WR) {
-+#ifdef VIN_TWO_BUFFER
-+ if (active_index)
-+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
-+ new_addr[0]);
-+ else
-+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev,
-+ new_addr[0]);
-+#else
-+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev,
-+ new_addr[0]);
-+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
-+ new_addr[0]);
-+#endif
-+ }
-+ break;
-+ }
-+
-+ vin_buf_add_ready(output, ready_buf);
-+ }
-+
-+ spin_unlock_irqrestore(&line->output_lock, flags);
-+ return;
-+
-+out_unlock:
-+ spin_unlock_irqrestore(&line->output_lock, flags);
-+}
-+
-+static int vin_queue_buffer(struct stfcamss_video *vid,
-+ struct stfcamss_buffer *buf)
-+{
-+ struct vin_line *line = container_of(vid, struct vin_line, video_out);
-+ struct vin_output *output;
-+ unsigned long flags;
-+
-+
-+ output = &line->output;
-+
-+ spin_lock_irqsave(&line->output_lock, flags);
-+
-+ vin_buf_update_on_new(line, output, buf);
-+
-+ spin_unlock_irqrestore(&line->output_lock, flags);
-+
-+ return 0;
-+}
-+
-+static int vin_flush_buffers(struct stfcamss_video *vid,
-+ enum vb2_buffer_state state)
-+{
-+ struct vin_line *line = container_of(vid, struct vin_line, video_out);
-+ struct vin_output *output = &line->output;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&line->output_lock, flags);
-+
-+ vin_buf_flush(output, state);
-+ if (output->buf[0])
-+ vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state);
-+
-+ if (output->buf[1])
-+ vb2_buffer_done(&output->buf[1]->vb.vb2_buf, state);
-+
-+ if (output->last_buffer) {
-+ vb2_buffer_done(&output->last_buffer->vb.vb2_buf, state);
-+ output->last_buffer = NULL;
-+ }
-+ output->buf[0] = output->buf[1] = NULL;
-+
-+ spin_unlock_irqrestore(&line->output_lock, flags);
-+ return 0;
-+}
-+
-+static int vin_link_setup(struct media_entity *entity,
-+ const struct media_pad *local,
-+ const struct media_pad *remote, u32 flags)
-+{
-+ if (flags & MEDIA_LNK_FL_ENABLED)
-+ if (media_pad_remote_pad_first(local))
-+ return -EBUSY;
-+ return 0;
-+}
-+
-+static int stf_vin_subscribe_event(struct v4l2_subdev *sd,
-+ struct v4l2_fh *fh,
-+ struct v4l2_event_subscription *sub)
-+{
-+ switch (sub->type) {
-+ case V4L2_EVENT_FRAME_SYNC:
-+ return v4l2_event_subscribe(fh, sub, 0, NULL);
-+ default:
-+ st_debug(ST_VIN, "unsupport subscribe_event\n");
-+ return -EINVAL;
-+ }
-+}
-+
-+static const struct v4l2_subdev_core_ops vin_core_ops = {
-+ .s_power = vin_set_power,
-+ .subscribe_event = stf_vin_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops vin_video_ops = {
-+ .s_stream = vin_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops vin_pad_ops = {
-+ .enum_mbus_code = vin_enum_mbus_code,
-+ .enum_frame_size = vin_enum_frame_size,
-+ .get_fmt = vin_get_format,
-+ .set_fmt = vin_set_format,
-+};
-+
-+static const struct v4l2_subdev_ops vin_v4l2_ops = {
-+ .core = &vin_core_ops,
-+ .video = &vin_video_ops,
-+ .pad = &vin_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops vin_v4l2_internal_ops = {
-+ .open = vin_init_formats,
-+};
-+
-+static const struct stfcamss_video_ops stfcamss_vin_video_ops = {
-+ .queue_buffer = vin_queue_buffer,
-+ .flush_buffers = vin_flush_buffers,
-+};
-+
-+static const struct media_entity_operations vin_media_ops = {
-+ .link_setup = vin_link_setup,
-+ .link_validate = v4l2_subdev_link_validate,
-+};
-+
-+int stf_vin_register(struct stf_vin2_dev *vin_dev, struct v4l2_device *v4l2_dev)
-+{
-+ struct v4l2_subdev *sd;
-+ struct stfcamss_video *video_out;
-+ struct media_pad *pads;
-+ int ret;
-+ int i;
-+
-+ for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) {
-+ char name[32];
-+ char *sub_name = get_line_subdevname(i);
-+ int is_mp;
-+
-+#ifdef STF_CAMSS_SKIP_ITI
-+ if ((stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC_ITIW) ||
-+ (stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC_ITIR))
-+ continue;
-+#endif
-+ is_mp = (stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC) ? true : false;
-+ is_mp = false;
-+ sd = &vin_dev->line[i].subdev;
-+ pads = vin_dev->line[i].pads;
-+ video_out = &vin_dev->line[i].video_out;
-+ video_out->id = i;
-+
-+ v4l2_subdev_init(sd, &vin_v4l2_ops);
-+ sd->internal_ops = &vin_v4l2_internal_ops;
-+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
-+ snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s",
-+ STF_VIN_NAME, 0, sub_name);
-+ v4l2_set_subdevdata(sd, &vin_dev->line[i]);
-+
-+ ret = vin_init_formats(sd, NULL);
-+ if (ret < 0) {
-+ st_err(ST_VIN, "Failed to init format: %d\n", ret);
-+ goto err_init;
-+ }
-+
-+ pads[STF_VIN_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
-+ pads[STF_VIN_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
-+
-+ sd->entity.function =
-+ MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
-+ sd->entity.ops = &vin_media_ops;
-+ ret = media_entity_pads_init(&sd->entity,
-+ STF_VIN_PADS_NUM, pads);
-+ if (ret < 0) {
-+ st_err(ST_VIN, "Failed to init media entity: %d\n", ret);
-+ goto err_init;
-+ }
-+
-+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
-+ if (ret < 0) {
-+ st_err(ST_VIN, "Failed to register subdev: %d\n", ret);
-+ goto err_reg_subdev;
-+ }
-+
-+ video_out->ops = &stfcamss_vin_video_ops;
-+ video_out->bpl_alignment = 16 * 8;
-+
-+ snprintf(name, ARRAY_SIZE(name), "%s_%s%d",
-+ sd->name, "video", i);
-+ ret = stf_video_register(video_out, v4l2_dev, name, is_mp);
-+ if (ret < 0) {
-+ st_err(ST_VIN, "Failed to register video node: %d\n",
-+ ret);
-+ goto err_vid_reg;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &sd->entity, STF_VIN_PAD_SRC,
-+ &video_out->vdev.entity, 0,
-+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
-+ if (ret < 0) {
-+ st_err(ST_VIN, "Failed to link %s->%s entities: %d\n",
-+ sd->entity.name, video_out->vdev.entity.name,
-+ ret);
-+ goto err_create_link;
-+ }
-+ }
-+
-+ return 0;
-+
-+err_create_link:
-+ stf_video_unregister(video_out);
-+err_vid_reg:
-+ v4l2_device_unregister_subdev(sd);
-+err_reg_subdev:
-+ media_entity_cleanup(&sd->entity);
-+err_init:
-+ for (i--; i >= 0; i--) {
-+ sd = &vin_dev->line[i].subdev;
-+ video_out = &vin_dev->line[i].video_out;
-+
-+ stf_video_unregister(video_out);
-+ v4l2_device_unregister_subdev(sd);
-+ media_entity_cleanup(&sd->entity);
-+ }
-+ return ret;
-+}
-+
-+int stf_vin_unregister(struct stf_vin2_dev *vin_dev)
-+{
-+ struct v4l2_subdev *sd;
-+ struct stfcamss_video *video_out;
-+ int i;
-+
-+ mutex_destroy(&vin_dev->power_lock);
-+ for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++)
-+ mutex_destroy(&vin_dev->dummy_buffer[i].stream_lock);
-+
-+ for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) {
-+ sd = &vin_dev->line[i].subdev;
-+ video_out = &vin_dev->line[i].video_out;
-+
-+ stf_video_unregister(video_out);
-+ v4l2_device_unregister_subdev(sd);
-+ media_entity_cleanup(&sd->entity);
-+ mutex_destroy(&vin_dev->line[i].stream_lock);
-+ mutex_destroy(&vin_dev->line[i].power_lock);
-+ }
-+ return 0;
-+}
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.h
-@@ -0,0 +1,182 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STF_VIN_H
-+#define STF_VIN_H
-+
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-subdev.h>
-+#include <linux/spinlock_types.h>
-+#include <video/stf-vin.h>
-+#include <linux/platform_device.h>
-+
-+#include "stf_video.h"
-+
-+#define STF_VIN_NAME "stf_vin"
-+
-+#define STF_VIN_PAD_SINK 0
-+#define STF_VIN_PAD_SRC 1
-+#define STF_VIN_PADS_NUM 2
-+
-+struct vin2_format {
-+ u32 code;
-+ u8 bpp;
-+};
-+
-+struct vin2_format_table {
-+ const struct vin2_format *fmts;
-+ int nfmts;
-+};
-+
-+enum vin_output_state {
-+ VIN_OUTPUT_OFF,
-+ VIN_OUTPUT_RESERVED,
-+ VIN_OUTPUT_SINGLE,
-+ VIN_OUTPUT_CONTINUOUS,
-+ VIN_OUTPUT_IDLE,
-+ VIN_OUTPUT_STOPPING
-+};
-+
-+struct vin_output {
-+ int active_buf;
-+ struct stfcamss_buffer *buf[2];
-+ struct stfcamss_buffer *last_buffer;
-+ struct list_head pending_bufs;
-+ struct list_head ready_bufs;
-+ enum vin_output_state state;
-+ unsigned int sequence;
-+ unsigned int frame_skip;
-+};
-+
-+/* The vin output lines include all isp controller lines,
-+ * and one vin_wr output line.
-+ */
-+enum vin_line_id {
-+ VIN_LINE_NONE = -1,
-+ VIN_LINE_WR = 0,
-+ VIN_LINE_ISP = 1,
-+ VIN_LINE_ISP_SS0 = 2,
-+ VIN_LINE_ISP_SS1 = 3,
-+ VIN_LINE_ISP_ITIW = 4,
-+ VIN_LINE_ISP_ITIR = 5,
-+ VIN_LINE_ISP_RAW = 6,
-+ VIN_LINE_ISP_SCD_Y = 7,
-+ VIN_LINE_MAX = 8,
-+};
-+
-+enum subdev_type;
-+
-+struct vin_line {
-+ enum subdev_type sdev_type; // must be frist
-+ enum vin_line_id id;
-+ struct v4l2_subdev subdev;
-+ struct media_pad pads[STF_VIN_PADS_NUM];
-+ struct v4l2_mbus_framefmt fmt[STF_VIN_PADS_NUM];
-+ struct stfcamss_video video_out;
-+ struct mutex stream_lock;
-+ int stream_count;
-+ struct mutex power_lock;
-+ int power_count;
-+ struct vin_output output;
-+ spinlock_t output_lock;
-+ const struct vin2_format *formats;
-+ unsigned int nformats;
-+#ifdef CONFIG_PM_SLEEP
-+ int pm_stream_count;
-+ int pm_power_count;
-+#endif
-+};
-+
-+struct stf_vin2_dev;
-+
-+struct vin_hw_ops {
-+ int (*vin_clk_enable)(struct stf_vin2_dev *vin_dev);
-+ int (*vin_clk_disable)(struct stf_vin2_dev *vin_dev);
-+ int (*vin_config_set)(struct stf_vin2_dev *vin_dev);
-+ int (*vin_wr_stream_set)(struct stf_vin2_dev *vin_dev, int on);
-+ void (*vin_wr_irq_enable)(struct stf_vin2_dev *vin_dev, int enable);
-+ void (*vin_power_on)(struct stf_vin2_dev *vin_dev, int on);
-+ void (*wr_rd_set_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t wr_addr, dma_addr_t rd_addr);
-+ void (*vin_wr_set_ping_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t addr);
-+ void (*vin_wr_set_pong_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t addr);
-+ void (*vin_wr_get_ping_pong_status)(struct stf_vin2_dev *vin_dev);
-+ void (*vin_isp_set_yuv_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr);
-+ void (*vin_isp_set_raw_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t raw_addr);
-+ void (*vin_isp_set_ss0_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr);
-+ void (*vin_isp_set_ss1_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr);
-+ void (*vin_isp_set_itiw_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr);
-+ void (*vin_isp_set_itir_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr);
-+ void (*vin_isp_set_scd_addr)(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t yhist_addr,
-+ dma_addr_t scd_addr, int scd_type);
-+ int (*vin_isp_get_scd_type)(struct stf_vin2_dev *vin_dev);
-+ irqreturn_t (*vin_wr_irq_handler)(int irq, void *priv);
-+ irqreturn_t (*vin_isp_irq_handler)(int irq, void *priv);
-+ irqreturn_t (*vin_isp_csi_irq_handler)(int irq, void *priv);
-+ irqreturn_t (*vin_isp_scd_irq_handler)(int irq, void *priv);
-+ irqreturn_t (*vin_isp_irq_csiline_handler)(int irq, void *priv);
-+ void (*isr_buffer_done)(struct vin_line *line,
-+ struct vin_params *params);
-+ void (*isr_change_buffer)(struct vin_line *line);
-+};
-+
-+#define ISP_DUMMY_BUFFER_NUMS STF_ISP_PAD_MAX
-+#define VIN_DUMMY_BUFFER_NUMS 1
-+
-+enum {
-+ STF_DUMMY_VIN,
-+ STF_DUMMY_ISP,
-+ STF_DUMMY_MODULE_NUMS,
-+};
-+
-+struct vin_dummy_buffer {
-+ dma_addr_t paddr[3];
-+ void *vaddr;
-+ u32 buffer_size;
-+ u32 width;
-+ u32 height;
-+ u32 mcode;
-+};
-+
-+struct dummy_buffer {
-+ struct vin_dummy_buffer *buffer;
-+ u32 nums;
-+ struct mutex stream_lock;
-+ int stream_count;
-+ atomic_t frame_skip;
-+};
-+
-+struct stf_vin2_dev {
-+ struct stfcamss *stfcamss;
-+ struct vin_line line[VIN_LINE_MAX];
-+ struct dummy_buffer dummy_buffer[STF_DUMMY_MODULE_NUMS];
-+ struct vin_hw_ops *hw_ops;
-+ atomic_t ref_count;
-+ struct mutex power_lock;
-+ int power_count;
-+};
-+
-+extern void sifive_l2_flush64_range(unsigned long start, unsigned long len);
-+extern int stf_vin_subdev_init(struct stfcamss *stfcamss);
-+extern int stf_vin_register(struct stf_vin2_dev *vin_dev,
-+ struct v4l2_device *v4l2_dev);
-+extern int stf_vin_unregister(struct stf_vin2_dev *vin_dev);
-+
-+extern struct vin_hw_ops vin_ops;
-+extern void dump_vin_reg(void *__iomem regbase);
-+extern enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line,
-+ enum isp_pad_id def);
-+
-+#endif /* STF_VIN_H */
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c
-@@ -0,0 +1,433 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include "stfcamss.h"
-+#include <linux/of_graph.h>
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-subdev.h>
-+
-+static void vin_intr_clear(void __iomem *sysctrl_base)
-+{
-+ reg_set_bit(sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_INTR_CLEAN,
-+ 0x1);
-+ reg_set_bit(sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_INTR_CLEAN,
-+ 0x0);
-+}
-+
-+static irqreturn_t stf_vin_wr_irq_handler(int irq, void *priv)
-+{
-+ static struct vin_params params;
-+ struct stf_vin2_dev *vin_dev = priv;
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ struct dummy_buffer *dummy_buffer =
-+ &vin_dev->dummy_buffer[STF_DUMMY_VIN];
-+
-+ if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) {
-+ vin_dev->hw_ops->isr_change_buffer(&vin_dev->line[VIN_LINE_WR]);
-+ vin_dev->hw_ops->isr_buffer_done(&vin_dev->line[VIN_LINE_WR], ¶ms);
-+ }
-+
-+ vin_intr_clear(vin->sysctrl_base);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void __iomem *stf_vin_get_ispbase(struct stf_vin_dev *vin)
-+{
-+ void __iomem *base = vin->isp_base;
-+
-+ return base;
-+}
-+
-+static irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
-+{
-+ static struct vin_params params;
-+ struct stf_vin2_dev *vin_dev = priv;
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+ u32 int_status, value;
-+
-+ ispbase = stf_vin_get_ispbase(vin);
-+
-+ int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
-+
-+ if (int_status & BIT(24)) {
-+ if ((int_status & BIT(11)))
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_SS0], ¶ms);
-+
-+ if ((int_status & BIT(12)))
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_SS1], ¶ms);
-+
-+ if ((int_status & BIT(20)))
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP], ¶ms);
-+
-+ value = reg_read(ispbase, ISP_REG_ITIDPSR);
-+ if ((value & BIT(17)))
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_ITIW], ¶ms);
-+ if ((value & BIT(16)))
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_ITIR], ¶ms);
-+
-+#ifndef ISP_USE_CSI_AND_SC_DONE_INTERRUPT
-+ if (int_status & BIT(25))
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_RAW], ¶ms);
-+
-+ if (int_status & BIT(26))
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_SCD_Y], ¶ms);
-+
-+ /* clear interrupt */
-+ reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL)
-+ | EN_INT_ISP_DONE | EN_INT_CSI_DONE | EN_INT_SC_DONE);
-+#else
-+ /* clear interrupt */
-+ reg_write(ispbase, ISP_REG_ISP_CTRL_0,
-+ (int_status & ~EN_INT_ALL) | EN_INT_ISP_DONE);
-+#endif
-+ } else
-+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t stf_vin_isp_csi_irq_handler(int irq, void *priv)
-+{
-+ static struct vin_params params;
-+ struct stf_vin2_dev *vin_dev = priv;
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+ u32 int_status;
-+
-+ ispbase = stf_vin_get_ispbase(vin);
-+
-+ int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
-+
-+ if (int_status & BIT(25)) {
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_RAW], ¶ms);
-+
-+ /* clear interrupt */
-+ reg_write(ispbase, ISP_REG_ISP_CTRL_0,
-+ (int_status & ~EN_INT_ALL) | EN_INT_CSI_DONE);
-+ } else
-+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t stf_vin_isp_scd_irq_handler(int irq, void *priv)
-+{
-+ static struct vin_params params;
-+ struct stf_vin2_dev *vin_dev = priv;
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase;
-+ u32 int_status;
-+
-+ ispbase = stf_vin_get_ispbase(vin);
-+
-+ int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
-+
-+ if (int_status & BIT(26)) {
-+ vin_dev->hw_ops->isr_buffer_done(
-+ &vin_dev->line[VIN_LINE_ISP_SCD_Y], ¶ms);
-+
-+ /* clear interrupt */
-+ reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL) | EN_INT_SC_DONE);
-+ } else
-+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv)
-+{
-+ struct stf_vin2_dev *vin_dev = priv;
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ struct stf_isp_dev *isp_dev;
-+ void __iomem *ispbase;
-+ u32 int_status, value;
-+
-+ ispbase = stf_vin_get_ispbase(vin);
-+
-+ isp_dev = vin_dev->stfcamss->isp_dev;
-+
-+ int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
-+ if (int_status & BIT(27)) {
-+ struct dummy_buffer *dummy_buffer =
-+ &vin_dev->dummy_buffer[STF_DUMMY_ISP];
-+
-+ if (!atomic_read(&isp_dev->shadow_count)) {
-+ if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) {
-+ if ((int_status & BIT(11)))
-+ vin_dev->hw_ops->isr_change_buffer(
-+ &vin_dev->line[VIN_LINE_ISP_SS0]);
-+ if ((int_status & BIT(12)))
-+ vin_dev->hw_ops->isr_change_buffer(
-+ &vin_dev->line[VIN_LINE_ISP_SS1]);
-+ if ((int_status & BIT(20)))
-+ vin_dev->hw_ops->isr_change_buffer(
-+ &vin_dev->line[VIN_LINE_ISP]);
-+
-+ value = reg_read(ispbase, ISP_REG_ITIDPSR);
-+ if ((value & BIT(17)))
-+ vin_dev->hw_ops->isr_change_buffer(
-+ &vin_dev->line[VIN_LINE_ISP_ITIW]);
-+ if ((value & BIT(16)))
-+ vin_dev->hw_ops->isr_change_buffer(
-+ &vin_dev->line[VIN_LINE_ISP_ITIR]);
-+
-+ value = reg_read(ispbase, ISP_REG_CSI_MODULE_CFG);
-+ if ((value & BIT(19)))
-+ vin_dev->hw_ops->isr_change_buffer(
-+ &vin_dev->line[VIN_LINE_ISP_RAW]);
-+ if ((value & BIT(17)))
-+ vin_dev->hw_ops->isr_change_buffer(
-+ &vin_dev->line[VIN_LINE_ISP_SCD_Y]);
-+ }
-+
-+ // shadow update
-+ reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x30000, 0x30000);
-+ reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3);
-+ } else {
-+ st_warn(ST_VIN, "isp shadow_lock locked. skip this frame\n");
-+ }
-+
-+ /* clear interrupt */
-+ reg_write(ispbase, ISP_REG_ISP_CTRL_0,
-+ (int_status & ~EN_INT_ALL) | EN_INT_LINE_INT);
-+ } else
-+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int stf_vin_clk_enable(struct stf_vin2_dev *vin_dev)
-+{
-+ struct stfcamss *stfcamss = vin_dev->stfcamss;
-+
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_PCLK].clk);
-+ clk_set_rate(stfcamss->sys_clk[STFCLK_APB_FUNC].clk, 49500000);
-+ clk_set_rate(stfcamss->sys_clk[STFCLK_SYS_CLK].clk, 297000000);
-+
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_PCLK].rstc);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_SYS_CLK].rstc);
-+
-+ return 0;
-+}
-+
-+
-+static int stf_vin_clk_disable(struct stf_vin2_dev *vin_dev)
-+{
-+ struct stfcamss *stfcamss = vin_dev->stfcamss;
-+
-+ reset_control_assert(stfcamss->sys_rst[STFRST_PCLK].rstc);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_SYS_CLK].rstc);
-+
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_PCLK].clk);
-+
-+ return 0;
-+}
-+
-+static int stf_vin_config_set(struct stf_vin2_dev *vin_dev)
-+{
-+ return 0;
-+}
-+
-+static int stf_vin_wr_stream_set(struct stf_vin2_dev *vin_dev, int on)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+
-+ //make the axiwr alway on
-+ if (on)
-+ reg_set(vin->sysctrl_base, SYSCONSAIF_SYSCFG_20, U0_VIN_CNFG_AXIWR0_EN);
-+
-+ return 0;
-+}
-+
-+static void stf_vin_wr_irq_enable(struct stf_vin2_dev *vin_dev,
-+ int enable)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ unsigned int value = 0;
-+
-+ if (enable) {
-+ value = ~(0x1 << 1);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_MASK,
-+ value);
-+ } else {
-+ /* clear vin interrupt */
-+ value = 0x1 << 1;
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_INTR_CLEAN,
-+ 0x1);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_INTR_CLEAN,
-+ 0x0);
-+ reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_28,
-+ U0_VIN_CNFG_AXIWR0_MASK,
-+ value);
-+ }
-+}
-+
-+static void stf_vin_wr_rd_set_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t wr_addr, dma_addr_t rd_addr)
-+{
-+#ifdef UNUSED_CODE
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+
-+ /* set the start address*/
-+ reg_write(vin->sysctrl_base,
-+ SYSCTRL_VIN_WR_START_ADDR, (long)wr_addr);
-+ reg_write(vin->sysctrl_base,
-+ SYSCTRL_VIN_RD_END_ADDR, (long)rd_addr);
-+#endif
-+}
-+
-+void stf_vin_wr_set_ping_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t addr)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+
-+ /* set the start address */
-+ reg_write(vin->sysctrl_base, SYSCONSAIF_SYSCFG_24, (long)addr);
-+}
-+
-+void stf_vin_wr_set_pong_addr(struct stf_vin2_dev *vin_dev, dma_addr_t addr)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+
-+ /* set the start address */
-+ reg_write(vin->sysctrl_base, SYSCONSAIF_SYSCFG_32, (long)addr);
-+}
-+
-+void stf_vin_isp_set_yuv_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr)
-+{
-+
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ reg_write(ispbase, ISP_REG_Y_PLANE_START_ADDR, y_addr);
-+ reg_write(ispbase, ISP_REG_UV_PLANE_START_ADDR, uv_addr);
-+ // reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 1);
-+}
-+
-+void stf_vin_isp_set_raw_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t raw_addr)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ reg_write(ispbase, ISP_REG_DUMP_CFG_0, raw_addr);
-+}
-+
-+void stf_vin_isp_set_ss0_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ reg_write(ispbase, ISP_REG_SS0AY, y_addr);
-+ reg_write(ispbase, ISP_REG_SS0AUV, uv_addr);
-+}
-+
-+void stf_vin_isp_set_ss1_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ reg_write(ispbase, ISP_REG_SS1AY, y_addr);
-+ reg_write(ispbase, ISP_REG_SS1AUV, uv_addr);
-+}
-+
-+void stf_vin_isp_set_itiw_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ reg_write(ispbase, ISP_REG_ITIDWYSAR, y_addr);
-+ reg_write(ispbase, ISP_REG_ITIDWUSAR, uv_addr);
-+}
-+
-+void stf_vin_isp_set_itir_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t y_addr, dma_addr_t uv_addr)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ reg_write(ispbase, ISP_REG_ITIDRYSAR, y_addr);
-+ reg_write(ispbase, ISP_REG_ITIDRUSAR, uv_addr);
-+}
-+
-+int stf_vin_isp_get_scd_type(struct stf_vin2_dev *vin_dev)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ return (reg_read(ispbase, ISP_REG_SC_CFG_1) & (0x3 << 30)) >> 30;
-+}
-+
-+void stf_vin_isp_set_scd_addr(struct stf_vin2_dev *vin_dev,
-+ dma_addr_t yhist_addr, dma_addr_t scd_addr, int scd_type)
-+{
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
-+
-+ reg_set_bit(ispbase, ISP_REG_SC_CFG_1, 0x3 << 30, scd_type << 30);
-+ reg_write(ispbase, ISP_REG_SCD_CFG_0, scd_addr);
-+ reg_write(ispbase, ISP_REG_YHIST_CFG_4, yhist_addr);
-+}
-+
-+void dump_vin_reg(void *__iomem regbase)
-+{
-+ st_debug(ST_VIN, "DUMP VIN register:\n");
-+ print_reg(ST_VIN, regbase, 0x00);
-+ print_reg(ST_VIN, regbase, 0x04);
-+ print_reg(ST_VIN, regbase, 0x08);
-+ print_reg(ST_VIN, regbase, 0x0c);
-+ print_reg(ST_VIN, regbase, 0x10);
-+ print_reg(ST_VIN, regbase, 0x14);
-+ print_reg(ST_VIN, regbase, 0x18);
-+ print_reg(ST_VIN, regbase, 0x1c);
-+ print_reg(ST_VIN, regbase, 0x20);
-+ print_reg(ST_VIN, regbase, 0x24);
-+ print_reg(ST_VIN, regbase, 0x28);
-+}
-+
-+struct vin_hw_ops vin_ops = {
-+ .vin_clk_enable = stf_vin_clk_enable,
-+ .vin_clk_disable = stf_vin_clk_disable,
-+ .vin_config_set = stf_vin_config_set,
-+ .vin_wr_stream_set = stf_vin_wr_stream_set,
-+ .vin_wr_irq_enable = stf_vin_wr_irq_enable,
-+ .wr_rd_set_addr = stf_vin_wr_rd_set_addr,
-+ .vin_wr_set_ping_addr = stf_vin_wr_set_ping_addr,
-+ .vin_wr_set_pong_addr = stf_vin_wr_set_pong_addr,
-+ .vin_isp_set_yuv_addr = stf_vin_isp_set_yuv_addr,
-+ .vin_isp_set_raw_addr = stf_vin_isp_set_raw_addr,
-+ .vin_isp_set_ss0_addr = stf_vin_isp_set_ss0_addr,
-+ .vin_isp_set_ss1_addr = stf_vin_isp_set_ss1_addr,
-+ .vin_isp_set_itiw_addr = stf_vin_isp_set_itiw_addr,
-+ .vin_isp_set_itir_addr = stf_vin_isp_set_itir_addr,
-+ .vin_isp_set_scd_addr = stf_vin_isp_set_scd_addr,
-+ .vin_isp_get_scd_type = stf_vin_isp_get_scd_type,
-+ .vin_wr_irq_handler = stf_vin_wr_irq_handler,
-+ .vin_isp_irq_handler = stf_vin_isp_irq_handler,
-+ .vin_isp_csi_irq_handler = stf_vin_isp_csi_irq_handler,
-+ .vin_isp_scd_irq_handler = stf_vin_isp_scd_irq_handler,
-+ .vin_isp_irq_csiline_handler = stf_vin_isp_irq_csiline_handler,
-+};
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stfcamss.c
-@@ -0,0 +1,1369 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#include <linux/completion.h>
-+#include <linux/delay.h>
-+#include <linux/dmaengine.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_reserved_mem.h>
-+#include <linux/of_graph.h>
-+#include <linux/of_address.h>
-+#include <linux/pinctrl/consumer.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/io.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/uaccess.h>
-+#include <linux/mfd/syscon.h>
-+
-+#include <linux/videodev2.h>
-+
-+#include <media/media-device.h>
-+#include <media/v4l2-async.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-mc.h>
-+#include <media/v4l2-fwnode.h>
-+#include <linux/debugfs.h>
-+
-+#include "stfcamss.h"
-+
-+#ifdef STF_DEBUG
-+unsigned int stdbg_level = ST_DEBUG;
-+unsigned int stdbg_mask = 0x7F;
-+#else
-+unsigned int stdbg_level = ST_ERR;
-+unsigned int stdbg_mask = 0x7F;
-+#endif
-+EXPORT_SYMBOL_GPL(stdbg_level);
-+EXPORT_SYMBOL_GPL(stdbg_mask);
-+
-+static const struct reg_name mem_reg_name[] = {
-+ {"csi2rx"},
-+ {"vclk"},
-+ {"vrst"},
-+ {"sctrl"},
-+ {"isp"},
-+ {"trst"},
-+ {"pmu"},
-+ {"syscrg"},
-+};
-+
-+static struct clk_bulk_data stfcamss_clocks[] = {
-+ { .id = "clk_apb_func" },
-+ { .id = "clk_pclk" },
-+ { .id = "clk_sys_clk" },
-+ { .id = "clk_wrapper_clk_c" },
-+ { .id = "clk_dvp_inv" },
-+ { .id = "clk_axiwr" },
-+ { .id = "clk_mipi_rx0_pxl" },
-+ { .id = "clk_pixel_clk_if0" },
-+ { .id = "clk_pixel_clk_if1" },
-+ { .id = "clk_pixel_clk_if2" },
-+ { .id = "clk_pixel_clk_if3" },
-+ { .id = "clk_m31dphy_cfgclk_in" },
-+ { .id = "clk_m31dphy_refclk_in" },
-+ { .id = "clk_m31dphy_txclkesc_lan0" },
-+ { .id = "clk_ispcore_2x" },
-+ { .id = "clk_isp_axi" },
-+};
-+
-+static struct reset_control_bulk_data stfcamss_resets[] = {
-+ { .id = "rst_wrapper_p" },
-+ { .id = "rst_wrapper_c" },
-+ { .id = "rst_pclk" },
-+ { .id = "rst_sys_clk" },
-+ { .id = "rst_axird" },
-+ { .id = "rst_axiwr" },
-+ { .id = "rst_pixel_clk_if0" },
-+ { .id = "rst_pixel_clk_if1" },
-+ { .id = "rst_pixel_clk_if2" },
-+ { .id = "rst_pixel_clk_if3" },
-+ { .id = "rst_m31dphy_hw" },
-+ { .id = "rst_m31dphy_b09_always_on" },
-+ { .id = "rst_isp_top_n" },
-+ { .id = "rst_isp_top_axi" },
-+};
-+
-+int stfcamss_get_mem_res(struct platform_device *pdev, struct stf_vin_dev *vin)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct resource *res;
-+ char *name;
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(mem_reg_name); i++) {
-+ name = (char *)(&mem_reg_name[i]);
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-+
-+ if (!res)
-+ return -EINVAL;
-+
-+ if (!strcmp(name, "csi2rx")) {
-+ vin->csi2rx_base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(vin->csi2rx_base))
-+ return PTR_ERR(vin->csi2rx_base);
-+ } else if (!strcmp(name, "vclk")) {
-+ vin->clkgen_base = ioremap(res->start, resource_size(res));
-+ if (!vin->clkgen_base)
-+ return -ENOMEM;
-+ } else if (!strcmp(name, "vrst")) {
-+ vin->rstgen_base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(vin->rstgen_base))
-+ return PTR_ERR(vin->rstgen_base);
-+ } else if (!strcmp(name, "sctrl")) {
-+ vin->sysctrl_base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(vin->sysctrl_base))
-+ return PTR_ERR(vin->sysctrl_base);
-+ } else if (!strcmp(name, "isp")) {
-+ vin->isp_base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(vin->isp_base))
-+ return PTR_ERR(vin->isp_base);
-+ } else if (!strcmp(name, "trst")) {
-+ vin->vin_top_rstgen_base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(vin->vin_top_rstgen_base))
-+ return PTR_ERR(vin->vin_top_rstgen_base);
-+ } else if (!strcmp(name, "pmu")) {
-+ vin->pmu_test = ioremap(res->start, resource_size(res));
-+ if (!vin->pmu_test)
-+ return -ENOMEM;
-+ } else if (!strcmp(name, "syscrg")) {
-+ vin->sys_crg = ioremap(res->start, resource_size(res));
-+ if (!vin->sys_crg)
-+ return -ENOMEM;
-+ } else {
-+ st_err(ST_CAMSS, "Could not match resource name\n");
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+int vin_parse_dt(struct device *dev, struct stf_vin_dev *vin)
-+{
-+ int ret = 0;
-+ struct device_node *np = dev->of_node;
-+
-+ if (!np)
-+ return -EINVAL;
-+
-+ return ret;
-+}
-+
-+struct media_entity *stfcamss_find_sensor(struct media_entity *entity)
-+{
-+ struct media_pad *pad;
-+
-+ while (1) {
-+ if (!entity->pads)
-+ return NULL;
-+
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ return NULL;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ return NULL;
-+
-+ entity = pad->entity;
-+
-+ if (entity->function == MEDIA_ENT_F_CAM_SENSOR)
-+ return entity;
-+ }
-+}
-+
-+static int stfcamss_of_parse_endpoint_node(struct device *dev,
-+ struct device_node *node,
-+ struct stfcamss_async_subdev *csd)
-+{
-+ struct v4l2_fwnode_endpoint vep = { { 0 } };
-+ struct v4l2_mbus_config_parallel *parallel_bus = &vep.bus.parallel;
-+ struct v4l2_mbus_config_mipi_csi2 *csi2_bus = &vep.bus.mipi_csi2;
-+ struct dvp_cfg *dvp = &csd->interface.dvp;
-+ struct csi2phy_cfg *csiphy = &csd->interface.csiphy;
-+
-+ v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
-+ st_debug(ST_CAMSS, "%s: vep.base.port = 0x%x, id = 0x%x\n",
-+ __func__, vep.base.port, vep.base.id);
-+
-+ csd->port = vep.base.port;
-+ switch (csd->port) {
-+ case DVP_SENSOR_PORT_NUMBER:
-+ st_debug(ST_CAMSS, "%s, flags = 0x%x\n", __func__,
-+ parallel_bus->flags);
-+ dvp->flags = parallel_bus->flags;
-+ dvp->bus_width = parallel_bus->bus_width;
-+ dvp->data_shift = parallel_bus->data_shift;
-+ break;
-+ case CSI2RX_SENSOR_PORT_NUMBER:
-+ st_debug(ST_CAMSS, "%s, CSI2 flags = 0x%x\n",
-+ __func__, parallel_bus->flags);
-+ csiphy->flags = csi2_bus->flags;
-+ memcpy(csiphy->data_lanes,
-+ csi2_bus->data_lanes, csi2_bus->num_data_lanes);
-+ csiphy->clock_lane = csi2_bus->clock_lane;
-+ csiphy->num_data_lanes = csi2_bus->num_data_lanes;
-+ memcpy(csiphy->lane_polarities,
-+ csi2_bus->lane_polarities,
-+ csi2_bus->num_data_lanes + 1);
-+ break;
-+ default:
-+ break;
-+ };
-+
-+ return 0;
-+}
-+
-+static int stfcamss_of_parse_ports(struct stfcamss *stfcamss)
-+{
-+ struct device *dev = stfcamss->dev;
-+ struct device_node *node = NULL;
-+ struct device_node *remote = NULL;
-+ int ret, num_subdevs = 0;
-+
-+ for_each_endpoint_of_node(dev->of_node, node) {
-+ struct stfcamss_async_subdev *csd;
-+
-+ if (!of_device_is_available(node))
-+ continue;
-+
-+ remote = of_graph_get_remote_port_parent(node);
-+ if (!remote) {
-+ st_err(ST_CAMSS, "Cannot get remote parent\n");
-+ ret = -EINVAL;
-+ goto err_cleanup;
-+ }
-+
-+ csd = v4l2_async_nf_add_fwnode(&stfcamss->notifier,
-+ of_fwnode_handle(remote),
-+ struct stfcamss_async_subdev);
-+ of_node_put(remote);
-+ if (IS_ERR(csd)) {
-+ ret = PTR_ERR(csd);
-+ goto err_cleanup;
-+ }
-+
-+ ret = stfcamss_of_parse_endpoint_node(dev, node, csd);
-+ if (ret < 0)
-+ goto err_cleanup;
-+
-+ num_subdevs++;
-+ }
-+
-+ return num_subdevs;
-+
-+err_cleanup:
-+ of_node_put(node);
-+ return ret;
-+}
-+
-+static int stfcamss_init_subdevices(struct stfcamss *stfcamss)
-+{
-+ int ret;
-+
-+ ret = stf_dvp_subdev_init(stfcamss);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to init stf_dvp sub-device: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ ret = stf_csiphy_subdev_init(stfcamss);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to init stf_csiphy sub-device: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ ret = stf_csi_subdev_init(stfcamss);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to init stf_csi sub-device: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ ret = stf_isp_subdev_init(stfcamss);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to init stf_isp sub-device: %d\n",
-+ ret);
-+ return ret;
-+ }
-+
-+ ret = stf_vin_subdev_init(stfcamss);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to init stf_vin sub-device: %d\n",
-+ ret);
-+ return ret;
-+ }
-+ return ret;
-+}
-+
-+static int stfcamss_register_subdevices(struct stfcamss *stfcamss)
-+{
-+ int ret;
-+ struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
-+ struct stf_dvp_dev *dvp_dev = stfcamss->dvp_dev;
-+ struct stf_csiphy_dev *csiphy_dev = stfcamss->csiphy_dev;
-+ struct stf_csi_dev *csi_dev = stfcamss->csi_dev;
-+ struct stf_isp_dev *isp_dev = stfcamss->isp_dev;
-+
-+ ret = stf_dvp_register(dvp_dev, &stfcamss->v4l2_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to register stf dvp%d entity: %d\n",
-+ 0, ret);
-+ goto err_reg_dvp;
-+ }
-+
-+ ret = stf_csiphy_register(csiphy_dev, &stfcamss->v4l2_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to register stf csiphy%d entity: %d\n",
-+ 0, ret);
-+ goto err_reg_csiphy;
-+ }
-+
-+ ret = stf_csi_register(csi_dev, &stfcamss->v4l2_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to register stf csi%d entity: %d\n",
-+ 0, ret);
-+ goto err_reg_csi;
-+ }
-+
-+ ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to register stf isp%d entity: %d\n",
-+ 0, ret);
-+ goto err_reg_isp;
-+ }
-+
-+ ret = stf_vin_register(vin_dev, &stfcamss->v4l2_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to register vin entity: %d\n",
-+ ret);
-+ goto err_reg_vin;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &dvp_dev->subdev.entity,
-+ STF_DVP_PAD_SRC,
-+ &vin_dev->line[VIN_LINE_WR].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->vin entities: %d\n",
-+ dvp_dev->subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &csi_dev->subdev.entity,
-+ STF_CSI_PAD_SRC,
-+ &vin_dev->line[VIN_LINE_WR].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->vin entities: %d\n",
-+ csi_dev->subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &csiphy_dev->subdev.entity,
-+ STF_CSIPHY_PAD_SRC,
-+ &csi_dev->subdev.entity,
-+ STF_CSI_PAD_SINK,
-+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ csiphy_dev->subdev.entity.name,
-+ csi_dev->subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SRC,
-+ &vin_dev->line[VIN_LINE_ISP].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ isp_dev->subdev.entity.name,
-+ vin_dev->line[VIN_LINE_ISP]
-+ .subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SRC_SS0,
-+ &vin_dev->line[VIN_LINE_ISP_SS0].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ isp_dev->subdev.entity.name,
-+ vin_dev->line[VIN_LINE_ISP_SS0]
-+ .subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SRC_SS1,
-+ &vin_dev->line[VIN_LINE_ISP_SS1].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ isp_dev->subdev.entity.name,
-+ vin_dev->line[VIN_LINE_ISP_SS1]
-+ .subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+#ifndef STF_CAMSS_SKIP_ITI
-+ ret = media_create_pad_link(
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SRC_ITIW,
-+ &vin_dev->line[VIN_LINE_ISP_ITIW].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ isp_dev->subdev.entity.name,
-+ vin_dev->line[VIN_LINE_ISP_ITIW]
-+ .subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SRC_ITIR,
-+ &vin_dev->line[VIN_LINE_ISP_ITIR].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ isp_dev->subdev.entity.name,
-+ vin_dev->line[VIN_LINE_ISP_ITIR]
-+ .subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+#endif
-+
-+ ret = media_create_pad_link(
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SRC_RAW,
-+ &vin_dev->line[VIN_LINE_ISP_RAW].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ isp_dev->subdev.entity.name,
-+ vin_dev->line[VIN_LINE_ISP_RAW]
-+ .subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SRC_SCD_Y,
-+ &vin_dev->line[VIN_LINE_ISP_SCD_Y].subdev.entity,
-+ STF_VIN_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ isp_dev->subdev.entity.name,
-+ vin_dev->line[VIN_LINE_ISP_SCD_Y]
-+ .subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &dvp_dev->subdev.entity,
-+ STF_DVP_PAD_SRC,
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ dvp_dev->subdev.entity.name,
-+ isp_dev->subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ ret = media_create_pad_link(
-+ &csi_dev->subdev.entity,
-+ STF_CSI_PAD_SRC,
-+ &isp_dev->subdev.entity,
-+ STF_ISP_PAD_SINK,
-+ 0);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ csi_dev->subdev.entity.name,
-+ isp_dev->subdev.entity.name,
-+ ret);
-+ goto err_link;
-+ }
-+
-+ return ret;
-+
-+err_link:
-+ stf_vin_unregister(stfcamss->vin_dev);
-+err_reg_vin:
-+ stf_isp_unregister(stfcamss->isp_dev);
-+err_reg_isp:
-+ stf_csi_unregister(stfcamss->csi_dev);
-+err_reg_csi:
-+ stf_csiphy_unregister(stfcamss->csiphy_dev);
-+err_reg_csiphy:
-+ stf_dvp_unregister(stfcamss->dvp_dev);
-+err_reg_dvp:
-+ return ret;
-+}
-+
-+static void stfcamss_unregister_subdevices(struct stfcamss *stfcamss)
-+{
-+ stf_dvp_unregister(stfcamss->dvp_dev);
-+ stf_csiphy_unregister(stfcamss->csiphy_dev);
-+ stf_csi_unregister(stfcamss->csi_dev);
-+ stf_isp_unregister(stfcamss->isp_dev);
-+ stf_vin_unregister(stfcamss->vin_dev);
-+}
-+
-+static int stfcamss_register_mediadevice_subdevnodes(
-+ struct v4l2_async_notifier *async,
-+ struct v4l2_subdev *sd)
-+{
-+ struct stfcamss *stfcamss =
-+ container_of(async, struct stfcamss, notifier);
-+ int ret;
-+
-+ if (sd->host_priv) {
-+ struct media_entity *sensor = &sd->entity;
-+ struct media_entity *input = sd->host_priv;
-+ unsigned int i;
-+
-+ for (i = 0; i < sensor->num_pads; i++) {
-+ if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE)
-+ break;
-+ }
-+ if (i == sensor->num_pads) {
-+ st_err(ST_CAMSS,
-+ "No source pad in external entity\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = media_create_pad_link(sensor, i,
-+ input, STF_PAD_SINK,
-+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ sensor->name, input->name, ret);
-+ return ret;
-+ }
-+ }
-+
-+ ret = v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (stfcamss->media_dev.devnode)
-+ return ret;
-+
-+ st_debug(ST_CAMSS, "stfcamss register media device\n");
-+ return media_device_register(&stfcamss->media_dev);
-+}
-+
-+static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async,
-+ struct v4l2_subdev *subdev,
-+ struct v4l2_async_connection *asd)
-+{
-+ struct stfcamss *stfcamss =
-+ container_of(async, struct stfcamss, notifier);
-+ struct stfcamss_async_subdev *csd =
-+ container_of(asd, struct stfcamss_async_subdev, asd);
-+ enum port_num port = csd->port;
-+ struct stf_dvp_dev *dvp_dev = stfcamss->dvp_dev;
-+ struct stf_csiphy_dev *csiphy_dev = stfcamss->csiphy_dev;
-+
-+ switch (port) {
-+ case DVP_SENSOR_PORT_NUMBER:
-+ dvp_dev->dvp = &csd->interface.dvp;
-+ subdev->host_priv = &dvp_dev->subdev.entity;
-+ break;
-+ case CSI2RX_SENSOR_PORT_NUMBER:
-+ csiphy_dev->csiphy = &csd->interface.csiphy;
-+ subdev->host_priv = &csiphy_dev->subdev.entity;
-+ break;
-+ default:
-+ break;
-+ };
-+
-+ stfcamss_register_mediadevice_subdevnodes(async, subdev);
-+
-+ return 0;
-+}
-+
-+#ifdef UNUSED_CODE
-+static int stfcamss_subdev_notifier_complete(
-+ struct v4l2_async_notifier *async)
-+{
-+ struct stfcamss *stfcamss =
-+ container_of(async, struct stfcamss, notifier);
-+ struct v4l2_device *v4l2_dev = &stfcamss->v4l2_dev;
-+ struct v4l2_subdev *sd;
-+ int ret;
-+
-+ list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
-+ if (sd->host_priv) {
-+ struct media_entity *sensor = &sd->entity;
-+ struct media_entity *input = sd->host_priv;
-+ unsigned int i;
-+
-+ for (i = 0; i < sensor->num_pads; i++) {
-+ if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE)
-+ break;
-+ }
-+ if (i == sensor->num_pads) {
-+ st_err(ST_CAMSS,
-+ "No source pad in external entity\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = media_create_pad_link(sensor, i,
-+ input, STF_PAD_SINK,
-+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to link %s->%s entities: %d\n",
-+ sensor->name, input->name, ret);
-+ return ret;
-+ }
-+ }
-+ }
-+
-+ ret = v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ return media_device_register(&stfcamss->media_dev);
-+}
-+#endif
-+
-+static const struct v4l2_async_notifier_operations
-+stfcamss_subdev_notifier_ops = {
-+ .bound = stfcamss_subdev_notifier_bound,
-+};
-+
-+static const struct media_device_ops stfcamss_media_ops = {
-+ .link_notify = v4l2_pipeline_link_notify,
-+};
-+
-+#ifdef CONFIG_DEBUG_FS
-+enum module_id {
-+ VIN_MODULE = 0,
-+ ISP_MODULE,
-+ CSI_MODULE,
-+ CSIPHY_MODULE,
-+ DVP_MODULE,
-+ CLK_MODULE,
-+};
-+
-+static enum module_id id_num = ISP_MODULE;
-+
-+void dump_clk_reg(void __iomem *reg_base)
-+{
-+ int i;
-+
-+ st_info(ST_CAMSS, "DUMP Clk register:\n");
-+ for (i = 0; i <= CLK_C_ISP_CTRL; i += 4)
-+ print_reg(ST_CAMSS, reg_base, i);
-+}
-+
-+static ssize_t vin_debug_read(struct file *file, char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct device *dev = file->private_data;
-+ void __iomem *reg_base;
-+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
-+ struct stf_vin_dev *vin = stfcamss->vin;
-+ struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
-+ struct stf_isp_dev *isp_dev = stfcamss->isp_dev;
-+ struct stf_csi_dev *csi0_dev = stfcamss->csi_dev;
-+
-+ switch (id_num) {
-+ case VIN_MODULE:
-+ case CSIPHY_MODULE:
-+ case DVP_MODULE:
-+ mutex_lock(&vin_dev->power_lock);
-+ if (vin_dev->power_count > 0) {
-+ reg_base = vin->sysctrl_base;
-+ dump_vin_reg(reg_base);
-+ }
-+ mutex_unlock(&vin_dev->power_lock);
-+ break;
-+ case ISP_MODULE:
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (isp_dev->stream_count > 0) {
-+ reg_base = vin->isp_base;
-+ dump_isp_reg(reg_base);
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+ break;
-+ case CSI_MODULE:
-+ mutex_lock(&csi0_dev->stream_lock);
-+ if (csi0_dev->stream_count > 0) {
-+ reg_base = vin->csi2rx_base;
-+ dump_csi_reg(reg_base);
-+ }
-+ mutex_unlock(&csi0_dev->stream_lock);
-+ break;
-+ case CLK_MODULE:
-+ mutex_lock(&vin_dev->power_lock);
-+ if (vin_dev->power_count > 0) {
-+ reg_base = vin->clkgen_base;
-+ dump_clk_reg(reg_base);
-+ }
-+ mutex_unlock(&vin_dev->power_lock);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return 0;
-+}
-+
-+static void set_reg_val(struct stfcamss *stfcamss, int id, u32 offset, u32 val)
-+{
-+ struct stf_vin_dev *vin = stfcamss->vin;
-+ struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
-+ struct stf_isp_dev *isp_dev = stfcamss->isp_dev;
-+ struct stf_csi_dev *csi_dev = stfcamss->csi_dev;
-+ void __iomem *reg_base;
-+
-+ switch (id) {
-+ case VIN_MODULE:
-+ case CSIPHY_MODULE:
-+ case DVP_MODULE:
-+ mutex_lock(&vin_dev->power_lock);
-+ if (vin_dev->power_count > 0) {
-+ reg_base = vin->sysctrl_base;
-+ print_reg(ST_VIN, reg_base, offset);
-+ reg_write(reg_base, offset, val);
-+ print_reg(ST_VIN, reg_base, offset);
-+ }
-+ mutex_unlock(&vin_dev->power_lock);
-+ break;
-+ case ISP_MODULE:
-+ mutex_lock(&isp_dev->stream_lock);
-+ if (isp_dev->stream_count > 0) {
-+ reg_base = vin->isp_base;
-+ print_reg(ST_ISP, reg_base, offset);
-+ reg_write(reg_base, offset, val);
-+ print_reg(ST_ISP, reg_base, offset);
-+ }
-+ mutex_unlock(&isp_dev->stream_lock);
-+ break;
-+ case CSI_MODULE:
-+ mutex_lock(&csi_dev->stream_lock);
-+ if (csi_dev->stream_count > 0) {
-+ reg_base = vin->csi2rx_base;
-+ print_reg(ST_CSI, reg_base, offset);
-+ reg_write(reg_base, offset, val);
-+ print_reg(ST_CSI, reg_base, offset);
-+ }
-+ mutex_unlock(&csi_dev->stream_lock);
-+ break;
-+ case CLK_MODULE:
-+ mutex_lock(&vin_dev->power_lock);
-+ if (vin_dev->power_count > 0) {
-+ reg_base = vin->clkgen_base;
-+ print_reg(ST_CAMSS, reg_base, offset);
-+ reg_write(reg_base, offset, val);
-+ print_reg(ST_CAMSS, reg_base, offset);
-+ }
-+ mutex_unlock(&vin_dev->power_lock);
-+ break;
-+ default:
-+ break;
-+
-+ }
-+}
-+
-+static u32 atoi(const char *s)
-+{
-+ u32 ret = 0, d = 0;
-+ char ch;
-+ int hex = 0;
-+
-+ if ((*s == '0') && (*(s+1) == 'x')) {
-+ hex = 1;
-+ s += 2;
-+ }
-+
-+ while (1) {
-+ if (!hex) {
-+ d = (*s++) - '0';
-+ if (d > 9)
-+ break;
-+ ret *= 10;
-+ ret += d;
-+ } else {
-+ ch = tolower(*s++);
-+ if (isdigit(ch))
-+ d = ch - '0';
-+ else if (islower(ch))
-+ d = ch - 'a' + 10;
-+ else
-+ break;
-+ if (d > 15)
-+ break;
-+ ret *= 16;
-+ ret += d;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static ssize_t vin_debug_write(struct file *file, const char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct device *dev = file->private_data;
-+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
-+ char *buf;
-+ char *line;
-+ char *p;
-+ static const char *delims = " \t\r";
-+ char *token;
-+ u32 offset, val;
-+
-+ buf = memdup_user_nul(user_buf, min_t(size_t, PAGE_SIZE, count));
-+ if (IS_ERR(buf))
-+ return PTR_ERR(buf);
-+ p = buf;
-+ st_debug(ST_CAMSS, "dup buf: %s, len: %lu, count: %lu\n", p, strlen(p), count);
-+ while (p && *p) {
-+ p = skip_spaces(p);
-+ line = strsep(&p, "\n");
-+ if (!*line || *line == '#')
-+ break;
-+ token = strsep(&line, delims);
-+ if (!token)
-+ goto out;
-+ id_num = atoi(token);
-+ token = strsep(&line, delims);
-+ if (!token)
-+ goto out;
-+ offset = atoi(token);
-+ token = strsep(&line, delims);
-+ if (!token)
-+ goto out;
-+ val = atoi(token);
-+ }
-+ set_reg_val(stfcamss, id_num, offset, val);
-+out:
-+ kfree(buf);
-+ st_info(ST_CAMSS, "id_num = %d, offset = 0x%x, 0x%x\n", id_num, offset, val);
-+ return count;
-+}
-+
-+static const struct file_operations vin_debug_fops = {
-+ .open = simple_open,
-+ .read = vin_debug_read,
-+ .write = vin_debug_write,
-+};
-+#endif /* CONFIG_DEBUG_FS */
-+
-+
-+static int stfcamss_probe(struct platform_device *pdev)
-+{
-+ struct stfcamss *stfcamss;
-+ struct stf_vin_dev *vin;
-+ struct device *dev = &pdev->dev;
-+ struct of_phandle_args args;
-+ int ret = 0, num_subdevs;
-+
-+ dev_info(dev, "stfcamss probe enter!\n");
-+
-+ stfcamss = devm_kzalloc(dev, sizeof(struct stfcamss), GFP_KERNEL);
-+ if (!stfcamss)
-+ return -ENOMEM;
-+
-+ stfcamss->dvp_dev = devm_kzalloc(dev,
-+ sizeof(*stfcamss->dvp_dev), GFP_KERNEL);
-+ if (!stfcamss->dvp_dev) {
-+ ret = -ENOMEM;
-+ goto err_cam;
-+ }
-+
-+ stfcamss->csiphy_dev = devm_kzalloc(dev,
-+ sizeof(*stfcamss->csiphy_dev),
-+ GFP_KERNEL);
-+ if (!stfcamss->csiphy_dev) {
-+ ret = -ENOMEM;
-+ goto err_cam;
-+ }
-+
-+ stfcamss->csi_dev = devm_kzalloc(dev,
-+ sizeof(*stfcamss->csi_dev),
-+ GFP_KERNEL);
-+ if (!stfcamss->csi_dev) {
-+ ret = -ENOMEM;
-+ goto err_cam;
-+ }
-+
-+ stfcamss->isp_dev = devm_kzalloc(dev,
-+ sizeof(*stfcamss->isp_dev),
-+ GFP_KERNEL);
-+ if (!stfcamss->isp_dev) {
-+ ret = -ENOMEM;
-+ goto err_cam;
-+ }
-+
-+ stfcamss->vin_dev = devm_kzalloc(dev,
-+ sizeof(*stfcamss->vin_dev),
-+ GFP_KERNEL);
-+ if (!stfcamss->vin_dev) {
-+ ret = -ENOMEM;
-+ goto err_cam;
-+ }
-+
-+ stfcamss->vin = devm_kzalloc(dev,
-+ sizeof(struct stf_vin_dev),
-+ GFP_KERNEL);
-+ if (!stfcamss->vin) {
-+ ret = -ENOMEM;
-+ goto err_cam;
-+ }
-+
-+ vin = stfcamss->vin;
-+
-+ vin->irq = platform_get_irq(pdev, 0);
-+ if (vin->irq <= 0) {
-+ st_err(ST_CAMSS, "Could not get irq\n");
-+ goto err_cam;
-+ }
-+
-+ vin->isp_irq = platform_get_irq(pdev, 1);
-+ if (vin->isp_irq <= 0) {
-+ st_err(ST_CAMSS, "Could not get isp irq\n");
-+ goto err_cam;
-+ }
-+
-+ vin->isp_csi_irq = platform_get_irq(pdev, 2);
-+ if (vin->isp_csi_irq <= 0) {
-+ st_err(ST_CAMSS, "Could not get isp csi irq\n");
-+ goto err_cam;
-+ }
-+
-+ vin->isp_scd_irq = platform_get_irq(pdev, 3);
-+ if (vin->isp_scd_irq <= 0) {
-+ st_err(ST_CAMSS, "Could not get isp scd irq\n");
-+ goto err_cam;
-+ }
-+
-+ vin->isp_irq_csiline = platform_get_irq(pdev, 4);
-+ if (vin->isp_irq_csiline <= 0) {
-+ st_err(ST_CAMSS, "Could not get isp irq csiline\n");
-+ goto err_cam;
-+ }
-+
-+ pm_runtime_enable(dev);
-+
-+ stfcamss->nclks = ARRAY_SIZE(stfcamss_clocks);
-+ stfcamss->sys_clk = stfcamss_clocks;
-+
-+ ret = devm_clk_bulk_get(dev, stfcamss->nclks, stfcamss->sys_clk);
-+ if (ret) {
-+ st_err(ST_CAMSS, "Failed to get clk controls\n");
-+ return ret;
-+ }
-+
-+ stfcamss->nrsts = ARRAY_SIZE(stfcamss_resets);
-+ stfcamss->sys_rst = stfcamss_resets;
-+
-+ ret = devm_reset_control_bulk_get_shared(dev, stfcamss->nrsts,
-+ stfcamss->sys_rst);
-+ if (ret) {
-+ st_err(ST_CAMSS, "Failed to get reset controls\n");
-+ return ret;
-+ }
-+
-+ ret = of_parse_phandle_with_fixed_args(dev->of_node,
-+ "starfive,aon-syscon", 1, 0, &args);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS, "Failed to parse starfive,aon-syscon\n");
-+ return -EINVAL;
-+ }
-+
-+ stfcamss->stf_aon_syscon = syscon_node_to_regmap(args.np);
-+ of_node_put(args.np);
-+ if (IS_ERR(stfcamss->stf_aon_syscon))
-+ return PTR_ERR(stfcamss->stf_aon_syscon);
-+
-+ stfcamss->aon_gp_reg = args.args[0];
-+
-+ ret = stfcamss_get_mem_res(pdev, vin);
-+ if (ret) {
-+ st_err(ST_CAMSS, "Could not map registers\n");
-+ goto err_cam;
-+ }
-+
-+ ret = vin_parse_dt(dev, vin);
-+ if (ret)
-+ goto err_cam;
-+
-+ vin->dev = dev;
-+ stfcamss->dev = dev;
-+ platform_set_drvdata(pdev, stfcamss);
-+
-+ v4l2_async_nf_init(&stfcamss->notifier, &stfcamss->v4l2_dev);
-+
-+ num_subdevs = stfcamss_of_parse_ports(stfcamss);
-+ if (num_subdevs < 0) {
-+ ret = num_subdevs;
-+ goto err_cam_noti;
-+ }
-+
-+ ret = stfcamss_init_subdevices(stfcamss);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS, "Failed to init subdevice: %d\n", ret);
-+ goto err_cam_noti;
-+ }
-+
-+ stfcamss->media_dev.dev = stfcamss->dev;
-+ strscpy(stfcamss->media_dev.model, "Starfive Camera Subsystem",
-+ sizeof(stfcamss->media_dev.model));
-+ strscpy(stfcamss->media_dev.serial, "0123456789ABCDEF",
-+ sizeof(stfcamss->media_dev.serial));
-+ snprintf(stfcamss->media_dev.bus_info, sizeof(stfcamss->media_dev.bus_info),
-+ "%s:%s", dev_bus_name(dev), pdev->name);
-+ stfcamss->media_dev.hw_revision = 0x01;
-+ stfcamss->media_dev.ops = &stfcamss_media_ops;
-+ media_device_init(&stfcamss->media_dev);
-+
-+ stfcamss->v4l2_dev.mdev = &stfcamss->media_dev;
-+
-+ ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS, "Failed to register V4L2 device: %d\n", ret);
-+ goto err_cam_noti_med;
-+ }
-+
-+ ret = stfcamss_register_subdevices(stfcamss);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS, "Failed to register subdevice: %d\n", ret);
-+ goto err_cam_noti_med_vreg;
-+ }
-+
-+ if (num_subdevs) {
-+ stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops;
-+ ret = v4l2_async_nf_register(&stfcamss->notifier);
-+ if (ret) {
-+ st_err(ST_CAMSS,
-+ "Failed to register async subdev nodes: %d\n",
-+ ret);
-+ goto err_cam_noti_med_vreg_sub;
-+ }
-+ } else {
-+ ret = v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS,
-+ "Failed to register subdev nodes: %d\n",
-+ ret);
-+ goto err_cam_noti_med_vreg_sub;
-+ }
-+
-+ ret = media_device_register(&stfcamss->media_dev);
-+ if (ret < 0) {
-+ st_err(ST_CAMSS, "Failed to register media device: %d\n",
-+ ret);
-+ goto err_cam_noti_med_vreg_sub_medreg;
-+ }
-+ }
-+
-+#ifdef CONFIG_DEBUG_FS
-+ stfcamss->debugfs_entry = debugfs_create_dir("stfcamss", NULL);
-+ stfcamss->vin_debugfs = debugfs_create_file("stf_vin",
-+ 0644, stfcamss->debugfs_entry,
-+ (void *)dev, &vin_debug_fops);
-+ debugfs_create_u32("dbg_level",
-+ 0644, stfcamss->debugfs_entry,
-+ &stdbg_level);
-+ debugfs_create_u32("dbg_mask",
-+ 0644, stfcamss->debugfs_entry,
-+ &stdbg_mask);
-+#endif
-+ dev_info(dev, "stfcamss probe success!\n");
-+
-+ return 0;
-+
-+#ifdef CONFIG_DEBUG_FS
-+ debugfs_remove(stfcamss->vin_debugfs);
-+ debugfs_remove_recursive(stfcamss->debugfs_entry);
-+ stfcamss->debugfs_entry = NULL;
-+#endif
-+
-+err_cam_noti_med_vreg_sub_medreg:
-+err_cam_noti_med_vreg_sub:
-+ stfcamss_unregister_subdevices(stfcamss);
-+err_cam_noti_med_vreg:
-+ v4l2_device_unregister(&stfcamss->v4l2_dev);
-+err_cam_noti_med:
-+ media_device_cleanup(&stfcamss->media_dev);
-+err_cam_noti:
-+ v4l2_async_nf_cleanup(&stfcamss->notifier);
-+err_cam:
-+ // kfree(stfcamss);
-+ return ret;
-+}
-+
-+static int stfcamss_remove(struct platform_device *pdev)
-+{
-+ struct stfcamss *stfcamss = platform_get_drvdata(pdev);
-+
-+ dev_info(&pdev->dev, "remove done\n");
-+
-+#ifdef CONFIG_DEBUG_FS
-+ debugfs_remove(stfcamss->vin_debugfs);
-+ debugfs_remove_recursive(stfcamss->debugfs_entry);
-+ stfcamss->debugfs_entry = NULL;
-+#endif
-+
-+ stfcamss_unregister_subdevices(stfcamss);
-+ v4l2_device_unregister(&stfcamss->v4l2_dev);
-+ media_device_cleanup(&stfcamss->media_dev);
-+ pm_runtime_disable(&pdev->dev);
-+
-+ kfree(stfcamss);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id stfcamss_of_match[] = {
-+ { .compatible = "starfive,jh7110-vin" },
-+ { /* end node */ },
-+};
-+
-+MODULE_DEVICE_TABLE(of, stfcamss_of_match);
-+
-+#ifdef CONFIG_PM_SLEEP
-+static int stfcamss_suspend(struct device *dev)
-+{
-+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
-+ struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
-+ struct media_entity *entity;
-+ struct media_pad *pad;
-+ struct v4l2_subdev *subdev;
-+ struct stfcamss_video *video;
-+ struct video_device *vdev;
-+ int i = 0;
-+ int pm_power_count;
-+ int pm_stream_count;
-+
-+ for (i = 0; i < VIN_LINE_MAX; i++) {
-+ video = &vin_dev->line[i].video_out;
-+ vdev = &vin_dev->line[i].video_out.vdev;
-+ vin_dev->line[i].pm_power_count = vin_dev->line[i].power_count;
-+ vin_dev->line[i].pm_stream_count = vin_dev->line[i].stream_count;
-+ pm_power_count = vin_dev->line[i].pm_power_count;
-+ pm_stream_count = vin_dev->line[i].pm_stream_count;
-+
-+ if (pm_stream_count) {
-+ while (pm_stream_count--) {
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ v4l2_subdev_call(subdev, video, s_stream, 0);
-+ }
-+ }
-+ video_device_pipeline_stop(vdev);
-+ video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
-+ }
-+
-+ if (!pm_power_count)
-+ continue;
-+
-+ v4l2_pipeline_pm_put(&vdev->entity);
-+ }
-+
-+ return pm_runtime_force_suspend(dev);
-+}
-+
-+static int stfcamss_resume(struct device *dev)
-+{
-+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
-+ struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
-+ struct media_entity *entity;
-+ struct media_pad *pad;
-+ struct v4l2_subdev *subdev;
-+ struct stfcamss_video *video;
-+ struct video_device *vdev;
-+ int i = 0;
-+ int pm_power_count;
-+ int pm_stream_count;
-+ int ret = 0;
-+
-+ pm_runtime_force_resume(dev);
-+
-+ for (i = 0; i < VIN_LINE_MAX; i++) {
-+ video = &vin_dev->line[i].video_out;
-+ vdev = &vin_dev->line[i].video_out.vdev;
-+ pm_power_count = vin_dev->line[i].pm_power_count;
-+ pm_stream_count = vin_dev->line[i].pm_stream_count;
-+
-+ if (!pm_power_count)
-+ continue;
-+
-+ ret = v4l2_pipeline_pm_get(&vdev->entity);
-+ if (ret < 0)
-+ goto err;
-+
-+ if (pm_stream_count) {
-+ ret = video_device_pipeline_start(vdev, &video->stfcamss->pipe);
-+ if (ret < 0)
-+ goto err_pm_put;
-+
-+ while (pm_stream_count--) {
-+ entity = &vdev->entity;
-+ while (1) {
-+ pad = &entity->pads[0];
-+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+ break;
-+
-+ pad = media_pad_remote_pad_first(pad);
-+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
-+ break;
-+
-+ entity = pad->entity;
-+ subdev = media_entity_to_v4l2_subdev(entity);
-+
-+ ret = v4l2_subdev_call(subdev, video, s_stream, 1);
-+ if (ret < 0 && ret != -ENOIOCTLCMD)
-+ goto err_pipeline_stop;
-+ }
-+ }
-+ }
-+ }
-+
-+ return 0;
-+
-+err_pipeline_stop:
-+ video_device_pipeline_stop(vdev);
-+err_pm_put:
-+ v4l2_pipeline_pm_put(&vdev->entity);
-+err:
-+ return ret;
-+}
-+#endif /* CONFIG_PM_SLEEP */
-+
-+#ifdef CONFIG_PM
-+static int stfcamss_runtime_suspend(struct device *dev)
-+{
-+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
-+
-+ reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc);
-+ reset_control_assert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc);
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISP_AXI].clk);
-+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk);
-+
-+ return 0;
-+}
-+
-+static int stfcamss_runtime_resume(struct device *dev)
-+{
-+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
-+
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISPCORE_2X].clk);
-+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_ISP_AXI].clk);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_N].rstc);
-+ reset_control_deassert(stfcamss->sys_rst[STFRST_ISP_TOP_AXI].rstc);
-+
-+ return 0;
-+}
-+#endif /* CONFIG_PM */
-+
-+static const struct dev_pm_ops stfcamss_pm_ops = {
-+ SET_SYSTEM_SLEEP_PM_OPS(stfcamss_suspend, stfcamss_resume)
-+ SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend, stfcamss_runtime_resume, NULL)
-+};
-+
-+static struct platform_driver stfcamss_driver = {
-+ .probe = stfcamss_probe,
-+ .remove = stfcamss_remove,
-+ .driver = {
-+ .name = DRV_NAME,
-+ .pm = &stfcamss_pm_ops,
-+ .of_match_table = of_match_ptr(stfcamss_of_match),
-+ },
-+};
-+
-+static int __init stfcamss_init(void)
-+{
-+ return platform_driver_register(&stfcamss_driver);
-+}
-+
-+static void __exit stfcamss_cleanup(void)
-+{
-+ platform_driver_unregister(&stfcamss_driver);
-+}
-+
-+module_init(stfcamss_init);
-+//fs_initcall(stfcamss_init);
-+module_exit(stfcamss_cleanup);
-+
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/media/platform/starfive/v4l2_driver/stfcamss.h
-@@ -0,0 +1,117 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
-+ *
-+ */
-+
-+#ifndef STFCAMSS_H
-+#define STFCAMSS_H
-+
-+#include <linux/io.h>
-+#include <linux/delay.h>
-+#include <linux/reset.h>
-+#include <linux/clk.h>
-+
-+enum sensor_type {
-+ SENSOR_VIN,
-+ /* need replace sensor */
-+ SENSOR_ISP,
-+};
-+
-+enum subdev_type {
-+ VIN_DEV_TYPE,
-+ ISP_DEV_TYPE,
-+};
-+
-+#include "stf_common.h"
-+#include "stf_dvp.h"
-+#include "stf_csi.h"
-+#include "stf_csiphy.h"
-+#include "stf_isp.h"
-+#include "stf_vin.h"
-+
-+#define STF_PAD_SINK 0
-+#define STF_PAD_SRC 1
-+#define STF_PADS_NUM 2
-+
-+#define STF_CAMSS_SKIP_ITI
-+
-+enum port_num {
-+ DVP_SENSOR_PORT_NUMBER = 0,
-+ CSI2RX_SENSOR_PORT_NUMBER
-+};
-+
-+enum stf_clk_num {
-+ STFCLK_APB_FUNC = 0,
-+ STFCLK_PCLK,
-+ STFCLK_SYS_CLK,
-+ STFCLK_WRAPPER_CLK_C,
-+ STFCLK_DVP_INV,
-+ STFCLK_AXIWR,
-+ STFCLK_MIPI_RX0_PXL,
-+ STFCLK_PIXEL_CLK_IF0,
-+ STFCLK_PIXEL_CLK_IF1,
-+ STFCLK_PIXEL_CLK_IF2,
-+ STFCLK_PIXEL_CLK_IF3,
-+ STFCLK_M31DPHY_CFGCLK_IN,
-+ STFCLK_M31DPHY_REFCLK_IN,
-+ STFCLK_M31DPHY_TXCLKESC_LAN0,
-+ STFCLK_ISPCORE_2X,
-+ STFCLK_ISP_AXI,
-+ STFCLK_NUM
-+};
-+
-+enum stf_rst_num {
-+ STFRST_WRAPPER_P = 0,
-+ STFRST_WRAPPER_C,
-+ STFRST_PCLK,
-+ STFRST_SYS_CLK,
-+ STFRST_AXIRD,
-+ STFRST_AXIWR,
-+ STFRST_PIXEL_CLK_IF0,
-+ STFRST_PIXEL_CLK_IF1,
-+ STFRST_PIXEL_CLK_IF2,
-+ STFRST_PIXEL_CLK_IF3,
-+ STFRST_M31DPHY_HW,
-+ STFRST_M31DPHY_B09_ALWAYS_ON,
-+ STFRST_ISP_TOP_N,
-+ STFRST_ISP_TOP_AXI,
-+ STFRST_NUM
-+};
-+
-+struct stfcamss {
-+ struct stf_vin_dev *vin; // stfcamss phy res
-+ struct v4l2_device v4l2_dev;
-+ struct media_device media_dev;
-+ struct media_pipeline pipe;
-+ struct device *dev;
-+ struct stf_vin2_dev *vin_dev; // subdev
-+ struct stf_dvp_dev *dvp_dev; // subdev
-+ struct stf_csi_dev *csi_dev; // subdev
-+ struct stf_csiphy_dev *csiphy_dev; // subdev
-+ struct stf_isp_dev *isp_dev; // subdev
-+ struct v4l2_async_notifier notifier;
-+ struct clk_bulk_data *sys_clk;
-+ int nclks;
-+ struct reset_control_bulk_data *sys_rst;
-+ int nrsts;
-+ struct regmap *stf_aon_syscon;
-+ uint32_t aon_gp_reg;
-+#ifdef CONFIG_DEBUG_FS
-+ struct dentry *debugfs_entry;
-+ struct dentry *vin_debugfs;
-+#endif
-+};
-+
-+struct stfcamss_async_subdev {
-+ struct v4l2_async_connection asd; // must be first
-+ enum port_num port;
-+ struct {
-+ struct dvp_cfg dvp;
-+ struct csi2phy_cfg csiphy;
-+ } interface;
-+};
-+
-+extern struct media_entity *stfcamss_find_sensor(struct media_entity *entity);
-+
-+#endif /* STFCAMSS_H */
---- /dev/null
-+++ b/include/uapi/linux/jh7110-isp.h
-@@ -0,0 +1,253 @@
-+/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) */
-+/*
-+ * jh7110-isp.h
-+ *
-+ * JH7110 ISP driver - user space header file.
-+ *
-+ * Copyright © 2023 Starfive Technology Co., Ltd.
-+ *
-+ * Author: Su Zejian (zejian.su@starfivetech.com)
-+ *
-+ */
-+
-+#ifndef __JH7110_ISP_H_
-+#define __JH7110_ISP_H_
-+
-+#include <linux/v4l2-controls.h>
-+
-+#define V4L2_CID_USER_JH7110_ISP_WB_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0001)
-+#define V4L2_CID_USER_JH7110_ISP_CAR_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0002)
-+#define V4L2_CID_USER_JH7110_ISP_CCM_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0003)
-+#define V4L2_CID_USER_JH7110_ISP_CFA_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0004)
-+#define V4L2_CID_USER_JH7110_ISP_CTC_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0005)
-+#define V4L2_CID_USER_JH7110_ISP_DBC_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0006)
-+#define V4L2_CID_USER_JH7110_ISP_DNYUV_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0007)
-+#define V4L2_CID_USER_JH7110_ISP_GMARGB_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0008)
-+#define V4L2_CID_USER_JH7110_ISP_LCCF_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0009)
-+#define V4L2_CID_USER_JH7110_ISP_OBC_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000a)
-+#define V4L2_CID_USER_JH7110_ISP_OECF_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000b)
-+#define V4L2_CID_USER_JH7110_ISP_R2Y_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000c)
-+#define V4L2_CID_USER_JH7110_ISP_SAT_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000d)
-+#define V4L2_CID_USER_JH7110_ISP_SHRP_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000e)
-+#define V4L2_CID_USER_JH7110_ISP_YCRV_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x000f)
-+
-+struct jh7110_isp_wb_gain {
-+ __u16 gain_r;
-+ __u16 gain_g;
-+ __u16 gain_b;
-+};
-+
-+struct jh7110_isp_wb_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_wb_gain gains;
-+};
-+
-+struct jh7110_isp_car_setting {
-+ __u32 enabled;
-+};
-+
-+struct jh7110_isp_ccm_smlow {
-+ __s32 ccm[3][3];
-+ __s32 offsets[3];
-+};
-+
-+struct jh7110_isp_ccm_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_ccm_smlow ccm_smlow;
-+};
-+
-+struct jh7110_isp_cfa_params {
-+ __s32 hv_width;
-+ __s32 cross_cov;
-+};
-+
-+struct jh7110_isp_cfa_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_cfa_params settings;
-+};
-+
-+struct jh7110_isp_ctc_params {
-+ __u8 saf_mode;
-+ __u8 daf_mode;
-+ __s32 max_gt;
-+ __s32 min_gt;
-+};
-+
-+struct jh7110_isp_ctc_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_ctc_params settings;
-+};
-+
-+struct jh7110_isp_dbc_params {
-+ __s32 bad_gt;
-+ __s32 bad_xt;
-+};
-+
-+struct jh7110_isp_dbc_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_dbc_params settings;
-+};
-+
-+struct jh7110_isp_dnyuv_params {
-+ __u8 y_sweight[10];
-+ __u16 y_curve[7];
-+ __u8 uv_sweight[10];
-+ __u16 uv_curve[7];
-+};
-+
-+struct jh7110_isp_dnyuv_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_dnyuv_params settings;
-+};
-+
-+struct jh7110_isp_gmargb_point {
-+ __u16 g_val;
-+ __u16 sg_val;
-+};
-+
-+struct jh7110_isp_gmargb_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_gmargb_point curve[15];
-+};
-+
-+struct jh7110_isp_lccf_circle {
-+ __s16 center_x;
-+ __s16 center_y;
-+ __u8 radius;
-+};
-+
-+struct jh7110_isp_lccf_curve_param {
-+ __s16 f1;
-+ __s16 f2;
-+};
-+
-+struct jh7110_isp_lccf_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_lccf_circle circle;
-+ struct jh7110_isp_lccf_curve_param r_param;
-+ struct jh7110_isp_lccf_curve_param gr_param;
-+ struct jh7110_isp_lccf_curve_param gb_param;
-+ struct jh7110_isp_lccf_curve_param b_param;
-+};
-+
-+struct jh7110_isp_blacklevel_win_size {
-+ __u32 width;
-+ __u32 height;
-+};
-+
-+struct jh7110_isp_blacklevel_gain {
-+ __u8 tl_gain;
-+ __u8 tr_gain;
-+ __u8 bl_gain;
-+ __u8 br_gain;
-+};
-+
-+struct jh7110_isp_blacklevel_offset {
-+ __u8 tl_offset;
-+ __u8 tr_offset;
-+ __u8 bl_offset;
-+ __u8 br_offset;
-+};
-+
-+struct jh7110_isp_blacklevel_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_blacklevel_win_size win_size;
-+ struct jh7110_isp_blacklevel_gain gain[4];
-+ struct jh7110_isp_blacklevel_offset offset[4];
-+};
-+
-+struct jh7110_isp_oecf_point {
-+ __u16 x;
-+ __u16 y;
-+ __s16 slope;
-+};
-+
-+struct jh7110_isp_oecf_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_oecf_point r_curve[16];
-+ struct jh7110_isp_oecf_point gr_curve[16];
-+ struct jh7110_isp_oecf_point gb_curve[16];
-+ struct jh7110_isp_oecf_point b_curve[16];
-+};
-+
-+struct jh7110_isp_r2y_matrix {
-+ __s16 m[9];
-+};
-+
-+struct jh7110_isp_r2y_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_r2y_matrix matrix;
-+};
-+
-+struct jh7110_isp_sat_curve {
-+ __s16 yi_min;
-+ __s16 yo_ir;
-+ __s16 yo_min;
-+ __s16 yo_max;
-+};
-+
-+struct jh7110_isp_sat_hue_info {
-+ __s16 sin;
-+ __s16 cos;
-+};
-+
-+struct jh7110_isp_sat_info {
-+ __s16 gain_cmab;
-+ __s16 gain_cmad;
-+ __s16 threshold_cmb;
-+ __s16 threshold_cmd;
-+ __s16 offset_u;
-+ __s16 offset_v;
-+ __s16 cmsf;
-+};
-+
-+struct jh7110_isp_sat_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_sat_curve curve;
-+ struct jh7110_isp_sat_hue_info hue_info;
-+ struct jh7110_isp_sat_info sat_info;
-+};
-+
-+struct jh7110_isp_sharp_weight {
-+ __u8 weight[15];
-+ __u32 recip_wei_sum;
-+};
-+
-+struct jh7110_isp_sharp_strength {
-+ __s16 diff[4];
-+ __s16 f[4];
-+};
-+
-+struct jh7110_isp_sharp_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_sharp_weight weight;
-+ struct jh7110_isp_sharp_strength strength;
-+ __s8 pdirf;
-+ __s8 ndirf;
-+};
-+
-+struct jh7110_isp_ycrv_curve {
-+ __s16 y[64];
-+};
-+
-+struct jh7110_isp_ycrv_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_ycrv_curve curve;
-+};
-+
-+#endif
---- a/include/uapi/linux/v4l2-controls.h
-+++ b/include/uapi/linux/v4l2-controls.h
-@@ -203,6 +203,12 @@ enum v4l2_colorfx {
- */
- #define V4L2_CID_USER_ASPEED_BASE (V4L2_CID_USER_BASE + 0x11a0)
-
-+/*
-+ * The base for the jh7110-isp driver controls.
-+ * We reserve 16 controls for this driver.
-+ */
-+#define V4L2_CID_USER_JH7110_ISP_BASE (V4L2_CID_USER_BASE + 0x1170)
-+
- /* MPEG-class control IDs */
- /* The MPEG controls are applicable to all codec controls
- * and the 'MPEG' part of the define is historical */
---- /dev/null
-+++ b/include/video/stf-vin.h
-@@ -0,0 +1,443 @@
-+/* include/video/stf-vin.h
-+ *
-+ * Copyright 2020 starfive tech.
-+ * Eric Tang <eric.tang@starfivetech.com>
-+ *
-+ * Generic vin notifier interface
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+*/
-+#ifndef _VIDEO_VIN_H
-+#define _VIDEO_VIN_H
-+
-+#include <linux/cdev.h>
-+
-+#define DRV_NAME "jh7110-vin"
-+#define FB_FIRST_ADDR 0xf9000000
-+#define FB_SECOND_ADDR 0xf97e9000
-+
-+#define RESERVED_MEM_SIZE 0x1000000
-+
-+#define VIN_MIPI_CONTROLLER0_OFFSET 0x00000
-+#define VIN_CLKGEN_OFFSET 0x10000
-+#define VIN_RSTGEN_OFFSET 0x20000
-+#define VIN_MIPI_CONTROLLER1_OFFSET 0x30000
-+#define VIN_SYSCONTROLLER_OFFSET 0x40000
-+
-+#define VD_1080P 1080
-+#define VD_720P 720
-+#define VD_PAL 480
-+
-+#define VD_HEIGHT_1080P VD_1080P
-+#define VD_WIDTH_1080P 1920
-+
-+#define VD_HEIGHT_720P VD_720P
-+#define VD_WIDTH_720P 1080
-+
-+#define VD_HEIGHT_480 480
-+#define VD_WIDTH_640 640
-+
-+#define SEEED_WIDTH_800 800
-+#define SEEED_HIGH_480 480
-+
-+#define VIN_TOP_CLKGEN_BASE_ADDR 0x11800000
-+#define VIN_TOP_RSTGEN_BASE_ADDR 0x11840000
-+#define VIN_TOP_IOPAD_BASE_ADDR 0x11858000
-+
-+#define ISP_BASE_MIPI0_ADDR 0x19800000
-+#define ISP_BASE_CLKGEN_ADDR 0x19810000
-+#define ISP_BASE_RSTGEN_ADDR 0x19820000
-+#define ISP_BASE_MIPI1_ADDR 0x19830000
-+#define ISP_BASE_SYSCTRL_ADDR 0x19840000
-+#define ISP_BASE_ISP0_ADDR 0x19870000
-+#define ISP_BASE_ISP1_ADDR 0x198a0000
-+
-+
-+//vin clk registers
-+#define CLK_VIN_SRC_CTRL 0x188
-+#define CLK_ISP0_AXI_CTRL 0x190
-+#define CLK_ISP0NOC_AXI_CTRL 0x194
-+#define CLK_ISPSLV_AXI_CTRL 0x198
-+#define CLK_ISP1_AXI_CTRL 0x1A0
-+#define CLK_ISP1NOC_AXI_CTRL 0x1A4
-+#define CLK_VIN_AXI 0x1AC
-+#define CLK_VINNOC_AXI 0x1B0
-+
-+
-+#define CLK_DOM4_APB_FUNC 0x0
-+#define CLK_MUX_SEL 0xffffff
-+
-+#define CLK_MIPI_RX0_PXL 0x4
-+
-+#define CLK_DVP_INV 0x8
-+#define CLK_U0_VIN_PCLK 0x18
-+#define CLK_U0_VIN_PCLK_ICG (0x1<<31)
-+
-+#define CLK_U0_VIN_SYS_CLK 0x1c
-+#define CLK_U0_VIN_CLK_P_AXIWR 0x30
-+#define CLK_U0_VIN_MUX_SEL (BIT(24) | BIT(25) | BIT(26) | BIT(27) | BIT(28) | BIT(29))
-+
-+#define CLK_U0_VIN_PIXEL_CLK_IF0 0x20
-+#define CLK_U0_VIN_PIXEL_CLK_IF1 0x24
-+#define CLK_U0_VIN_PIXEL_CLK_IF2 0x28
-+#define CLK_U0_VIN_PIXEL_CLK_IF3 0x2c
-+
-+#define CLK_U0_VIN_CLK_P_AXIWR 0x30
-+
-+#define CLK_U0_ISPV2_TOP_WRAPPER_CLK_C 0x34u
-+#define CLK_U0_ISPV2_MUX_SEL (0x1<<24 | 0x1<<25 | 0x1<<26 | 0x1<<27 | 0x1<<28 | 0x1<< 29)
-+
-+#define CLK_U0_ISPV2_CLK_ICG (0x1<<31)
-+
-+#define SOFTWARE_RESET_ASSERT0_ASSERT_SET 0x38U
-+#define SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE 0x3CU
-+#define RST_U0_ISPV2_TOP_WRAPPER_RST_P BIT(0)
-+#define RST_U0_ISPV2_TOP_WRAPPER_RST_C BIT(1)
-+#define RSTN_U0_VIN_RST_N_PCLK BIT(4)
-+#define RSTN_U0_VIN_RST_N_SYS_CLK BIT(9)
-+#define RSTN_U0_VIN_RST_P_AXIRD BIT(10)
-+#define RSTN_U0_VIN_RST_P_AXIWR BIT(11)
-+
-+
-+#define CLK_POLARITY (0x1<<30)
-+
-+#define M31DPHY_APBCFGSAIF__SYSCFG_0 0x0
-+#define M31DPHY_APBCFGSAIF__SYSCFG_4 0x4
-+#define M31DPHY_APBCFGSAIF__SYSCFG_8 0x8
-+#define M31DPHY_APBCFGSAIF__SYSCFG_12 0xc
-+#define M31DPHY_APBCFGSAIF__SYSCFG_16 0x10
-+#define M31DPHY_APBCFGSAIF__SYSCFG_20 0x14
-+#define M31DPHY_APBCFGSAIF__SYSCFG_24 0x18
-+#define M31DPHY_APBCFGSAIF__SYSCFG_28 0x1c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_32 0x20
-+#define M31DPHY_APBCFGSAIF__SYSCFG_36 0x24
-+#define M31DPHY_APBCFGSAIF__SYSCFG_40 0x28
-+#define M31DPHY_APBCFGSAIF__SYSCFG_44 0x2c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_48 0x30
-+#define M31DPHY_APBCFGSAIF__SYSCFG_52 0x34
-+#define M31DPHY_APBCFGSAIF__SYSCFG_56 0x38
-+#define M31DPHY_APBCFGSAIF__SYSCFG_60 0x3c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_64 0x40
-+#define M31DPHY_APBCFGSAIF__SYSCFG_68 0x44
-+#define M31DPHY_APBCFGSAIF__SYSCFG_72 0x48
-+#define M31DPHY_APBCFGSAIF__SYSCFG_76 0x4c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_80 0x50
-+#define M31DPHY_APBCFGSAIF__SYSCFG_84 0x54
-+#define M31DPHY_APBCFGSAIF__SYSCFG_88 0x58
-+#define M31DPHY_APBCFGSAIF__SYSCFG_92 0x5c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_96 0x60
-+#define M31DPHY_APBCFGSAIF__SYSCFG_100 0x64
-+#define M31DPHY_APBCFGSAIF__SYSCFG_104 0x68
-+#define M31DPHY_APBCFGSAIF__SYSCFG_108 0x6c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_112 0x70
-+#define M31DPHY_APBCFGSAIF__SYSCFG_116 0x74
-+#define M31DPHY_APBCFGSAIF__SYSCFG_120 0x78
-+#define M31DPHY_APBCFGSAIF__SYSCFG_124 0x7c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_128 0x80
-+#define M31DPHY_APBCFGSAIF__SYSCFG_132 0x84
-+#define M31DPHY_APBCFGSAIF__SYSCFG_136 0x88
-+#define M31DPHY_APBCFGSAIF__SYSCFG_140 0x8c
-+#define M31DPHY_APBCFGSAIF__SYSCFG_144 0x90
-+#define M31DPHY_APBCFGSAIF__SYSCFG_184 0xb8
-+
-+//pmu registers
-+#define SW_DEST_POWER_ON 0x0C
-+#define SW_DEST_POWER_OFF 0x10
-+#define SW_ENCOURAGE 0x44
-+
-+
-+//isp clk registers
-+#define CLK_DPHY_CFGCLK_ISPCORE_2X_CTRL 0x00
-+#define CLK_DPHY_REFCLK_ISPCORE_2X_CTRL 0x04
-+#define CLK_DPHY_TXCLKESC_IN_CTRL 0x08
-+#define CLK_MIPI_RX0_PXL_CTRL 0x0c
-+#define CLK_MIPI_RX1_PXL_CTRL 0x10
-+#define CLK_MIPI_RX0_PXL_0_CTRL 0X14
-+#define CLK_MIPI_RX0_PXL_1_CTRL 0X18
-+#define CLK_MIPI_RX0_PXL_2_CTRL 0X1C
-+#define CLK_MIPI_RX0_PXL_3_CTRL 0X20
-+#define CLK_MIPI_RX0_SYS0_CTRL 0x24
-+#define CLK_MIPI_RX1_PXL_0_CTRL 0X28
-+#define CLK_MIPI_RX1_PXL_1_CTRL 0X2C
-+#define CLK_MIPI_RX1_PXL_2_CTRL 0X30
-+#define CLK_MIPI_RX1_PXL_3_CTRL 0X34
-+#define CLK_MIPI_RX1_SYS1_CTRL 0x38
-+#define CLK_ISP_CTRL 0x3c
-+#define CLK_ISP_2X_CTRL 0x40
-+#define CLK_ISP_MIPI_CTRL 0x44
-+#define CLK_C_ISP_CTRL 0x64
-+#define CLK_CSI2RX0_APB_CTRL 0x58
-+
-+
-+#define CLK_VIN_AXI_WR_CTRL 0x5C
-+
-+#define SOFTWARE_RESET_ASSERT0 0x0
-+#define SOFTWARE_RESET_ASSERT1 0x4
-+#define SOFTWARE_RESET_STATUS 0x4
-+
-+#define IOPAD_REG81 0x144
-+#define IOPAD_REG82 0x148
-+#define IOPAD_REG83 0x14C
-+#define IOPAD_REG84 0x150
-+#define IOPAD_REG85 0x154
-+#define IOPAD_REG86 0x158
-+#define IOPAD_REG87 0x15C
-+#define IOPAD_REG88 0x160
-+#define IOPAD_REG89 0x164
-+
-+//sys control REG DEFINE
-+#define SYSCONSAIF_SYSCFG_0 0X0
-+#define U0_VIN_SCFG_SRAM_CONFIG (BIT(0) | BIT(1))
-+
-+#define SYSCONSAIF_SYSCFG_4 0x4
-+#define U0_VIN_CNFG_AXIRD_END_ADDR 0xffffffff
-+#define SYSCONSAIF_SYSCFG_8 0x8
-+#define U0_VIN_CNFG_AXIRD_LINE_CNT_END (BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13))
-+#define U0_VIN_CNFG_AXIRD_LINE_CNT_START (BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23) | BIT(24) | BIT(25))
-+#define SYSCONSAIF_SYSCFG_12 0xc
-+#define U0_VIN_CNFG_AXIRD_PIX_CNT_END (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12))
-+#define U0_VIN_CNFG_AXIRD_PIX_CNT_START (BIT(13) | BIT(14) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23) | BIT(24) | BIT(25))
-+#define U0_VIN_CNFG_AXIRD_PIX_CT (BIT(26) | BIT(27))
-+#define SYSCONSAIF_SYSCFG_16 0x10
-+#define U0_VIN_CNFG_AXIRD_START_ADDR 0xFFFFFFFF
-+#define SYSCONSAIF_SYSCFG_20 0x14
-+#define U0_VIN_CNFG_AXIWR0_EN BIT(4)
-+#define U0_VIN_CNFG_AXIWR0_CHANNEL_SEL (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-+#define SYSCONSAIF_SYSCFG_24 0x18
-+#define U0_VIN_CNFG_AXIWR0_END_ADDR 0xFFFFFFFF
-+
-+#define SYSCONSAIF_SYSCFG_28 0x1c
-+#define U0_VIN_CNFG_AXIWR0_INTR_CLEAN BIT(0)
-+#define U0_VIN_CNFG_AXIWR0_MASK BIT(1)
-+#define U0_VIN_CNFG_AXIWR0_PIX_CNT_END (BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12))
-+#define U0_VIN_CNFG_AXIWR0_PIX_CT (BIT(13) | BIT(14))
-+#define UO_VIN_CNFG_AXIWR0_PIXEL_HEIGH_BIT_SEL (BIT(15) | BIT(16))
-+#define SYSCONSAIF_SYSCFG_32 0x20
-+
-+#define SYSCONSAIF_SYSCFG_36 0x24
-+#define UO_VIN_CNFG_COLOR_BAR_EN BIT(0)
-+#define U0_VIN_CNFG_DVP_HS_POS (0x1<<1)
-+#define U0_VIN_CNFG_DVP_SWAP_EN BIT(2)
-+#define U0_VIN_CNFG_DVP_VS_POS (0x1<<3)
-+#define U0_VIN_CNFG_GEN_EN_AXIRD BIT(4)
-+#define U0_VIN_CNFG_ISP_DVP_EN0 BIT(5)
-+#define U0_VIN_CNFG_MIPI_BYTE_EN_ISP0 (BIT(6) |BIT(7))
-+#define U0_VIN_CNFG_P_I_MIPI_CHANNEL_SEL0 (BIT(8) |BIT(9) | BIT(10) | BIT(11))
-+#define U0_VIN_CNFG_P_I_MIPI_HEADER_EN0 BIT(12)
-+
-+#define U0_VIN_CNFG_PIX_NUM (0x1<<13 | 0x1<<14 | 0x1<<15 | 0x1<<16)
-+#define U0_VIN_CNFG_AXIRD_AXI_CNT_END (BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13))
-+
-+#define U0_VIN_CNFG_AXI_DVP_EN BIT(2)
-+#define U0_VIN_CNFG_AXIRD_INTR_MASK BIT(1)
-+#define U0_VIN_CNFG_AXIWRD_INTR_MASK BIT(1)
-+#define U0_VIN_CNFG_AXIWR0_START_ADDR 0xffffffff
-+#define U0_VIN_CNFG_COLOR_BAR_EN 0X0
-+#define U0_VIN_CNFG_AXIWR0_PIX_CNT_CT (BIT(13) | BIT(14))
-+#define U0_VIN_CNFG_AXIWR0_PIX_CNT_CNT_END (BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12))
-+#define U0_VIN_CNFG_AXIWR0_PIXEL_HITH_BIT_SEL (BIT(15) | BIT(16))
-+
-+#define SYSCTRL_REG4 0x10
-+#define SYSCTRL_DPHY_CTRL 0x14
-+#define SYSCTRL_VIN_AXI_CTRL 0x18
-+#define SYSCTRL_VIN_WR_START_ADDR 0x28
-+#define SYSCTRL_VIN_RD_END_ADDR 0x2C
-+#define SYSCTRL_VIN_WR_PIX_TOTAL 0x30
-+#define SYSCTRL_VIN_RD_PIX_TOTAL 0x34
-+#define SYSCTRL_VIN_RW_CTRL 0x38
-+#define SYSCTRL_VIN_SRC_CHAN_SEL 0x24
-+#define SYSCTRL_VIN_SRC_DW_SEL 0x40
-+#define SYSCTRL_VIN_RD_VBLANK 0x44
-+#define SYSCTRL_VIN_RD_VEND 0x48
-+#define SYSCTRL_VIN_RD_HBLANK 0x4C
-+#define SYSCTRL_VIN_RD_HEND 0x50
-+#define SYSCTRL_VIN_INTP_CTRL 0x54
-+
-+#define ISP_NO_SCALE_ENABLE (0x1<<20)
-+#define ISP_MULTI_FRAME_ENABLE (0x1<<17)
-+#define ISP_SS0_ENABLE (0x1<<11)
-+#define ISP_SS1_ENABLE (0x1<<12)
-+#define ISP_RESET (0x1<<1)
-+#define ISP_ENBALE (0x1)
-+
-+
-+
-+ //ISP REG DEFINE
-+#define ISP_REG_DVP_POLARITY_CFG 0x00000014
-+#define ISP_REG_RAW_FORMAT_CFG 0x00000018
-+#define ISP_REG_CFA_MODE 0x00000A1C
-+#define ISP_REG_PIC_CAPTURE_START_CFG 0x0000001C
-+#define ISP_REG_PIC_CAPTURE_END_CFG 0x00000020
-+#define ISP_REG_PIPELINE_XY_SIZE 0x00000A0C
-+#define ISP_REG_Y_PLANE_START_ADDR 0x00000A80
-+#define ISP_REG_UV_PLANE_START_ADDR 0x00000A84
-+#define ISP_REG_STRIDE 0x00000A88
-+#define ISP_REG_PIXEL_COORDINATE_GEN 0x00000A8C
-+#define ISP_REG_PIXEL_AXI_CONTROL 0x00000A90
-+#define ISP_REG_SS_AXI_CONTROL 0x00000AC4
-+#define ISP_REG_RGB_TO_YUV_COVERSION0 0x00000E40
-+#define ISP_REG_RGB_TO_YUV_COVERSION1 0x00000E44
-+#define ISP_REG_RGB_TO_YUV_COVERSION2 0x00000E48
-+#define ISP_REG_RGB_TO_YUV_COVERSION3 0x00000E4C
-+#define ISP_REG_RGB_TO_YUV_COVERSION4 0x00000E50
-+#define ISP_REG_RGB_TO_YUV_COVERSION5 0x00000E54
-+#define ISP_REG_RGB_TO_YUV_COVERSION6 0x00000E58
-+#define ISP_REG_RGB_TO_YUV_COVERSION7 0x00000E5C
-+#define ISP_REG_RGB_TO_YUV_COVERSION8 0x00000E60
-+#define ISP_REG_CSI_MODULE_CFG 0x00000010
-+#define ISP_REG_ISP_CTRL_1 0x00000A08
-+#define ISP_REG_ISP_CTRL_0 0x00000A00
-+#define ISP_REG_DC_AXI_ID 0x00000044
-+#define ISP_REG_CSI_INPUT_EN_AND_STATUS 0x00000000
-+
-+//CSI registers
-+#define DEVICE_CONFIG 0x00
-+#define SOFT_RESET 0x04
-+#define STATIC_CFG 0x08
-+#define ERROR_BYPASS_CFG 0x10
-+#define MONITOR_IRQS 0x18
-+#define MONITOR_IRQS_MASK_CFG 0x1c
-+#define INFO_IRQS 0x20
-+#define INFO_IRQS_MASK_CFG 0x24
-+#define ERROR_IRQS 0x28
-+#define ERROR_IRQS_MASK_CFG 0x2c
-+#define DPHY_LANE_CONTROL 0x40
-+#define DPHY_STATUS 0x48
-+#define DPHY_ERR_STATUS_IRQ 0x4C
-+#define DPHY_ERR_IRQ_MASK_CFG 0x50
-+#define INTEGRATION_DEBUG 0x60
-+#define ERROR_DEBUG 0x74
-+
-+#define STREAM0_CTRL 0x100
-+#define STREAM0_STATUS 0x104
-+#define STREAM0_DATA_CFG 0x108
-+#define STREAM0_CFG 0x10c
-+#define STREAM0_MONITOR_CTRL 0x110
-+#define STREAM0_MONITOR_FRAME 0x114
-+#define STREAM0_MONITOR_LB 0x118
-+#define STREAM0_TIMER 0x11c
-+#define STREAM0_FCC_CFG 0x120
-+#define STREAM0_FCC_CTRL 0x124
-+#define STREAM0_FIFO_FILL_LVL 0x128
-+
-+//m31_dphy registers
-+#define M31DPHY_APBCFGSAIF__SYSCFG_188 0xbc
-+#define M31DPHY_APBCFGSAIF__SYSCFG_192 0xc0
-+#define M31DPHY_APBCFGSAIF__SYSCFG_196 0xc4
-+#define M31DPHY_APBCFGSAIF__SYSCFG_200 0xc8
-+
-+typedef enum
-+{
-+ DT_RAW6 = 0x28,
-+ DT_RAW7 = 0x29,
-+ DT_RAW8 = 0x2a,
-+ DT_RAW10 = 0x2b,
-+ DT_RAW12 = 0x2c,
-+ DT_RAW14 = 0x2d,
-+} mipicam_data_type_t;
-+
-+
-+enum VIN_SOURCE_FORMAT {
-+ SRC_COLORBAR_VIN_ISP = 0,
-+ SRC_DVP_SENSOR_VIN,
-+ SRC_DVP_SENSOR_VIN_ISP,//need replace sensor
-+ SRC_CSI2RX_VIN_ISP,
-+ SRC_DVP_SENSOR_VIN_OV5640,
-+};
-+
-+struct reg_name {
-+ char name[10];
-+};
-+
-+typedef struct
-+{
-+ int dlane_nb;
-+ int dlane_map[4];
-+ int dlane_en[4];
-+ int dlane_pn_swap[4];
-+ int clane_nb;
-+ int clane_map[2];
-+ int clane_pn_swap[2];
-+} csi2rx_dphy_cfg_t;
-+
-+typedef struct
-+{
-+ int lane_nb;
-+ int dlane_map[4];
-+ int dt;
-+ int hsize;
-+ int vsize;
-+} csi2rx_cfg_t;
-+
-+
-+typedef struct
-+{
-+ int mipi_id, w, h, dt, bpp, fps,lane;
-+ u8 clane_swap;
-+ u8 clane_pn_swap;
-+ u8 dlane_swap[4];
-+ u8 dlane_pn_swap[4];
-+} csi_format;
-+
-+struct vin_params {
-+ void *paddr;
-+ unsigned long size;
-+};
-+
-+struct vin_buf {
-+ void *vaddr;
-+ dma_addr_t paddr;
-+ u32 size;
-+};
-+
-+struct vin_framesize {
-+ u32 width;
-+ u32 height;
-+};
-+
-+struct vin_format {
-+ enum VIN_SOURCE_FORMAT format;
-+ u8 fps;
-+};
-+
-+struct stf_vin_dev {
-+ /* Protects the access of variables shared within the interrupt */
-+ spinlock_t irqlock;
-+ int irq;
-+ struct device *dev;
-+ struct cdev vin_cdev;
-+ void __iomem *base;
-+ void __iomem *csi2rx_base;
-+ void __iomem *clkgen_base;
-+ void __iomem *rstgen_base;
-+ void __iomem *sysctrl_base;
-+ void __iomem *isp_base;
-+ void __iomem *vin_top_clkgen_base;
-+ void __iomem *vin_top_rstgen_base;
-+ void __iomem *vin_top_iopad_base;
-+ void __iomem *pmu_test;
-+ void __iomem *sys_crg;
-+ struct vin_framesize frame;
-+ struct vin_format format;
-+ bool isp;
-+ int isp_irq;
-+ int isp_csi_irq;
-+ int isp_scd_irq;
-+ int isp_irq_csiline;
-+ u32 major;
-+ struct vin_buf buf;
-+
-+ wait_queue_head_t wq;
-+ bool condition;
-+ int odd;
-+
-+ csi_format csi_fmt;
-+};
-+
-+extern int vin_notifier_register(struct notifier_block *nb);
-+extern void vin_notifier_unregister(struct notifier_block *nb);
-+extern int vin_notifier_call(unsigned long e, void *v);
-+#endif
+++ /dev/null
-From baec350a0994467584e7e390746e0bb365957a89 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Tue, 13 Jun 2023 16:55:23 +0800
-Subject: [PATCH 086/116] dt-bindings: media: i2c: Add IMX708 CMOS sensor
- binding
-
-Add YAML devicetree binding for IMX708 CMOS image sensor.
-Let's also add a MAINTAINERS entry for the binding and driver.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
----
- .../devicetree/bindings/media/i2c/imx708.yaml | 117 ++++++++++++++++++
- 1 file changed, 117 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/media/i2c/imx708.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/media/i2c/imx708.yaml
-@@ -0,0 +1,117 @@
-+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/media/i2c/imx708.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Sony 1/2.3-Inch 12Mpixel CMOS Digital Image Sensor
-+
-+maintainers:
-+ - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.om>
-+
-+description: |-
-+ The Sony IMX708 is a 1/2.3-inch CMOS active pixel digital mage sensor
-+ with an active array size of 4608H x 2592V. It is rogrammable through
-+ I2C interface. The I2C address is fixed to 0x1A as per ensor data sheet.
-+ Image data is sent through MIPI CSI-2, which is configured s either 2 or
-+ 4 data lanes.
-+
-+properties:
-+ compatible:
-+ const: sony,imx708
-+
-+ reg:
-+ description: I2C device address
-+ maxItems: 1
-+
-+ clocks:
-+ maxItems: 1
-+
-+ VDIG-supply:
-+ description:
-+ Digital I/O voltage supply, 1.1 volts
-+
-+ VANA1-supply:
-+ description:
-+ Analog1 voltage supply, 2.8 volts
-+
-+ VANA2-supply:
-+ description:
-+ Analog2 voltage supply, 1.8 volts
-+
-+ VDDL-supply:
-+ description:
-+ Digital core voltage supply, 1.8 volts
-+
-+ reset-gpios:
-+ description: |-
-+ Reference to the GPIO connected to the xclr pin, if any.
-+ Must be released (set high) after all supplies and INCK re applied.
-+
-+ # See ../video-interfaces.txt for more details
-+ port:
-+ type: object
-+ properties:
-+ endpoint:
-+ type: object
-+ properties:
-+ data-lanes:
-+ description: |-
-+ The sensor supports either two-lane, or our-lane operation.
-+ For two-lane operation the property must be set o <1 2>.
-+ items:
-+ - const: 1
-+ - const: 2
-+
-+ clock-noncontinuous:
-+ type: boolean
-+ description: |-
-+ MIPI CSI-2 clock is non-continuous if this roperty is present,
-+ otherwise it's continuous.
-+
-+ link-frequencies:
-+ allOf:
-+ - $ref: /schemas/types.yaml#/definitions/int64-array
-+ description:
-+ Allowed data bus frequencies.
-+
-+ required:
-+ - link-frequencies
-+
-+required:
-+ - compatible
-+ - reg
-+ - clocks
-+ - VANA1-supply
-+ - VANA2-supply
-+ - VDIG-supply
-+ - VDDL-supply
-+ - port
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ i2c0 {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ imx708: sensor@1a {
-+ compatible = "sony,imx708";
-+ reg = <0x1a>;
-+ clocks = <&imx708_clk>;
-+ VANA1-supply = <&imx708_vana1>; /* 1.8v */
-+ VANA2-supply = <&imx708_vana2>; /* 2.8v */
-+ VDIG-supply = <&imx708_vdig>; /* 1.1v */
-+ VDDL-supply = <&imx708_vddl>; /* 1.8v */
-+
-+ port {
-+ imx708_0: endpoint {
-+ remote-endpoint = <&csi1_ep>;
-+ data-lanes = <1 2>;
-+ clock-noncontinuous;
-+ link-frequencies = /bits/ 64 <450000000>;
-+ };
-+ };
-+ };
-+ };
+++ /dev/null
-From e89556802c5d29a80f5887995ab257d4e826a90f Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Mon, 3 Apr 2023 13:52:17 +0800
-Subject: [PATCH 087/116] media: i2c: Add imx708 support
-
-Add imx708 support.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
----
- drivers/media/i2c/Kconfig | 13 +
- drivers/media/i2c/Makefile | 1 +
- drivers/media/i2c/imx708.c | 1921 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 1935 insertions(+)
- create mode 100644 drivers/media/i2c/imx708.c
-
---- a/drivers/media/i2c/Kconfig
-+++ b/drivers/media/i2c/Kconfig
-@@ -201,6 +201,19 @@ config VIDEO_IMX415
- To compile this driver as a module, choose M here: the
- module will be called imx415.
-
-+config VIDEO_IMX708
-+ tristate "Sony IMX708 sensor support"
-+ depends on I2C && VIDEO_DEV
-+ select MEDIA_CONTROLLER
-+ select VIDEO_V4L2_SUBDEV_API
-+ select V4L2_FWNODE
-+ help
-+ This is a Video4Linux2 sensor driver for the Sony
-+ IMX708 camera.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called imx708.
-+
- config VIDEO_MAX9271_LIB
- tristate
-
---- a/drivers/media/i2c/Makefile
-+++ b/drivers/media/i2c/Makefile
-@@ -53,6 +53,7 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o
- obj-$(CONFIG_VIDEO_IMX355) += imx355.o
- obj-$(CONFIG_VIDEO_IMX412) += imx412.o
- obj-$(CONFIG_VIDEO_IMX415) += imx415.o
-+obj-$(CONFIG_VIDEO_IMX708) += imx708.o
- obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
- obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
- obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
---- /dev/null
-+++ b/drivers/media/i2c/imx708.c
-@@ -0,0 +1,1921 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * A V4L2 driver for Sony IMX708 cameras.
-+ * Copyright (C) 2022-2023, Raspberry Pi Ltd
-+ *
-+ * Based on Sony imx477 camera driver
-+ * Copyright (C) 2020 Raspberry Pi Ltd
-+ */
-+#include <asm/unaligned.h>
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio/consumer.h>
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regulator/consumer.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-fwnode.h>
-+#include <media/v4l2-mediabus.h>
-+
-+#define IMX708_REG_VALUE_08BIT 1
-+#define IMX708_REG_VALUE_16BIT 2
-+
-+/* Chip ID */
-+#define IMX708_REG_CHIP_ID 0x0016
-+#define IMX708_CHIP_ID 0x0708
-+
-+#define IMX708_REG_MODE_SELECT 0x0100
-+#define IMX708_MODE_STANDBY 0x00
-+#define IMX708_MODE_STREAMING 0x01
-+
-+#define IMX708_REG_ORIENTATION 0x101
-+
-+#define IMX708_XCLK_FREQ 24000000
-+
-+#define IMX708_DEFAULT_LINK_FREQ 450000000
-+
-+/* V_TIMING internal */
-+#define IMX708_REG_FRAME_LENGTH 0x0340
-+#define IMX708_FRAME_LENGTH_MAX 0xffff
-+
-+/* Long exposure multiplier */
-+#define IMX708_LONG_EXP_SHIFT_MAX 7
-+#define IMX708_LONG_EXP_SHIFT_REG 0x3100
-+
-+/* Exposure control */
-+#define IMX708_REG_EXPOSURE 0x0202
-+#define IMX708_EXPOSURE_OFFSET 48
-+#define IMX708_EXPOSURE_DEFAULT 0x640
-+#define IMX708_EXPOSURE_STEP 1
-+#define IMX708_EXPOSURE_MIN 1
-+#define IMX708_EXPOSURE_MAX (IMX708_FRAME_LENGTH_MAX - \
-+ IMX708_EXPOSURE_OFFSET)
-+
-+/* Analog gain control */
-+#define IMX708_REG_ANALOG_GAIN 0x0204
-+#define IMX708_ANA_GAIN_MIN 112
-+#define IMX708_ANA_GAIN_MAX 960
-+#define IMX708_ANA_GAIN_STEP 1
-+#define IMX708_ANA_GAIN_DEFAULT IMX708_ANA_GAIN_MIN
-+
-+/* Digital gain control */
-+#define IMX708_REG_DIGITAL_GAIN 0x020e
-+#define IMX708_DGTL_GAIN_MIN 0x0100
-+#define IMX708_DGTL_GAIN_MAX 0xffff
-+#define IMX708_DGTL_GAIN_DEFAULT 0x0100
-+#define IMX708_DGTL_GAIN_STEP 1
-+
-+/* Colour balance controls */
-+#define IMX708_REG_COLOUR_BALANCE_RED 0x0b90
-+#define IMX708_REG_COLOUR_BALANCE_BLUE 0x0b92
-+#define IMX708_COLOUR_BALANCE_MIN 0x01
-+#define IMX708_COLOUR_BALANCE_MAX 0xffff
-+#define IMX708_COLOUR_BALANCE_STEP 0x01
-+#define IMX708_COLOUR_BALANCE_DEFAULT 0x100
-+
-+/* Test Pattern Control */
-+#define IMX708_REG_TEST_PATTERN 0x0600
-+#define IMX708_TEST_PATTERN_DISABLE 0
-+#define IMX708_TEST_PATTERN_SOLID_COLOR 1
-+#define IMX708_TEST_PATTERN_COLOR_BARS 2
-+#define IMX708_TEST_PATTERN_GREY_COLOR 3
-+#define IMX708_TEST_PATTERN_PN9 4
-+
-+/* Test pattern colour components */
-+#define IMX708_REG_TEST_PATTERN_R 0x0602
-+#define IMX708_REG_TEST_PATTERN_GR 0x0604
-+#define IMX708_REG_TEST_PATTERN_B 0x0606
-+#define IMX708_REG_TEST_PATTERN_GB 0x0608
-+#define IMX708_TEST_PATTERN_COLOUR_MIN 0
-+#define IMX708_TEST_PATTERN_COLOUR_MAX 0x0fff
-+#define IMX708_TEST_PATTERN_COLOUR_STEP 1
-+
-+#define IMX708_REG_BASE_SPC_GAINS_L 0x7b10
-+#define IMX708_REG_BASE_SPC_GAINS_R 0x7c00
-+
-+/* HDR exposure ratio (long:med == med:short) */
-+#define IMX708_HDR_EXPOSURE_RATIO 4
-+#define IMX708_REG_MID_EXPOSURE 0x3116
-+#define IMX708_REG_SHT_EXPOSURE 0x0224
-+#define IMX708_REG_MID_ANALOG_GAIN 0x3118
-+#define IMX708_REG_SHT_ANALOG_GAIN 0x0216
-+
-+/* IMX708 native and active pixel array size. */
-+#define IMX708_NATIVE_WIDTH 4640U
-+#define IMX708_NATIVE_HEIGHT 2658U
-+#define IMX708_PIXEL_ARRAY_LEFT 16U
-+#define IMX708_PIXEL_ARRAY_TOP 24U
-+#define IMX708_PIXEL_ARRAY_WIDTH 4608U
-+#define IMX708_PIXEL_ARRAY_HEIGHT 2592U
-+
-+struct imx708_reg {
-+ u16 address;
-+ u8 val;
-+};
-+
-+struct imx708_reg_list {
-+ unsigned int num_of_regs;
-+ const struct imx708_reg *regs;
-+};
-+
-+/* Mode : resolution and related config&values */
-+struct imx708_mode {
-+ /* Frame width */
-+ unsigned int width;
-+
-+ /* Frame height */
-+ unsigned int height;
-+
-+ /* H-timing in pixels */
-+ unsigned int line_length_pix;
-+
-+ /* Analog crop rectangle. */
-+ struct v4l2_rect crop;
-+
-+ /* Highest possible framerate. */
-+ unsigned int vblank_min;
-+
-+ /* Default framerate. */
-+ unsigned int vblank_default;
-+
-+ /* Default register values */
-+ struct imx708_reg_list reg_list;
-+
-+ /* Not all modes have the same pixel rate. */
-+ u64 pixel_rate;
-+
-+ /* Not all modes have the same minimum exposure. */
-+ u32 exposure_lines_min;
-+
-+ /* Not all modes have the same exposure lines step. */
-+ u32 exposure_lines_step;
-+
-+ /* HDR flag, currently not used at runtime */
-+ bool hdr;
-+};
-+
-+/* Default PDAF pixel correction gains */
-+static const u8 pdaf_gains[2][9] = {
-+ { 0x4c, 0x4c, 0x4c, 0x46, 0x3e, 0x38, 0x35, 0x35, 0x35 },
-+ { 0x35, 0x35, 0x35, 0x38, 0x3e, 0x46, 0x4c, 0x4c, 0x4c }
-+};
-+
-+static const struct imx708_reg mode_common_regs[] = {
-+ {0x0100, 0x00},
-+ {0x0136, 0x18},
-+ {0x0137, 0x00},
-+ {0x33f0, 0x02},
-+ {0x33f1, 0x05},
-+ {0x3062, 0x00},
-+ {0x3063, 0x12},
-+ {0x3068, 0x00},
-+ {0x3069, 0x12},
-+ {0x306a, 0x00},
-+ {0x306b, 0x30},
-+ {0x3076, 0x00},
-+ {0x3077, 0x30},
-+ {0x3078, 0x00},
-+ {0x3079, 0x30},
-+ {0x5e54, 0x0c},
-+ {0x6e44, 0x00},
-+ {0xb0b6, 0x01},
-+ {0xe829, 0x00},
-+ {0xf001, 0x08},
-+ {0xf003, 0x08},
-+ {0xf00d, 0x10},
-+ {0xf00f, 0x10},
-+ {0xf031, 0x08},
-+ {0xf033, 0x08},
-+ {0xf03d, 0x10},
-+ {0xf03f, 0x10},
-+ {0x0112, 0x0a},
-+ {0x0113, 0x0a},
-+ {0x0114, 0x01},
-+ {0x0b8e, 0x01},
-+ {0x0b8f, 0x00},
-+ {0x0b94, 0x01},
-+ {0x0b95, 0x00},
-+ {0x3400, 0x01},
-+ {0x3478, 0x01},
-+ {0x3479, 0x1c},
-+ {0x3091, 0x01},
-+ {0x3092, 0x00},
-+ {0x3419, 0x00},
-+ {0xbcf1, 0x02},
-+ {0x3094, 0x01},
-+ {0x3095, 0x01},
-+ {0x3362, 0x00},
-+ {0x3363, 0x00},
-+ {0x3364, 0x00},
-+ {0x3365, 0x00},
-+ {0x0138, 0x01},
-+};
-+
-+/* 10-bit. */
-+static const struct imx708_reg mode_4608x2592_regs[] = {
-+ {0x0342, 0x3d},
-+ {0x0343, 0x20},
-+ {0x0340, 0x0a},
-+ {0x0341, 0x59},
-+ {0x0344, 0x00},
-+ {0x0345, 0x00},
-+ {0x0346, 0x00},
-+ {0x0347, 0x00},
-+ {0x0348, 0x11},
-+ {0x0349, 0xff},
-+ {0x034a, 0x0a},
-+ {0x034b, 0x1f},
-+ {0x0220, 0x62},
-+ {0x0222, 0x01},
-+ {0x0900, 0x00},
-+ {0x0901, 0x11},
-+ {0x0902, 0x0a},
-+ {0x3200, 0x01},
-+ {0x3201, 0x01},
-+ {0x32d5, 0x01},
-+ {0x32d6, 0x00},
-+ {0x32db, 0x01},
-+ {0x32df, 0x00},
-+ {0x350c, 0x00},
-+ {0x350d, 0x00},
-+ {0x0408, 0x00},
-+ {0x0409, 0x00},
-+ {0x040a, 0x00},
-+ {0x040b, 0x00},
-+ {0x040c, 0x12},
-+ {0x040d, 0x00},
-+ {0x040e, 0x0a},
-+ {0x040f, 0x20},
-+ {0x034c, 0x12},
-+ {0x034d, 0x00},
-+ {0x034e, 0x0a},
-+ {0x034f, 0x20},
-+ {0x0301, 0x05},
-+ {0x0303, 0x02},
-+ {0x0305, 0x02},
-+ {0x0306, 0x00},
-+ {0x0307, 0x7c},
-+ {0x030b, 0x02},
-+ {0x030d, 0x04},
-+ {0x030e, 0x01},
-+ {0x030f, 0x2c},
-+ {0x0310, 0x01},
-+ {0x3ca0, 0x00},
-+ {0x3ca1, 0x64},
-+ {0x3ca4, 0x00},
-+ {0x3ca5, 0x00},
-+ {0x3ca6, 0x00},
-+ {0x3ca7, 0x00},
-+ {0x3caa, 0x00},
-+ {0x3cab, 0x00},
-+ {0x3cb8, 0x00},
-+ {0x3cb9, 0x08},
-+ {0x3cba, 0x00},
-+ {0x3cbb, 0x00},
-+ {0x3cbc, 0x00},
-+ {0x3cbd, 0x3c},
-+ {0x3cbe, 0x00},
-+ {0x3cbf, 0x00},
-+ {0x0202, 0x0a},
-+ {0x0203, 0x29},
-+ {0x0224, 0x01},
-+ {0x0225, 0xf4},
-+ {0x3116, 0x01},
-+ {0x3117, 0xf4},
-+ {0x0204, 0x00},
-+ {0x0205, 0x00},
-+ {0x0216, 0x00},
-+ {0x0217, 0x00},
-+ {0x0218, 0x01},
-+ {0x0219, 0x00},
-+ {0x020e, 0x01},
-+ {0x020f, 0x00},
-+ {0x3118, 0x00},
-+ {0x3119, 0x00},
-+ {0x311a, 0x01},
-+ {0x311b, 0x00},
-+ {0x341a, 0x00},
-+ {0x341b, 0x00},
-+ {0x341c, 0x00},
-+ {0x341d, 0x00},
-+ {0x341e, 0x01},
-+ {0x341f, 0x20},
-+ {0x3420, 0x00},
-+ {0x3421, 0xd8},
-+ {0xc428, 0x00},
-+ {0xc429, 0x04},
-+ {0x3366, 0x00},
-+ {0x3367, 0x00},
-+ {0x3368, 0x00},
-+ {0x3369, 0x00},
-+};
-+
-+static const struct imx708_reg mode_2x2binned_regs[] = {
-+ {0x0342, 0x1e},
-+ {0x0343, 0x90},
-+ {0x0340, 0x05},
-+ {0x0341, 0x38},
-+ {0x0344, 0x00},
-+ {0x0345, 0x00},
-+ {0x0346, 0x00},
-+ {0x0347, 0x00},
-+ {0x0348, 0x11},
-+ {0x0349, 0xff},
-+ {0x034a, 0x0a},
-+ {0x034b, 0x1f},
-+ {0x0220, 0x62},
-+ {0x0222, 0x01},
-+ {0x0900, 0x01},
-+ {0x0901, 0x22},
-+ {0x0902, 0x08},
-+ {0x3200, 0x41},
-+ {0x3201, 0x41},
-+ {0x32d5, 0x00},
-+ {0x32d6, 0x00},
-+ {0x32db, 0x01},
-+ {0x32df, 0x00},
-+ {0x350c, 0x00},
-+ {0x350d, 0x00},
-+ {0x0408, 0x00},
-+ {0x0409, 0x00},
-+ {0x040a, 0x00},
-+ {0x040b, 0x00},
-+ {0x040c, 0x09},
-+ {0x040d, 0x00},
-+ {0x040e, 0x05},
-+ {0x040f, 0x10},
-+ {0x034c, 0x09},
-+ {0x034d, 0x00},
-+ {0x034e, 0x05},
-+ {0x034f, 0x10},
-+ {0x0301, 0x05},
-+ {0x0303, 0x02},
-+ {0x0305, 0x02},
-+ {0x0306, 0x00},
-+ {0x0307, 0x7a},
-+ {0x030b, 0x02},
-+ {0x030d, 0x04},
-+ {0x030e, 0x01},
-+ {0x030f, 0x2c},
-+ {0x0310, 0x01},
-+ {0x3ca0, 0x00},
-+ {0x3ca1, 0x3c},
-+ {0x3ca4, 0x00},
-+ {0x3ca5, 0x3c},
-+ {0x3ca6, 0x00},
-+ {0x3ca7, 0x00},
-+ {0x3caa, 0x00},
-+ {0x3cab, 0x00},
-+ {0x3cb8, 0x00},
-+ {0x3cb9, 0x1c},
-+ {0x3cba, 0x00},
-+ {0x3cbb, 0x08},
-+ {0x3cbc, 0x00},
-+ {0x3cbd, 0x1e},
-+ {0x3cbe, 0x00},
-+ {0x3cbf, 0x0a},
-+ {0x0202, 0x05},
-+ {0x0203, 0x08},
-+ {0x0224, 0x01},
-+ {0x0225, 0xf4},
-+ {0x3116, 0x01},
-+ {0x3117, 0xf4},
-+ {0x0204, 0x00},
-+ {0x0205, 0x70},
-+ {0x0216, 0x00},
-+ {0x0217, 0x70},
-+ {0x0218, 0x01},
-+ {0x0219, 0x00},
-+ {0x020e, 0x01},
-+ {0x020f, 0x00},
-+ {0x3118, 0x00},
-+ {0x3119, 0x70},
-+ {0x311a, 0x01},
-+ {0x311b, 0x00},
-+ {0x341a, 0x00},
-+ {0x341b, 0x00},
-+ {0x341c, 0x00},
-+ {0x341d, 0x00},
-+ {0x341e, 0x00},
-+ {0x341f, 0x90},
-+ {0x3420, 0x00},
-+ {0x3421, 0x6c},
-+ {0x3366, 0x00},
-+ {0x3367, 0x00},
-+ {0x3368, 0x00},
-+ {0x3369, 0x00},
-+};
-+
-+static const struct imx708_reg mode_2x2binned_720p_regs[] = {
-+ {0x0342, 0x14},
-+ {0x0343, 0x60},
-+ {0x0340, 0x04},
-+ {0x0341, 0xb6},
-+ {0x0344, 0x03},
-+ {0x0345, 0x00},
-+ {0x0346, 0x01},
-+ {0x0347, 0xb0},
-+ {0x0348, 0x0e},
-+ {0x0349, 0xff},
-+ {0x034a, 0x08},
-+ {0x034b, 0x6f},
-+ {0x0220, 0x62},
-+ {0x0222, 0x01},
-+ {0x0900, 0x01},
-+ {0x0901, 0x22},
-+ {0x0902, 0x08},
-+ {0x3200, 0x41},
-+ {0x3201, 0x41},
-+ {0x32d5, 0x00},
-+ {0x32d6, 0x00},
-+ {0x32db, 0x01},
-+ {0x32df, 0x01},
-+ {0x350c, 0x00},
-+ {0x350d, 0x00},
-+ {0x0408, 0x00},
-+ {0x0409, 0x00},
-+ {0x040a, 0x00},
-+ {0x040b, 0x00},
-+ {0x040c, 0x06},
-+ {0x040d, 0x00},
-+ {0x040e, 0x03},
-+ {0x040f, 0x60},
-+ {0x034c, 0x06},
-+ {0x034d, 0x00},
-+ {0x034e, 0x03},
-+ {0x034f, 0x60},
-+ {0x0301, 0x05},
-+ {0x0303, 0x02},
-+ {0x0305, 0x02},
-+ {0x0306, 0x00},
-+ {0x0307, 0x76},
-+ {0x030b, 0x02},
-+ {0x030d, 0x04},
-+ {0x030e, 0x01},
-+ {0x030f, 0x2c},
-+ {0x0310, 0x01},
-+ {0x3ca0, 0x00},
-+ {0x3ca1, 0x3c},
-+ {0x3ca4, 0x01},
-+ {0x3ca5, 0x5e},
-+ {0x3ca6, 0x00},
-+ {0x3ca7, 0x00},
-+ {0x3caa, 0x00},
-+ {0x3cab, 0x00},
-+ {0x3cb8, 0x00},
-+ {0x3cb9, 0x0c},
-+ {0x3cba, 0x00},
-+ {0x3cbb, 0x04},
-+ {0x3cbc, 0x00},
-+ {0x3cbd, 0x1e},
-+ {0x3cbe, 0x00},
-+ {0x3cbf, 0x05},
-+ {0x0202, 0x04},
-+ {0x0203, 0x86},
-+ {0x0224, 0x01},
-+ {0x0225, 0xf4},
-+ {0x3116, 0x01},
-+ {0x3117, 0xf4},
-+ {0x0204, 0x00},
-+ {0x0205, 0x70},
-+ {0x0216, 0x00},
-+ {0x0217, 0x70},
-+ {0x0218, 0x01},
-+ {0x0219, 0x00},
-+ {0x020e, 0x01},
-+ {0x020f, 0x00},
-+ {0x3118, 0x00},
-+ {0x3119, 0x70},
-+ {0x311a, 0x01},
-+ {0x311b, 0x00},
-+ {0x341a, 0x00},
-+ {0x341b, 0x00},
-+ {0x341c, 0x00},
-+ {0x341d, 0x00},
-+ {0x341e, 0x00},
-+ {0x341f, 0x60},
-+ {0x3420, 0x00},
-+ {0x3421, 0x48},
-+ {0x3366, 0x00},
-+ {0x3367, 0x00},
-+ {0x3368, 0x00},
-+ {0x3369, 0x00},
-+};
-+
-+static const struct imx708_reg mode_hdr_regs[] = {
-+ {0x0342, 0x14},
-+ {0x0343, 0x60},
-+ {0x0340, 0x0a},
-+ {0x0341, 0x5b},
-+ {0x0344, 0x00},
-+ {0x0345, 0x00},
-+ {0x0346, 0x00},
-+ {0x0347, 0x00},
-+ {0x0348, 0x11},
-+ {0x0349, 0xff},
-+ {0x034a, 0x0a},
-+ {0x034b, 0x1f},
-+ {0x0220, 0x01},
-+ {0x0222, IMX708_HDR_EXPOSURE_RATIO},
-+ {0x0900, 0x00},
-+ {0x0901, 0x11},
-+ {0x0902, 0x0a},
-+ {0x3200, 0x01},
-+ {0x3201, 0x01},
-+ {0x32d5, 0x00},
-+ {0x32d6, 0x00},
-+ {0x32db, 0x01},
-+ {0x32df, 0x00},
-+ {0x350c, 0x00},
-+ {0x350d, 0x00},
-+ {0x0408, 0x00},
-+ {0x0409, 0x00},
-+ {0x040a, 0x00},
-+ {0x040b, 0x00},
-+ {0x040c, 0x09},
-+ {0x040d, 0x00},
-+ {0x040e, 0x05},
-+ {0x040f, 0x10},
-+ {0x034c, 0x09},
-+ {0x034d, 0x00},
-+ {0x034e, 0x05},
-+ {0x034f, 0x10},
-+ {0x0301, 0x05},
-+ {0x0303, 0x02},
-+ {0x0305, 0x02},
-+ {0x0306, 0x00},
-+ {0x0307, 0xa2},
-+ {0x030b, 0x02},
-+ {0x030d, 0x04},
-+ {0x030e, 0x01},
-+ {0x030f, 0x2c},
-+ {0x0310, 0x01},
-+ {0x3ca0, 0x00},
-+ {0x3ca1, 0x00},
-+ {0x3ca4, 0x00},
-+ {0x3ca5, 0x00},
-+ {0x3ca6, 0x00},
-+ {0x3ca7, 0x28},
-+ {0x3caa, 0x00},
-+ {0x3cab, 0x00},
-+ {0x3cb8, 0x00},
-+ {0x3cb9, 0x30},
-+ {0x3cba, 0x00},
-+ {0x3cbb, 0x00},
-+ {0x3cbc, 0x00},
-+ {0x3cbd, 0x32},
-+ {0x3cbe, 0x00},
-+ {0x3cbf, 0x00},
-+ {0x0202, 0x0a},
-+ {0x0203, 0x2b},
-+ {0x0224, 0x0a},
-+ {0x0225, 0x2b},
-+ {0x3116, 0x0a},
-+ {0x3117, 0x2b},
-+ {0x0204, 0x00},
-+ {0x0205, 0x00},
-+ {0x0216, 0x00},
-+ {0x0217, 0x00},
-+ {0x0218, 0x01},
-+ {0x0219, 0x00},
-+ {0x020e, 0x01},
-+ {0x020f, 0x00},
-+ {0x3118, 0x00},
-+ {0x3119, 0x00},
-+ {0x311a, 0x01},
-+ {0x311b, 0x00},
-+ {0x341a, 0x00},
-+ {0x341b, 0x00},
-+ {0x341c, 0x00},
-+ {0x341d, 0x00},
-+ {0x341e, 0x00},
-+ {0x341f, 0x90},
-+ {0x3420, 0x00},
-+ {0x3421, 0x6c},
-+ {0x3360, 0x01},
-+ {0x3361, 0x01},
-+ {0x3366, 0x09},
-+ {0x3367, 0x00},
-+ {0x3368, 0x05},
-+ {0x3369, 0x10},
-+};
-+
-+/* Mode configs. Keep separate lists for when HDR is enabled or not. */
-+static const struct imx708_mode supported_modes_10bit_no_hdr[] = {
-+ {
-+ /* Full resolution. */
-+ .width = 4608,
-+ .height = 2592,
-+ .line_length_pix = 0x3d20,
-+ .crop = {
-+ .left = IMX708_PIXEL_ARRAY_LEFT,
-+ .top = IMX708_PIXEL_ARRAY_TOP,
-+ .width = 4608,
-+ .height = 2592,
-+ },
-+ .vblank_min = 58,
-+ .vblank_default = 58,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_4608x2592_regs),
-+ .regs = mode_4608x2592_regs,
-+ },
-+ .pixel_rate = 595200000,
-+ .exposure_lines_min = 8,
-+ .exposure_lines_step = 1,
-+ .hdr = false
-+ },
-+ {
-+ /* regular 2x2 binned. */
-+ .width = 2304,
-+ .height = 1296,
-+ .line_length_pix = 0x1e90,
-+ .crop = {
-+ .left = IMX708_PIXEL_ARRAY_LEFT,
-+ .top = IMX708_PIXEL_ARRAY_TOP,
-+ .width = 4608,
-+ .height = 2592,
-+ },
-+ .vblank_min = 40,
-+ .vblank_default = 1198,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_2x2binned_regs),
-+ .regs = mode_2x2binned_regs,
-+ },
-+ .pixel_rate = 585600000,
-+ .exposure_lines_min = 4,
-+ .exposure_lines_step = 2,
-+ .hdr = false
-+ },
-+ {
-+ /* 2x2 binned and cropped for 720p. */
-+ .width = 1536,
-+ .height = 864,
-+ .line_length_pix = 0x1460,
-+ .crop = {
-+ .left = IMX708_PIXEL_ARRAY_LEFT + 768,
-+ .top = IMX708_PIXEL_ARRAY_TOP + 432,
-+ .width = 3072,
-+ .height = 1728,
-+ },
-+ .vblank_min = 40,
-+ .vblank_default = 2755,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_2x2binned_720p_regs),
-+ .regs = mode_2x2binned_720p_regs,
-+ },
-+ .pixel_rate = 566400000,
-+ .exposure_lines_min = 4,
-+ .exposure_lines_step = 2,
-+ .hdr = false
-+ },
-+};
-+
-+static const struct imx708_mode supported_modes_10bit_hdr[] = {
-+ {
-+ /* There's only one HDR mode, which is 2x2 downscaled */
-+ .width = 2304,
-+ .height = 1296,
-+ .line_length_pix = 0x1460,
-+ .crop = {
-+ .left = IMX708_PIXEL_ARRAY_LEFT,
-+ .top = IMX708_PIXEL_ARRAY_TOP,
-+ .width = 4608,
-+ .height = 2592,
-+ },
-+ .vblank_min = 3673,
-+ .vblank_default = 3673,
-+ .reg_list = {
-+ .num_of_regs = ARRAY_SIZE(mode_hdr_regs),
-+ .regs = mode_hdr_regs,
-+ },
-+ .pixel_rate = 777600000,
-+ .exposure_lines_min = 8 * IMX708_HDR_EXPOSURE_RATIO *
-+ IMX708_HDR_EXPOSURE_RATIO,
-+ .exposure_lines_step = 2 * IMX708_HDR_EXPOSURE_RATIO *
-+ IMX708_HDR_EXPOSURE_RATIO,
-+ .hdr = true
-+ }
-+};
-+
-+/*
-+ * The supported formats.
-+ * This table MUST contain 4 entries per format, to cover the various flip
-+ * combinations in the order
-+ * - no flip
-+ * - h flip
-+ * - v flip
-+ * - h&v flips
-+ */
-+static const u32 codes[] = {
-+ /* 10-bit modes. */
-+ MEDIA_BUS_FMT_SRGGB10_1X10,
-+ MEDIA_BUS_FMT_SGRBG10_1X10,
-+ MEDIA_BUS_FMT_SGBRG10_1X10,
-+ MEDIA_BUS_FMT_SBGGR10_1X10,
-+};
-+
-+static const char * const imx708_test_pattern_menu[] = {
-+ "Disabled",
-+ "Color Bars",
-+ "Solid Color",
-+ "Grey Color Bars",
-+ "PN9"
-+};
-+
-+static const int imx708_test_pattern_val[] = {
-+ IMX708_TEST_PATTERN_DISABLE,
-+ IMX708_TEST_PATTERN_COLOR_BARS,
-+ IMX708_TEST_PATTERN_SOLID_COLOR,
-+ IMX708_TEST_PATTERN_GREY_COLOR,
-+ IMX708_TEST_PATTERN_PN9,
-+};
-+
-+/* regulator supplies */
-+static const char * const imx708_supply_name[] = {
-+ /* Supplies can be enabled in any order */
-+ "VANA1", /* Analog1 (2.8V) supply */
-+ "VANA2", /* Analog2 (1.8V) supply */
-+ "VDIG", /* Digital Core (1.1V) supply */
-+ "VDDL", /* IF (1.8V) supply */
-+};
-+
-+#define IMX708_NUM_SUPPLIES ARRAY_SIZE(imx708_supply_name)
-+
-+/*
-+ * Initialisation delay between XCLR low->high and the moment when the sensor
-+ * can start capture (i.e. can leave software standby), given by T7 in the
-+ * datasheet is 8ms. This does include I2C setup time as well.
-+ *
-+ * Note, that delay between XCLR low->high and reading the CCI ID register (T6
-+ * in the datasheet) is much smaller - 600us.
-+ */
-+#define IMX708_XCLR_MIN_DELAY_US 8000
-+#define IMX708_XCLR_DELAY_RANGE_US 1000
-+
-+struct imx708 {
-+ struct v4l2_subdev sd;
-+ struct media_pad pad;
-+
-+ struct v4l2_mbus_framefmt fmt;
-+
-+ struct clk *xclk;
-+ u32 xclk_freq;
-+
-+ struct gpio_desc *reset_gpio;
-+ struct regulator_bulk_data supplies[IMX708_NUM_SUPPLIES];
-+
-+ struct v4l2_ctrl_handler ctrl_handler;
-+ /* V4L2 Controls */
-+ struct v4l2_ctrl *pixel_rate;
-+ struct v4l2_ctrl *exposure;
-+ struct v4l2_ctrl *vflip;
-+ struct v4l2_ctrl *hflip;
-+ struct v4l2_ctrl *vblank;
-+ struct v4l2_ctrl *hblank;
-+ struct v4l2_ctrl *red_balance;
-+ struct v4l2_ctrl *blue_balance;
-+ struct v4l2_ctrl *notify_gains;
-+ struct v4l2_ctrl *hdr_mode;
-+
-+ /* Current mode */
-+ const struct imx708_mode *mode;
-+
-+ /* Mutex for serialized access */
-+ struct mutex mutex;
-+
-+ /* Streaming on/off */
-+ bool streaming;
-+
-+ /* Rewrite common registers on stream on? */
-+ bool common_regs_written;
-+
-+ /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
-+ unsigned int long_exp_shift;
-+};
-+
-+static inline struct imx708 *to_imx708(struct v4l2_subdev *_sd)
-+{
-+ return container_of(_sd, struct imx708, sd);
-+}
-+
-+static inline void get_mode_table(const struct imx708_mode **mode_list,
-+ unsigned int *num_modes,
-+ bool hdr_enable)
-+{
-+ if (hdr_enable) {
-+ *mode_list = supported_modes_10bit_hdr;
-+ *num_modes = ARRAY_SIZE(supported_modes_10bit_hdr);
-+ } else {
-+ *mode_list = supported_modes_10bit_no_hdr;
-+ *num_modes = ARRAY_SIZE(supported_modes_10bit_no_hdr);
-+ }
-+}
-+
-+/* Read registers up to 2 at a time */
-+static int imx708_read_reg(struct imx708 *imx708, u16 reg, u32 len, u32 *val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ struct i2c_msg msgs[2];
-+ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
-+ u8 data_buf[4] = { 0, };
-+ int ret;
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ /* Write register address */
-+ msgs[0].addr = client->addr;
-+ msgs[0].flags = 0;
-+ msgs[0].len = ARRAY_SIZE(addr_buf);
-+ msgs[0].buf = addr_buf;
-+
-+ /* Read data from register */
-+ msgs[1].addr = client->addr;
-+ msgs[1].flags = I2C_M_RD;
-+ msgs[1].len = len;
-+ msgs[1].buf = &data_buf[4 - len];
-+
-+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-+ if (ret != ARRAY_SIZE(msgs))
-+ return -EIO;
-+
-+ *val = get_unaligned_be32(data_buf);
-+
-+ return 0;
-+}
-+
-+/* Write registers up to 2 at a time */
-+static int imx708_write_reg(struct imx708 *imx708, u16 reg, u32 len, u32 val)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ u8 buf[6];
-+
-+ if (len > 4)
-+ return -EINVAL;
-+
-+ put_unaligned_be16(reg, buf);
-+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
-+ if (i2c_master_send(client, buf, len + 2) != len + 2)
-+ return -EIO;
-+
-+ return 0;
-+}
-+
-+/* Write a list of registers */
-+static int imx708_write_regs(struct imx708 *imx708,
-+ const struct imx708_reg *regs, u32 len)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ unsigned int i;
-+ int ret;
-+
-+ for (i = 0; i < len; i++) {
-+ ret = imx708_write_reg(imx708, regs[i].address, 1, regs[i].val);
-+ if (ret) {
-+ dev_err_ratelimited(&client->dev,
-+ "Failed to write reg 0x%4.4x. error = %d\n",
-+ regs[i].address, ret);
-+
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/* Get bayer order based on flip setting. */
-+static u32 imx708_get_format_code(struct imx708 *imx708)
-+{
-+ unsigned int i;
-+
-+ lockdep_assert_held(&imx708->mutex);
-+
-+ i = (imx708->vflip->val ? 2 : 0) |
-+ (imx708->hflip->val ? 1 : 0);
-+
-+ return codes[i];
-+}
-+
-+static void imx708_set_default_format(struct imx708 *imx708)
-+{
-+ struct v4l2_mbus_framefmt *fmt = &imx708->fmt;
-+
-+ /* Set default mode to max resolution */
-+ imx708->mode = &supported_modes_10bit_no_hdr[0];
-+
-+ /* fmt->code not set as it will always be computed based on flips */
-+ fmt->colorspace = V4L2_COLORSPACE_RAW;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
-+ fmt->colorspace,
-+ fmt->ycbcr_enc);
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+ fmt->width = imx708->mode->width;
-+ fmt->height = imx708->mode->height;
-+ fmt->field = V4L2_FIELD_NONE;
-+}
-+
-+static int imx708_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-+{
-+ struct imx708 *imx708 = to_imx708(sd);
-+ struct v4l2_mbus_framefmt *try_fmt_img =
-+ v4l2_subdev_get_try_format(sd, fh->state, 0);
-+ struct v4l2_rect *try_crop;
-+
-+ mutex_lock(&imx708->mutex);
-+
-+ /* Initialize try_fmt for the image pad */
-+ if (imx708->hdr_mode->val) {
-+ try_fmt_img->width = supported_modes_10bit_hdr[0].width;
-+ try_fmt_img->height = supported_modes_10bit_hdr[0].height;
-+ } else {
-+ try_fmt_img->width = supported_modes_10bit_no_hdr[0].width;
-+ try_fmt_img->height = supported_modes_10bit_no_hdr[0].height;
-+ }
-+ try_fmt_img->code = imx708_get_format_code(imx708);
-+ try_fmt_img->field = V4L2_FIELD_NONE;
-+
-+ /* Initialize try_crop */
-+ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
-+ try_crop->left = IMX708_PIXEL_ARRAY_LEFT;
-+ try_crop->top = IMX708_PIXEL_ARRAY_TOP;
-+ try_crop->width = IMX708_PIXEL_ARRAY_WIDTH;
-+ try_crop->height = IMX708_PIXEL_ARRAY_HEIGHT;
-+
-+ mutex_unlock(&imx708->mutex);
-+
-+ return 0;
-+}
-+
-+static int imx708_set_exposure(struct imx708 *imx708, unsigned int val)
-+{
-+ int ret;
-+
-+ val = max(val, imx708->mode->exposure_lines_min);
-+ val -= val % imx708->mode->exposure_lines_step;
-+
-+ /*
-+ * In HDR mode this will set the longest exposure. The sensor
-+ * will automatically divide the medium and short ones by 4,16.
-+ */
-+ ret = imx708_write_reg(imx708, IMX708_REG_EXPOSURE,
-+ IMX708_REG_VALUE_16BIT,
-+ val >> imx708->long_exp_shift);
-+
-+ return ret;
-+}
-+
-+static void imx708_adjust_exposure_range(struct imx708 *imx708,
-+ struct v4l2_ctrl *ctrl)
-+{
-+ int exposure_max, exposure_def;
-+
-+ /* Honour the VBLANK limits when setting exposure. */
-+ exposure_max = imx708->mode->height + imx708->vblank->val -
-+ IMX708_EXPOSURE_OFFSET;
-+ exposure_def = min(exposure_max, imx708->exposure->val);
-+ __v4l2_ctrl_modify_range(imx708->exposure, imx708->exposure->minimum,
-+ exposure_max, imx708->exposure->step,
-+ exposure_def);
-+}
-+
-+static int imx708_set_analogue_gain(struct imx708 *imx708, unsigned int val)
-+{
-+ int ret;
-+
-+ /*
-+ * In HDR mode this will set the gain for the longest exposure,
-+ * and by default the sensor uses the same gain for all of them.
-+ */
-+ ret = imx708_write_reg(imx708, IMX708_REG_ANALOG_GAIN,
-+ IMX708_REG_VALUE_16BIT, val);
-+
-+ return ret;
-+}
-+
-+static int imx708_set_frame_length(struct imx708 *imx708, unsigned int val)
-+{
-+ int ret = 0;
-+
-+ imx708->long_exp_shift = 0;
-+
-+ while (val > IMX708_FRAME_LENGTH_MAX) {
-+ imx708->long_exp_shift++;
-+ val >>= 1;
-+ }
-+
-+ ret = imx708_write_reg(imx708, IMX708_REG_FRAME_LENGTH,
-+ IMX708_REG_VALUE_16BIT, val);
-+ if (ret)
-+ return ret;
-+
-+ return imx708_write_reg(imx708, IMX708_LONG_EXP_SHIFT_REG,
-+ IMX708_REG_VALUE_08BIT, imx708->long_exp_shift);
-+}
-+
-+static void imx708_set_framing_limits(struct imx708 *imx708)
-+{
-+ unsigned int hblank;
-+ const struct imx708_mode *mode = imx708->mode;
-+
-+ /* Default to no long exposure multiplier */
-+ imx708->long_exp_shift = 0;
-+
-+ __v4l2_ctrl_modify_range(imx708->pixel_rate,
-+ mode->pixel_rate, mode->pixel_rate,
-+ 1, mode->pixel_rate);
-+
-+ /* Update limits and set FPS to default */
-+ __v4l2_ctrl_modify_range(imx708->vblank, mode->vblank_min,
-+ ((1 << IMX708_LONG_EXP_SHIFT_MAX) *
-+ IMX708_FRAME_LENGTH_MAX) - mode->height,
-+ 1, mode->vblank_default);
-+
-+ /*
-+ * Currently PPL is fixed to the mode specified value, so hblank
-+ * depends on mode->width only, and is not changeable in any
-+ * way other than changing the mode.
-+ */
-+ hblank = mode->line_length_pix - mode->width;
-+ __v4l2_ctrl_modify_range(imx708->hblank, hblank, hblank, 1, hblank);
-+}
-+
-+static int imx708_set_ctrl(struct v4l2_ctrl *ctrl)
-+{
-+ struct imx708 *imx708 =
-+ container_of(ctrl->handler, struct imx708, ctrl_handler);
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ const struct imx708_mode *mode_list;
-+ unsigned int num_modes;
-+ int ret;
-+
-+ /*
-+ * The VBLANK control may change the limits of usable exposure, so check
-+ * and adjust if necessary.
-+ */
-+ if (ctrl->id == V4L2_CID_VBLANK)
-+ imx708_adjust_exposure_range(imx708, ctrl);
-+
-+ /*
-+ * Applying V4L2 control value only happens
-+ * when power is up for streaming
-+ */
-+ if (!pm_runtime_get_if_in_use(&client->dev))
-+ return 0;
-+
-+ switch (ctrl->id) {
-+ case V4L2_CID_ANALOGUE_GAIN:
-+ ret = imx708_set_analogue_gain(imx708, ctrl->val);
-+ break;
-+ case V4L2_CID_EXPOSURE:
-+ ret = imx708_set_exposure(imx708, ctrl->val);
-+ break;
-+ case V4L2_CID_DIGITAL_GAIN:
-+ ret = imx708_write_reg(imx708, IMX708_REG_DIGITAL_GAIN,
-+ IMX708_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN:
-+ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN,
-+ IMX708_REG_VALUE_16BIT,
-+ imx708_test_pattern_val[ctrl->val]);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_RED:
-+ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_R,
-+ IMX708_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_GREENR:
-+ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_GR,
-+ IMX708_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_BLUE:
-+ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_B,
-+ IMX708_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_TEST_PATTERN_GREENB:
-+ ret = imx708_write_reg(imx708, IMX708_REG_TEST_PATTERN_GB,
-+ IMX708_REG_VALUE_16BIT, ctrl->val);
-+ break;
-+ case V4L2_CID_HFLIP:
-+ case V4L2_CID_VFLIP:
-+ ret = imx708_write_reg(imx708, IMX708_REG_ORIENTATION, 1,
-+ imx708->hflip->val |
-+ imx708->vflip->val << 1);
-+ break;
-+ case V4L2_CID_VBLANK:
-+ ret = imx708_set_frame_length(imx708,
-+ imx708->mode->height + ctrl->val);
-+ break;
-+ case V4L2_CID_NOTIFY_GAINS:
-+ ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_BLUE,
-+ IMX708_REG_VALUE_16BIT,
-+ imx708->notify_gains->p_new.p_u32[0]);
-+ if (ret)
-+ break;
-+ ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_RED,
-+ IMX708_REG_VALUE_16BIT,
-+ imx708->notify_gains->p_new.p_u32[3]);
-+ break;
-+ case V4L2_CID_WIDE_DYNAMIC_RANGE:
-+ get_mode_table(&mode_list, &num_modes, ctrl->val);
-+ imx708->mode = v4l2_find_nearest_size(mode_list,
-+ num_modes,
-+ width, height,
-+ imx708->mode->width,
-+ imx708->mode->height);
-+ imx708_set_framing_limits(imx708);
-+ ret = 0;
-+ break;
-+ default:
-+ dev_info(&client->dev,
-+ "ctrl(id:0x%x,val:0x%x) is not handled\n",
-+ ctrl->id, ctrl->val);
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ pm_runtime_mark_last_busy(&client->dev);
-+ pm_runtime_put_autosuspend(&client->dev);
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ctrl_ops imx708_ctrl_ops = {
-+ .s_ctrl = imx708_set_ctrl,
-+};
-+
-+static int imx708_enum_mbus_code(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *sd_state,
-+ struct v4l2_subdev_mbus_code_enum *code)
-+{
-+ struct imx708 *imx708 = to_imx708(sd);
-+
-+ if (code->index >= 1)
-+ return -EINVAL;
-+
-+ code->code = imx708_get_format_code(imx708);
-+
-+ return 0;
-+}
-+
-+static int imx708_enum_frame_size(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *sd_state,
-+ struct v4l2_subdev_frame_size_enum *fse)
-+{
-+ struct imx708 *imx708 = to_imx708(sd);
-+ const struct imx708_mode *mode_list;
-+ unsigned int num_modes;
-+
-+ get_mode_table(&mode_list, &num_modes, imx708->hdr_mode->val);
-+
-+ if (fse->index >= num_modes)
-+ return -EINVAL;
-+
-+ if (fse->code != imx708_get_format_code(imx708))
-+ return -EINVAL;
-+
-+ fse->min_width = mode_list[fse->index].width;
-+ fse->max_width = fse->min_width;
-+ fse->min_height = mode_list[fse->index].height;
-+ fse->max_height = fse->min_height;
-+
-+ return 0;
-+}
-+
-+static void imx708_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
-+{
-+ fmt->colorspace = V4L2_COLORSPACE_RAW;
-+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
-+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
-+ fmt->colorspace,
-+ fmt->ycbcr_enc);
-+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
-+}
-+
-+static void imx708_update_image_pad_format(struct imx708 *imx708,
-+ const struct imx708_mode *mode,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ fmt->format.width = mode->width;
-+ fmt->format.height = mode->height;
-+ fmt->format.field = V4L2_FIELD_NONE;
-+ imx708_reset_colorspace(&fmt->format);
-+}
-+
-+static int imx708_get_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *sd_state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct imx708 *imx708 = to_imx708(sd);
-+
-+ mutex_lock(&imx708->mutex);
-+
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-+ struct v4l2_mbus_framefmt *try_fmt =
-+ v4l2_subdev_get_try_format(&imx708->sd, sd_state,
-+ fmt->pad);
-+ /* update the code which could change due to vflip or hflip */
-+ try_fmt->code = imx708_get_format_code(imx708);
-+ fmt->format = *try_fmt;
-+ } else {
-+ imx708_update_image_pad_format(imx708, imx708->mode, fmt);
-+ fmt->format.code = imx708_get_format_code(imx708);
-+ }
-+
-+ mutex_unlock(&imx708->mutex);
-+ return 0;
-+}
-+
-+static int imx708_set_pad_format(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *sd_state,
-+ struct v4l2_subdev_format *fmt)
-+{
-+ struct v4l2_mbus_framefmt *framefmt;
-+ const struct imx708_mode *mode;
-+ struct imx708 *imx708 = to_imx708(sd);
-+ const struct imx708_mode *mode_list;
-+ unsigned int num_modes;
-+
-+ mutex_lock(&imx708->mutex);
-+
-+ /* Bayer order varies with flips */
-+ fmt->format.code = imx708_get_format_code(imx708);
-+
-+ get_mode_table(&mode_list, &num_modes, imx708->hdr_mode->val);
-+
-+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
-+ fmt->format.width, fmt->format.height);
-+ imx708_update_image_pad_format(imx708, mode, fmt);
-+
-+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-+ framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
-+ *framefmt = fmt->format;
-+ } else {
-+ imx708->mode = mode;
-+ imx708_set_framing_limits(imx708);
-+ }
-+
-+ mutex_unlock(&imx708->mutex);
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_rect *
-+__imx708_get_pad_crop(struct imx708 *imx708, struct v4l2_subdev_state *sd_state,
-+ unsigned int pad, enum v4l2_subdev_format_whence which)
-+{
-+ switch (which) {
-+ case V4L2_SUBDEV_FORMAT_TRY:
-+ return v4l2_subdev_get_try_crop(&imx708->sd, sd_state, pad);
-+ case V4L2_SUBDEV_FORMAT_ACTIVE:
-+ return &imx708->mode->crop;
-+ }
-+
-+ return NULL;
-+}
-+
-+static int imx708_get_selection(struct v4l2_subdev *sd,
-+ struct v4l2_subdev_state *sd_state,
-+ struct v4l2_subdev_selection *sel)
-+{
-+ switch (sel->target) {
-+ case V4L2_SEL_TGT_CROP: {
-+ struct imx708 *imx708 = to_imx708(sd);
-+
-+ mutex_lock(&imx708->mutex);
-+ sel->r = *__imx708_get_pad_crop(imx708, sd_state, sel->pad,
-+ sel->which);
-+ mutex_unlock(&imx708->mutex);
-+
-+ return 0;
-+ }
-+
-+ case V4L2_SEL_TGT_NATIVE_SIZE:
-+ sel->r.left = 0;
-+ sel->r.top = 0;
-+ sel->r.width = IMX708_NATIVE_WIDTH;
-+ sel->r.height = IMX708_NATIVE_HEIGHT;
-+
-+ return 0;
-+
-+ case V4L2_SEL_TGT_CROP_DEFAULT:
-+ case V4L2_SEL_TGT_CROP_BOUNDS:
-+ sel->r.left = IMX708_PIXEL_ARRAY_LEFT;
-+ sel->r.top = IMX708_PIXEL_ARRAY_TOP;
-+ sel->r.width = IMX708_PIXEL_ARRAY_WIDTH;
-+ sel->r.height = IMX708_PIXEL_ARRAY_HEIGHT;
-+
-+ return 0;
-+ }
-+
-+ return -EINVAL;
-+}
-+
-+/* Start streaming */
-+static int imx708_start_streaming(struct imx708 *imx708)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ const struct imx708_reg_list *reg_list;
-+ int i, ret;
-+ u32 val;
-+
-+ if (!imx708->common_regs_written) {
-+ ret = imx708_write_regs(imx708, mode_common_regs,
-+ ARRAY_SIZE(mode_common_regs));
-+ if (ret) {
-+ dev_err(&client->dev, "%s failed to set common settings\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = imx708_read_reg(imx708, IMX708_REG_BASE_SPC_GAINS_L,
-+ IMX708_REG_VALUE_08BIT, &val);
-+ if (ret == 0 && val == 0x40) {
-+ for (i = 0; i < 54 && ret == 0; i++) {
-+ u16 reg = IMX708_REG_BASE_SPC_GAINS_L + i;
-+
-+ ret = imx708_write_reg(imx708, reg,
-+ IMX708_REG_VALUE_08BIT,
-+ pdaf_gains[0][i % 9]);
-+ }
-+ for (i = 0; i < 54 && ret == 0; i++) {
-+ u16 reg = IMX708_REG_BASE_SPC_GAINS_R + i;
-+
-+ ret = imx708_write_reg(imx708, reg,
-+ IMX708_REG_VALUE_08BIT,
-+ pdaf_gains[1][i % 9]);
-+ }
-+ }
-+ if (ret) {
-+ dev_err(&client->dev, "%s failed to set PDAF gains\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ imx708->common_regs_written = true;
-+ }
-+
-+ /* Apply default values of current mode */
-+ reg_list = &imx708->mode->reg_list;
-+ ret = imx708_write_regs(imx708, reg_list->regs, reg_list->num_of_regs);
-+ if (ret) {
-+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
-+ return ret;
-+ }
-+
-+ /* Apply customized values from user */
-+ ret = __v4l2_ctrl_handler_setup(imx708->sd.ctrl_handler);
-+ if (ret)
-+ return ret;
-+
-+ /* set stream on register */
-+ return imx708_write_reg(imx708, IMX708_REG_MODE_SELECT,
-+ IMX708_REG_VALUE_08BIT, IMX708_MODE_STREAMING);
-+}
-+
-+/* Stop streaming */
-+static void imx708_stop_streaming(struct imx708 *imx708)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ int ret;
-+
-+ /* set stream off register */
-+ ret = imx708_write_reg(imx708, IMX708_REG_MODE_SELECT,
-+ IMX708_REG_VALUE_08BIT, IMX708_MODE_STANDBY);
-+ if (ret)
-+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
-+}
-+
-+static int imx708_set_stream(struct v4l2_subdev *sd, int enable)
-+{
-+ struct imx708 *imx708 = to_imx708(sd);
-+ struct i2c_client *client = v4l2_get_subdevdata(sd);
-+ int ret = 0;
-+
-+ mutex_lock(&imx708->mutex);
-+ if (imx708->streaming == enable) {
-+ mutex_unlock(&imx708->mutex);
-+ return 0;
-+ }
-+
-+ if (enable) {
-+ ret = pm_runtime_resume_and_get(&client->dev);
-+ if (ret < 0)
-+ goto err_unlock;
-+
-+ /*
-+ * Apply default & customized values
-+ * and then start streaming.
-+ */
-+ ret = imx708_start_streaming(imx708);
-+ if (ret)
-+ goto err_rpm_put;
-+ } else {
-+ imx708_stop_streaming(imx708);
-+ pm_runtime_mark_last_busy(&client->dev);
-+ pm_runtime_put_autosuspend(&client->dev);
-+ }
-+
-+ imx708->streaming = enable;
-+
-+ /* vflip/hflip and hdr mode cannot change during streaming */
-+ __v4l2_ctrl_grab(imx708->vflip, enable);
-+ __v4l2_ctrl_grab(imx708->hflip, enable);
-+ __v4l2_ctrl_grab(imx708->hdr_mode, enable);
-+
-+ mutex_unlock(&imx708->mutex);
-+
-+ return ret;
-+
-+err_rpm_put:
-+ pm_runtime_put_sync(&client->dev);
-+err_unlock:
-+ mutex_unlock(&imx708->mutex);
-+
-+ return ret;
-+}
-+
-+/* Power/clock management functions */
-+static int imx708_power_on(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx708 *imx708 = to_imx708(sd);
-+ int ret;
-+
-+ ret = regulator_bulk_enable(IMX708_NUM_SUPPLIES,
-+ imx708->supplies);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable regulators\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ ret = clk_prepare_enable(imx708->xclk);
-+ if (ret) {
-+ dev_err(&client->dev, "%s: failed to enable clock\n",
-+ __func__);
-+ goto reg_off;
-+ }
-+
-+ gpiod_set_value_cansleep(imx708->reset_gpio, 1);
-+ usleep_range(IMX708_XCLR_MIN_DELAY_US,
-+ IMX708_XCLR_MIN_DELAY_US + IMX708_XCLR_DELAY_RANGE_US);
-+
-+ return 0;
-+
-+reg_off:
-+ regulator_bulk_disable(IMX708_NUM_SUPPLIES, imx708->supplies);
-+ return ret;
-+}
-+
-+static int imx708_power_off(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx708 *imx708 = to_imx708(sd);
-+
-+ gpiod_set_value_cansleep(imx708->reset_gpio, 0);
-+ clk_disable_unprepare(imx708->xclk);
-+ regulator_bulk_disable(IMX708_NUM_SUPPLIES, imx708->supplies);
-+
-+ /* Force reprogramming of the common registers when powered up again. */
-+ imx708->common_regs_written = false;
-+
-+ return 0;
-+}
-+
-+static int __maybe_unused imx708_suspend(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx708 *imx708 = to_imx708(sd);
-+
-+ if (imx708->streaming)
-+ imx708_stop_streaming(imx708);
-+
-+ return 0;
-+}
-+
-+static int __maybe_unused imx708_resume(struct device *dev)
-+{
-+ struct i2c_client *client = to_i2c_client(dev);
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx708 *imx708 = to_imx708(sd);
-+ int ret;
-+
-+ if (imx708->streaming) {
-+ ret = imx708_start_streaming(imx708);
-+ if (ret)
-+ goto error;
-+ }
-+
-+ return 0;
-+
-+error:
-+ imx708_stop_streaming(imx708);
-+ imx708->streaming = 0;
-+ return ret;
-+}
-+
-+static int imx708_get_regulators(struct imx708 *imx708)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ unsigned int i;
-+
-+ for (i = 0; i < IMX708_NUM_SUPPLIES; i++)
-+ imx708->supplies[i].supply = imx708_supply_name[i];
-+
-+ return devm_regulator_bulk_get(&client->dev,
-+ IMX708_NUM_SUPPLIES,
-+ imx708->supplies);
-+}
-+
-+/* Verify chip ID */
-+static int imx708_identify_module(struct imx708 *imx708)
-+{
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ int ret;
-+ u32 val;
-+
-+ ret = imx708_read_reg(imx708, IMX708_REG_CHIP_ID,
-+ IMX708_REG_VALUE_16BIT, &val);
-+ if (ret) {
-+ dev_err(&client->dev, "failed to read chip id %x, with error %d\n",
-+ IMX708_CHIP_ID, ret);
-+ return ret;
-+ }
-+
-+ if (val != IMX708_CHIP_ID) {
-+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
-+ IMX708_CHIP_ID, val);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct v4l2_subdev_core_ops imx708_core_ops = {
-+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
-+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+};
-+
-+static const struct v4l2_subdev_video_ops imx708_video_ops = {
-+ .s_stream = imx708_set_stream,
-+};
-+
-+static const struct v4l2_subdev_pad_ops imx708_pad_ops = {
-+ .enum_mbus_code = imx708_enum_mbus_code,
-+ .get_fmt = imx708_get_pad_format,
-+ .set_fmt = imx708_set_pad_format,
-+ .get_selection = imx708_get_selection,
-+ .enum_frame_size = imx708_enum_frame_size,
-+};
-+
-+static const struct v4l2_subdev_ops imx708_subdev_ops = {
-+ .core = &imx708_core_ops,
-+ .video = &imx708_video_ops,
-+ .pad = &imx708_pad_ops,
-+};
-+
-+static const struct v4l2_subdev_internal_ops imx708_internal_ops = {
-+ .open = imx708_open,
-+};
-+
-+static const struct v4l2_ctrl_config imx708_notify_gains_ctrl = {
-+ .ops = &imx708_ctrl_ops,
-+ .id = V4L2_CID_NOTIFY_GAINS,
-+ .type = V4L2_CTRL_TYPE_U32,
-+ .min = IMX708_COLOUR_BALANCE_MIN,
-+ .max = IMX708_COLOUR_BALANCE_MAX,
-+ .step = IMX708_COLOUR_BALANCE_STEP,
-+ .def = IMX708_COLOUR_BALANCE_DEFAULT,
-+ .dims = { 4 },
-+ .elem_size = sizeof(u32),
-+};
-+
-+/* Initialize control handlers */
-+static int imx708_init_controls(struct imx708 *imx708)
-+{
-+ struct v4l2_ctrl_handler *ctrl_hdlr;
-+ struct i2c_client *client = v4l2_get_subdevdata(&imx708->sd);
-+ struct v4l2_fwnode_device_properties props;
-+ unsigned int i;
-+ int ret;
-+
-+ ctrl_hdlr = &imx708->ctrl_handler;
-+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16);
-+ if (ret)
-+ return ret;
-+
-+ mutex_init(&imx708->mutex);
-+ ctrl_hdlr->lock = &imx708->mutex;
-+
-+ /* By default, PIXEL_RATE is read only */
-+ imx708->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_PIXEL_RATE,
-+ imx708->mode->pixel_rate,
-+ imx708->mode->pixel_rate, 1,
-+ imx708->mode->pixel_rate);
-+
-+ /*
-+ * Create the controls here, but mode specific limits are setup
-+ * in the imx708_set_framing_limits() call below.
-+ */
-+ imx708->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_VBLANK, 0, 0xffff, 1, 0);
-+ imx708->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_HBLANK, 0, 0xffff, 1, 0);
-+
-+ imx708->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_EXPOSURE,
-+ IMX708_EXPOSURE_MIN,
-+ IMX708_EXPOSURE_MAX,
-+ IMX708_EXPOSURE_STEP,
-+ IMX708_EXPOSURE_DEFAULT);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
-+ IMX708_ANA_GAIN_MIN, IMX708_ANA_GAIN_MAX,
-+ IMX708_ANA_GAIN_STEP, IMX708_ANA_GAIN_DEFAULT);
-+
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
-+ IMX708_DGTL_GAIN_MIN, IMX708_DGTL_GAIN_MAX,
-+ IMX708_DGTL_GAIN_STEP, IMX708_DGTL_GAIN_DEFAULT);
-+
-+ imx708->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_HFLIP, 0, 1, 1, 0);
-+
-+ imx708->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_VFLIP, 0, 1, 1, 0);
-+
-+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_TEST_PATTERN,
-+ ARRAY_SIZE(imx708_test_pattern_menu) - 1,
-+ 0, 0, imx708_test_pattern_menu);
-+ for (i = 0; i < 4; i++) {
-+ /*
-+ * The assumption is that
-+ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
-+ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
-+ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
-+ */
-+ v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_TEST_PATTERN_RED + i,
-+ IMX708_TEST_PATTERN_COLOUR_MIN,
-+ IMX708_TEST_PATTERN_COLOUR_MAX,
-+ IMX708_TEST_PATTERN_COLOUR_STEP,
-+ IMX708_TEST_PATTERN_COLOUR_MAX);
-+ /* The "Solid color" pattern is white by default */
-+ }
-+
-+ imx708->notify_gains = v4l2_ctrl_new_custom(ctrl_hdlr,
-+ &imx708_notify_gains_ctrl,
-+ NULL);
-+
-+ imx708->hdr_mode = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
-+ V4L2_CID_WIDE_DYNAMIC_RANGE,
-+ 0, 1, 1, 0);
-+
-+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
-+ if (ret)
-+ goto error;
-+
-+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx708_ctrl_ops, &props);
-+
-+ if (ctrl_hdlr->error) {
-+ ret = ctrl_hdlr->error;
-+ dev_err(&client->dev, "%s control init failed (%d)\n",
-+ __func__, ret);
-+ goto error;
-+ }
-+
-+ imx708->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-+ imx708->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
-+ imx708->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
-+ imx708->hdr_mode->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
-+
-+ imx708->sd.ctrl_handler = ctrl_hdlr;
-+
-+ /* Setup exposure and frame/line length limits. */
-+ imx708_set_framing_limits(imx708);
-+
-+ return 0;
-+
-+error:
-+ v4l2_ctrl_handler_free(ctrl_hdlr);
-+ mutex_destroy(&imx708->mutex);
-+
-+ return ret;
-+}
-+
-+static void imx708_free_controls(struct imx708 *imx708)
-+{
-+ v4l2_ctrl_handler_free(imx708->sd.ctrl_handler);
-+ mutex_destroy(&imx708->mutex);
-+}
-+
-+static int imx708_check_hwcfg(struct device *dev)
-+{
-+ struct fwnode_handle *endpoint;
-+ struct v4l2_fwnode_endpoint ep_cfg = {
-+ .bus_type = V4L2_MBUS_CSI2_DPHY
-+ };
-+ int ret = -EINVAL;
-+
-+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
-+ if (!endpoint) {
-+ dev_err(dev, "endpoint node not found\n");
-+ return -EINVAL;
-+ }
-+
-+ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
-+ dev_err(dev, "could not parse endpoint\n");
-+ goto error_out;
-+ }
-+
-+ /* Check the number of MIPI CSI2 data lanes */
-+ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
-+ dev_err(dev, "only 2 data lanes are currently supported\n");
-+ goto error_out;
-+ }
-+
-+ /* Check the link frequency set in device tree */
-+ if (!ep_cfg.nr_of_link_frequencies) {
-+ dev_err(dev, "link-frequency property not found in DT\n");
-+ goto error_out;
-+ }
-+
-+ if (ep_cfg.nr_of_link_frequencies != 1 ||
-+ ep_cfg.link_frequencies[0] != IMX708_DEFAULT_LINK_FREQ) {
-+ dev_err(dev, "Link frequency not supported: %lld\n",
-+ ep_cfg.link_frequencies[0]);
-+ goto error_out;
-+ }
-+
-+ ret = 0;
-+
-+error_out:
-+ v4l2_fwnode_endpoint_free(&ep_cfg);
-+ fwnode_handle_put(endpoint);
-+
-+ return ret;
-+}
-+
-+static int imx708_probe(struct i2c_client *client)
-+{
-+ struct device *dev = &client->dev;
-+ struct imx708 *imx708;
-+ int ret;
-+
-+ imx708 = devm_kzalloc(&client->dev, sizeof(*imx708), GFP_KERNEL);
-+ if (!imx708)
-+ return -ENOMEM;
-+
-+ v4l2_i2c_subdev_init(&imx708->sd, client, &imx708_subdev_ops);
-+
-+ /* Check the hardware configuration in device tree */
-+ if (imx708_check_hwcfg(dev))
-+ return -EINVAL;
-+
-+ /* Get system clock (xclk) */
-+ imx708->xclk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(imx708->xclk)) {
-+ dev_err(dev, "failed to get xclk\n");
-+ return PTR_ERR(imx708->xclk);
-+ }
-+
-+ imx708->xclk_freq = clk_get_rate(imx708->xclk);
-+ if (imx708->xclk_freq != IMX708_XCLK_FREQ) {
-+ dev_err(dev, "xclk frequency not supported: %d Hz\n",
-+ imx708->xclk_freq);
-+ return -EINVAL;
-+ }
-+
-+ ret = imx708_get_regulators(imx708);
-+ if (ret) {
-+ dev_err(dev, "failed to get regulators\n");
-+ return ret;
-+ }
-+
-+ /* Request optional enable pin */
-+ imx708->reset_gpio = devm_gpiod_get_optional(dev, "reset",
-+ GPIOD_OUT_HIGH);
-+
-+ /*
-+ * The sensor must be powered for imx708_identify_module()
-+ * to be able to read the CHIP_ID register
-+ */
-+ ret = imx708_power_on(dev);
-+ if (ret)
-+ return ret;
-+
-+ ret = imx708_identify_module(imx708);
-+ if (ret)
-+ goto error_power_off;
-+
-+ /* Initialize default format */
-+ imx708_set_default_format(imx708);
-+
-+ /*
-+ * Enable runtime PM with autosuspend. As the device has been powered
-+ * manually, mark it as active, and increase the usage count without
-+ * resuming the device.
-+ */
-+ pm_runtime_set_active(dev);
-+ pm_runtime_get_noresume(dev);
-+ pm_runtime_enable(dev);
-+ pm_runtime_set_autosuspend_delay(dev, 1000);
-+ pm_runtime_use_autosuspend(dev);
-+
-+ /* This needs the pm runtime to be registered. */
-+ ret = imx708_init_controls(imx708);
-+ if (ret)
-+ goto error_power_off;
-+
-+ /* Initialize subdev */
-+ imx708->sd.internal_ops = &imx708_internal_ops;
-+ imx708->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
-+ V4L2_SUBDEV_FL_HAS_EVENTS;
-+ imx708->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-+
-+ /* Initialize source pad */
-+ imx708->pad.flags = MEDIA_PAD_FL_SOURCE;
-+
-+ ret = media_entity_pads_init(&imx708->sd.entity, 1, &imx708->pad);
-+ if (ret) {
-+ dev_err(dev, "failed to init entity pads: %d\n", ret);
-+ goto error_handler_free;
-+ }
-+
-+ ret = v4l2_async_register_subdev_sensor(&imx708->sd);
-+ if (ret < 0) {
-+ dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
-+ goto error_media_entity;
-+ }
-+
-+ /*
-+ * Decrease the PM usage count. The device will get suspended after the
-+ * autosuspend delay, turning the power off.
-+ */
-+ pm_runtime_mark_last_busy(dev);
-+ pm_runtime_put_autosuspend(dev);
-+
-+ return 0;
-+
-+error_media_entity:
-+ media_entity_cleanup(&imx708->sd.entity);
-+
-+error_handler_free:
-+ imx708_free_controls(imx708);
-+
-+error_power_off:
-+ pm_runtime_disable(&client->dev);
-+ pm_runtime_put_noidle(&client->dev);
-+ imx708_power_off(&client->dev);
-+
-+ return ret;
-+}
-+
-+static void imx708_remove(struct i2c_client *client)
-+{
-+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
-+ struct imx708 *imx708 = to_imx708(sd);
-+
-+ v4l2_async_unregister_subdev(sd);
-+ media_entity_cleanup(&sd->entity);
-+ imx708_free_controls(imx708);
-+
-+ pm_runtime_disable(&client->dev);
-+ if (!pm_runtime_status_suspended(&client->dev))
-+ imx708_power_off(&client->dev);
-+ pm_runtime_set_suspended(&client->dev);
-+}
-+
-+static const struct of_device_id imx708_dt_ids[] = {
-+ { .compatible = "sony,imx708" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, imx708_dt_ids);
-+
-+static const struct dev_pm_ops imx708_pm_ops = {
-+ SET_SYSTEM_SLEEP_PM_OPS(imx708_suspend, imx708_resume)
-+ SET_RUNTIME_PM_OPS(imx708_power_off, imx708_power_on, NULL)
-+};
-+
-+static struct i2c_driver imx708_i2c_driver = {
-+ .driver = {
-+ .name = "imx708",
-+ .of_match_table = imx708_dt_ids,
-+ .pm = &imx708_pm_ops,
-+ },
-+ .probe = imx708_probe,
-+ .remove = imx708_remove,
-+};
-+
-+module_i2c_driver(imx708_i2c_driver);
-+
-+MODULE_AUTHOR("David Plowman <david.plowman@raspberrypi.com>");
-+MODULE_DESCRIPTION("Sony IMX708 sensor driver");
-+MODULE_LICENSE("GPL");
+++ /dev/null
-From 280ab217867d0b934454a837540eab665e854b47 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Mon, 3 Apr 2023 15:28:11 +0800
-Subject: [PATCH 088/116] media: i2c: imx708: Delete gain
-
-Delete gain.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
----
- drivers/media/i2c/imx708.c | 27 ---------------------------
- 1 file changed, 27 deletions(-)
-
---- a/drivers/media/i2c/imx708.c
-+++ b/drivers/media/i2c/imx708.c
-@@ -777,7 +777,6 @@ struct imx708 {
- struct v4l2_ctrl *hblank;
- struct v4l2_ctrl *red_balance;
- struct v4l2_ctrl *blue_balance;
-- struct v4l2_ctrl *notify_gains;
- struct v4l2_ctrl *hdr_mode;
-
- /* Current mode */
-@@ -1108,16 +1107,6 @@ static int imx708_set_ctrl(struct v4l2_c
- ret = imx708_set_frame_length(imx708,
- imx708->mode->height + ctrl->val);
- break;
-- case V4L2_CID_NOTIFY_GAINS:
-- ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_BLUE,
-- IMX708_REG_VALUE_16BIT,
-- imx708->notify_gains->p_new.p_u32[0]);
-- if (ret)
-- break;
-- ret = imx708_write_reg(imx708, IMX708_REG_COLOUR_BALANCE_RED,
-- IMX708_REG_VALUE_16BIT,
-- imx708->notify_gains->p_new.p_u32[3]);
-- break;
- case V4L2_CID_WIDE_DYNAMIC_RANGE:
- get_mode_table(&mode_list, &num_modes, ctrl->val);
- imx708->mode = v4l2_find_nearest_size(mode_list,
-@@ -1584,18 +1573,6 @@ static const struct v4l2_subdev_internal
- .open = imx708_open,
- };
-
--static const struct v4l2_ctrl_config imx708_notify_gains_ctrl = {
-- .ops = &imx708_ctrl_ops,
-- .id = V4L2_CID_NOTIFY_GAINS,
-- .type = V4L2_CTRL_TYPE_U32,
-- .min = IMX708_COLOUR_BALANCE_MIN,
-- .max = IMX708_COLOUR_BALANCE_MAX,
-- .step = IMX708_COLOUR_BALANCE_STEP,
-- .def = IMX708_COLOUR_BALANCE_DEFAULT,
-- .dims = { 4 },
-- .elem_size = sizeof(u32),
--};
--
- /* Initialize control handlers */
- static int imx708_init_controls(struct imx708 *imx708)
- {
-@@ -1670,10 +1647,6 @@ static int imx708_init_controls(struct i
- /* The "Solid color" pattern is white by default */
- }
-
-- imx708->notify_gains = v4l2_ctrl_new_custom(ctrl_hdlr,
-- &imx708_notify_gains_ctrl,
-- NULL);
--
- imx708->hdr_mode = v4l2_ctrl_new_std(ctrl_hdlr, &imx708_ctrl_ops,
- V4L2_CID_WIDE_DYNAMIC_RANGE,
- 0, 1, 1, 0);
+++ /dev/null
-From aa4febf074cbaad81c981a5c6b55324a6f676fb7 Mon Sep 17 00:00:00 2001
-From: "shengyang.chen" <shengyang.chen@starfivetech.com>
-Date: Tue, 13 Jun 2023 14:22:29 +0800
-Subject: [PATCH 089/116] dt-bindings: display: Add yamls for JH7110 display
- system and hdmi
-
-StarFive SoCs like the jh7110 use display system based on verisilicon IP, use hdmi
-base on innosilicon IP. Add bindings for them.
-
-Signed-off-by: Shengyang Chen <shengyang.chen@starfivetech.com>
----
- .../display/verisilicon/starfive-hdmi.yaml | 92 +++++++++++++++
- .../display/verisilicon/verisilicon-dc.yaml | 109 ++++++++++++++++++
- .../display/verisilicon/verisilicon-drm.yaml | 41 +++++++
- 3 files changed, 242 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
- create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
- create mode 100644 Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/display/verisilicon/starfive-hdmi.yaml
-@@ -0,0 +1,92 @@
-+# SPDX-License-Identifier: GPL-2.0
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/display/verisilicon/starfive-hdmi.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: StarFive SoC HDMI transmiter
-+
-+description:
-+ The StarFive SoC uses the HDMI signal transmiter based on innosilicon IP
-+ to generate HDMI signal from its input and transmit the signal to the screen.
-+
-+maintainers:
-+ - Keith Zhao <keith.zhao@starfivetech.com>
-+
-+properties:
-+ compatible:
-+ const: starfive,hdmi
-+
-+ reg:
-+ minItems: 1
-+
-+ interrupts:
-+ items:
-+ - description: The HDMI hot plug detection interrupt.
-+
-+ clocks:
-+ items:
-+ - description: System clock of HDMI module.
-+ - description: Mclk clock of HDMI audio.
-+ - description: Bclk clock of HDMI audio.
-+ - description: Pixel clock generated by HDMI module.
-+
-+ clock-names:
-+ items:
-+ - const: sysclk
-+ - const: mclk
-+ - const: bclk
-+ - const: pclk
-+
-+ resets:
-+ items:
-+ - description: Reset for HDMI module.
-+
-+ reset-names:
-+ items:
-+ - const: hdmi_tx
-+
-+ '#sound-dai-cells':
-+ const: 0
-+
-+ port:
-+ $ref: /schemas/graph.yaml#/properties/port
-+ description:
-+ Port node with one endpoint connected to a display connector node.
-+
-+required:
-+ - compatible
-+ - reg
-+ - interrupts
-+ - clocks
-+ - clock-names
-+ - resets
-+ - reset-names
-+ - '#sound-dai-cells'
-+ - port
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ hdmi: hdmi@29590000 {
-+ compatible = "starfive,hdmi";
-+ reg = <0x29590000 0x4000>;
-+ interrupts = <99>;
-+ clocks = <&voutcrg 17>,
-+ <&voutcrg 15>,
-+ <&voutcrg 16>,
-+ <&hdmitx0_pixelclk>;
-+ clock-names = "sysclk", "mclk","bclk","pclk";
-+ resets = <&voutcrg 9>;
-+ reset-names = "hdmi_tx";
-+ #sound-dai-cells = <0>;
-+ hdmi_in: port {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ hdmi_input: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&dc_out_dpi0>;
-+ };
-+ };
-+ };
---- /dev/null
-+++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
-@@ -0,0 +1,109 @@
-+# SPDX-License-Identifier: GPL-2.0
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-dc.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: StarFive SoC display controller
-+
-+description:
-+ The StarFive SoC uses the display controller based on Verisilicon IP
-+ to transfer the image data from a video memory
-+ buffer to an external LCD interface.
-+
-+maintainers:
-+ - Keith Zhao <keith.zhao@starfivetech.com>
-+
-+properties:
-+ compatible:
-+ const: verisilicon,dc8200
-+
-+ reg:
-+ maxItems: 3
-+
-+ interrupts:
-+ items:
-+ - description: The interrupt will be generated when DC finish one frame
-+
-+ clocks:
-+ items:
-+ - description: Clock for display system noc bus.
-+ - description: Pixel clock for display channel 0.
-+ - description: Pixel clock for display channel 1.
-+ - description: Clock for axi interface of display controller.
-+ - description: Core clock for display controller.
-+ - description: Clock for ahb interface of display controller.
-+ - description: External HDMI pixel clock.
-+ - description: Parent clock for pixel clock
-+
-+ clock-names:
-+ items:
-+ - const: clk_vout_noc_disp
-+ - const: clk_vout_pix0
-+ - const: clk_vout_pix1
-+ - const: clk_vout_axi
-+ - const: clk_vout_core
-+ - const: clk_vout_vout_ahb
-+ - const: hdmitx0_pixel
-+ - const: clk_vout_dc8200
-+
-+ resets:
-+ items:
-+ - description: Reset for axi interface of display controller.
-+ - description: Reset for ahb interface of display controller.
-+ - description: Core reset of display controller.
-+
-+ reset-names:
-+ items:
-+ - const: rst_vout_axi
-+ - const: rst_vout_ahb
-+ - const: rst_vout_core
-+
-+ port:
-+ $ref: /schemas/graph.yaml#/properties/port
-+ description:
-+ Port node with one endpoint connected to a hdmi node.
-+
-+required:
-+ - compatible
-+ - reg
-+ - interrupts
-+ - clocks
-+ - clock-names
-+ - resets
-+ - reset-names
-+ - port
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ dc8200: dc8200@29400000 {
-+ compatible = "verisilicon,dc8200";
-+ reg = <0x29400000 0x100>,
-+ <0x29400800 0x2000>,
-+ <0x295B0000 0x90>;
-+ interrupts = <95>;
-+ clocks = <&syscrg 60>,
-+ <&voutcrg 7>,
-+ <&voutcrg 8>,
-+ <&voutcrg 4>,
-+ <&voutcrg 5>,
-+ <&voutcrg 6>,
-+ <&hdmitx0_pixelclk>,
-+ <&voutcrg 1>;
-+ clock-names = "clk_vout_noc_disp", "clk_vout_pix0", "clk_vout_pix1", "clk_vout_axi",
-+ "clk_vout_core", "clk_vout_vout_ahb", "hdmitx0_pixel","clk_vout_dc8200";
-+ resets = <&voutcrg 0>,
-+ <&voutcrg 1>,
-+ <&voutcrg 2>;
-+ reset-names = "rst_vout_axi","rst_vout_ahb","rst_vout_core";
-+ dc_out: port {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ dc_out_dpi0: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&hdmi_input>;
-+ };
-+ };
-+ };
---- /dev/null
-+++ b/Documentation/devicetree/bindings/display/verisilicon/verisilicon-drm.yaml
-@@ -0,0 +1,41 @@
-+# SPDX-License-Identifier: (GPL-2.0-only)
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/display/verisilicon/verisilicon-drm.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: Verisilicon DRM master device
-+
-+maintainers:
-+ - Keith Zhao <keith.zhao@starfivetech.com>
-+
-+description: |
-+ The Verisilicon DRM master device is a virtual device needed to list all
-+ display controller or other display interface nodes that comprise the
-+ graphics subsystem.
-+
-+properties:
-+ compatible:
-+ const: verisilicon,display-subsystem
-+
-+ ports:
-+ $ref: /schemas/types.yaml#/definitions/phandle-array
-+ items:
-+ maxItems: 1
-+ description: |
-+ Should contain a list of phandles pointing to display interface ports
-+ of display controller devices. Display controller definitions as defined in
-+ Documentation/devicetree/bindings/display/verisilicon/verisilicon-dc.yaml
-+
-+required:
-+ - compatible
-+ - ports
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ display-subsystem {
-+ compatible = "verisilicon,display-subsystem";
-+ ports = <&dc_out>;
-+ };
+++ /dev/null
-From 5cbf4154da600af8a2e6a2f8d57d1f212abf3f92 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Fri, 13 Oct 2023 14:10:24 +0800
-Subject: [PATCH 090/116] soc: starfive: jh71xx_pmu: Add EVENT_TURN_OFF
- register writing support
-
-Add and export starfive_pmu_hw_event_turn_off_mask() to
-write EVENT_TURN_OFF register.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/pmdomain/starfive/jh71xx-pmu.c | 11 ++++++++++
- include/soc/starfive/jh7110_pmu.h | 29 ++++++++++++++++++++++++++
- 2 files changed, 40 insertions(+)
- create mode 100644 include/soc/starfive/jh7110_pmu.h
-
---- a/drivers/pmdomain/starfive/jh71xx-pmu.c
-+++ b/drivers/pmdomain/starfive/jh71xx-pmu.c
-@@ -16,6 +16,7 @@
- #include <dt-bindings/power/starfive,jh7110-pmu.h>
-
- /* register offset */
-+#define JH71XX_PMU_HW_EVENT_TURN_OFF 0x08
- #define JH71XX_PMU_SW_TURN_ON_POWER 0x0C
- #define JH71XX_PMU_SW_TURN_OFF_POWER 0x10
- #define JH71XX_PMU_SW_ENCOURAGE 0x44
-@@ -83,6 +84,14 @@ struct jh71xx_pmu_dev {
- struct generic_pm_domain genpd;
- };
-
-+static void __iomem *pmu_base;
-+
-+void starfive_pmu_hw_event_turn_off_mask(u32 mask)
-+{
-+ writel(mask, pmu_base + JH71XX_PMU_HW_EVENT_TURN_OFF);
-+}
-+EXPORT_SYMBOL(starfive_pmu_hw_event_turn_off_mask);
-+
- static int jh71xx_pmu_get_state(struct jh71xx_pmu_dev *pmd, u32 mask, bool *is_on)
- {
- struct jh71xx_pmu *pmu = pmd->pmu;
-@@ -334,6 +343,8 @@ static int jh71xx_pmu_probe(struct platf
- if (IS_ERR(pmu->base))
- return PTR_ERR(pmu->base);
-
-+ pmu_base = pmu->base;
-+
- spin_lock_init(&pmu->lock);
-
- match_data = of_device_get_match_data(dev);
---- /dev/null
-+++ b/include/soc/starfive/jh7110_pmu.h
-@@ -0,0 +1,29 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+/*
-+ * PMU driver for the StarFive JH7110 SoC
-+ *
-+ * Copyright (C) 2022 samin <samin.guo@starfivetech.com>
-+ */
-+
-+#ifndef __SOC_STARFIVE_JH7110_PMU_H__
-+#define __SOC_STARFIVE_JH7110_PMU_H__
-+
-+#include <linux/bits.h>
-+#include <linux/types.h>
-+
-+enum PMU_HARD_EVENT {
-+ PMU_HW_EVENT_RTC = BIT(0),
-+ PMU_HW_EVENT_GMAC = BIT(1),
-+ PMU_HW_EVENT_RFU = BIT(2),
-+ PMU_HW_EVENT_RGPIO0 = BIT(3),
-+ PMU_HW_EVENT_RGPIO1 = BIT(4),
-+ PMU_HW_EVENT_RGPIO2 = BIT(5),
-+ PMU_HW_EVENT_RGPIO3 = BIT(6),
-+ PMU_HW_EVENT_GPU = BIT(7),
-+ PMU_HW_EVENT_ALL = GENMASK(7, 0),
-+};
-+
-+void starfive_pmu_hw_event_turn_off_mask(u32 mask);
-+
-+#endif /* __SOC_STARFIVE_JH7110_PMU_H__ */
-+
+++ /dev/null
-From ab436ea7ffb6c464616addad98632c81a321844a Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Tue, 12 Dec 2023 17:56:58 +0800
-Subject: [PATCH 091/116] workqueue: Enable flush_scheduled_work()
-
-Enable flush_scheduled_work() for JH7110 GPU.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- include/linux/workqueue.h | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/include/linux/workqueue.h
-+++ b/include/linux/workqueue.h
-@@ -636,7 +636,6 @@ extern void __warn_flushing_systemwide_w
- /* Please stop using this function, for this function will be removed in near future. */
- #define flush_scheduled_work() \
- ({ \
-- __warn_flushing_systemwide_wq(); \
- __flush_workqueue(system_wq); \
- })
-
+++ /dev/null
-From dedbbfd891e4d0cdb825454eddfbf8386d0025b3 Mon Sep 17 00:00:00 2001
-From: Mason Huo <mason.huo@starfivetech.com>
-Date: Tue, 20 Jun 2023 13:37:52 +0800
-Subject: [PATCH 092/116] riscv: Optimize memcpy with aligned version
-
-Optimizing the 128 byte align case, this will improve the
-performance of large block memcpy.
-
-Here we combine the memcpy of glibc and kernel.
-
-Signed-off-by: Mason Huo <mason.huo@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/lib/Makefile | 3 +-
- arch/riscv/lib/{memcpy.S => memcpy_aligned.S} | 36 +--
- arch/riscv/lib/string.c | 266 ++++++++++++++++++
- 3 files changed, 273 insertions(+), 32 deletions(-)
- rename arch/riscv/lib/{memcpy.S => memcpy_aligned.S} (67%)
- 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
- lib-y += strcmp.o
-@@ -9,5 +8,7 @@ lib-y += strncmp.o
- lib-$(CONFIG_MMU) += uaccess.o
- lib-$(CONFIG_64BIT) += tishift.o
- lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o
-+lib-y += string.o
-+lib-y += memcpy_aligned.o
-
- obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
---- a/arch/riscv/lib/memcpy.S
-+++ /dev/null
-@@ -1,110 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0-only */
--/*
-- * Copyright (C) 2013 Regents of the University of California
-- */
--
--#include <linux/linkage.h>
--#include <asm/asm.h>
--
--/* void *memcpy(void *, const void *, size_t) */
--ENTRY(__memcpy)
--WEAK(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
--END(__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,84 @@
-+/* SPDX-License-Identifier: GPL-2.0-only */
-+/*
-+ * Copyright (C) 2013 Regents of the University of California
-+ */
-+
-+#include <linux/linkage.h>
-+#include <asm/asm.h>
-+
-+/* void *__memcpy_aligned(void *, const void *, size_t) */
-+ENTRY(__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
-+END(__memcpy_aligned)
-+SYM_FUNC_ALIAS(__pi_memcpy, __memcpy_aligned)
-+SYM_FUNC_ALIAS(__pi___memcpy, __memcpy_aligned)
---- /dev/null
-+++ b/arch/riscv/lib/string.c
-@@ -0,0 +1,266 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copy memory to memory until the specified number of bytes
-+ * has been copied. Overlap is NOT handled correctly.
-+ * Copyright (C) 1991-2020 Free Software Foundation, Inc.
-+ * This file is part of the GNU C Library.
-+ * Contributed by Torbjorn Granlund (tege@sics.se).
-+ *
-+ * The GNU C Library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * The GNU C Library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with the GNU C Library; if not, see
-+ * <https://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+#define __NO_FORTIFY
-+#include <linux/types.h>
-+#include <linux/module.h>
-+
-+#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
-+#define OP_T_THRES 16
-+#define op_t unsigned long
-+#define OPSIZ (sizeof(op_t))
-+#define OPSIZ_MASK (sizeof(op_t) - 1)
-+#define FAST_COPY_THRES (128)
-+#define byte unsigned char
-+
-+static void _wordcopy_fwd_aligned(long dstp, long srcp, size_t len)
-+{
-+ op_t a0, a1;
-+
-+ switch (len % 8) {
-+ case 2:
-+ a0 = ((op_t *) srcp)[0];
-+ srcp -= 6 * OPSIZ;
-+ dstp -= 7 * OPSIZ;
-+ len += 6;
-+ goto do1;
-+ case 3:
-+ a1 = ((op_t *) srcp)[0];
-+ srcp -= 5 * OPSIZ;
-+ dstp -= 6 * OPSIZ;
-+ len += 5;
-+ goto do2;
-+ case 4:
-+ a0 = ((op_t *) srcp)[0];
-+ srcp -= 4 * OPSIZ;
-+ dstp -= 5 * OPSIZ;
-+ len += 4;
-+ goto do3;
-+ case 5:
-+ a1 = ((op_t *) srcp)[0];
-+ srcp -= 3 * OPSIZ;
-+ dstp -= 4 * OPSIZ;
-+ len += 3;
-+ goto do4;
-+ case 6:
-+ a0 = ((op_t *) srcp)[0];
-+ srcp -= 2 * OPSIZ;
-+ dstp -= 3 * OPSIZ;
-+ len += 2;
-+ goto do5;
-+ case 7:
-+ a1 = ((op_t *) srcp)[0];
-+ srcp -= 1 * OPSIZ;
-+ dstp -= 2 * OPSIZ;
-+ len += 1;
-+ goto do6;
-+
-+ case 0:
-+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-+ return;
-+ a0 = ((op_t *) srcp)[0];
-+ srcp -= 0 * OPSIZ;
-+ dstp -= 1 * OPSIZ;
-+ goto do7;
-+ case 1:
-+ a1 = ((op_t *) srcp)[0];
-+ srcp -= -1 * OPSIZ;
-+ dstp -= 0 * OPSIZ;
-+ len -= 1;
-+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-+ goto do0;
-+ goto do8; /* No-op. */
-+ }
-+
-+ do {
-+do8:
-+ a0 = ((op_t *) srcp)[0];
-+ ((op_t *) dstp)[0] = a1;
-+do7:
-+ a1 = ((op_t *) srcp)[1];
-+ ((op_t *) dstp)[1] = a0;
-+do6:
-+ a0 = ((op_t *) srcp)[2];
-+ ((op_t *) dstp)[2] = a1;
-+do5:
-+ a1 = ((op_t *) srcp)[3];
-+ ((op_t *) dstp)[3] = a0;
-+do4:
-+ a0 = ((op_t *) srcp)[4];
-+ ((op_t *) dstp)[4] = a1;
-+do3:
-+ a1 = ((op_t *) srcp)[5];
-+ ((op_t *) dstp)[5] = a0;
-+do2:
-+ a0 = ((op_t *) srcp)[6];
-+ ((op_t *) dstp)[6] = a1;
-+do1:
-+ a1 = ((op_t *) srcp)[7];
-+ ((op_t *) dstp)[7] = a0;
-+
-+ srcp += 8 * OPSIZ;
-+ dstp += 8 * OPSIZ;
-+ len -= 8;
-+ } while (len != 0);
-+
-+ /* This is the right position for do0. Please don't move
-+ * it into the loop.
-+ */
-+do0:
-+ ((op_t *) dstp)[0] = a1;
-+}
-+
-+static void _wordcopy_fwd_dest_aligned(long dstp, long srcp, size_t len)
-+{
-+ op_t a0, a1, a2, a3;
-+ int sh_1, sh_2;
-+
-+ /* Calculate how to shift a word read at the memory operation
-+ * aligned srcp to make it aligned for copy.
-+ */
-+
-+ sh_1 = 8 * (srcp % OPSIZ);
-+ sh_2 = 8 * OPSIZ - sh_1;
-+
-+ /* Make SRCP aligned by rounding it down to the beginning of the `op_t'
-+ * it points in the middle of.
-+ */
-+ srcp &= -OPSIZ;
-+
-+ switch (len % 4) {
-+ case 2:
-+ a1 = ((op_t *) srcp)[0];
-+ a2 = ((op_t *) srcp)[1];
-+ srcp -= 1 * OPSIZ;
-+ dstp -= 3 * OPSIZ;
-+ len += 2;
-+ goto do1;
-+ case 3:
-+ a0 = ((op_t *) srcp)[0];
-+ a1 = ((op_t *) srcp)[1];
-+ srcp -= 0 * OPSIZ;
-+ dstp -= 2 * OPSIZ;
-+ len += 1;
-+ goto do2;
-+ case 0:
-+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-+ return;
-+ a3 = ((op_t *) srcp)[0];
-+ a0 = ((op_t *) srcp)[1];
-+ srcp -= -1 * OPSIZ;
-+ dstp -= 1 * OPSIZ;
-+ len += 0;
-+ goto do3;
-+ case 1:
-+ a2 = ((op_t *) srcp)[0];
-+ a3 = ((op_t *) srcp)[1];
-+ srcp -= -2 * OPSIZ;
-+ dstp -= 0 * OPSIZ;
-+ len -= 1;
-+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-+ goto do0;
-+ goto do4; /* No-op. */
-+ }
-+
-+ do {
-+do4:
-+ a0 = ((op_t *) srcp)[0];
-+ ((op_t *) dstp)[0] = MERGE(a2, sh_1, a3, sh_2);
-+do3:
-+ a1 = ((op_t *) srcp)[1];
-+ ((op_t *) dstp)[1] = MERGE(a3, sh_1, a0, sh_2);
-+do2:
-+ a2 = ((op_t *) srcp)[2];
-+ ((op_t *) dstp)[2] = MERGE(a0, sh_1, a1, sh_2);
-+do1:
-+ a3 = ((op_t *) srcp)[3];
-+ ((op_t *) dstp)[3] = MERGE(a1, sh_1, a2, sh_2);
-+
-+ srcp += 4 * OPSIZ;
-+ dstp += 4 * OPSIZ;
-+ len -= 4;
-+ } while (len != 0);
-+
-+ /* This is the right position for do0. Please don't move
-+ * it into the loop.
-+ */
-+do0:
-+ ((op_t *) dstp)[0] = MERGE(a2, sh_1, a3, sh_2);
-+}
-+
-+#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \
-+do { \
-+ size_t __nbytes = (nbytes); \
-+ while (__nbytes > 0) { \
-+ byte __x = ((byte *) src_bp)[0]; \
-+ src_bp += 1; \
-+ __nbytes -= 1; \
-+ ((byte *) dst_bp)[0] = __x; \
-+ dst_bp += 1; \
-+ } \
-+} while (0)
-+
-+#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \
-+do { \
-+ if (src_bp % OPSIZ == 0) \
-+ _wordcopy_fwd_aligned(dst_bp, src_bp, (nbytes) / OPSIZ); \
-+ else \
-+ _wordcopy_fwd_dest_aligned(dst_bp, src_bp, (nbytes) / OPSIZ); \
-+ src_bp += (nbytes) & -OPSIZ; \
-+ dst_bp += (nbytes) & -OPSIZ; \
-+ (nbytes_left) = (nbytes) % OPSIZ; \
-+} while (0)
-+
-+extern void *__memcpy_aligned(void *dest, const void *src, size_t len);
-+void *__memcpy(void *dest, const void *src, size_t len)
-+{
-+ unsigned long dstp = (long) dest;
-+ unsigned long srcp = (long) src;
-+
-+ /* If there not too few bytes to copy, use word copy. */
-+ if (len >= OP_T_THRES) {
-+ if ((len >= FAST_COPY_THRES) && ((dstp & OPSIZ_MASK) == 0) &&
-+ ((srcp & OPSIZ_MASK) == 0)) {
-+ __memcpy_aligned(dest, src, len);
-+ return dest;
-+ }
-+ /* Copy just a few bytes to make DSTP aligned. */
-+ len -= (-dstp) % OPSIZ;
-+ BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ);
-+
-+ /* Copy from SRCP to DSTP taking advantage of the known alignment of
-+ * DSTP. Number of bytes remaining is put in the third argument,
-+ * i.e. in LEN. This number may vary from machine to machine.
-+ */
-+ WORD_COPY_FWD(dstp, srcp, len, len);
-+ /* Fall out and copy the tail. */
-+ }
-+
-+ /* There are just a few bytes to copy. Use byte memory operations. */
-+ BYTE_COPY_FWD(dstp, srcp, len);
-+
-+ return dest;
-+}
-+
-+void *memcpy(void *dest, const void *src, size_t len) __weak __alias(__memcpy);
+++ /dev/null
-From 41c9e97bb70321f7848bd489e45246a9dc985974 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Sun, 4 Feb 2024 15:27:09 +0800
-Subject: [PATCH 093/116] riscv/purgatory: Change memcpy to the aligned version
-
-Change memcpy to the aligned version, for purgatory.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/purgatory/Makefile | 7 +++++--
- 1 file changed, 5 insertions(+), 2 deletions(-)
-
---- a/arch/riscv/purgatory/Makefile
-+++ b/arch/riscv/purgatory/Makefile
-@@ -1,7 +1,7 @@
- # SPDX-License-Identifier: GPL-2.0
- OBJECT_FILES_NON_STANDARD := y
-
--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
- purgatory-y += strcmp.o strlen.o strncmp.o
-
- targets += $(purgatory-y)
-@@ -13,9 +13,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)
-
+++ /dev/null
-From f36d458104101050478e290919ef4f05fbde0b3e Mon Sep 17 00:00:00 2001
-From: "zejian.su" <zejian.su@starfivetech.com>
-Date: Mon, 3 Jul 2023 16:52:13 +0800
-Subject: [PATCH 094/116] Add 16 ISP controls, remove the frame SYNC event to
- video7 (SC) These controls are: WB, CAR, CCM, CFA, CTC, DBC, DNYUV, GMARGB,
- LCCF, OBC, OECF, R2Y, SAT, SHRP, YCRV, SC
-
----
- .../platform/starfive/v4l2_driver/stf_isp.c | 628 ++++++++++++++++++
- .../platform/starfive/v4l2_driver/stf_video.c | 22 +
- .../platform/starfive/v4l2_driver/stf_vin.c | 16 +-
- include/uapi/linux/jh7110-isp.h | 48 +-
- 4 files changed, 706 insertions(+), 8 deletions(-)
-
---- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-@@ -195,6 +195,41 @@ static const char * const test_pattern_m
- "Color squares w/ rolling bar",
- };
-
-+enum isp_modules_index {
-+ imi_obc = 0,
-+ imi_oecf,
-+ imi_lccf,
-+ imi_awb,
-+ imi_dbc,
-+ imi_ctc,
-+ imi_cfa,
-+ imi_car,
-+ imi_ccm,
-+ imi_gmargb,
-+ imi_r2y,
-+ imi_ycrv,
-+ imi_shrp,
-+ imi_dnyuv,
-+ imi_sat,
-+ imi_sc
-+};
-+
-+#define MODULE_ENABLE_REGISTER0 0x10
-+#define MODULE_ENABLE_REGISTER1 0xa08
-+
-+struct module_register_info {
-+ __u32 en_reg;
-+ __u32 en_nbit;
-+ __u32 cfg_reg;
-+};
-+
-+static const struct module_register_info mod_reg_info[] = {
-+ {MODULE_ENABLE_REGISTER0, 2, 0x034}, {MODULE_ENABLE_REGISTER0, 4, 0x100}, {MODULE_ENABLE_REGISTER0, 6, 0x050}, {MODULE_ENABLE_REGISTER0, 7, 0x280},
-+ {MODULE_ENABLE_REGISTER1, 22, 0xa14}, {MODULE_ENABLE_REGISTER1, 21, 0xa10}, {MODULE_ENABLE_REGISTER1, 1, 0xa1c}, {MODULE_ENABLE_REGISTER1, 2, 0x000},
-+ {MODULE_ENABLE_REGISTER1, 3, 0xc40}, {MODULE_ENABLE_REGISTER1, 4, 0xe00}, {MODULE_ENABLE_REGISTER1, 5, 0xe40}, {MODULE_ENABLE_REGISTER1, 19, 0xf00},
-+ {MODULE_ENABLE_REGISTER1, 7, 0xe80}, {MODULE_ENABLE_REGISTER1, 17, 0xc00}, {MODULE_ENABLE_REGISTER1, 8, 0xa30}, {MODULE_ENABLE_REGISTER0, 17, 0x09c}
-+};
-+
- #define ISP_TEST_ENABLE BIT(7)
- #define ISP_TEST_ROLLING BIT(6) /* rolling horizontal bar */
- #define ISP_TEST_TRANSPARENT BIT(5)
-@@ -260,6 +295,401 @@ static int isp_g_volatile_ctrl(struct v4
- return 0;
- }
-
-+#define CREATE_REG_VALUE_FUNCTION(type) \
-+ static u32 create_reg_value_##type(const type * value, s32 size, u32 mask, s32 nbits) { \
-+ s32 npos = 0; \
-+ u32 res = 0; \
-+ s32 sz = size; \
-+ s32 i = 0; \
-+ if(size * nbits > 32) sz = 32 / nbits; \
-+ for(i = 0; i < sz; i++, npos += nbits, value++) res |= (u32)(value[0] & mask) << npos; \
-+ return res; \
-+}
-+
-+CREATE_REG_VALUE_FUNCTION(u8);
-+CREATE_REG_VALUE_FUNCTION(u16);
-+#define CREATE_REG_VALUE(type, value, size, mask, nbits) create_reg_value_##type(value, size, mask, nbits)
-+
-+#define FILL_ISP_REGS_FUNC(type) \
-+static void fill_isp_regs_##type(void __iomem *ispbase, u32 offset, const type * value, s32 size, u32 mask, u32 nbits) { \
-+ s32 i; \
-+ for(i = 0; i < size; i++, value++) \
-+ reg_write(ispbase, offset + i * 4, (u32)(value[0] & mask) << nbits); \
-+}
-+FILL_ISP_REGS_FUNC(u32);
-+FILL_ISP_REGS_FUNC(u8);
-+FILL_ISP_REGS_FUNC(u16);
-+
-+#define FILL_ISP_REGS(type, ispbase, offset, value, size, mask, nbits) \
-+ fill_isp_regs_##type(ispbase, offset, value, size, mask, nbits)
-+
-+static int isp_set_ctrl_wb(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_awb];
-+ const struct jh7110_isp_wb_setting * setting = (const struct jh7110_isp_wb_setting *)value;
-+ const struct jh7110_isp_wb_gain * gains = &setting->gains;
-+ u32 r_g = (((u32)gains->gain_r << 16) | gains->gain_r) & 0x03ff03ff;
-+ u32 g_g = (((u32)gains->gain_g << 16) | gains->gain_g) & 0x03ff03ff;
-+ u32 b_g = (((u32)gains->gain_b << 16) | gains->gain_b) & 0x03ff03ff;
-+ u32 reg_addr = reg_info->cfg_reg + 16 * sizeof(u32);
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+
-+ reg_write(ispbase, reg_addr, r_g);
-+ reg_write(ispbase, reg_addr + 1 * 4, r_g);
-+ reg_write(ispbase, reg_addr + 2 * 4, g_g);
-+ reg_write(ispbase, reg_addr + 3 * 4, g_g);
-+ reg_write(ispbase, reg_addr + 4 * 4, g_g);
-+ reg_write(ispbase, reg_addr + 5 * 4, g_g);
-+ reg_write(ispbase, reg_addr + 6 * 4, b_g);
-+ reg_write(ispbase, reg_addr + 7 * 4, b_g);
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_car(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_car];
-+ const struct jh7110_isp_car_setting * setting = (const struct jh7110_isp_car_setting *)value;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_ccm(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_ccm];
-+ const struct jh7110_isp_ccm_setting * setting = (const struct jh7110_isp_ccm_setting *)value;
-+ const struct jh7110_isp_ccm_smlow * ccm = (const struct jh7110_isp_ccm_smlow *)(&(setting->ccm_smlow));
-+ u32 reg_addr = reg_info->cfg_reg + 12 * sizeof(u32);
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+
-+ reg_write(ispbase, reg_info->cfg_reg, 6 << 16);
-+ FILL_ISP_REGS(u32, ispbase, reg_addr, (u32 *)ccm, 12, 0x7ff, 0);
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_cfa(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_cfa];
-+ const struct jh7110_isp_cfa_setting * setting = (const struct jh7110_isp_cfa_setting *)value;
-+ const struct jh7110_isp_cfa_params * cfg = (const struct jh7110_isp_cfa_params *)(&(setting->settings));
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+
-+ reg_write(ispbase, reg_addr, ((u32)(cfg->cross_cov & 0x3) << 4) | (cfg->hv_width & 0xf));
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_ctc(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_ctc];
-+ const struct jh7110_isp_ctc_setting * setting = (const struct jh7110_isp_ctc_setting *)value;
-+ const struct jh7110_isp_ctc_params * cfg = (const struct jh7110_isp_ctc_params *)(&(setting->settings));
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ u32 reg_value = (u32)(((cfg->saf_mode & 1) << 1) | (cfg->daf_mode & 1)) << 30;
-+
-+ reg_value |= ((u32)(cfg->max_gt & 0x3ff) << 16) | (cfg->min_gt & 0x3ff);
-+ reg_write(ispbase, reg_addr, reg_value);
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_dbc(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_dbc];
-+ const struct jh7110_isp_dbc_setting * setting = (const struct jh7110_isp_dbc_setting *)value;
-+ const struct jh7110_isp_dbc_params * cfg = (const struct jh7110_isp_dbc_params *)(&(setting->settings));
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+
-+ reg_write(ispbase, reg_addr, ((u32)(cfg->bad_gt & 0x3ff) << 16) | (cfg->bad_xt & 0x3ff));
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_dnyuv(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_dnyuv];
-+ const struct jh7110_isp_dnyuv_setting * setting = (const struct jh7110_isp_dnyuv_setting *)value;
-+ const struct jh7110_isp_dnyuv_params * cfg = (const struct jh7110_isp_dnyuv_params *)(&(setting->settings));
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, cfg->y_sweight, 6, 0x7, 4));
-+ reg_write(ispbase, reg_addr + 4, CREATE_REG_VALUE(u8, &cfg->y_sweight[6], 4, 0x7, 4));
-+ reg_write(ispbase, reg_addr + 8, CREATE_REG_VALUE(u8, cfg->uv_sweight, 6, 0x7, 4));
-+ reg_write(ispbase, reg_addr + 12, CREATE_REG_VALUE(u8, &cfg->uv_sweight[6], 4, 0x7, 4));
-+ reg_write(ispbase, reg_addr + 16, CREATE_REG_VALUE(u16, &cfg->y_curve[0], 2, 0x3ff, 16));
-+ reg_write(ispbase, reg_addr + 20, CREATE_REG_VALUE(u16, &cfg->y_curve[2], 2, 0x3ff, 16));
-+ reg_write(ispbase, reg_addr + 24, CREATE_REG_VALUE(u16, &cfg->y_curve[4], 2, 0x3ff, 16));
-+ reg_write(ispbase, reg_addr + 28, CREATE_REG_VALUE(u16, &cfg->uv_curve[0], 2, 0x3ff, 16));
-+ reg_write(ispbase, reg_addr + 32, CREATE_REG_VALUE(u16, &cfg->uv_curve[2], 2, 0x3ff, 16));
-+ reg_write(ispbase, reg_addr + 36, CREATE_REG_VALUE(u16, &cfg->uv_curve[4], 2, 0x3ff, 16));
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_gmargb(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_gmargb];
-+ const struct jh7110_isp_gmargb_setting * setting = (const struct jh7110_isp_gmargb_setting *)value;
-+ const struct jh7110_isp_gmargb_point * curve = setting->curve;
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ s32 i;
-+
-+ for(i = 0; i < 15; i++, curve++, reg_addr += 4)
-+ reg_write(ispbase, reg_addr, ((u32)curve->sg_val << 16) | (curve->g_val & 0x3ff));
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_lccf(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_lccf];
-+ const struct jh7110_isp_lccf_setting * setting = (const struct jh7110_isp_lccf_setting *)value;
-+ const s16 * params = (s16 *)(&setting->r_param);
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ s32 i;
-+
-+ reg_write(ispbase, reg_addr, ((u32)(setting->circle.center_y & 0x7fff) << 16) | (setting->circle.center_x & 0x7fff));
-+ reg_write(ispbase, reg_addr + 8, setting->circle.radius & 0xf);
-+ reg_addr += 0x90;
-+ for(i = 0; i < 4; i++, reg_addr += 4, params += 2)
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0x1fff, 16));
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_obc(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_obc];
-+ const struct jh7110_isp_blacklevel_setting * setting = (const struct jh7110_isp_blacklevel_setting *)value;
-+ const u8 * params = (u8 *)setting->gain;
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ s32 i;
-+
-+ reg_write(ispbase, reg_addr, ((u32)(setting->win_size.height & 0xf) << 4) | (setting->win_size.width & 0xf));
-+
-+ reg_addr += 0x2ac; //0x2e0
-+ for(i = 0; i < 8; i++, reg_addr += 4, params += 4)
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, params, 4, 0xff, 8));
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_oecf(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_oecf];
-+ const struct jh7110_isp_oecf_setting * setting = (const struct jh7110_isp_oecf_setting *)value;
-+ const struct jh7110_isp_oecf_point * pts = (struct jh7110_isp_oecf_point *)(setting->r_curve);
-+ u32 reg_x_addr = reg_info->cfg_reg;
-+ u32 reg_y_addr = reg_info->cfg_reg + 0x080;
-+ u32 reg_s_addr = reg_info->cfg_reg + 0x100;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ u32 x, y, slope;
-+ s32 i;
-+
-+ for(i = 0; i < 32; i++, reg_x_addr += 4, reg_y_addr += 4, reg_s_addr += 4) {
-+ x = pts->x & 0x3ff;
-+ y = pts->y & 0x3ff;
-+ slope = pts->slope & 0x3ff;
-+ pts++;
-+ x |= ((pts->x & 0x3ff) << 16);
-+ y |= ((pts->y & 0x3ff) << 16);
-+ slope |= ((pts->slope & 0x3ff) << 16);
-+ pts++;
-+
-+ reg_write(ispbase, reg_x_addr, x);
-+ reg_write(ispbase, reg_y_addr, y);
-+ reg_write(ispbase, reg_s_addr, slope);
-+ }
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_r2y(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_r2y];
-+ const struct jh7110_isp_r2y_setting * setting = (const struct jh7110_isp_r2y_setting *)value;
-+ const s16 * params = setting->matrix.m;
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ s32 i;
-+
-+ for(i = 0; i < 9; i++, reg_addr += 4)
-+ reg_write(ispbase, reg_addr, (u32)(params[i] & 0x1ff));
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+
-+static int isp_set_ctrl_sat(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_sat];
-+ const struct jh7110_isp_sat_setting * setting = (const struct jh7110_isp_sat_setting *)value;
-+ const u16 * params = (u16 *)(&setting->sat_info);
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ s32 i;
-+
-+ for(i = 0; i < 3; i++, reg_addr += 4, params += 2)
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0xfff, 16));
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, &setting->hue_info.cos, 2, 0x3ff, 16));
-+ reg_addr += 4;
-+ reg_write(ispbase, reg_addr, setting->sat_info.cmsf & 0xf);
-+
-+ params = (u16 *)(&setting->curve);
-+ reg_addr += 0x14; // 0xa54
-+ for(i = 0; i < 2; i++, reg_addr += 4, params += 2)
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0x3fff, 16));
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_shrp(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_shrp];
-+ const struct jh7110_isp_sharp_setting * setting = (const struct jh7110_isp_sharp_setting *)value;
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ s32 i;
-+
-+ for(i = 0; i < 4; i++, reg_addr += 4)
-+ reg_write(ispbase, reg_addr, ((u32)(setting->strength.diff[i] & 0x3ff) << 16) | ((u32)(setting->weight.weight[i] & 0xf) << 8));
-+ FILL_ISP_REGS(u8, ispbase, reg_addr, (u8 *)(&setting->weight.weight[4]), 15 - 4, 0xf, 8);
-+ reg_addr += (15 - 4) * 4;
-+
-+ for(i = 0; i < 3; i++, reg_addr += 4)
-+ reg_write(ispbase, reg_addr, ((u32)(setting->strength.f[i] & 0x7f) << 24) | (setting->strength.s[i] & 0x1fffff));
-+
-+ reg_addr += 3 * 4;
-+ reg_write(ispbase, reg_addr, ((u32)(setting->pdirf & 0xf) << 28) | ((u32)(setting->ndirf & 0xf) << 24) | (setting->weight.recip_wei_sum & 0x3fffff));
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_ycrv(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_ycrv];
-+ const struct jh7110_isp_ycrv_setting * setting = (const struct jh7110_isp_ycrv_setting *)value;
-+ u32 reg_addr = reg_info->cfg_reg;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+
-+ FILL_ISP_REGS(u16, ispbase, reg_addr, (u16 *)(setting->curve.y), 64, 0x3ff, 0);
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
-+static int isp_set_ctrl_sc(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct module_register_info * reg_info = &mod_reg_info[imi_sc];
-+ const struct jh7110_isp_sc_setting * setting = (const struct jh7110_isp_sc_setting *)value;
-+ const u8 * params = setting->awb_config.awb_cw;
-+ u32 reg_addr = 0x00;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ u32 weight_cfg[6] = {0};
-+ u32 * weight = weight_cfg;
-+ u32 * w_diff = weight_cfg + 2;
-+ s32 i;
-+
-+ // AF register
-+ reg_write(ispbase, 0xc0,
-+ ((u32)(setting->af_config.es_hor_thr & 0x1ff) << 16) |
-+ ((u32)(setting->af_config.es_ver_thr & 0xff) << 8) |
-+ ((setting->af_config.ver_en & 0x1) << 3) |
-+ ((setting->af_config.hor_en & 0x1) << 2) |
-+ ((setting->af_config.es_sum_mode & 0x1) << 1) |
-+ (setting->af_config.es_hor_mode & 0x1));
-+
-+ // AWB weight sum register
-+ reg_write(ispbase, 0x5d0, CREATE_REG_VALUE(u8, &setting->awb_config.ws_config.awb_ws_rl, 4, 0xff, 8));
-+ reg_write(ispbase, 0x5d4, CREATE_REG_VALUE(u8, &setting->awb_config.ws_config.awb_ws_gbl, 4, 0xff, 8));
-+
-+ // AWB weight value point
-+ reg_addr = 0x4d0;
-+ for(i = 0; i < 13; i++) {
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, params, 8, 0xf, 4));
-+ reg_addr += 4;
-+ params += 8;
-+ reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, params, 5, 0xf, 4));
-+ reg_addr += 4;
-+ params += 5;
-+ }
-+
-+ // AWB intensity weight curve register
-+ reg_addr = 0x538;
-+ for(i = 0; i < 4; i++) {
-+ weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4);
-+ w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8);
-+ }
-+ for(w_diff++; i < 8; i++) {
-+ weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4);
-+ w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8);
-+ }
-+ for(weight++, w_diff++; i < 12; i++) {
-+ weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4);
-+ w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8);
-+ }
-+ for(w_diff++; i < 16; i++) {
-+ weight[0] |= (setting->awb_config.pts[i].weight & 0xf) << (i * 4);
-+ w_diff[0] |= ((((s16)(setting->awb_config.pts[i + 1].weight & 0xf) - (s16)(setting->awb_config.pts[i].weight & 0xf)) * 2) & 0xff) << (i * 8);
-+ }
-+
-+ FILL_ISP_REGS(u32, ispbase, reg_addr, weight_cfg, 6, 0xffffffff, 0);
-+
-+ reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-+
-+ return 0;
-+}
-+
- static int isp_s_ctrl(struct v4l2_ctrl *ctrl)
- {
- struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-@@ -310,10 +740,52 @@ static int isp_s_ctrl(struct v4l2_ctrl *
- ret = isp_set_ctrl_vflip(isp_dev, ctrl->val);
- break;
- case V4L2_CID_USER_JH7110_ISP_WB_SETTING:
-+ ret = isp_set_ctrl_wb(isp_dev, ctrl->p_new.p_u8);
- break;
- case V4L2_CID_USER_JH7110_ISP_CAR_SETTING:
-+ ret = isp_set_ctrl_car(isp_dev, ctrl->p_new.p_u8);
- break;
- case V4L2_CID_USER_JH7110_ISP_CCM_SETTING:
-+ ret = isp_set_ctrl_ccm(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_CFA_SETTING:
-+ ret = isp_set_ctrl_cfa(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_CTC_SETTING:
-+ ret = isp_set_ctrl_ctc(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_DBC_SETTING:
-+ ret = isp_set_ctrl_dbc(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_DNYUV_SETTING:
-+ ret = isp_set_ctrl_dnyuv(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_GMARGB_SETTING:
-+ ret = isp_set_ctrl_gmargb(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_LCCF_SETTING:
-+ ret = isp_set_ctrl_lccf(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_OBC_SETTING:
-+ ret = isp_set_ctrl_obc(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_OECF_SETTING:
-+ ret = isp_set_ctrl_oecf(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_R2Y_SETTING:
-+ ret = isp_set_ctrl_r2y(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_SAT_SETTING:
-+ ret = isp_set_ctrl_sat(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_SHRP_SETTING:
-+ ret = isp_set_ctrl_shrp(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_YCRV_SETTING:
-+ ret = isp_set_ctrl_ycrv(isp_dev, ctrl->p_new.p_u8);
-+ break;
-+ case V4L2_CID_USER_JH7110_ISP_STAT_SETTING:
-+ ret = isp_set_ctrl_sc(isp_dev, ctrl->p_new.p_u8);
- break;
- default:
- ret = -EINVAL;
-@@ -365,6 +837,162 @@ struct v4l2_ctrl_config isp_ctrl[] = {
- .dims[0] = sizeof(struct jh7110_isp_ccm_setting),
- .flags = 0,
- },
-+ [3] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "CFA Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_CFA_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_cfa_setting),
-+ .flags = 0,
-+ },
-+ [4] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "CTC Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_CTC_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_ctc_setting),
-+ .flags = 0,
-+ },
-+ [5] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "CTC Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_DBC_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_dbc_setting),
-+ .flags = 0,
-+ },
-+ [6] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "DNYUV Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_DNYUV_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_dnyuv_setting),
-+ .flags = 0,
-+ },
-+ [7] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "DNYUV Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_GMARGB_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_gmargb_setting),
-+ .flags = 0,
-+ },
-+ [8] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "LCCF Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_LCCF_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_lccf_setting),
-+ .flags = 0,
-+ },
-+ [9] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "OBC Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_OBC_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_blacklevel_setting),
-+ .flags = 0,
-+ },
-+ [10] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "OECF Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_OECF_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_oecf_setting),
-+ .flags = 0,
-+ },
-+ [11] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "R2Y Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_R2Y_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_r2y_setting),
-+ .flags = 0,
-+ },
-+ [12] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "SAT Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_SAT_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_sat_setting),
-+ .flags = 0,
-+ },
-+ [13] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "SAT Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_SHRP_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_sharp_setting),
-+ .flags = 0,
-+ },
-+ [14] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "YCRV Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_YCRV_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_ycrv_setting),
-+ .flags = 0,
-+ },
-+ [15] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "SC Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_STAT_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_sc_setting),
-+ .flags = 0,
-+ },
- };
-
- static int isp_init_controls(struct stf_isp_dev *isp_dev)
---- a/drivers/media/platform/starfive/v4l2_driver/stf_video.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.c
-@@ -1281,6 +1281,22 @@ int video_s_selection(struct file *file,
- return ret;
- }
-
-+static int stf_video_subscribe_event(struct v4l2_fh *fh,
-+ const struct v4l2_event_subscription *sub)
-+{
-+ switch (sub->type) {
-+ case V4L2_EVENT_FRAME_SYNC:
-+ return v4l2_event_subscribe(fh, sub, 2, NULL);
-+ //int ret = v4l2_event_subscribe(fh, sub, 2, NULL);
-+ //pr_info("subscribe ret: %d\n", ret);
-+ //return ret;
-+ default:
-+ return v4l2_ctrl_subscribe_event(fh, sub);
-+ //st_debug(ST_VIN, "unsupport subscribe_event\n");
-+ //return -EINVAL;
-+ }
-+}
-+
- static const struct v4l2_ioctl_ops stf_vid_ioctl_ops = {
- .vidioc_querycap = video_querycap,
- .vidioc_enum_fmt_vid_cap = video_enum_fmt,
-@@ -1305,6 +1321,8 @@ static const struct v4l2_ioctl_ops stf_v
- .vidioc_s_parm = video_s_parm,
- .vidioc_s_selection = video_s_selection,
- .vidioc_g_selection = video_g_selection,
-+ .vidioc_subscribe_event = stf_video_subscribe_event,
-+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- };
-
- static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_mp = {
-@@ -1331,6 +1349,8 @@ static const struct v4l2_ioctl_ops stf_v
- .vidioc_s_parm = video_s_parm,
- .vidioc_s_selection = video_s_selection,
- .vidioc_g_selection = video_g_selection,
-+ .vidioc_subscribe_event = stf_video_subscribe_event,
-+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- };
-
- static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_out = {
-@@ -1350,6 +1370,8 @@ static const struct v4l2_ioctl_ops stf_v
- .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
- .vidioc_streamon = vb2_ioctl_streamon,
- .vidioc_streamoff = vb2_ioctl_streamoff,
-+ .vidioc_subscribe_event = stf_video_subscribe_event,
-+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- };
-
- static int video_open(struct file *file)
---- a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c
-@@ -1145,9 +1145,12 @@ static void vin_buffer_done(struct vin_l
- spin_lock_irqsave(&line->output_lock, flags);
-
- while ((ready_buf = vin_buf_get_ready(output))) {
-- if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) {
-+ //if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) {
-+ if (line->id == VIN_LINE_ISP_SCD_Y) {
- event.u.frame_sync.frame_sequence = output->sequence;
-- v4l2_event_queue(line->subdev.devnode, &event);
-+ v4l2_event_queue(&(line->video_out.vdev), &event);
-+ //v4l2_event_queue(line->subdev.devnode, &event);
-+ //pr_info("----------frame sync-----------\n");
- }
-
- ready_buf->vb.vb2_buf.timestamp = ts;
-@@ -1346,7 +1349,10 @@ static int stf_vin_subscribe_event(struc
- {
- switch (sub->type) {
- case V4L2_EVENT_FRAME_SYNC:
-- return v4l2_event_subscribe(fh, sub, 0, NULL);
-+ //return v4l2_event_subscribe(fh, sub, 2, NULL);
-+ int ret = v4l2_event_subscribe(fh, sub, 2, NULL);
-+ pr_info("subscribe ret: %d\n", ret);
-+ return ret;
- default:
- st_debug(ST_VIN, "unsupport subscribe_event\n");
- return -EINVAL;
-@@ -1355,8 +1361,8 @@ static int stf_vin_subscribe_event(struc
-
- static const struct v4l2_subdev_core_ops vin_core_ops = {
- .s_power = vin_set_power,
-- .subscribe_event = stf_vin_subscribe_event,
-- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-+ //.subscribe_event = stf_vin_subscribe_event,
-+ //.unsubscribe_event = v4l2_event_subdev_unsubscribe,
- };
-
- static const struct v4l2_subdev_video_ops vin_video_ops = {
---- a/include/uapi/linux/jh7110-isp.h
-+++ b/include/uapi/linux/jh7110-isp.h
-@@ -15,6 +15,8 @@
-
- #include <linux/v4l2-controls.h>
-
-+#define V4L2_CID_USER_JH7110_ISP_BASE (V4L2_CID_USER_BASE + 0x1170)
-+
- #define V4L2_CID_USER_JH7110_ISP_WB_SETTING \
- (V4L2_CID_USER_JH7110_ISP_BASE + 0x0001)
- #define V4L2_CID_USER_JH7110_ISP_CAR_SETTING \
-@@ -45,6 +47,8 @@
- (V4L2_CID_USER_JH7110_ISP_BASE + 0x000e)
- #define V4L2_CID_USER_JH7110_ISP_YCRV_SETTING \
- (V4L2_CID_USER_JH7110_ISP_BASE + 0x000f)
-+#define V4L2_CID_USER_JH7110_ISP_STAT_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0010)
-
- struct jh7110_isp_wb_gain {
- __u16 gain_r;
-@@ -202,13 +206,13 @@ struct jh7110_isp_sat_curve {
- };
-
- struct jh7110_isp_sat_hue_info {
-- __s16 sin;
- __s16 cos;
-+ __s16 sin;
- };
-
- struct jh7110_isp_sat_info {
- __s16 gain_cmab;
-- __s16 gain_cmad;
-+ __s16 gain_cmmd;
- __s16 threshold_cmb;
- __s16 threshold_cmd;
- __s16 offset_u;
-@@ -230,7 +234,8 @@ struct jh7110_isp_sharp_weight {
-
- struct jh7110_isp_sharp_strength {
- __s16 diff[4];
-- __s16 f[4];
-+ __s16 f[3];
-+ __s32 s[3];
- };
-
- struct jh7110_isp_sharp_setting {
-@@ -250,4 +255,41 @@ struct jh7110_isp_ycrv_setting {
- struct jh7110_isp_ycrv_curve curve;
- };
-
-+struct jh7110_isp_sc_af_config {
-+ __u8 es_hor_mode;
-+ __u8 es_sum_mode;
-+ __u8 hor_en;
-+ __u8 ver_en;
-+ __u8 es_ver_thr;
-+ __u16 es_hor_thr;
-+};
-+
-+struct jh7110_isp_sc_awb_ws {
-+ __u8 awb_ws_rl;
-+ __u8 awb_ws_ru;
-+ __u8 awb_ws_grl;
-+ __u8 awb_ws_gru;
-+ __u8 awb_ws_gbl;
-+ __u8 awb_ws_gbu;
-+ __u8 awb_ws_bl;
-+ __u8 awb_ws_bu;
-+};
-+
-+struct jh7110_isp_sc_awb_point {
-+ __u16 intensity;
-+ __u8 weight;
-+};
-+
-+struct jh7110_isp_sc_awb_config {
-+ struct jh7110_isp_sc_awb_ws ws_config;
-+ __u8 awb_cw[169];
-+ struct jh7110_isp_sc_awb_point pts[17];
-+};
-+
-+struct jh7110_isp_sc_setting {
-+ __u32 enabled;
-+ struct jh7110_isp_sc_af_config af_config;
-+ struct jh7110_isp_sc_awb_config awb_config;
-+};
-+
- #endif
+++ /dev/null
-From 5d61c6fd10144605238311d68c99449c4667a345 Mon Sep 17 00:00:00 2001
-From: "zejian.su" <zejian.su@starfivetech.com>
-Date: Mon, 7 Aug 2023 10:38:36 +0800
-Subject: [PATCH 095/116] Expand 2 bytes after the SC buffer for the AE/AWB
- flag and copy the histogram data to the SC buffer.
-
----
- .../platform/starfive/v4l2_driver/stf_isp.c | 37 ++++++++++++++++++-
- .../platform/starfive/v4l2_driver/stf_isp.h | 2 +-
- .../platform/starfive/v4l2_driver/stf_video.c | 5 ---
- .../platform/starfive/v4l2_driver/stf_vin.c | 36 +++++++++---------
- include/uapi/linux/jh7110-isp.h | 33 +++++++++++++++++
- 5 files changed, 87 insertions(+), 26 deletions(-)
-
---- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-@@ -323,6 +323,13 @@ FILL_ISP_REGS_FUNC(u16);
- #define FILL_ISP_REGS(type, ispbase, offset, value, size, mask, nbits) \
- fill_isp_regs_##type(ispbase, offset, value, size, mask, nbits)
-
-+static void fill_regs_with_zero(void __iomem *ispbase, u32 offset, u32 size)
-+{
-+ u32 i;
-+ for(i = 0; i < size; i++, offset += 4)
-+ reg_write(ispbase, offset, 0);
-+}
-+
- static int isp_set_ctrl_wb(struct stf_isp_dev *isp_dev, const void * value)
- {
- const struct module_register_info * reg_info = &mod_reg_info[imi_awb];
-@@ -335,6 +342,8 @@ static int isp_set_ctrl_wb(struct stf_is
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
-
-+ fill_regs_with_zero(ispbase, reg_info->cfg_reg, 16);
-+
- reg_write(ispbase, reg_addr, r_g);
- reg_write(ispbase, reg_addr + 1 * 4, r_g);
- reg_write(ispbase, reg_addr + 2 * 4, g_g);
-@@ -370,8 +379,13 @@ static int isp_set_ctrl_ccm(struct stf_i
- void __iomem *ispbase = vin->isp_base;
-
- reg_write(ispbase, reg_info->cfg_reg, 6 << 16);
-+ fill_regs_with_zero(ispbase, reg_info->cfg_reg + 4, 11);
-+
- FILL_ISP_REGS(u32, ispbase, reg_addr, (u32 *)ccm, 12, 0x7ff, 0);
-
-+ reg_addr += 12 * 4;
-+ fill_regs_with_zero(ispbase, reg_addr, 2);
-+
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
-
- return 0;
-@@ -640,6 +654,27 @@ static int isp_set_ctrl_sc(struct stf_is
- u32 * w_diff = weight_cfg + 2;
- s32 i;
-
-+ // SC dumping axi id
-+ reg_write(ispbase, 0x9c, 1 << 24);
-+
-+ // SC frame crop
-+ reg_write(ispbase, 0xb8, ((u32)(setting->crop_config.v_start) << 16) | setting->crop_config.h_start);
-+
-+ // SC config1
-+ reg_write(ispbase, 0xbc, ((u32)(setting->awb_config.sel) << 30) | ((u32)(setting->awb_config.awb_ps_grb_ba) << 16) |
-+ ((u32)(setting->crop_config.sw_height) << 8) | setting->crop_config.sw_width);
-+
-+ // SC decimation config
-+ reg_write(ispbase, 0xd8, ((u32)(setting->crop_config.vkeep) << 24) | ((u32)(setting->crop_config.vperiod) << 16) |
-+ ((u32)(setting->crop_config.hkeep) << 8) | setting->crop_config.hperiod);
-+
-+ // SC AWB pixel sum config
-+ reg_write(ispbase, 0xc4, CREATE_REG_VALUE(u8, &setting->awb_config.ws_ps_config.awb_ps_rl, 4, 0xff, 8));
-+ reg_write(ispbase, 0xc8, CREATE_REG_VALUE(u8, &setting->awb_config.ws_ps_config.awb_ps_bl, 4, 0xff, 8));
-+ reg_write(ispbase, 0xcc, CREATE_REG_VALUE(u16, &setting->awb_config.ws_ps_config.awb_ps_grl, 2, 0xffff, 16));
-+ reg_write(ispbase, 0xd0, CREATE_REG_VALUE(u16, &setting->awb_config.ws_ps_config.awb_ps_gbl, 2, 0xffff, 16));
-+ reg_write(ispbase, 0xd4, CREATE_REG_VALUE(u16, &setting->awb_config.ws_ps_config.awb_ps_grbl, 2, 0xffff, 16));
-+
- // AF register
- reg_write(ispbase, 0xc0,
- ((u32)(setting->af_config.es_hor_thr & 0x1ff) << 16) |
-@@ -686,7 +721,7 @@ static int isp_set_ctrl_sc(struct stf_is
- FILL_ISP_REGS(u32, ispbase, reg_addr, weight_cfg, 6, 0xffffffff, 0);
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
---- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.h
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.h
-@@ -18,7 +18,7 @@
-
- #define ISP_SCD_BUFFER_SIZE (19 * 256 * 4) // align 128
- #define ISP_YHIST_BUFFER_SIZE (64 * 4)
--#define ISP_SCD_Y_BUFFER_SIZE (ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)
-+#define ISP_SCD_Y_BUFFER_SIZE (ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE + 2)
- #define ISP_RAW_DATA_BITS 12
- #define SCALER_RATIO_MAX 1 // no compose function
- #define STF_ISP_REG_OFFSET_MAX 0x0FFF
---- a/drivers/media/platform/starfive/v4l2_driver/stf_video.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_video.c
-@@ -1287,13 +1287,8 @@ static int stf_video_subscribe_event(str
- switch (sub->type) {
- case V4L2_EVENT_FRAME_SYNC:
- return v4l2_event_subscribe(fh, sub, 2, NULL);
-- //int ret = v4l2_event_subscribe(fh, sub, 2, NULL);
-- //pr_info("subscribe ret: %d\n", ret);
-- //return ret;
- default:
- return v4l2_ctrl_subscribe_event(fh, sub);
-- //st_debug(ST_VIN, "unsupport subscribe_event\n");
-- //return -EINVAL;
- }
- }
-
---- a/drivers/media/platform/starfive/v4l2_driver/stf_vin.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_vin.c
-@@ -1147,6 +1147,17 @@ static void vin_buffer_done(struct vin_l
- while ((ready_buf = vin_buf_get_ready(output))) {
- //if (line->id >= VIN_LINE_ISP && line->id <= VIN_LINE_ISP_SS1) {
- if (line->id == VIN_LINE_ISP_SCD_Y) {
-+#define ADDR_REG_YHIST_ACC_0 0x0D00
-+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
-+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ u32 y_hist_reg_addr = ADDR_REG_YHIST_ACC_0;
-+ u32 * y_hist_addr = (u32 *)ready_buf->vaddr_sc;
-+ s32 i = 0;
-+
-+ for(i = 0; i < 64; i++, y_hist_reg_addr += 4)
-+ y_hist_addr[i] = reg_read(ispbase, y_hist_reg_addr);
-+
- event.u.frame_sync.frame_sequence = output->sequence;
- v4l2_event_queue(&(line->video_out.vdev), &event);
- //v4l2_event_queue(line->subdev.devnode, &event);
-@@ -1246,9 +1257,14 @@ static void vin_change_buffer(struct vin
- scd_type = vin_dev->hw_ops->vin_isp_get_scd_type(vin_dev);
- ready_buf->vb.flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME);
- if (scd_type == AWB_TYPE)
-+ {
- ready_buf->vb.flags |= V4L2_BUF_FLAG_PFRAME;
-- else
-+ *((u16 *)(ready_buf->vaddr_sc + ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)) = 0xffff;
-+ }else{
- ready_buf->vb.flags |= V4L2_BUF_FLAG_BFRAME;
-+ *((u16 *)(ready_buf->vaddr_sc + ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)) = 0;
-+ }
-+
- if (!output->frame_skip) {
- output->frame_skip = ISP_AWB_OECF_SKIP_FRAME;
- scd_type = scd_type == AWB_TYPE ? OECF_TYPE : AWB_TYPE;
-@@ -1343,26 +1359,8 @@ static int vin_link_setup(struct media_e
- return 0;
- }
-
--static int stf_vin_subscribe_event(struct v4l2_subdev *sd,
-- struct v4l2_fh *fh,
-- struct v4l2_event_subscription *sub)
--{
-- switch (sub->type) {
-- case V4L2_EVENT_FRAME_SYNC:
-- //return v4l2_event_subscribe(fh, sub, 2, NULL);
-- int ret = v4l2_event_subscribe(fh, sub, 2, NULL);
-- pr_info("subscribe ret: %d\n", ret);
-- return ret;
-- default:
-- st_debug(ST_VIN, "unsupport subscribe_event\n");
-- return -EINVAL;
-- }
--}
--
- static const struct v4l2_subdev_core_ops vin_core_ops = {
- .s_power = vin_set_power,
-- //.subscribe_event = stf_vin_subscribe_event,
-- //.unsubscribe_event = v4l2_event_subdev_unsubscribe,
- };
-
- static const struct v4l2_subdev_video_ops vin_video_ops = {
---- a/include/uapi/linux/jh7110-isp.h
-+++ b/include/uapi/linux/jh7110-isp.h
-@@ -255,6 +255,17 @@ struct jh7110_isp_ycrv_setting {
- struct jh7110_isp_ycrv_curve curve;
- };
-
-+struct jh7110_isp_sc_config {
-+ __u16 h_start;
-+ __u16 v_start;
-+ __u8 sw_width;
-+ __u8 sw_height;
-+ __u8 hperiod;
-+ __u8 hkeep;
-+ __u8 vperiod;
-+ __u8 vkeep;
-+};
-+
- struct jh7110_isp_sc_af_config {
- __u8 es_hor_mode;
- __u8 es_sum_mode;
-@@ -264,6 +275,23 @@ struct jh7110_isp_sc_af_config {
- __u16 es_hor_thr;
- };
-
-+struct jh7110_isp_sc_awb_ps {
-+ __u8 awb_ps_rl;
-+ __u8 awb_ps_ru;
-+ __u8 awb_ps_gl;
-+ __u8 awb_ps_gu;
-+ __u8 awb_ps_bl;
-+ __u8 awb_ps_bu;
-+ __u8 awb_ps_yl;
-+ __u8 awb_ps_yu;
-+ __u16 awb_ps_grl;
-+ __u16 awb_ps_gru;
-+ __u16 awb_ps_gbl;
-+ __u16 awb_ps_gbu;
-+ __u16 awb_ps_grbl;
-+ __u16 awb_ps_grbu;
-+};
-+
- struct jh7110_isp_sc_awb_ws {
- __u8 awb_ws_rl;
- __u8 awb_ws_ru;
-@@ -275,12 +303,16 @@ struct jh7110_isp_sc_awb_ws {
- __u8 awb_ws_bu;
- };
-
-+
- struct jh7110_isp_sc_awb_point {
- __u16 intensity;
- __u8 weight;
- };
-
- struct jh7110_isp_sc_awb_config {
-+ struct jh7110_isp_sc_awb_ps ws_ps_config;
-+ __u8 awb_ps_grb_ba;
-+ __u8 sel;
- struct jh7110_isp_sc_awb_ws ws_config;
- __u8 awb_cw[169];
- struct jh7110_isp_sc_awb_point pts[17];
-@@ -288,6 +320,7 @@ struct jh7110_isp_sc_awb_config {
-
- struct jh7110_isp_sc_setting {
- __u32 enabled;
-+ struct jh7110_isp_sc_config crop_config;
- struct jh7110_isp_sc_af_config af_config;
- struct jh7110_isp_sc_awb_config awb_config;
- };
+++ /dev/null
-From 04eff0f76091015cbecd39de41d45c493e7a91db Mon Sep 17 00:00:00 2001
-From: "zejian.su" <zejian.su@starfivetech.com>
-Date: Mon, 30 Oct 2023 16:09:58 +0800
-Subject: [PATCH 096/116] Add ISP control for video2 and video3.
-
-Signed-off-by: zejian.su <zejian.su@starfivetech.com>
----
- .../platform/starfive/v4l2_driver/stf_isp.c | 46 +++++++++++++++++++
- include/uapi/linux/jh7110-isp.h | 23 ++++++++++
- 2 files changed, 69 insertions(+)
-
---- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-@@ -725,6 +725,24 @@ static int isp_set_ctrl_sc(struct stf_is
- return 0;
- }
-
-+static int isp_set_ctrl_outss(struct stf_isp_dev *isp_dev, const void * value)
-+{
-+ const struct jh7110_isp_outss_setting * setting = (const struct jh7110_isp_outss_setting *)value;
-+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
-+ void __iomem *ispbase = vin->isp_base;
-+ u32 reg_addr = !setting->which ? 0xa9c : 0xab4;
-+
-+ if(!setting->stride)
-+ return 0;
-+
-+ // Output Image Stride Register, 8-byte(64bit) granularity.
-+ reg_write(ispbase, reg_addr, setting->stride);
-+ reg_write(ispbase, reg_addr + 4, ((setting->hsm << 16) | (setting->hsm & 0x3)));
-+ reg_write(ispbase, reg_addr + 8, ((setting->vsm << 16) | (setting->vsm & 0x3)));
-+
-+ return 0;
-+}
-+
- static int isp_s_ctrl(struct v4l2_ctrl *ctrl)
- {
- struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
-@@ -822,6 +840,10 @@ static int isp_s_ctrl(struct v4l2_ctrl *
- case V4L2_CID_USER_JH7110_ISP_STAT_SETTING:
- ret = isp_set_ctrl_sc(isp_dev, ctrl->p_new.p_u8);
- break;
-+ case V4L2_CID_USER_JH7110_ISP_OUTSS0_SETTING:
-+ case V4L2_CID_USER_JH7110_ISP_OUTSS1_SETTING:
-+ ret = isp_set_ctrl_outss(isp_dev, ctrl->p_new.p_u8);
-+ break;
- default:
- ret = -EINVAL;
- break;
-@@ -1028,6 +1050,30 @@ struct v4l2_ctrl_config isp_ctrl[] = {
- .dims[0] = sizeof(struct jh7110_isp_sc_setting),
- .flags = 0,
- },
-+ [16] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "OUTSS Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_OUTSS0_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_outss_setting),
-+ .flags = 0,
-+ },
-+ [17] = {
-+ .ops = &isp_ctrl_ops,
-+ .type = V4L2_CTRL_TYPE_U8,
-+ .def = 0,
-+ .min = 0x00,
-+ .max = 0xff,
-+ .step = 1,
-+ .name = "OUTSS Setting",
-+ .id = V4L2_CID_USER_JH7110_ISP_OUTSS1_SETTING,
-+ .dims[0] = sizeof(struct jh7110_isp_outss_setting),
-+ .flags = 0,
-+ },
- };
-
- static int isp_init_controls(struct stf_isp_dev *isp_dev)
---- a/include/uapi/linux/jh7110-isp.h
-+++ b/include/uapi/linux/jh7110-isp.h
-@@ -49,6 +49,10 @@
- (V4L2_CID_USER_JH7110_ISP_BASE + 0x000f)
- #define V4L2_CID_USER_JH7110_ISP_STAT_SETTING \
- (V4L2_CID_USER_JH7110_ISP_BASE + 0x0010)
-+#define V4L2_CID_USER_JH7110_ISP_OUTSS0_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0011)
-+#define V4L2_CID_USER_JH7110_ISP_OUTSS1_SETTING \
-+ (V4L2_CID_USER_JH7110_ISP_BASE + 0x0012)
-
- struct jh7110_isp_wb_gain {
- __u16 gain_r;
-@@ -325,4 +329,23 @@ struct jh7110_isp_sc_setting {
- struct jh7110_isp_sc_awb_config awb_config;
- };
-
-+struct jh7110_isp_outss_setting {
-+ __u8 which;
-+ __u16 stride; // Output Image Stride Register, 8-byte(64bit) granularity.
-+ __u8 hsm; // horizontal scale mode
-+ __u32 hsf; // horizontal scale factor (time 4096)
-+ __u8 vsm; // vertical scale mode
-+ __u32 vsf; // vertical scale factor (time 4096)
-+};
-+
-+struct jh7110_isp_sc_buffer {
-+ __u32 y_histogram[64];
-+ __u32 reserv0[33];
-+ __u32 bright_sc[4096];
-+ __u32 reserv1[96];
-+ __u32 ae_hist_y[128];
-+ __u32 reserv2[511];
-+ __u16 flag;
-+};
-+
- #endif
+++ /dev/null
-From 883745d4728e524babfe7d04cbb8a925c22aa6b5 Mon Sep 17 00:00:00 2001
-From: Changhuang Liang <changhuang.liang@starfivetech.com>
-Date: Mon, 13 Nov 2023 14:46:50 +0800
-Subject: [PATCH 097/116] media: starfive: Update ISP initialzation
-
-ISP compatible stf_isp_ctrl and libcamera.
-
-Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
----
- .../platform/starfive/v4l2_driver/stf_isp.c | 55 ++++++++-----------
- 1 file changed, 24 insertions(+), 31 deletions(-)
-
---- a/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-+++ b/drivers/media/platform/starfive/v4l2_driver/stf_isp.c
-@@ -402,7 +402,7 @@ static int isp_set_ctrl_cfa(struct stf_i
-
- reg_write(ispbase, reg_addr, ((u32)(cfg->cross_cov & 0x3) << 4) | (cfg->hv_width & 0xf));
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -419,7 +419,7 @@ static int isp_set_ctrl_ctc(struct stf_i
- reg_value |= ((u32)(cfg->max_gt & 0x3ff) << 16) | (cfg->min_gt & 0x3ff);
- reg_write(ispbase, reg_addr, reg_value);
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -434,7 +434,7 @@ static int isp_set_ctrl_dbc(struct stf_i
-
- reg_write(ispbase, reg_addr, ((u32)(cfg->bad_gt & 0x3ff) << 16) | (cfg->bad_xt & 0x3ff));
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -459,7 +459,7 @@ static int isp_set_ctrl_dnyuv(struct stf
- reg_write(ispbase, reg_addr + 36, CREATE_REG_VALUE(u16, &cfg->uv_curve[4], 2, 0x3ff, 16));
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -472,7 +472,7 @@ static int isp_set_ctrl_gmargb(struct st
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
- s32 i;
--
-+
- for(i = 0; i < 15; i++, curve++, reg_addr += 4)
- reg_write(ispbase, reg_addr, ((u32)curve->sg_val << 16) | (curve->g_val & 0x3ff));
-
-@@ -490,7 +490,7 @@ static int isp_set_ctrl_lccf(struct stf_
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
- s32 i;
--
-+
- reg_write(ispbase, reg_addr, ((u32)(setting->circle.center_y & 0x7fff) << 16) | (setting->circle.center_x & 0x7fff));
- reg_write(ispbase, reg_addr + 8, setting->circle.radius & 0xf);
- reg_addr += 0x90;
-@@ -498,7 +498,7 @@ static int isp_set_ctrl_lccf(struct stf_
- reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0x1fff, 16));
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -511,7 +511,7 @@ static int isp_set_ctrl_obc(struct stf_i
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
- s32 i;
--
-+
- reg_write(ispbase, reg_addr, ((u32)(setting->win_size.height & 0xf) << 4) | (setting->win_size.width & 0xf));
-
- reg_addr += 0x2ac; //0x2e0
-@@ -519,7 +519,7 @@ static int isp_set_ctrl_obc(struct stf_i
- reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u8, params, 4, 0xff, 8));
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -535,7 +535,7 @@ static int isp_set_ctrl_oecf(struct stf_
- void __iomem *ispbase = vin->isp_base;
- u32 x, y, slope;
- s32 i;
--
-+
- for(i = 0; i < 32; i++, reg_x_addr += 4, reg_y_addr += 4, reg_s_addr += 4) {
- x = pts->x & 0x3ff;
- y = pts->y & 0x3ff;
-@@ -565,12 +565,12 @@ static int isp_set_ctrl_r2y(struct stf_i
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
- s32 i;
--
-+
- for(i = 0; i < 9; i++, reg_addr += 4)
- reg_write(ispbase, reg_addr, (u32)(params[i] & 0x1ff));
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -584,7 +584,7 @@ static int isp_set_ctrl_sat(struct stf_i
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
- s32 i;
--
-+
- for(i = 0; i < 3; i++, reg_addr += 4, params += 2)
- reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0xfff, 16));
- reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, &setting->hue_info.cos, 2, 0x3ff, 16));
-@@ -597,7 +597,7 @@ static int isp_set_ctrl_sat(struct stf_i
- reg_write(ispbase, reg_addr, CREATE_REG_VALUE(u16, params, 2, 0x3fff, 16));
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -609,7 +609,7 @@ static int isp_set_ctrl_shrp(struct stf_
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
- s32 i;
--
-+
- for(i = 0; i < 4; i++, reg_addr += 4)
- reg_write(ispbase, reg_addr, ((u32)(setting->strength.diff[i] & 0x3ff) << 16) | ((u32)(setting->weight.weight[i] & 0xf) << 8));
- FILL_ISP_REGS(u8, ispbase, reg_addr, (u8 *)(&setting->weight.weight[4]), 15 - 4, 0xf, 8);
-@@ -622,7 +622,7 @@ static int isp_set_ctrl_shrp(struct stf_
- reg_write(ispbase, reg_addr, ((u32)(setting->pdirf & 0xf) << 28) | ((u32)(setting->ndirf & 0xf) << 24) | (setting->weight.recip_wei_sum & 0x3fffff));
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -633,11 +633,11 @@ static int isp_set_ctrl_ycrv(struct stf_
- u32 reg_addr = reg_info->cfg_reg;
- struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
- void __iomem *ispbase = vin->isp_base;
--
-+
- FILL_ISP_REGS(u16, ispbase, reg_addr, (u16 *)(setting->curve.y), 64, 0x3ff, 0);
-
- reg_set_bit(ispbase, reg_info->en_reg, 1 << reg_info->en_nbit, setting->enabled ? 1 << reg_info->en_nbit : 0);
--
-+
- return 0;
- }
-
-@@ -661,11 +661,11 @@ static int isp_set_ctrl_sc(struct stf_is
- reg_write(ispbase, 0xb8, ((u32)(setting->crop_config.v_start) << 16) | setting->crop_config.h_start);
-
- // SC config1
-- reg_write(ispbase, 0xbc, ((u32)(setting->awb_config.sel) << 30) | ((u32)(setting->awb_config.awb_ps_grb_ba) << 16) |
-+ reg_write(ispbase, 0xbc, ((u32)(setting->awb_config.sel) << 30) | ((u32)(setting->awb_config.awb_ps_grb_ba) << 16) |
- ((u32)(setting->crop_config.sw_height) << 8) | setting->crop_config.sw_width);
-
- // SC decimation config
-- reg_write(ispbase, 0xd8, ((u32)(setting->crop_config.vkeep) << 24) | ((u32)(setting->crop_config.vperiod) << 16) |
-+ reg_write(ispbase, 0xd8, ((u32)(setting->crop_config.vkeep) << 24) | ((u32)(setting->crop_config.vperiod) << 16) |
- ((u32)(setting->crop_config.hkeep) << 8) | setting->crop_config.hperiod);
-
- // SC AWB pixel sum config
-@@ -676,7 +676,7 @@ static int isp_set_ctrl_sc(struct stf_is
- reg_write(ispbase, 0xd4, CREATE_REG_VALUE(u16, &setting->awb_config.ws_ps_config.awb_ps_grbl, 2, 0xffff, 16));
-
- // AF register
-- reg_write(ispbase, 0xc0,
-+ reg_write(ispbase, 0xc0,
- ((u32)(setting->af_config.es_hor_thr & 0x1ff) << 16) |
- ((u32)(setting->af_config.es_ver_thr & 0xff) << 8) |
- ((setting->af_config.ver_en & 0x1) << 3) |
-@@ -1217,7 +1217,7 @@ static int isp_get_interface_type(struct
- static int isp_set_stream(struct v4l2_subdev *sd, int enable)
- {
- struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-- int ret = 0, interface_type;
-+ int interface_type;
- struct v4l2_mbus_framefmt *fmt;
- struct v4l2_event src_ch = { 0 };
-
-@@ -1225,6 +1225,7 @@ static int isp_set_stream(struct v4l2_su
- mutex_lock(&isp_dev->stream_lock);
- if (enable) {
- if (isp_dev->stream_count == 0) {
-+ v4l2_ctrl_handler_setup(&isp_dev->ctrls.handler);
- isp_dev->hw_ops->isp_clk_enable(isp_dev);
- if (!user_config_isp)
- isp_dev->hw_ops->isp_config_set(isp_dev);
-@@ -1256,15 +1257,7 @@ static int isp_set_stream(struct v4l2_su
- exit:
- mutex_unlock(&isp_dev->stream_lock);
-
-- mutex_lock(&isp_dev->power_lock);
-- /* restore controls */
-- if (enable && isp_dev->power_count == 1) {
-- mutex_unlock(&isp_dev->power_lock);
-- ret = v4l2_ctrl_handler_setup(&isp_dev->ctrls.handler);
-- } else
-- mutex_unlock(&isp_dev->power_lock);
--
-- return ret;
-+ return 0;
- }
-
- /*Try to match sensor format with sink, and then get the index as default.*/
+++ /dev/null
-From 02f84ff43453b0f8dc2a1e4885e7003929349ee6 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Tue, 5 Mar 2024 11:00:21 +0800
-Subject: [PATCH 098/116] crypto: jh7110: Comment RSA algo register
-
-There are some issues in RSA algo, which will cause kernel crash.
-So comment RSA algo register temporarily.
-This commit should be reverted after the RSA issues are fixed.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/crypto/starfive/jh7110-cryp.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
---- a/drivers/crypto/starfive/jh7110-cryp.c
-+++ b/drivers/crypto/starfive/jh7110-cryp.c
-@@ -194,14 +194,14 @@ static int starfive_cryp_probe(struct pl
- if (ret)
- goto err_algs_hash;
-
-- ret = starfive_rsa_register_algs();
-- if (ret)
-- goto err_algs_rsa;
-+// ret = starfive_rsa_register_algs();
-+// if (ret)
-+// goto err_algs_rsa;
-
- return 0;
-
--err_algs_rsa:
-- starfive_hash_unregister_algs();
-+// err_algs_rsa:
-+// starfive_hash_unregister_algs();
- err_algs_hash:
- starfive_aes_unregister_algs();
- err_algs_aes:
+++ /dev/null
-From a7ff2b51e2941526d6924dcf8f1760187d7e5d03 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Mon, 11 Mar 2024 11:10:45 +0800
-Subject: [PATCH 099/116] riscv: dts: starfive: jh7110-evb: Add qspi norflash
- partition for uboot-env
-
-Add qspi norflash partition "uboot-env@f0000",
-for synchronizing with other branches.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/jh7110-evb.dtsi | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7110-evb.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb.dtsi
-@@ -568,6 +568,9 @@
- spl@0 {
- reg = <0x0 0x40000>;
- };
-+ uboot-env@f0000 {
-+ reg = <0xf0000 0x10000>;
-+ };
- uboot@100000 {
- reg = <0x100000 0x300000>;
- };
+++ /dev/null
-From f96ba2eb39ba950f67edf43e0c5c88ac660bc2a0 Mon Sep 17 00:00:00 2001
-From: Ziv Xu <ziv.xu@starfivetech.com>
-Date: Wed, 13 Mar 2024 18:43:27 +0800
-Subject: [PATCH 100/116] driver: regulator: pmic driver support kernel 6.6
-
-pmic driver support kernel 6.6
-
-Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com>
----
- drivers/regulator/axp20x-regulator.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/regulator/axp20x-regulator.c
-+++ b/drivers/regulator/axp20x-regulator.c
-@@ -20,6 +20,7 @@
- #include <linux/mfd/axp20x.h>
- #include <linux/module.h>
- #include <linux/of.h>
-+#include <linux/of_device.h>
- #include <linux/platform_device.h>
- #include <linux/regmap.h>
- #include <linux/regulator/driver.h>
+++ /dev/null
-From c609818850807a1ae5fa17e165f2b66b914188b4 Mon Sep 17 00:00:00 2001
-From: "xingyu.wu" <xingyu.wu@starfivetech.com>
-Date: Tue, 28 Jun 2022 22:48:15 +0800
-Subject: [PATCH 101/116] spi-pl022:starfive:Add platform bus register to adapt
- overlay
-
-Add platform bus register to adapt dtbo overlay.
-
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/spi/spi-pl022.c | 137 ++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 131 insertions(+), 6 deletions(-)
-
---- a/drivers/spi/spi-pl022.c
-+++ b/drivers/spi/spi-pl022.c
-@@ -34,6 +34,7 @@
- #include <linux/of.h>
- #include <linux/pinctrl/consumer.h>
- #include <linux/reset.h>
-+#include <linux/platform_device.h>
-
- /*
- * This macro is used to define some register default values.
-@@ -2088,7 +2089,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;
-
-@@ -2108,6 +2112,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);
-@@ -2161,7 +2173,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;
-@@ -2170,7 +2186,10 @@ 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(&adev->dev, NULL);
-+ if (platform_flag)
-+ pl022->clk = clk_get(&adev->dev, NULL);
-+ else
-+ pl022->clk = devm_clk_get(&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");
-@@ -2183,7 +2202,10 @@ static int pl022_probe(struct amba_devic
- goto err_no_clk_en;
- }
-
-- pl022->rst = devm_reset_control_get(&adev->dev, NULL);
-+ 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");
-@@ -2205,7 +2227,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);
-@@ -2230,7 +2256,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");
-@@ -2255,15 +2284,26 @@ 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:
- clk_disable_unprepare(pl022->clk);
- err_no_clk_en:
-+ 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;
- }
-
-@@ -2464,6 +2504,91 @@ 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 int starfive_of_pl022_remove(struct platform_device *pdev)
-+{
-+ u32 size;
-+ int irq;
-+ struct pl022 *pl022 = dev_get_drvdata(&pdev->dev);
-+
-+ if (!pl022)
-+ return 0;
-+
-+ 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);
-+ tasklet_disable(&pl022->pump_transfers);
-+ return 0;
-+}
-+
-+static const struct of_device_id starfive_of_pl022_match[] = {
-+ { .compatible = "starfive,jh7110-spi-pl022" },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(of, starfive_of_pl022_match);
-+
-+static struct platform_driver starfive_of_pl022_driver = {
-+ .driver = {
-+ .name = "starfive-spi-pl022",
-+ .of_match_table = starfive_of_pl022_match,
-+ .pm = &pl022_dev_pm_ops,
-+ },
-+ .probe = starfive_of_pl022_probe,
-+ .remove = starfive_of_pl022_remove,
-+};
-+
-+module_platform_driver(starfive_of_pl022_driver);
-+/* platform register end */
-+
-+MODULE_AUTHOR("xingyu.wu <xingyu.wu@starfivetech.com>");
- MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
- MODULE_DESCRIPTION("PL022 SSP Controller Driver");
- MODULE_LICENSE("GPL");
+++ /dev/null
-From f94a07310f18720faa0cc773a1aec5a7b1bf3928 Mon Sep 17 00:00:00 2001
-From: "xingyu.wu" <xingyu.wu@starfivetech.com>
-Date: Tue, 19 Jul 2022 14:49:20 +0800
-Subject: [PATCH 102/116] spi:pl022-starfive:Avoid power device error when
- CONFIG_PM enable
-
-It would be error when CONFIG_PM enable and use overlay by of-platform to register.
-
-Add some power manager operation in platform probe function.
-
-Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
-Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/spi/spi-pl022.c | 36 ++++++++++++++++++++++++++++++++++--
- 1 file changed, 34 insertions(+), 2 deletions(-)
-
---- a/drivers/spi/spi-pl022.c
-+++ b/drivers/spi/spi-pl022.c
-@@ -35,6 +35,8 @@
- #include <linux/pinctrl/consumer.h>
- #include <linux/reset.h>
- #include <linux/platform_device.h>
-+#include <linux/clk/clk-conf.h>
-+#include <linux/pm_domain.h>
-
- /*
- * This macro is used to define some register default values.
-@@ -2266,7 +2268,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,
-@@ -2276,7 +2279,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;
-
-@@ -2534,8 +2540,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;
- }
-
-@@ -2566,6 +2597,7 @@ static int starfive_of_pl022_remove(stru
- size = resource_size(pdev->resource);
- release_mem_region(pdev->resource->start, size);
- tasklet_disable(&pl022->pump_transfers);
-+ pm_runtime_disable(&pdev->dev);
- return 0;
- }
-
+++ /dev/null
-From 733e7bd23a1efad15a724fbdbce8d9f06aa6813a Mon Sep 17 00:00:00 2001
-From: "ziv.xu" <ziv.xu@starfive.com>
-Date: Wed, 23 Nov 2022 14:53:58 +0800
-Subject: [PATCH 103/116] spi-pl022-starfive:fix the problem of spi overlay
- reload
-
-fix the problem of spi overlay reload
-
-Signed-off-by: ziv.xu <ziv.xu@starfive.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/spi/spi-pl022.c | 270 ++++++++++++++++++++++++++++------------
- 1 file changed, 188 insertions(+), 82 deletions(-)
-
---- a/drivers/spi/spi-pl022.c
-+++ b/drivers/spi/spi-pl022.c
-@@ -2106,6 +2106,172 @@ 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_message = pl022_transfer_one_message;
-+ 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(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;
-+ }
-+ status = clk_prepare_enable(pl022->clk);
-+ if (status) {
-+ dev_err(dev, "could not enable SSP/SPI bus clock\n");
-+ goto err_no_clk_en;
-+ }
-+
-+ pl022->rst = devm_reset_control_get_exclusive(dev, NULL);
-+ if (!IS_ERR(pl022->rst)) {
-+ status = reset_control_deassert(pl022->rst);
-+ if (status) {
-+ dev_err(dev, "could not deassert SSP/SPI bus reset\n");
-+ goto err_no_rst_clr;
-+ }
-+ } else {
-+ status = PTR_ERR(pl022->rst);
-+ dev_err(dev, "could not retrieve SSP/SPI bus reset\n");
-+ goto err_no_rst;
-+ }
-+
-+ /* Initialize transfer pump */
-+ tasklet_init(&pl022->pump_transfers, pump_transfers,
-+ (unsigned long)pl022);
-+
-+ /* 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_clr:
-+ err_no_rst:
-+ clk_disable_unprepare(pl022->clk);
-+ err_no_clk_en:
-+ 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;
-@@ -2114,14 +2280,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);
-@@ -2175,11 +2333,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;
-@@ -2188,10 +2342,7 @@ 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(&adev->dev, NULL);
-+ pl022->clk = devm_clk_get(&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");
-@@ -2204,10 +2355,7 @@ static int pl022_probe(struct amba_devic
- 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");
-@@ -2229,11 +2377,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);
-@@ -2258,18 +2402,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,
-@@ -2279,10 +2421,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;
-
-@@ -2290,26 +2430,17 @@ 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:
- clk_disable_unprepare(pl022->clk);
- err_no_clk_en:
-- 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;
- }
-
-@@ -2523,23 +2654,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;
-@@ -2548,16 +2664,11 @@ static int starfive_of_pl022_probe(struc
- if (ret)
- goto err_probe;
-
-- ret = pl022_probe(pcdev, &id);
-+ ret = pl022_platform_probe(pdev, &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);
-+ pm_runtime_enable(dev);
-+ pm_runtime_set_autosuspend_delay(dev, 100);
-+ pm_runtime_use_autosuspend(dev);
-
- if (ret) {
- pm_runtime_disable(dev);
-@@ -2572,32 +2683,27 @@ err_probe:
-
- static int starfive_of_pl022_remove(struct platform_device *pdev)
- {
-- u32 size;
-- int irq;
- struct pl022 *pl022 = dev_get_drvdata(&pdev->dev);
-
- if (!pl022)
- return 0;
-
-+ 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);
- tasklet_disable(&pl022->pump_transfers);
-+
-+ 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);
-+
- return 0;
- }
-
+++ /dev/null
-From 11a917bf429a5714e34584f90ab1ac376d399d8f Mon Sep 17 00:00:00 2001
-From: "ziv.xu" <ziv.xu@starfive.com>
-Date: Wed, 18 Jan 2023 15:50:47 +0800
-Subject: [PATCH 104/116] spi-pl022-starfive:Enable spi to be compiled into
- modules
-
-Enable spi to be compiled into modules
-
-Signed-off-by: ziv.xu <ziv.xu@starfive.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/spi/spi-pl022.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/drivers/spi/spi-pl022.c
-+++ b/drivers/spi/spi-pl022.c
-@@ -2633,7 +2633,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)
- {
-@@ -2723,7 +2727,9 @@ static struct platform_driver starfive_o
- .remove = starfive_of_pl022_remove,
- };
-
-+#if !IS_MODULE(CONFIG_SPI_PL022)
- module_platform_driver(starfive_of_pl022_driver);
-+#endif
- /* platform register end */
-
- MODULE_AUTHOR("xingyu.wu <xingyu.wu@starfivetech.com>");
+++ /dev/null
-From e7b01c0a9ad79c1933ce85c4aeca6a037cc4f77f Mon Sep 17 00:00:00 2001
-From: Ziv Xu <ziv.xu@starfivetech.com>
-Date: Wed, 13 Mar 2024 18:37:31 +0800
-Subject: [PATCH 105/116] riscv: configs: add visionfive2 defconfig to kernel
- 6.6
-
-add visionfive2 defconfig to kernel 6.6
-
-Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com>
----
- .../configs/starfive_visionfive2_defconfig | 427 ++++++++++++++++++
- 1 file changed, 427 insertions(+)
- create mode 100644 arch/riscv/configs/starfive_visionfive2_defconfig
-
---- /dev/null
-+++ b/arch/riscv/configs/starfive_visionfive2_defconfig
-@@ -0,0 +1,427 @@
-+CONFIG_COMPILE_TEST=y
-+# CONFIG_WERROR is not set
-+CONFIG_DEFAULT_HOSTNAME="StarFive"
-+CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_USELIB=y
-+CONFIG_NO_HZ_IDLE=y
-+CONFIG_HIGH_RES_TIMERS=y
-+CONFIG_BPF_SYSCALL=y
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_CGROUPS=y
-+CONFIG_CGROUP_SCHED=y
-+CONFIG_CFS_BANDWIDTH=y
-+CONFIG_CGROUP_BPF=y
-+CONFIG_NAMESPACES=y
-+CONFIG_USER_NS=y
-+CONFIG_CHECKPOINT_RESTORE=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_EXPERT=y
-+CONFIG_PERF_EVENTS=y
-+CONFIG_SOC_STARFIVE=y
-+CONFIG_NONPORTABLE=y
-+CONFIG_SMP=y
-+CONFIG_HZ_100=y
-+CONFIG_HIBERNATION=y
-+CONFIG_PM_DEBUG=y
-+CONFIG_PM_ADVANCED_DEBUG=y
-+CONFIG_PM_TEST_SUSPEND=y
-+CONFIG_CPU_IDLE=y
-+CONFIG_RISCV_SBI_CPUIDLE=y
-+CONFIG_CPU_FREQ=y
-+CONFIG_CPU_FREQ_STAT=y
-+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
-+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
-+CONFIG_CPU_FREQ_GOV_USERSPACE=y
-+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
-+CONFIG_CPUFREQ_DT=y
-+# CONFIG_SECCOMP is not set
-+CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+CONFIG_BINFMT_MISC=y
-+CONFIG_PAGE_REPORTING=y
-+CONFIG_CMA=y
-+CONFIG_NET=y
-+CONFIG_PACKET=y
-+CONFIG_IP_MULTICAST=y
-+CONFIG_IP_ADVANCED_ROUTER=y
-+CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_BOOTP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_NETFILTER=y
-+CONFIG_NETFILTER_NETLINK_ACCT=y
-+CONFIG_NETFILTER_NETLINK_QUEUE=y
-+CONFIG_NF_CONNTRACK=y
-+CONFIG_NF_TABLES=y
-+CONFIG_NFT_CT=y
-+CONFIG_NFT_COMPAT=y
-+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-+CONFIG_NETFILTER_XT_MATCH_IPCOMP=y
-+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-+CONFIG_NETFILTER_XT_MATCH_MAC=y
-+CONFIG_NETFILTER_XT_MATCH_MARK=y
-+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
-+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
-+CONFIG_NETFILTER_XT_MATCH_STATE=y
-+CONFIG_NETFILTER_XT_MATCH_STRING=y
-+CONFIG_NETFILTER_XT_MATCH_U32=y
-+CONFIG_NF_TABLES_IPV4=y
-+CONFIG_NFT_DUP_IPV4=y
-+CONFIG_NFT_FIB_IPV4=y
-+CONFIG_IP_NF_IPTABLES=y
-+CONFIG_IP_NF_FILTER=y
-+CONFIG_IP_NF_TARGET_REJECT=y
-+CONFIG_IP_NF_NAT=y
-+CONFIG_IP_NF_TARGET_MASQUERADE=y
-+CONFIG_IP_NF_TARGET_NETMAP=y
-+CONFIG_IP_NF_TARGET_REDIRECT=y
-+CONFIG_NETLINK_DIAG=y
-+CONFIG_CAN=y
-+CONFIG_BT=y
-+CONFIG_BT_RFCOMM=y
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=y
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HCIBTUSB=m
-+# CONFIG_BT_HCIBTUSB_BCM is not set
-+CONFIG_CFG80211=y
-+CONFIG_MAC80211=y
-+CONFIG_RFKILL=y
-+CONFIG_NET_9P=y
-+CONFIG_NET_9P_VIRTIO=y
-+CONFIG_PCI=y
-+# CONFIG_PCIEASPM is not set
-+CONFIG_PCIE_STARFIVE_HOST=y
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_MTD=y
-+CONFIG_MTD_BLOCK=y
-+CONFIG_MTD_CFI=y
-+CONFIG_MTD_CFI_ADV_OPTIONS=y
-+CONFIG_MTD_SPI_NOR=y
-+CONFIG_OF_CONFIGFS=y
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_VIRTIO_BLK=y
-+CONFIG_BLK_DEV_NVME=y
-+CONFIG_EEPROM_AT24=y
-+CONFIG_BLK_DEV_SD=y
-+CONFIG_BLK_DEV_SR=y
-+CONFIG_SCSI_VIRTIO=y
-+CONFIG_ATA=y
-+CONFIG_SATA_AHCI=y
-+CONFIG_MD=y
-+CONFIG_BLK_DEV_DM=m
-+CONFIG_NETDEVICES=y
-+CONFIG_VIRTIO_NET=y
-+# CONFIG_NET_VENDOR_ALACRITECH is not set
-+# CONFIG_NET_VENDOR_AMAZON is not set
-+# CONFIG_NET_VENDOR_AQUANTIA is not set
-+# CONFIG_NET_VENDOR_ARC is not set
-+# CONFIG_NET_VENDOR_BROADCOM is not set
-+# CONFIG_NET_VENDOR_CADENCE is not set
-+# CONFIG_NET_VENDOR_CAVIUM is not set
-+# CONFIG_NET_VENDOR_CORTINA is not set
-+# CONFIG_NET_VENDOR_EZCHIP is not set
-+# CONFIG_NET_VENDOR_GOOGLE is not set
-+# CONFIG_NET_VENDOR_HUAWEI is not set
-+# CONFIG_NET_VENDOR_INTEL is not set
-+# CONFIG_NET_VENDOR_MARVELL is not set
-+# CONFIG_NET_VENDOR_MELLANOX is not set
-+# CONFIG_NET_VENDOR_MICREL is not set
-+# CONFIG_NET_VENDOR_MICROCHIP is not set
-+# CONFIG_NET_VENDOR_MICROSEMI is not set
-+# CONFIG_NET_VENDOR_NI is not set
-+# CONFIG_NET_VENDOR_NATSEMI is not set
-+# CONFIG_NET_VENDOR_NETRONOME is not set
-+# CONFIG_NET_VENDOR_PENSANDO is not set
-+# CONFIG_NET_VENDOR_QUALCOMM is not set
-+CONFIG_R8169=y
-+# CONFIG_NET_VENDOR_RENESAS is not set
-+# CONFIG_NET_VENDOR_ROCKER is not set
-+# CONFIG_NET_VENDOR_SAMSUNG is not set
-+# CONFIG_NET_VENDOR_SEEQ is not set
-+# CONFIG_NET_VENDOR_SOLARFLARE is not set
-+# CONFIG_NET_VENDOR_SOCIONEXT is not set
-+CONFIG_STMMAC_ETH=y
-+CONFIG_STMMAC_SELFTESTS=y
-+CONFIG_DWMAC_DWC_QOS_ETH=y
-+CONFIG_DWMAC_STARFIVE=y
-+# CONFIG_NET_VENDOR_SYNOPSYS is not set
-+# CONFIG_NET_VENDOR_VIA is not set
-+# CONFIG_NET_VENDOR_WIZNET is not set
-+# CONFIG_NET_VENDOR_XILINX is not set
-+CONFIG_MARVELL_PHY=y
-+CONFIG_MICREL_PHY=y
-+CONFIG_MICROCHIP_PHY=y
-+CONFIG_MOTORCOMM_PHY=y
-+CONFIG_IPMS_CAN=y
-+CONFIG_IWLWIFI=y
-+CONFIG_IWLDVM=y
-+CONFIG_IWLMVM=y
-+CONFIG_HOSTAP=y
-+# CONFIG_RTL_CARDS is not set
-+CONFIG_USB_WIFI_ECR6600U=y
-+CONFIG_AIC_WLAN_SUPPORT=y
-+CONFIG_AIC8800_WLAN_SUPPORT=m
-+CONFIG_AIC_LOADFW_SUPPORT=m
-+CONFIG_INPUT_EVDEV=y
-+# CONFIG_INPUT_KEYBOARD is not set
-+# CONFIG_INPUT_MOUSE is not set
-+CONFIG_INPUT_TOUCHSCREEN=y
-+CONFIG_TOUCHSCREEN_GOODIX=y
-+CONFIG_TOUCHSCREEN_TINKER_FT5406=y
-+CONFIG_SERIO_LIBPS2=y
-+CONFIG_SERIAL_8250=y
-+CONFIG_SERIAL_8250_CONSOLE=y
-+CONFIG_SERIAL_8250_NR_UARTS=6
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=6
-+CONFIG_SERIAL_8250_EXTENDED=y
-+CONFIG_SERIAL_8250_MANY_PORTS=y
-+CONFIG_SERIAL_8250_DW=y
-+CONFIG_SERIAL_OF_PLATFORM=y
-+CONFIG_TTY_PRINTK=y
-+CONFIG_VIRTIO_CONSOLE=y
-+CONFIG_HW_RANDOM=y
-+CONFIG_HW_RANDOM_JH7110=y
-+CONFIG_I2C_CHARDEV=y
-+CONFIG_I2C_DESIGNWARE_PLATFORM=y
-+CONFIG_SPI=y
-+CONFIG_SPI_CADENCE_QUADSPI=y
-+CONFIG_SPI_PL022=y
-+CONFIG_SPI_SIFIVE=y
-+CONFIG_SPI_SPIDEV=y
-+# CONFIG_PTP_1588_CLOCK is not set
-+CONFIG_GPIO_SYSFS=y
-+CONFIG_POWER_RESET=y
-+CONFIG_POWER_RESET_GPIO_RESTART=y
-+CONFIG_POWER_RESET_SYSCON=y
-+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
-+CONFIG_SENSORS_SFCTEMP=y
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_WRITABLE_TRIPS=y
-+CONFIG_CPU_THERMAL=y
-+CONFIG_DEVFREQ_THERMAL=y
-+CONFIG_THERMAL_EMULATION=y
-+# CONFIG_HISI_THERMAL is not set
-+CONFIG_WATCHDOG=y
-+CONFIG_WATCHDOG_SYSFS=y
-+CONFIG_MFD_AXP20X_I2C=y
-+CONFIG_REGULATOR=y
-+CONFIG_REGULATOR_AXP20X=y
-+CONFIG_REGULATOR_GPIO=y
-+CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=y
-+# CONFIG_MEDIA_CEC_SUPPORT is not set
-+CONFIG_MEDIA_SUPPORT=y
-+CONFIG_MEDIA_USB_SUPPORT=y
-+CONFIG_USB_VIDEO_CLASS=y
-+CONFIG_V4L_PLATFORM_DRIVERS=y
-+CONFIG_V4L_MEM2MEM_DRIVERS=y
-+CONFIG_VIDEO_CADENCE_CSI2RX=y
-+CONFIG_VIDEO_WAVE_VPU=m
-+CONFIG_VIN_SENSOR_OV4689=y
-+CONFIG_VIN_SENSOR_IMX219=y
-+CONFIG_VIDEO_STF_VIN=y
-+CONFIG_VIDEO_IMX219=y
-+CONFIG_VIDEO_IMX708=y
-+CONFIG_DRM_PANEL_SIMPLE=y
-+CONFIG_DRM_PANEL_JADARD_JD9365DA_H3=y
-+CONFIG_DRM_TOSHIBA_TC358762=y
-+CONFIG_DRM_VERISILICON=y
-+CONFIG_STARFIVE_INNO_HDMI=y
-+CONFIG_STARFIVE_DSI=y
-+CONFIG_DRM_IMG_ROGUE=y
-+CONFIG_DRM_LEGACY=y
-+CONFIG_FB=y
-+CONFIG_BACKLIGHT_CLASS_DEVICE=y
-+CONFIG_SOUND=y
-+CONFIG_SND=y
-+CONFIG_SND_USB_AUDIO=y
-+CONFIG_SND_SOC=y
-+CONFIG_SND_DESIGNWARE_I2S=y
-+CONFIG_SND_SOC_RZ=m
-+CONFIG_SND_SOC_STARFIVE=y
-+CONFIG_SND_SOC_JH7110_PWMDAC=y
-+CONFIG_SND_SOC_JH7110_TDM=y
-+CONFIG_SND_SOC_AC108=y
-+CONFIG_SND_SOC_WM8960=y
-+CONFIG_SND_SIMPLE_CARD=y
-+CONFIG_UHID=y
-+CONFIG_USB=y
-+CONFIG_USB_OTG=y
-+CONFIG_USB_XHCI_HCD=y
-+CONFIG_USB_RENESAS_USBHS=y
-+CONFIG_USB_STORAGE=y
-+CONFIG_USB_UAS=y
-+CONFIG_USB_CDNS_SUPPORT=y
-+CONFIG_USB_CDNS3=y
-+CONFIG_USB_CDNS3_GADGET=y
-+CONFIG_USB_CDNS3_HOST=y
-+CONFIG_USB_CDNS3_STARFIVE=y
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+CONFIG_USB_SERIAL_AIRCABLE=m
-+CONFIG_USB_SERIAL_ARK3116=m
-+CONFIG_USB_SERIAL_BELKIN=m
-+CONFIG_USB_SERIAL_CH341=m
-+CONFIG_USB_SERIAL_WHITEHEAT=m
-+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-+CONFIG_USB_SERIAL_CP210X=m
-+CONFIG_USB_SERIAL_CYPRESS_M8=m
-+CONFIG_USB_SERIAL_EMPEG=m
-+CONFIG_USB_SERIAL_FTDI_SIO=m
-+CONFIG_USB_SERIAL_VISOR=m
-+CONFIG_USB_SERIAL_IPAQ=m
-+CONFIG_USB_SERIAL_IR=m
-+CONFIG_USB_SERIAL_EDGEPORT=m
-+CONFIG_USB_SERIAL_EDGEPORT_TI=m
-+CONFIG_USB_SERIAL_F81232=m
-+CONFIG_USB_SERIAL_GARMIN=m
-+CONFIG_USB_SERIAL_IPW=m
-+CONFIG_USB_SERIAL_IUU=m
-+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-+CONFIG_USB_SERIAL_KEYSPAN=m
-+CONFIG_USB_SERIAL_KLSI=m
-+CONFIG_USB_SERIAL_KOBIL_SCT=m
-+CONFIG_USB_SERIAL_MCT_U232=m
-+CONFIG_USB_SERIAL_METRO=m
-+CONFIG_USB_SERIAL_MOS7720=m
-+CONFIG_USB_SERIAL_MOS7840=m
-+CONFIG_USB_SERIAL_NAVMAN=m
-+CONFIG_USB_SERIAL_PL2303=m
-+CONFIG_USB_SERIAL_OTI6858=m
-+CONFIG_USB_SERIAL_QCAUX=m
-+CONFIG_USB_SERIAL_QUALCOMM=m
-+CONFIG_USB_SERIAL_SPCP8X5=m
-+CONFIG_USB_SERIAL_SAFE=m
-+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-+CONFIG_USB_SERIAL_SYMBOL=m
-+CONFIG_USB_SERIAL_TI=m
-+CONFIG_USB_SERIAL_CYBERJACK=m
-+CONFIG_USB_SERIAL_OMNINET=m
-+CONFIG_USB_SERIAL_OPTICON=m
-+CONFIG_USB_SERIAL_XSENS_MT=m
-+CONFIG_USB_SERIAL_WISHBONE=m
-+CONFIG_USB_SERIAL_SSU100=m
-+CONFIG_USB_SERIAL_DEBUG=m
-+CONFIG_USB_GADGET=y
-+CONFIG_USB_RENESAS_USBHS_UDC=m
-+CONFIG_USB_CONFIGFS=y
-+CONFIG_USB_CONFIGFS_SERIAL=y
-+CONFIG_USB_CONFIGFS_ACM=y
-+CONFIG_USB_CONFIGFS_OBEX=y
-+CONFIG_USB_CONFIGFS_NCM=y
-+CONFIG_USB_CONFIGFS_ECM=y
-+CONFIG_USB_CONFIGFS_ECM_SUBSET=y
-+CONFIG_USB_CONFIGFS_RNDIS=y
-+CONFIG_USB_CONFIGFS_EEM=y
-+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
-+CONFIG_USB_CONFIGFS_F_FS=y
-+CONFIG_MMC=y
-+CONFIG_MMC_DEBUG=y
-+CONFIG_MMC_SDHCI=y
-+CONFIG_MMC_SDHCI_PLTFM=y
-+CONFIG_MMC_SDHCI_OF_DWCMSHC=y
-+CONFIG_MMC_SPI=y
-+CONFIG_MMC_SDHI=y
-+CONFIG_MMC_DW=y
-+CONFIG_MMC_DW_STARFIVE=y
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=y
-+CONFIG_LEDS_GPIO=y
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-+CONFIG_RTC_CLASS=y
-+CONFIG_RTC_DRV_STARFIVE=y
-+CONFIG_RTC_DRV_GOLDFISH=y
-+CONFIG_DMADEVICES=y
-+CONFIG_AMBA_PL08X=y
-+CONFIG_DW_AXI_DMAC=y
-+CONFIG_DMATEST=y
-+# CONFIG_VIRTIO_MENU is not set
-+# CONFIG_VHOST_MENU is not set
-+CONFIG_GOLDFISH=y
-+CONFIG_CLK_STARFIVE_JH7110_AON=y
-+CONFIG_CLK_STARFIVE_JH7110_STG=y
-+CONFIG_CLK_STARFIVE_JH7110_ISP=y
-+CONFIG_CLK_STARFIVE_JH7110_VOUT=y
-+CONFIG_MAILBOX=y
-+CONFIG_STARFIVE_MBOX=m
-+CONFIG_STARFIVE_MBOX_TEST=m
-+# CONFIG_IOMMU_SUPPORT is not set
-+CONFIG_RPMSG_CHAR=y
-+CONFIG_RPMSG_VIRTIO=y
-+CONFIG_SIFIVE_CCACHE=y
-+CONFIG_PM_DEVFREQ=y
-+CONFIG_IIO=y
-+CONFIG_IIO_ST_ACCEL_3AXIS=y
-+CONFIG_PWM=y
-+CONFIG_PWM_OCORES=y
-+CONFIG_PHY_STARFIVE_JH7110_PCIE=y
-+CONFIG_PHY_STARFIVE_JH7110_USB=y
-+CONFIG_PHY_M31_DPHY_RX0=y
-+CONFIG_RAS=y
-+CONFIG_EXT4_FS=y
-+CONFIG_EXT4_FS_POSIX_ACL=y
-+CONFIG_BTRFS_FS=m
-+CONFIG_BTRFS_FS_POSIX_ACL=y
-+CONFIG_AUTOFS_FS=y
-+CONFIG_FUSE_FS=y
-+CONFIG_CUSE=y
-+CONFIG_VIRTIO_FS=y
-+CONFIG_FSCACHE=y
-+CONFIG_FSCACHE_STATS=y
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_UTF8=y
-+CONFIG_EXFAT_FS=y
-+CONFIG_NTFS_FS=y
-+CONFIG_NTFS_RW=y
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_HUGETLBFS=y
-+CONFIG_JFFS2_FS=y
-+CONFIG_NFS_FS=y
-+CONFIG_NFS_V4=y
-+CONFIG_NFS_V4_1=y
-+CONFIG_NFS_V4_2=y
-+CONFIG_ROOT_NFS=y
-+CONFIG_CIFS=m
-+# CONFIG_CIFS_STATS2 is not set
-+CONFIG_CIFS_UPCALL=y
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
-+# CONFIG_CIFS_DEBUG is not set
-+CONFIG_CIFS_DFS_UPCALL=y
-+CONFIG_CIFS_FSCACHE=y
-+CONFIG_SMB_SERVER=m
-+CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_ISO8859_1=y
-+CONFIG_INIT_STACK_NONE=y
-+CONFIG_CRYPTO_USER=y
-+CONFIG_CRYPTO_TEST=m
-+CONFIG_CRYPTO_USER_API_HASH=y
-+CONFIG_CRYPTO_USER_API_SKCIPHER=y
-+CONFIG_CRYPTO_USER_API_RNG=y
-+CONFIG_CRYPTO_USER_API_AEAD=y
-+CONFIG_CRYPTO_DEV_VIRTIO=y
-+CONFIG_CRYPTO_DEV_JH7110=y
-+CONFIG_DMA_CMA=y
-+CONFIG_PRINTK_TIME=y
-+CONFIG_DEBUG_FS=y
-+CONFIG_SOFTLOCKUP_DETECTOR=y
-+CONFIG_WQ_WATCHDOG=y
-+CONFIG_DEBUG_TIMEKEEPING=y
-+CONFIG_DEBUG_RT_MUTEXES=y
-+CONFIG_DEBUG_SPINLOCK=y
-+CONFIG_DEBUG_RWSEMS=y
-+CONFIG_DEBUG_LIST=y
-+CONFIG_DEBUG_PLIST=y
-+CONFIG_DEBUG_SG=y
-+# CONFIG_RCU_TRACE is not set
-+CONFIG_RCU_EQS_DEBUG=y
-+# CONFIG_FTRACE is not set
-+# CONFIG_RUNTIME_TESTING_MENU is not set
-+CONFIG_MEMTEST=y
+++ /dev/null
-From 51c1cccb202d741eeb1de57e0ecf8fcaa8f059e8 Mon Sep 17 00:00:00 2001
-From: Ziv Xu <ziv.xu@starfivetech.com>
-Date: Wed, 13 Mar 2024 18:36:31 +0800
-Subject: [PATCH 106/116] riscv: dts: starfive: update dts to kernel 6.6
-
-update dts to kernel 6.6
-
-Signed-off-by: Ziv Xu <ziv.xu@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/Makefile | 5 +-
- .../jh7110-starfive-visionfive-2-ac108.dts | 64 +++
- .../jh7110-starfive-visionfive-2-tdm.dts | 59 +++
- .../jh7110-starfive-visionfive-2-wm8960.dts | 71 +++
- .../jh7110-starfive-visionfive-2.dtsi | 437 +++++++++++++++++-
- 5 files changed, 633 insertions(+), 3 deletions(-)
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-ac108.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-tdm.dts
- create mode 100644 arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-wm8960.dts
-
---- a/arch/riscv/boot/dts/starfive/Makefile
-+++ b/arch/riscv/boot/dts/starfive/Makefile
-@@ -10,7 +10,10 @@ dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-be
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb
-
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb
--dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb
-+dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb \
-+ jh7110-starfive-visionfive-2-ac108.dtb \
-+ jh7110-starfive-visionfive-2-tdm.dtb \
-+ jh7110-starfive-visionfive-2-wm8960.dtb
-
- subdir-y += evb-overlay
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-evb.dtb \
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-ac108.dts
-@@ -0,0 +1,64 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ * Copyright (C) 2022 Hal Feng <hal.feng@starfivetech.com>
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-starfive-visionfive-2-v1.3b.dts"
-+
-+/ {
-+ /* i2s + ac108 */
-+ sound0: snd-card0 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "Starfive-AC108-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "i2s";
-+ bitclock-master = <&sndcodec1>;
-+ frame-master = <&sndcodec1>;
-+
-+ widgets =
-+ "Microphone", "Mic Jack",
-+ "Line", "Line In",
-+ "Line", "Line Out",
-+ "Speaker", "Speaker",
-+ "Headphone", "Headphone Jack";
-+ routing =
-+ "Headphone Jack", "HP_L",
-+ "Headphone Jack", "HP_R",
-+ "Speaker", "SPK_LP",
-+ "Speaker", "SPK_LN",
-+ "LINPUT1", "Mic Jack",
-+ "LINPUT3", "Mic Jack",
-+ "RINPUT1", "Mic Jack",
-+ "RINPUT2", "Mic Jack";
-+
-+ cpu {
-+ sound-dai = <&i2srx_mst>;
-+ };
-+
-+ sndcodec1: codec {
-+ sound-dai = <&ac108>;
-+ clocks = <&ac108_mclk>;
-+ clock-names = "mclk";
-+ };
-+ };
-+ };
-+};
-+
-+&i2c0 {
-+ ac108: ac108@3b {
-+ compatible = "x-power,ac108_0";
-+ reg = <0x3b>;
-+ #sound-dai-cells = <0>;
-+ data-protocol = <0>;
-+ };
-+};
-+
-+&i2srx_mst {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-tdm.dts
-@@ -0,0 +1,59 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ * Copyright (C) 2022 Hal Feng <hal.feng@starfivetech.com>
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-starfive-visionfive-2-v1.3b.dts"
-+
-+/ {
-+ sound-tdm {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "Starfive-TDM-Sound-Card";
-+ simple-audio-card,widgets = "Microphone", "Mic Jack",
-+ "Line", "Line In",
-+ "Line", "Line Out",
-+ "Speaker", "Speaker",
-+ "Headphone", "Headphone Jack";
-+ simple-audio-card,routing = "Headphone Jack", "HP_L",
-+ "Headphone Jack", "HP_R",
-+ "Speaker", "SPK_LP",
-+ "Speaker", "SPK_LN",
-+ "LINPUT1", "Mic Jack",
-+ "LINPUT3", "Mic Jack",
-+ "RINPUT1", "Mic Jack",
-+ "RINPUT2", "Mic Jack";
-+
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "dsp_a";
-+ bitclock-master = <&dailink_master>;
-+ frame-master = <&dailink_master>;
-+
-+ cpu {
-+ sound-dai = <&tdm>;
-+ };
-+ dailink_master: codec {
-+ sound-dai = <&wm8960>;
-+ clocks = <&wm8960_mclk>;
-+ };
-+ };
-+ };
-+};
-+
-+&i2c0 {
-+ wm8960: codec@1a {
-+ compatible = "wlf,wm8960";
-+ reg = <0x1a>;
-+ wlf,shared-lrclk;
-+ #sound-dai-cells = <0>;
-+ };
-+};
-+
-+&tdm {
-+ status = "okay";
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-wm8960.dts
-@@ -0,0 +1,71 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+/*
-+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
-+ * Copyright (C) 2022 Hal Feng <hal.feng@starfivetech.com>
-+ */
-+
-+/dts-v1/;
-+#include "jh7110-starfive-visionfive-2-v1.3b.dts"
-+
-+/ {
-+ /* i2s + wm8960 */
-+ sound-wm8960 {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "Starfive-WM8960-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ status = "okay";
-+ format = "i2s";
-+ bitclock-master = <&sndcodec1>;
-+ frame-master = <&sndcodec1>;
-+
-+ widgets =
-+ "Microphone", "Mic Jack",
-+ "Line", "Line In",
-+ "Line", "Line Out",
-+ "Speaker", "Speaker",
-+ "Headphone", "Headphone Jack";
-+ routing =
-+ "Headphone Jack", "HP_L",
-+ "Headphone Jack", "HP_R",
-+ "Speaker", "SPK_LP",
-+ "Speaker", "SPK_LN",
-+ "LINPUT1", "Mic Jack",
-+ "LINPUT3", "Mic Jack",
-+ "RINPUT1", "Mic Jack",
-+ "RINPUT2", "Mic Jack";
-+ cpu0 {
-+ sound-dai = <&i2srx>;
-+ };
-+ cpu1 {
-+ sound-dai = <&i2stx1>;
-+ };
-+
-+ sndcodec1:codec {
-+ sound-dai = <&wm8960>;
-+ clocks = <&wm8960_mclk>;
-+ clock-names = "mclk";
-+ };
-+ };
-+ };
-+};
-+
-+&i2c0 {
-+ wm8960: codec@1a {
-+ compatible = "wlf,wm8960";
-+ reg = <0x1a>;
-+ wlf,shared-lrclk;
-+ #sound-dai-cells = <0>;
-+ };
-+};
-+
-+&i2srx {
-+ status = "okay";
-+};
-+
-+&i2stx1 {
-+ status = "okay";
-+};
---- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-@@ -7,6 +7,7 @@
- /dts-v1/;
- #include "jh7110.dtsi"
- #include "jh7110-pinfunc.h"
-+#include <dt-bindings/leds/common.h>
- #include <dt-bindings/gpio/gpio.h>
-
- / {
-@@ -37,6 +38,44 @@
- reg = <0x0 0x40000000 0x1 0x0>;
- };
-
-+ reserved-memory {
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+ ranges;
-+
-+ linux,cma {
-+ compatible = "shared-dma-pool";
-+ reusable;
-+ size = <0x0 0x20000000>;
-+ alignment = <0x0 0x1000>;
-+ alloc-ranges = <0x0 0x70000000 0x0 0x20000000>;
-+ linux,cma-default;
-+ };
-+
-+ e24_mem: e24@c0000000 {
-+ reg = <0x0 0x6ce00000 0x0 0x1600000>;
-+ };
-+
-+ xrp_reserved: xrpbuffer@f0000000 {
-+ reg = <0x0 0x69c00000 0x0 0x01ffffff
-+ 0x0 0x6bc00000 0x0 0x00001000
-+ 0x0 0x6bc01000 0x0 0x00fff000
-+ 0x0 0x6cc00000 0x0 0x00001000>;
-+ };
-+ };
-+
-+ leds {
-+ compatible = "gpio-leds";
-+
-+ led-ack {
-+ gpios = <&aongpio 3 GPIO_ACTIVE_HIGH>;
-+ color = <LED_COLOR_ID_GREEN>;
-+ function = LED_FUNCTION_HEARTBEAT;
-+ linux,default-trigger = "heartbeat";
-+ label = "ack";
-+ };
-+ };
-+
- gpio-restart {
- compatible = "gpio-restart";
- gpios = <&sysgpio 35 GPIO_ACTIVE_HIGH>;
-@@ -69,6 +108,48 @@
- };
- };
- };
-+
-+ sound-hdmi {
-+ compatible = "simple-audio-card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ simple-audio-card,name = "StarFive-HDMI-Sound-Card";
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ format = "i2s";
-+ bitclock-master = <&sndi2s0>;
-+ frame-master = <&sndi2s0>;
-+ mclk-fs = <256>;
-+ status = "okay";
-+
-+ sndi2s0: cpu {
-+ sound-dai = <&i2stx0>;
-+ };
-+
-+ codec {
-+ sound-dai = <&hdmi>;
-+ };
-+ };
-+ };
-+
-+ ac108_mclk: ac108_mclk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24000000>;
-+ };
-+
-+ clk_ext_camera: clk-ext-camera {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24000000>;
-+ };
-+
-+ wm8960_mclk: wm8960_mclk {
-+ compatible = "fixed-clock";
-+ #clock-cells = <0>;
-+ clock-frequency = <24576000>;
-+ };
- };
-
- &dvp_clk {
-@@ -177,6 +258,42 @@
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins>;
- status = "okay";
-+
-+ seeed_plane_i2c@45 {
-+ compatible = "seeed_panel";
-+ reg = <0x45>;
-+
-+ port {
-+ panel_out0: endpoint {
-+ remote-endpoint = <&dsi0_output>;
-+ };
-+ };
-+ };
-+
-+ tinker_ft5406: tinker_ft5406@38 {
-+ compatible = "tinker_ft5406";
-+ reg = <0x38>;
-+ };
-+
-+ touchscreen@14 {
-+ compatible = "goodix,gt911";
-+ reg = <0x14>;
-+ irq-gpios = <&sysgpio 30 GPIO_ACTIVE_HIGH>;
-+ reset-gpios = <&sysgpio 31 GPIO_ACTIVE_HIGH>;
-+ };
-+
-+ panel_radxa@19 {
-+ compatible ="starfive_jadard";
-+ reg = <0x19>;
-+ reset-gpio = <&sysgpio 23 0>;
-+ enable-gpio = <&sysgpio 22 0>;
-+
-+ port {
-+ panel_out1: endpoint {
-+ remote-endpoint = <&dsi1_output>;
-+ };
-+ };
-+ };
- };
-
- &i2c5 {
-@@ -195,11 +312,36 @@
- #interrupt-cells = <1>;
-
- regulators {
-+ mipi_0p9: ALDO1 {
-+ regulator-boot-on;
-+ regulator-compatible = "aldo1";
-+ regulator-name = "mipi_0p9";
-+ regulator-min-microvolt = <900000>;
-+ regulator-max-microvolt = <900000>;
-+ };
-+
-+ hdmi_0p9: ALDO5 {
-+ regulator-boot-on;
-+ regulator-compatible = "aldo5";
-+ regulator-name = "hdmi_0p9";
-+ regulator-min-microvolt = <900000>;
-+ regulator-max-microvolt = <900000>;
-+ };
-+
-+ hdmi_1p8: ALDO3 {
-+ regulator-boot-on;
-+ regulator-compatible = "aldo3";
-+ regulator-name = "hdmi_1p8";
-+ regulator-min-microvolt = <1800000>;
-+ regulator-max-microvolt = <1800000>;
-+ };
-+
- vcc_3v3: dcdc1 {
- regulator-boot-on;
- regulator-always-on;
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
-+ regulator-compatible = "dcdc1";
- regulator-name = "vcc_3v3";
- };
-
-@@ -207,6 +349,7 @@
- regulator-always-on;
- regulator-min-microvolt = <500000>;
- regulator-max-microvolt = <1540000>;
-+ regulator-compatible = "dcdc2";
- regulator-name = "vdd-cpu";
- };
-
-@@ -215,6 +358,7 @@
- regulator-always-on;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
-+ regulator-compatible = "aldo4";
- regulator-name = "emmc_vdd";
- };
- };
-@@ -229,12 +373,68 @@
- pinctrl-names = "default";
- pinctrl-0 = <&i2c6_pins>;
- status = "okay";
-+
-+ imx219: imx219@10 {
-+ compatible = "sony,imx219";
-+ reg = <0x10>;
-+ clocks = <&clk_ext_camera>;
-+ clock-names = "xclk";
-+ reset-gpio = <&sysgpio 18 0>;
-+ rotation = <0>;
-+ orientation = <1>; //CAMERA_ORIENTATION_BACK
-+
-+ port {
-+ /* CSI2 bus endpoint */
-+ imx219_to_csi2rx0: endpoint {
-+ remote-endpoint = <&csi2rx0_from_imx219>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <4>;
-+ data-lanes = <0 1>;
-+ lane-polarities = <0 0 0>;
-+ link-frequencies = /bits/ 64 <456000000>;
-+ };
-+ };
-+ };
-+
-+ imx708: imx708@1a {
-+ compatible = "sony,imx708";
-+ reg = <0x1a>;
-+ clocks = <&clk_ext_camera>;
-+ reset-gpio = <&sysgpio 18 0>;
-+
-+ port {
-+ imx708_to_csi2rx0: endpoint {
-+ remote-endpoint = <&csi2rx0_from_imx708>;
-+ data-lanes = <1 2>;
-+ clock-noncontinuous;
-+ link-frequencies = /bits/ 64 <450000000>;
-+ };
-+ };
-+ };
-+
-+ ov4689: ov4689@36 {
-+ compatible = "ovti,ov4689";
-+ reg = <0x36>;
-+ clocks = <&clk_ext_camera>;
-+ clock-names = "xclk";
-+ rotation = <180>;
-+
-+ port {
-+ /* Parallel bus endpoint */
-+ ov4689_to_csi2rx0: endpoint {
-+ remote-endpoint = <&csi2rx0_from_ov4689>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <0>;
-+ data-lanes = <1 2>;
-+ };
-+ };
-+ };
- };
-
- &i2srx {
- pinctrl-names = "default";
- pinctrl-0 = <&i2srx_pins>;
-- status = "okay";
-+ status = "disabled";
- };
-
- &i2stx0 {
-@@ -246,7 +446,7 @@
- &i2stx1 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2stx1_pins>;
-- status = "okay";
-+ status = "disabled";
- };
-
- &mmc0 {
-@@ -661,6 +861,40 @@
- slew-rate = <0>;
- };
- };
-+
-+ hdmi_pins: hdmi-0 {
-+ scl-pins {
-+ pinmux = <GPIOMUX(0, GPOUT_SYS_HDMI_DDC_SCL,
-+ GPOEN_SYS_HDMI_DDC_SCL,
-+ GPI_SYS_HDMI_DDC_SCL)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+
-+ sda-pins {
-+ pinmux = <GPIOMUX(1, GPOUT_SYS_HDMI_DDC_SDA,
-+ GPOEN_SYS_HDMI_DDC_SDA,
-+ GPI_SYS_HDMI_DDC_SDA)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+
-+ cec-pins {
-+ pinmux = <GPIOMUX(14, GPOUT_SYS_HDMI_CEC_SDA,
-+ GPOEN_SYS_HDMI_CEC_SDA,
-+ GPI_SYS_HDMI_CEC_SDA)>;
-+ bias-pull-up;
-+ input-enable;
-+ };
-+
-+ hpd-pins {
-+ pinmux = <GPIOMUX(15, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_HDMI_HPD)>;
-+ bias-disable; /* external pull-up */
-+ input-enable;
-+ };
-+ };
- };
-
- &uart0 {
-@@ -689,3 +923,202 @@
- &U74_4 {
- cpu-supply = <&vdd_cpu>;
- };
-+
-+
-+&display {
-+ ports = <&dc_out_dpi0>;
-+ status = "okay";
-+};
-+
-+&dc8200 {
-+ status = "okay";
-+
-+ dc_out: port {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ dc_out_dpi0: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&hdmi_input0>;
-+ };
-+ dc_out_dpi1: endpoint@1 {
-+ reg = <1>;
-+ remote-endpoint = <&hdmi_in_lcdc>;
-+ };
-+
-+ dc_out_dpi2: endpoint@2 {
-+ reg = <2>;
-+ remote-endpoint = <&mipi_in>;
-+ };
-+ };
-+};
-+
-+&hdmi {
-+ status = "okay";
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&hdmi_pins>;
-+ hpd-gpio = <&sysgpio 15 GPIO_ACTIVE_HIGH>;
-+
-+ hdmi_in: port {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ hdmi_in_lcdc: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&dc_out_dpi1>;
-+ };
-+ };
-+};
-+
-+&rgb_output {
-+ status = "disabled";
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ port@0 {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ reg = <0>;
-+ hdmi_input0:endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&dc_out_dpi0>;
-+ };
-+ };
-+ };
-+};
-+
-+&dsi_output {
-+ status = "okay";
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ reg = <0>;
-+ mipi_in: endpoint {
-+ remote-endpoint = <&dc_out_dpi2>;
-+ };
-+ };
-+
-+ port@1 {
-+ reg = <1>;
-+ sf_dpi_output: endpoint {
-+ remote-endpoint = <&dsi_in_port>;
-+ };
-+ };
-+ };
-+};
-+
-+&mipi_dsi {
-+ status = "okay";
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@0 {
-+ reg = <0>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ dsi0_output: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&panel_out0>;
-+ };
-+
-+ dsi1_output: endpoint@1 {
-+ reg = <1>;
-+ remote-endpoint = <&panel_out1>;
-+ };
-+
-+ };
-+
-+ port@1{
-+ reg = <1>;
-+ dsi_in_port: endpoint {
-+ remote-endpoint = <&sf_dpi_output>;
-+ };
-+ };
-+
-+ };
-+};
-+
-+&mipi_dphy {
-+ status = "okay";
-+};
-+
-+&co_process {
-+ memory-region = <&e24_mem>;
-+ status = "okay";
-+};
-+
-+
-+&mailbox_contrl0 {
-+ status = "okay";
-+};
-+
-+&mailbox_client0 {
-+ status = "okay";
-+};
-+
-+&vpu_dec {
-+ status = "okay";
-+};
-+
-+&vpu_enc {
-+ status = "okay";
-+};
-+
-+&jpu {
-+ status = "okay";
-+};
-+
-+&gpu {
-+ status = "okay";
-+};
-+
-+&vin_sysctl {
-+ /* when use dvp open this pinctrl*/
-+ status = "okay";
-+
-+ ports {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ port@1 {
-+ reg = <1>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ /* CSI2 bus endpoint */
-+ csi2rx0_from_imx219: endpoint@0 {
-+ reg = <0>;
-+ remote-endpoint = <&imx219_to_csi2rx0>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <4>;
-+ data-lanes = <0 1>;
-+ lane-polarities = <0 0 0>;
-+ status = "okay";
-+ };
-+
-+ csi2rx0_from_imx708: endpoint@1 {
-+ reg = <1>;
-+ remote-endpoint = <&imx708_to_csi2rx0>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <4>;
-+ data-lanes = <0 1>;
-+ lane-polarities = <0 0 0>;
-+ status = "okay";
-+ };
-+
-+ csi2rx0_from_ov4689: endpoint@2 {
-+ reg = <2>;
-+ remote-endpoint = <&ov4689_to_csi2rx0>;
-+ bus-type = <4>; /* MIPI CSI-2 D-PHY */
-+ clock-lanes = <4>;
-+ data-lanes = <0 1>;
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
+++ /dev/null
-From 17a781895079f8f9b2c089d13a1e4d9789e018c5 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Wed, 20 Mar 2024 17:36:14 +0800
-Subject: [PATCH 107/116] riscv: dts: starfive: evb-overlay: Support SPI
- overlay
-
-Add new compatibles to support SPI overlay.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- .../dts/starfive/evb-overlay/jh7110-evb-overlay-spi.dtso | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-spi.dtso
-+++ b/arch/riscv/boot/dts/starfive/evb-overlay/jh7110-evb-overlay-spi.dtso
-@@ -9,6 +9,7 @@
- fragment@0 {
- target-path = "/soc/spi@10060000";
- __overlay__ {
-+ compatible = "starfive,jh7110-spi-pl022";
- status = "okay";
- };
- };
-@@ -17,6 +18,7 @@
- fragment@1 {
- target-path = "/soc/spi@10070000";
- __overlay__ {
-+ compatible = "starfive,jh7110-spi-pl022";
- status = "okay";
- };
- };
-@@ -25,6 +27,7 @@
- fragment@2 {
- target-path = "/soc/spi@10080000";
- __overlay__ {
-+ compatible = "starfive,jh7110-spi-pl022";
- status = "okay";
- };
- };
-@@ -33,6 +36,7 @@
- fragment@3 {
- target-path = "/soc/spi@12070000";
- __overlay__ {
-+ compatible = "starfive,jh7110-spi-pl022";
- status = "okay";
- };
- };
-@@ -41,6 +45,7 @@
- fragment@4 {
- target-path = "/soc/spi@12080000";
- __overlay__ {
-+ compatible = "starfive,jh7110-spi-pl022";
- status = "okay";
- };
- };
-@@ -49,6 +54,7 @@
- fragment@5 {
- target-path = "/soc/spi@12090000";
- __overlay__ {
-+ compatible = "starfive,jh7110-spi-pl022";
- status = "okay";
- };
- };
-@@ -57,6 +63,7 @@
- fragment@6 {
- target-path = "/soc/spi@120a0000";
- __overlay__ {
-+ compatible = "starfive,jh7110-spi-pl022";
- status = "okay";
- };
- };
+++ /dev/null
-From 49b818cdd08fca7ff761277635c0e5ab659becb8 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Thu, 21 Mar 2024 16:53:51 +0800
-Subject: [PATCH 108/116] riscv: configs: visionfive2: Add standard partition
- for hibernation
-
-Add CONFIG_PM_STD_PARTITION="PARTLABEL=hibernation".
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/configs/starfive_visionfive2_defconfig | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/riscv/configs/starfive_visionfive2_defconfig
-+++ b/arch/riscv/configs/starfive_visionfive2_defconfig
-@@ -24,6 +24,7 @@ CONFIG_NONPORTABLE=y
- CONFIG_SMP=y
- CONFIG_HZ_100=y
- CONFIG_HIBERNATION=y
-+CONFIG_PM_STD_PARTITION="PARTLABEL=hibernation"
- CONFIG_PM_DEBUG=y
- CONFIG_PM_ADVANCED_DEBUG=y
- CONFIG_PM_TEST_SUSPEND=y
+++ /dev/null
-From 146eb94a08d12b5831e1d30455469750f7c5f2a3 Mon Sep 17 00:00:00 2001
-From: "minda.chen" <minda.chen@starfivetech.com>
-Date: Tue, 18 Oct 2022 09:57:39 +0800
-Subject: [PATCH 109/116] usb:xhci:To improve performance,usb using lowmem for
- bulk xfer.
-
-Generate an usb low memory pool for usb 3.0 host
-read/write transfer, default size is 8M.
-
-Signed-off-by: minda.chen <minda.chen@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/jh7110-evb.dts | 1 +
- drivers/usb/core/hcd.c | 4 +-
- drivers/usb/host/xhci-mem.c | 64 +++++++++++++++++++++
- drivers/usb/host/xhci-plat.c | 8 +++
- drivers/usb/host/xhci-ring.c | 3 +-
- drivers/usb/host/xhci.c | 57 +++++++++++++++++-
- drivers/usb/host/xhci.h | 11 ++++
- 7 files changed, 145 insertions(+), 3 deletions(-)
-
---- a/arch/riscv/boot/dts/starfive/jh7110-evb.dts
-+++ b/arch/riscv/boot/dts/starfive/jh7110-evb.dts
-@@ -31,5 +31,6 @@
- };
-
- &usb0 {
-+ xhci-lowmem-pool;
- status = "okay";
- };
---- a/drivers/usb/core/hcd.c
-+++ b/drivers/usb/core/hcd.c
-@@ -1439,7 +1439,9 @@ int usb_hcd_map_urb_for_dma(struct usb_h
- if (ret == 0)
- urb->transfer_flags |= URB_MAP_LOCAL;
- } else if (hcd_uses_dma(hcd)) {
-- if (urb->num_sgs) {
-+ if (urb->transfer_flags & URB_MAP_LOCAL)
-+ return ret;
-+ else if (urb->num_sgs) {
- int n;
-
- /* We don't support sg for isoc transfers ! */
---- a/drivers/usb/host/xhci-mem.c
-+++ b/drivers/usb/host/xhci-mem.c
-@@ -14,6 +14,7 @@
- #include <linux/slab.h>
- #include <linux/dmapool.h>
- #include <linux/dma-mapping.h>
-+#include <linux/genalloc.h>
-
- #include "xhci.h"
- #include "xhci-trace.h"
-@@ -1878,6 +1879,7 @@ EXPORT_SYMBOL_GPL(xhci_remove_secondary_
- void xhci_mem_cleanup(struct xhci_hcd *xhci)
- {
- struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
-+ struct xhci_lowmem_pool *pool;
- int i, j, num_ports;
-
- cancel_delayed_work_sync(&xhci->cmd_timer);
-@@ -1928,6 +1930,13 @@ void xhci_mem_cleanup(struct xhci_hcd *x
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Freed medium stream array pool");
-
-+ if (xhci->lowmem_pool.pool) {
-+ pool = &xhci->lowmem_pool;
-+ dma_free_coherent(dev, pool->size, (void *)pool->cached_base, pool->dma_addr);
-+ gen_pool_destroy(pool->pool);
-+ pool->pool = NULL;
-+ }
-+
- if (xhci->dcbaa)
- dma_free_coherent(dev, sizeof(*xhci->dcbaa),
- xhci->dcbaa, xhci->dcbaa->dma);
-@@ -2399,6 +2408,55 @@ xhci_create_secondary_interrupter(struct
- }
- EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
-
-+int xhci_setup_local_lowmem(struct xhci_hcd *xhci, size_t size)
-+{
-+ int err;
-+ void *buffer;
-+ dma_addr_t dma_addr;
-+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
-+ struct xhci_lowmem_pool *pool = &xhci->lowmem_pool;
-+
-+ if (!pool->pool) {
-+ /* minimal alloc one page */
-+ pool->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(hcd->self.sysdev));
-+ if (IS_ERR(pool->pool))
-+ return PTR_ERR(pool->pool);
-+ }
-+
-+ buffer = dma_alloc_coherent(hcd->self.sysdev, size, &dma_addr,
-+ GFP_KERNEL | GFP_DMA32);
-+
-+ if (IS_ERR(buffer)) {
-+ err = PTR_ERR(buffer);
-+ goto destroy_pool;
-+ }
-+
-+ /*
-+ * Here we pass a dma_addr_t but the arg type is a phys_addr_t.
-+ * It's not backed by system memory and thus there's no kernel mapping
-+ * for it.
-+ */
-+ err = gen_pool_add_virt(pool->pool, (unsigned long)buffer,
-+ dma_addr, size, dev_to_node(hcd->self.sysdev));
-+ if (err < 0) {
-+ dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
-+ err);
-+ dma_free_coherent(hcd->self.sysdev, size, buffer, dma_addr);
-+ goto destroy_pool;
-+ }
-+
-+ pool->cached_base = (u64)buffer;
-+ pool->dma_addr = dma_addr;
-+
-+ return 0;
-+
-+destroy_pool:
-+ gen_pool_destroy(pool->pool);
-+ pool->pool = NULL;
-+ return err;
-+}
-+EXPORT_SYMBOL_GPL(xhci_setup_local_lowmem);
-+
- int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
- {
- struct xhci_interrupter *ir;
-@@ -2540,6 +2598,12 @@ int xhci_mem_init(struct xhci_hcd *xhci,
-
- xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
-
-+ if (xhci->quirks & XHCI_LOCAL_BUFFER) {
-+ if (xhci_setup_local_lowmem(xhci,
-+ xhci->lowmem_pool.size))
-+ goto fail;
-+ }
-+
- /*
- * XXX: Might need to set the Interrupter Moderation Register to
- * something other than the default (~1ms minimum between interrupts).
---- a/drivers/usb/host/xhci-plat.c
-+++ b/drivers/usb/host/xhci-plat.c
-@@ -253,6 +253,14 @@ int xhci_plat_probe(struct platform_devi
- if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
- xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
-
-+ if (device_property_read_bool(tmpdev, "xhci-lowmem-pool")) {
-+ xhci->quirks |= XHCI_LOCAL_BUFFER;
-+ if (device_property_read_u32(tmpdev, "lowmem-pool-size",
-+ &xhci->lowmem_pool.size)) {
-+ xhci->lowmem_pool.size = 8 << 20;
-+ } else
-+ xhci->lowmem_pool.size <<= 20;
-+ }
- device_property_read_u32(tmpdev, "imod-interval-ns",
- &xhci->imod_interval);
- }
---- a/drivers/usb/host/xhci-ring.c
-+++ b/drivers/usb/host/xhci-ring.c
-@@ -3721,7 +3721,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *
-
- full_len = urb->transfer_buffer_length;
- /* If we have scatter/gather list, we use it. */
-- if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)) {
-+ if (urb->num_sgs && !(urb->transfer_flags & URB_DMA_MAP_SINGLE)
-+ && !(urb->transfer_flags & URB_MAP_LOCAL)) {
- num_sgs = urb->num_mapped_sgs;
- sg = urb->sg;
- addr = (u64) sg_dma_address(sg);
---- a/drivers/usb/host/xhci.c
-+++ b/drivers/usb/host/xhci.c
-@@ -19,6 +19,8 @@
- #include <linux/slab.h>
- #include <linux/dmi.h>
- #include <linux/dma-mapping.h>
-+#include <linux/dma-map-ops.h>
-+#include <linux/genalloc.h>
-
- #include "xhci.h"
- #include "xhci-trace.h"
-@@ -1312,6 +1314,55 @@ static void xhci_unmap_temp_buf(struct u
- urb->transfer_buffer = NULL;
- }
-
-+static void xhci_map_urb_local(struct usb_hcd *hcd, struct urb *urb,
-+ gfp_t mem_flags)
-+{
-+ void *buffer;
-+ dma_addr_t dma_handle;
-+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-+ struct xhci_lowmem_pool *lowmem_pool = &xhci->lowmem_pool;
-+
-+ if (lowmem_pool->pool
-+ && (usb_endpoint_type(&urb->ep->desc) == USB_ENDPOINT_XFER_BULK)
-+ && (urb->transfer_buffer_length > PAGE_SIZE)
-+ && urb->num_sgs && urb->sg && (sg_phys(urb->sg) > 0xffffffff)) {
-+ buffer = gen_pool_dma_alloc(lowmem_pool->pool,
-+ urb->transfer_buffer_length, &dma_handle);
-+ if (buffer) {
-+ urb->transfer_dma = dma_handle;
-+ urb->transfer_buffer = buffer;
-+ urb->transfer_flags |= URB_MAP_LOCAL;
-+ if (usb_urb_dir_out(urb))
-+ sg_copy_to_buffer(urb->sg, urb->num_sgs,
-+ (void *)buffer,
-+ urb->transfer_buffer_length);
-+ }
-+ }
-+
-+}
-+
-+static void xhci_unmap_urb_local(struct usb_hcd *hcd, struct urb *urb)
-+{
-+ dma_addr_t dma_handle;
-+ u64 cached_buffer;
-+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-+ struct xhci_lowmem_pool *lowmem_pool = &xhci->lowmem_pool;
-+
-+ if (urb->transfer_flags & URB_MAP_LOCAL) {
-+ dma_handle = urb->transfer_dma;
-+ cached_buffer = lowmem_pool->cached_base +
-+ ((u32)urb->transfer_dma & (lowmem_pool->size - 1));
-+ if (usb_urb_dir_in(urb))
-+ sg_copy_from_buffer(urb->sg, urb->num_sgs,
-+ (void *)cached_buffer, urb->transfer_buffer_length);
-+ gen_pool_free(lowmem_pool->pool, (unsigned long)urb->transfer_buffer,
-+ urb->transfer_buffer_length);
-+ urb->transfer_flags &= ~URB_MAP_LOCAL;
-+ urb->transfer_buffer = NULL;
-+ }
-+}
-+
-+
- /*
- * Bypass the DMA mapping if URB is suitable for Immediate Transfer (IDT),
- * we'll copy the actual data into the TRB address register. This is limited to
-@@ -1332,9 +1383,11 @@ static int xhci_map_urb_for_dma(struct u
- if (xhci_urb_temp_buffer_required(hcd, urb))
- return xhci_map_temp_buffer(hcd, urb);
- }
-+ xhci_map_urb_local(hcd, urb, mem_flags);
- return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
- }
-
-+
- static void xhci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
- {
- struct xhci_hcd *xhci;
-@@ -1347,8 +1400,10 @@ static void xhci_unmap_urb_for_dma(struc
-
- if ((xhci->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK) && unmap_temp_buf)
- xhci_unmap_temp_buf(hcd, urb);
-- else
-+ else {
-+ xhci_unmap_urb_local(hcd, urb);
- usb_hcd_unmap_urb_for_dma(hcd, urb);
-+ }
- }
-
- /**
---- a/drivers/usb/host/xhci.h
-+++ b/drivers/usb/host/xhci.h
-@@ -1506,6 +1506,13 @@ struct xhci_hub {
- u8 min_rev;
- };
-
-+struct xhci_lowmem_pool {
-+ struct gen_pool *pool;
-+ u64 cached_base;
-+ dma_addr_t dma_addr;
-+ unsigned int size;
-+};
-+
- /* There is one xhci_hcd structure per controller */
- struct xhci_hcd {
- struct usb_hcd *main_hcd;
-@@ -1660,6 +1667,8 @@ struct xhci_hcd {
- #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
- #define XHCI_ETRON_HOST BIT_ULL(49)
-
-+#define XHCI_LOCAL_BUFFER BIT_ULL(63)
-+
- unsigned int num_active_eps;
- unsigned int limit_active_eps;
- struct xhci_port *hw_ports;
-@@ -1689,6 +1698,8 @@ struct xhci_hcd {
- struct list_head regset_list;
-
- void *dbc;
-+ struct xhci_lowmem_pool lowmem_pool;
-+
- /* platform-specific data -- must come last */
- unsigned long priv[] __aligned(sizeof(s64));
- };
+++ /dev/null
-From a170cb9936bb0b00d58aaea40984dbce1169fe42 Mon Sep 17 00:00:00 2001
-From: Minda Chen <minda.chen@starfivetech.com>
-Date: Mon, 3 Jul 2023 16:14:20 +0800
-Subject: [PATCH 110/116] usb: xhci: using dma_alloc_noncoherent to alloc low
- memory pool
-
-For RISCV_NONCACHEHERENT is set, using dma_alloc_noncoherent
-to alloc cached large block low memory buffer. And set default
-size to 4M. (largest size of continuous memory can be supported)
-
-Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
----
- drivers/usb/host/xhci-mem.c | 29 ++++++++++++++++-------------
- drivers/usb/host/xhci-plat.c | 9 +++++----
- 2 files changed, 21 insertions(+), 17 deletions(-)
-
---- a/drivers/usb/host/xhci-mem.c
-+++ b/drivers/usb/host/xhci-mem.c
-@@ -1932,7 +1932,8 @@ void xhci_mem_cleanup(struct xhci_hcd *x
-
- if (xhci->lowmem_pool.pool) {
- pool = &xhci->lowmem_pool;
-- dma_free_coherent(dev, pool->size, (void *)pool->cached_base, pool->dma_addr);
-+ dma_free_noncoherent(dev, pool->size, (void *)pool->cached_base,
-+ pool->dma_addr, DMA_BIDIRECTIONAL);
- gen_pool_destroy(pool->pool);
- pool->pool = NULL;
- }
-@@ -2419,15 +2420,15 @@ int xhci_setup_local_lowmem(struct xhci_
- if (!pool->pool) {
- /* minimal alloc one page */
- pool->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(hcd->self.sysdev));
-- if (IS_ERR(pool->pool))
-- return PTR_ERR(pool->pool);
-+ if (!pool->pool)
-+ return -ENOMEM;
- }
-
-- buffer = dma_alloc_coherent(hcd->self.sysdev, size, &dma_addr,
-- GFP_KERNEL | GFP_DMA32);
-+ buffer = dma_alloc_noncoherent(hcd->self.sysdev, size, &dma_addr,
-+ DMA_BIDIRECTIONAL, GFP_ATOMIC);
-
-- if (IS_ERR(buffer)) {
-- err = PTR_ERR(buffer);
-+ if (!buffer) {
-+ err = -ENOMEM;
- goto destroy_pool;
- }
-
-@@ -2437,11 +2438,11 @@ int xhci_setup_local_lowmem(struct xhci_
- * for it.
- */
- err = gen_pool_add_virt(pool->pool, (unsigned long)buffer,
-- dma_addr, size, dev_to_node(hcd->self.sysdev));
-+ dma_addr, size, dev_to_node(hcd->self.sysdev));
- if (err < 0) {
- dev_err(hcd->self.sysdev, "gen_pool_add_virt failed with %d\n",
- err);
-- dma_free_coherent(hcd->self.sysdev, size, buffer, dma_addr);
-+ dma_free_noncoherent(hcd->self.sysdev, size, buffer, dma_addr, DMA_BIDIRECTIONAL);
- goto destroy_pool;
- }
-
-@@ -2465,7 +2466,7 @@ int xhci_mem_init(struct xhci_hcd *xhci,
- unsigned int val, val2;
- u64 val_64;
- u32 page_size, temp;
-- int i;
-+ int i, ret;
-
- INIT_LIST_HEAD(&xhci->cmd_list);
-
-@@ -2599,9 +2600,11 @@ int xhci_mem_init(struct xhci_hcd *xhci,
- xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
-
- if (xhci->quirks & XHCI_LOCAL_BUFFER) {
-- if (xhci_setup_local_lowmem(xhci,
-- xhci->lowmem_pool.size))
-- goto fail;
-+ ret = xhci_setup_local_lowmem(xhci, xhci->lowmem_pool.size);
-+ if (ret) {
-+ xhci->quirks &= ~XHCI_LOCAL_BUFFER;
-+ xhci_warn(xhci, "WARN: Can't alloc lowmem pool\n");
-+ }
- }
-
- /*
---- a/drivers/usb/host/xhci-plat.c
-+++ b/drivers/usb/host/xhci-plat.c
-@@ -255,10 +255,11 @@ int xhci_plat_probe(struct platform_devi
-
- if (device_property_read_bool(tmpdev, "xhci-lowmem-pool")) {
- xhci->quirks |= XHCI_LOCAL_BUFFER;
-- if (device_property_read_u32(tmpdev, "lowmem-pool-size",
-- &xhci->lowmem_pool.size)) {
-- xhci->lowmem_pool.size = 8 << 20;
-- } else
-+ ret = device_property_read_u32(tmpdev, "lowmem-pool-size",
-+ &xhci->lowmem_pool.size);
-+ if (ret || xhci->lowmem_pool.size >= 4)
-+ xhci->lowmem_pool.size = 4 << 20;
-+ else
- xhci->lowmem_pool.size <<= 20;
- }
- device_property_read_u32(tmpdev, "imod-interval-ns",
+++ /dev/null
-From fc86405992c37b1898fd9b9bc077be673d774269 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Fri, 22 Mar 2024 09:54:28 +0800
-Subject: [PATCH 111/116] riscv: dts: starfive: Add vf2-overlay dtso subdir
-
-Create subdir vf2-overlay/ and add overlay .dtso for VF2 board.
-The code is ported from tag JH7110_VF2_6.1_v5.11.4
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/Makefile | 1 +
- .../boot/dts/starfive/vf2-overlay/Makefile | 3 +
- .../starfive/vf2-overlay/vf2-overlay-can.dtso | 23 ++++++
- .../vf2-overlay/vf2-overlay-uart3-i2c.dtso | 75 +++++++++++++++++++
- 4 files changed, 102 insertions(+)
- create mode 100644 arch/riscv/boot/dts/starfive/vf2-overlay/Makefile
- create mode 100644 arch/riscv/boot/dts/starfive/vf2-overlay/vf2-overlay-can.dtso
- create mode 100644 arch/riscv/boot/dts/starfive/vf2-overlay/vf2-overlay-uart3-i2c.dtso
-
---- a/arch/riscv/boot/dts/starfive/Makefile
-+++ b/arch/riscv/boot/dts/starfive/Makefile
-@@ -9,6 +9,7 @@ DTC_FLAGS_jh7110-evb := -@
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight.dtb
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb
-
-+subdir-y += vf2-overlay
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb
- dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.3b.dtb \
- jh7110-starfive-visionfive-2-ac108.dtb \
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/vf2-overlay/Makefile
-@@ -0,0 +1,3 @@
-+# SPDX-License-Identifier: GPL-2.0
-+dtb-$(CONFIG_ARCH_STARFIVE) += vf2-overlay-uart3-i2c.dtbo \
-+ vf2-overlay-can.dtbo
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/vf2-overlay/vf2-overlay-can.dtso
-@@ -0,0 +1,23 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //can0
-+ fragment@0 {
-+ target-path = "/soc/can@130d0000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+
-+ //can1
-+ fragment@1 {
-+ target-path = "/soc/can@130e0000";
-+ __overlay__ {
-+ status = "okay";
-+ };
-+ };
-+};
---- /dev/null
-+++ b/arch/riscv/boot/dts/starfive/vf2-overlay/vf2-overlay-uart3-i2c.dtso
-@@ -0,0 +1,75 @@
-+/dts-v1/;
-+/plugin/;
-+#include <dt-bindings/gpio/gpio.h>
-+#include "../jh7110-pinfunc.h"
-+/ {
-+ compatible = "starfive,jh7110";
-+
-+ //sysgpio
-+ fragment@0 {
-+ target-path = "/soc/pinctrl@13040000";
-+ __overlay__ {
-+ dt_uart3_pins: dt-uart3-0 {
-+ tx-pins {
-+ pinmux = <GPIOMUX(60, GPOUT_SYS_UART3_TX,
-+ GPOEN_ENABLE,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <12>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+
-+ rx-pins {
-+ pinmux = <GPIOMUX(63, GPOUT_LOW,
-+ GPOEN_DISABLE,
-+ GPI_SYS_UART3_RX)>;
-+ bias-pull-up;
-+ drive-strength = <2>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ dt_i2c1_pins: dt-i2c1-0 {
-+ i2c-pins {
-+ pinmux = <GPIOMUX(42, GPOUT_LOW,
-+ GPOEN_SYS_I2C1_CLK,
-+ GPI_SYS_I2C1_CLK)>,
-+ <GPIOMUX(43, GPOUT_LOW,
-+ GPOEN_SYS_I2C1_DATA,
-+ GPI_SYS_I2C1_DATA)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+ };
-+ };
-+
-+ //uart3
-+ fragment@1 {
-+ target-path = "/soc/serial@12000000";
-+ __overlay__ {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dt_uart3_pins>;
-+ status = "okay";
-+ };
-+ };
-+
-+ //i2c1
-+ fragment@2 {
-+ target-path = "/soc/i2c@10040000";
-+ __overlay__ {
-+ clock-frequency = <100000>;
-+ i2c-sda-hold-time-ns = <300>;
-+ i2c-sda-falling-time-ns = <510>;
-+ i2c-scl-falling-time-ns = <510>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&dt_i2c1_pins>;
-+ status = "okay";
-+ };
-+ };
-+};
+++ /dev/null
-From 2b098da69f9497e725683caf67fbecf79202b7fc Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Fri, 22 Mar 2024 11:33:40 +0800
-Subject: [PATCH 112/116] riscv: dts: starfive: visionfive 2: Add aliases for
- i2c* and uart3
-
-Fix the numbers of i2c and uart3.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- .../riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-@@ -15,7 +15,10 @@
- ethernet0 = &gmac0;
- ethernet1 = &gmac1;
- i2c0 = &i2c0;
-+ i2c1 = &i2c1;
- i2c2 = &i2c2;
-+ i2c3 = &i2c3;
-+ i2c4 = &i2c4;
- i2c5 = &i2c5;
- i2c6 = &i2c6;
- mmc0 = &mmc0;
-@@ -23,6 +26,7 @@
- pcie0 = &pcie0;
- pcie1 = &pcie1;
- serial0 = &uart0;
-+ serial3 = &uart3;
- };
-
- chosen {
+++ /dev/null
-From fdb2822982887c7048f34601688ae2406ccbcfcc Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Mon, 15 Apr 2024 11:29:17 +0800
-Subject: [PATCH 114/116] riscv: dts: starfive: visionfive 2: Sync the sound
- card names with v5.15 and v6.1
-
-Sync the sound card names. So we can build Debian images with the
-same process.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- .../dts/starfive/jh7110-starfive-visionfive-2-tdm.dts | 2 +-
- .../dts/starfive/jh7110-starfive-visionfive-2-wm8960.dts | 2 +-
- .../boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 8 ++++----
- 3 files changed, 6 insertions(+), 6 deletions(-)
-
---- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-tdm.dts
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-tdm.dts
-@@ -8,7 +8,7 @@
- #include "jh7110-starfive-visionfive-2-v1.3b.dts"
-
- / {
-- sound-tdm {
-+ sound5: snd-card5 {
- compatible = "simple-audio-card";
- #address-cells = <1>;
- #size-cells = <0>;
---- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-wm8960.dts
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-wm8960.dts
-@@ -9,7 +9,7 @@
-
- / {
- /* i2s + wm8960 */
-- sound-wm8960 {
-+ sound6: snd-card6 {
- compatible = "simple-audio-card";
- #address-cells = <1>;
- #size-cells = <0>;
---- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-@@ -91,9 +91,9 @@
- #sound-dai-cells = <0>;
- };
-
-- sound-pwmdac {
-+ sound3: snd-card3 {
- compatible = "simple-audio-card";
-- simple-audio-card,name = "StarFive-PWMDAC-Sound-Card";
-+ simple-audio-card,name = "Starfive-PWMDAC-Sound-Card";
- #address-cells = <1>;
- #size-cells = <0>;
-
-@@ -113,12 +113,12 @@
- };
- };
-
-- sound-hdmi {
-+ sound1: snd-card1 {
- compatible = "simple-audio-card";
- #address-cells = <1>;
- #size-cells = <0>;
-
-- simple-audio-card,name = "StarFive-HDMI-Sound-Card";
-+ simple-audio-card,name = "Starfive-HDMI-Sound-Card";
- simple-audio-card,dai-link@0 {
- reg = <0>;
- format = "i2s";
+++ /dev/null
-From dac6f3021895e7678552789edff22f1dc909e274 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Mon, 15 Apr 2024 20:59:35 +0800
-Subject: [PATCH 115/116] clk: starfive: jh7110: Change uart3-uart5 clk
- register info
-
-The core_clk division register of uart3-uart5 include fractional and
-integral parts, but now only use the integral part, so include shift
-operation. The integral part include 8 bit, so the max value can be
-configed is 255.
-
-Signed-off-by: Yanhong Wang <yanhong.wang@starfivetech.com>
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- drivers/clk/starfive/clk-starfive-jh71x0.c | 13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
---- a/drivers/clk/starfive/clk-starfive-jh71x0.c
-+++ b/drivers/clk/starfive/clk-starfive-jh71x0.c
-@@ -10,6 +10,8 @@
- #include <linux/device.h>
- #include <linux/io.h>
-
-+#include <dt-bindings/clock/starfive,jh7110-crg.h>
-+
- #include "clk-starfive-jh71x0.h"
-
- static struct jh71x0_clk *jh71x0_clk_from(struct clk_hw *hw)
-@@ -70,6 +72,11 @@ static unsigned long jh71x0_clk_recalc_r
- struct jh71x0_clk *clk = jh71x0_clk_from(hw);
- u32 div = jh71x0_clk_reg_get(clk) & JH71X0_CLK_DIV_MASK;
-
-+ if (clk->idx == JH7110_SYSCLK_UART3_CORE ||
-+ clk->idx == JH7110_SYSCLK_UART4_CORE ||
-+ clk->idx == JH7110_SYSCLK_UART5_CORE)
-+ div >>= 8;
-+
- return div ? parent_rate / div : 0;
- }
-
-@@ -110,6 +117,12 @@ static int jh71x0_clk_set_rate(struct cl
- unsigned long div = clamp(DIV_ROUND_CLOSEST(parent_rate, rate),
- 1UL, (unsigned long)clk->max_div);
-
-+ /* UART3-5: [15:8]: integer part of the divisor. [7:0] fraction part of the divisor */
-+ if (clk->idx == JH7110_SYSCLK_UART3_CORE ||
-+ clk->idx == JH7110_SYSCLK_UART4_CORE ||
-+ clk->idx == JH7110_SYSCLK_UART5_CORE)
-+ div <<= 8;
-+
- jh71x0_clk_reg_rmw(clk, JH71X0_CLK_DIV_MASK, div);
- return 0;
- }
+++ /dev/null
-From 1ea169bb83d3b556eb9054f1a3e8ce0411370293 Mon Sep 17 00:00:00 2001
-From: Hal Feng <hal.feng@starfivetech.com>
-Date: Wed, 24 Apr 2024 14:23:07 +0800
-Subject: [PATCH 116/116] riscv: dts: starfive: visionfive 2: Quote
- corresponding regulators in hdmi and vin
-
-So PMIC can start to work before HDMI and VIN.
-
-Signed-off-by: Hal Feng <hal.feng@starfivetech.com>
----
- arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi | 3 +++
- 1 file changed, 3 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
-@@ -961,6 +961,8 @@
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_pins>;
- hpd-gpio = <&sysgpio 15 GPIO_ACTIVE_HIGH>;
-+ hdmi_0p9-supply = <&hdmi_0p9>;
-+ hdmi_1p8-supply = <&hdmi_1p8>;
-
- hdmi_in: port {
- #address-cells = <1>;
-@@ -1084,6 +1086,7 @@
- &vin_sysctl {
- /* when use dvp open this pinctrl*/
- status = "okay";
-+ mipi_0p9-supply = <&mipi_0p9>;
-
- ports {
- #address-cells = <1>;
+++ /dev/null
-From b7b4fad8784d7ab4fcd929a56c3e5366046fe7fc Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Thu, 14 Oct 2021 20:56:54 +0200
-Subject: [PATCH 1000/1024] serial: 8250_dw: Add starfive,jh7100-hsuart
- compatible
-
-This adds a compatible for the high speed UARTs on the StarFive JH7100
-RISC-V SoC. Just like the regular uarts we also need to keep the input
-clocks at their default rate and rely only on the divisor in the UART.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- drivers/tty/serial/8250/8250_dw.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/tty/serial/8250/8250_dw.c
-+++ b/drivers/tty/serial/8250/8250_dw.c
-@@ -803,6 +803,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 */ }
- };
+++ /dev/null
-From 3051ab0102aaf969dd85f07b6ab731dadf97ef6c Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Sat, 20 Nov 2021 17:13:22 +0100
-Subject: [PATCH 1001/1024] RISC-V: Add StarFive JH7100 audio clock node
-
-Add device tree node for the audio clocks on the StarFive JH7100 RISC-V
-SoC.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- arch/riscv/boot/dts/starfive/jh7100.dtsi | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
-@@ -158,6 +158,16 @@
- riscv,ndev = <133>;
- };
-
-+ audclk: clock-controller@10480000 {
-+ compatible = "starfive,jh7100-audclk";
-+ reg = <0x0 0x10480000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_AUDIO_SRC>,
-+ <&clkgen JH7100_CLK_AUDIO_12288>,
-+ <&clkgen JH7100_CLK_DOM7AHB_BUS>;
-+ clock-names = "audio_src", "audio_12288", "dom7ahb_bus";
-+ #clock-cells = <1>;
-+ };
-+
- clkgen: clock-controller@11800000 {
- compatible = "starfive,jh7100-clkgen";
- reg = <0x0 0x11800000 0x0 0x10000>;
+++ /dev/null
-From 8ef30667e97363ca921416a60e50eb28bf88cc4f Mon Sep 17 00:00:00 2001
-From: Samin Guo <samin.guo@starfivetech.com>
-Date: Fri, 8 Jan 2021 03:11:04 +0800
-Subject: [PATCH 1002/1024] drivers/tty/serial/8250: update driver for JH7100
-
----
- drivers/tty/serial/8250/8250_port.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/tty/serial/8250/8250_port.c
-+++ b/drivers/tty/serial/8250/8250_port.c
-@@ -72,8 +72,16 @@ static const struct serial8250_config ua
- },
- [PORT_16550] = {
- .name = "16550",
-+#ifdef CONFIG_SOC_STARFIVE
-+ .fifo_size = 16,
-+ .tx_loadsz = 16,
-+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
-+ .rxtrig_bytes = {1, 4, 8, 14},
-+ .flags = UART_CAP_FIFO,
-+#else
- .fifo_size = 1,
- .tx_loadsz = 1,
-+#endif
- },
- [PORT_16550A] = {
- .name = "16550A",
+++ /dev/null
-From 2d5b71006c6a93e26eb86b7efd37440c020bab46 Mon Sep 17 00:00:00 2001
-From: Samin Guo <samin.guo@starfivetech.com>
-Date: Wed, 17 Nov 2021 14:50:45 +0800
-Subject: [PATCH 1003/1024] dmaengine: dw-axi-dmac: Handle xfer start while
- non-idle
-
-Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
-Signed-off-by: Curry Zhang <curry.zhang@starfivetech.com>
----
- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 12 +++++++++++-
- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 1 +
- 2 files changed, 12 insertions(+), 1 deletion(-)
-
---- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-@@ -382,11 +382,13 @@ static void axi_chan_block_xfer_start(st
- u32 irq_mask;
- u8 lms = 0; /* Select AXI0 master for LLI fetching */
-
-+ chan->is_err = false;
- if (unlikely(axi_chan_is_hw_enable(chan))) {
- dev_err(chan2dev(chan), "%s is non-idle!\n",
- axi_chan_name(chan));
-
-- return;
-+ axi_chan_disable(chan);
-+ chan->is_err = true;
- }
-
- axi_dma_enable(chan->chip);
-@@ -1028,6 +1030,14 @@ static noinline void axi_chan_handle_err
- axi_chan_name(chan));
- goto out;
- }
-+ if (chan->is_err) {
-+ struct axi_dma_desc *desc = vd_to_axi_desc(vd);
-+
-+ axi_chan_block_xfer_start(chan, desc);
-+ chan->is_err = false;
-+ goto out;
-+ }
-+
- /* Remove the completed descriptor from issued list */
- list_del(&vd->node);
-
---- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
-+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
-@@ -50,6 +50,7 @@ struct axi_dma_chan {
- struct dma_slave_config config;
- enum dma_transfer_direction direction;
- bool cyclic;
-+ bool is_err;
- /* these other elements are all protected by vc.lock */
- bool is_paused;
- };
+++ /dev/null
-From 933f8c33d466de20e9894ef8de5b6afe478a420d Mon Sep 17 00:00:00 2001
-From: Samin Guo <samin.guo@starfivetech.com>
-Date: Wed, 17 Nov 2021 14:50:45 +0800
-Subject: [PATCH 1004/1024] dmaengine: dw-axi-dmac: Add StarFive JH7100 support
-
-Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 12 ++++++++++++
- drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 4 ++++
- 2 files changed, 16 insertions(+)
-
---- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
-@@ -677,8 +677,13 @@ static int dw_axi_dma_set_hw_desc(struct
-
- hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
-
-+#ifdef CONFIG_SOC_STARFIVE
-+ ctllo |= DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_DST_MSIZE_POS |
-+ DWAXIDMAC_BURST_TRANS_LEN_16 << CH_CTL_L_SRC_MSIZE_POS;
-+#else
- ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
-+#endif
- hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
-
- set_desc_src_master(hw_desc);
-@@ -1502,7 +1507,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);
-@@ -1587,6 +1596,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
-@@ -284,7 +284,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
+++ /dev/null
-From c5019bf73d1e178beb6055cca254e7d3c916db7c Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Sat, 17 Jul 2021 21:50:38 +0200
-Subject: [PATCH 1005/1024] pinctrl: starfive: Reset pinmux settings
-
-Current u-boot doesn't seem to take into account that some GPIOs are
-configured as inputs/outputs of certain peripherals on power-up. This
-means it ends up configuring some GPIOs as inputs to more than one
-peripheral which the documentation explicitly says is illegal. Similarly
-it also ends up configuring more than one GPIO as output of the same
-peripheral. While not explicitly mentioned by the documentation this
-also seems like a bad idea.
-
-The easiest way to remedy this mess is to just disconnect all GPIOs from
-peripherals and have our pinmux configuration set everything up
-properly. This, however, means that we'd disconnect the serial console
-from its pins for a while, so add a device tree property to keep
-certain GPIOs from being reset.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- .../pinctrl/starfive,jh7100-pinctrl.yaml | 4 ++
- .../starfive/pinctrl-starfive-jh7100.c | 66 +++++++++++++++++++
- 2 files changed, 70 insertions(+)
-
---- a/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml
-+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml
-@@ -88,6 +88,10 @@ properties:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3, 4, 5, 6]
-
-+ starfive,keep-gpiomux:
-+ description: Keep pinmux for these GPIOs from being reset at boot.
-+ $ref: /schemas/types.yaml#/definitions/uint32-array
-+
- required:
- - compatible
- - reg
---- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
-+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
-@@ -203,6 +203,10 @@ static u16 starfive_drive_strength_from_
- return (clamp(i, 14U, 63U) - 14) / 7;
- }
-
-+static bool keepmux;
-+module_param(keepmux, bool, 0644);
-+MODULE_PARM_DESC(keepmux, "Keep pinmux settings from previous boot stage");
-+
- struct starfive_pinctrl {
- struct gpio_chip gc;
- struct pinctrl_gpio_range gpios;
-@@ -1225,6 +1229,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;
-@@ -1286,6 +1349,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:
+++ /dev/null
-From a4a2a8886c97e14643fe3e0ab8cf67a75c1bf14d Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Sat, 25 Mar 2023 22:57:06 +0100
-Subject: [PATCH 1006/1024] clk: starfive: Add flags argument to JH71X0__MUX
- macro
-
-This flag is needed to add the CLK_SET_RATE_PARENT flag on the gmac_tx
-clock on the JH7100, which in turn is needed by the dwmac-starfive
-driver to set the clock properly for 1000, 100 and 10 Mbps links.
-
-This change was mostly made using coccinelle:
-
-@ match @
-expression idx, name, nparents;
-@@
- JH71X0__MUX(
--idx, name, nparents,
-+idx, name, 0, nparents,
- ...)
-
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
----
- .../clk/starfive/clk-starfive-jh7100-audio.c | 2 +-
- drivers/clk/starfive/clk-starfive-jh7100.c | 32 +++++++++----------
- .../clk/starfive/clk-starfive-jh7110-aon.c | 6 ++--
- .../clk/starfive/clk-starfive-jh7110-isp.c | 2 +-
- .../clk/starfive/clk-starfive-jh7110-sys.c | 26 +++++++--------
- drivers/clk/starfive/clk-starfive-jh71x0.h | 4 +--
- 6 files changed, 36 insertions(+), 36 deletions(-)
-
---- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c
-@@ -79,7 +79,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB),
- JH71X0_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB),
- JH71X0__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS),
-- JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2,
-+ JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 0, 2,
- JH7100_AUDCLK_VAD_INTMEM,
- JH7100_AUDCLK_AUDIO_12288),
- };
---- a/drivers/clk/starfive/clk-starfive-jh7100.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7100.c
-@@ -24,48 +24,48 @@
- #define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3)
-
- static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = {
-- JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4,
-+ JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 0, 4,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL0_OUT,
- JH7100_CLK_PLL1_OUT,
- JH7100_CLK_PLL2_OUT),
-- JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3,
-+ JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 0, 3,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL1_OUT,
- JH7100_CLK_PLL2_OUT),
-- JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4,
-+ JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 0, 4,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL0_OUT,
- JH7100_CLK_PLL1_OUT,
- JH7100_CLK_PLL2_OUT),
-- JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3,
-+ JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 0, 3,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL0_OUT,
- JH7100_CLK_PLL2_OUT),
-- JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2,
-+ JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 0, 2,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL0_OUT),
-- JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2,
-+ JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 0, 2,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL2_OUT),
-- JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3,
-+ JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 0, 3,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL1_OUT,
- JH7100_CLK_PLL2_OUT),
-- JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3,
-+ JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 0, 3,
- JH7100_CLK_OSC_AUD,
- JH7100_CLK_PLL0_OUT,
- JH7100_CLK_PLL2_OUT),
- JH71X0_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT),
-- JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3,
-+ JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 0, 3,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL1_OUT,
- JH7100_CLK_PLL2_OUT),
-- JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3,
-+ JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 0, 3,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_PLL0_OUT,
- JH7100_CLK_PLL1_OUT),
-- JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3,
-+ JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 0, 3,
- JH7100_CLK_OSC_AUD,
- JH7100_CLK_PLL0_OUT,
- JH7100_CLK_PLL2_OUT),
-@@ -76,7 +76,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC),
- JH71X0_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT),
- JH71X0_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC),
-- JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2,
-+ JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 0, 2,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_OSC_AUD),
- JH71X0__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV),
-@@ -142,7 +142,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT),
- JH71X0_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS),
- JH71X0__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT),
-- JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2,
-+ JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 0, 2,
- JH7100_CLK_CPU_AXI,
- JH7100_CLK_NNEBUS_SRC1),
- JH71X0_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS),
-@@ -166,7 +166,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV),
- JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32,
- JH7100_CLK_USBPHY_ROOTDIV),
-- JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2,
-+ JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2,
- JH7100_CLK_OSC_SYS,
- JH7100_CLK_USBPHY_PLLDIV25M),
- JH71X0_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT),
-@@ -200,12 +200,12 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV),
- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
-- JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3,
-+ JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 0, 3,
- JH7100_CLK_GMAC_GTX,
- JH7100_CLK_GMAC_TX_INV,
- JH7100_CLK_GMAC_RMII_TX),
- JH71X0__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX),
-- JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2,
-+ JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 0, 2,
- JH7100_CLK_GMAC_GR_MII_RX,
- JH7100_CLK_GMAC_RMII_RX),
- JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE),
---- a/drivers/clk/starfive/clk-starfive-jh7110-aon.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7110-aon.c
-@@ -26,7 +26,7 @@
- static const struct jh71x0_clk_data jh7110_aonclk_data[] = {
- /* source */
- JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC),
-- JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 2,
-+ JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 0, 2,
- JH7110_AONCLK_OSC_DIV4,
- JH7110_AONCLK_OSC),
- /* gmac0 */
-@@ -39,7 +39,7 @@ static const struct jh71x0_clk_data jh71
- JH7110_AONCLK_GMAC0_GTXCLK,
- JH7110_AONCLK_GMAC0_RMII_RTX),
- JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX),
-- JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 2,
-+ JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 0, 2,
- JH7110_AONCLK_GMAC0_RGMII_RXIN,
- JH7110_AONCLK_GMAC0_RMII_RTX),
- JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX),
-@@ -48,7 +48,7 @@ static const struct jh71x0_clk_data jh71
- /* rtc */
- JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS),
- JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC),
-- JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 2,
-+ JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 0, 2,
- JH7110_AONCLK_RTC_OSC,
- JH7110_AONCLK_RTC_INTERNAL),
- JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC),
---- a/drivers/clk/starfive/clk-starfive-jh7110-isp.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
-@@ -53,7 +53,7 @@ static const struct jh71x0_clk_data jh71
- JH7110_ISPCLK_MIPI_RX0_PXL),
- JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF3, "vin_pixel_if3", 0,
- JH7110_ISPCLK_MIPI_RX0_PXL),
-- JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 2,
-+ JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 0, 2,
- JH7110_ISPCLK_MIPI_RX0_PXL,
- JH7110_ISPCLK_DVP_INV),
- /* ispv2_top_wrapper */
---- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
-@@ -36,18 +36,18 @@
-
- static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
- /* root */
-- JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 0, 2,
- JH7110_SYSCLK_OSC,
- JH7110_SYSCLK_PLL0_OUT),
- JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT),
- JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE),
-- JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 0, 2,
- JH7110_SYSCLK_PLL2_OUT,
- JH7110_SYSCLK_PLL1_OUT),
- JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2,
- JH7110_SYSCLK_PLL0_OUT,
- JH7110_SYSCLK_PLL2_OUT),
-- JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 0, 2,
- JH7110_SYSCLK_OSC,
- JH7110_SYSCLK_PLL2_OUT),
- JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT),
-@@ -62,7 +62,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT),
- JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT),
- JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT),
-- JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 0, 2,
- JH7110_SYSCLK_MCLK_INNER,
- JH7110_SYSCLK_MCLK_EXT),
- JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER),
-@@ -96,7 +96,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC),
- JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2),
- JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4),
-- JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 4,
-+ JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 0, 4,
- JH7110_SYSCLK_OSC_DIV2,
- JH7110_SYSCLK_PLL1_DIV2,
- JH7110_SYSCLK_PLL1_DIV4,
-@@ -186,7 +186,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30,
- JH7110_SYSCLK_GMAC1_RMII_REFIN),
- JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC),
-- JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 0, 2,
- JH7110_SYSCLK_GMAC1_RGMII_RXIN,
- JH7110_SYSCLK_GMAC1_RMII_RTX),
- JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX),
-@@ -270,11 +270,11 @@ static const struct jh71x0_clk_data jh71
- JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2,
- JH7110_SYSCLK_I2STX0_BCLK_MST_INV,
- JH7110_SYSCLK_I2STX0_BCLK_MST),
-- JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 0, 2,
- JH7110_SYSCLK_I2STX0_BCLK_MST,
- JH7110_SYSCLK_I2STX_BCLK_EXT),
- JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK),
-- JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 0, 2,
- JH7110_SYSCLK_I2STX0_LRCK_MST,
- JH7110_SYSCLK_I2STX_LRCK_EXT),
- /* i2stx1 */
-@@ -285,11 +285,11 @@ static const struct jh71x0_clk_data jh71
- JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2,
- JH7110_SYSCLK_I2STX1_BCLK_MST_INV,
- JH7110_SYSCLK_I2STX1_BCLK_MST),
-- JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 0, 2,
- JH7110_SYSCLK_I2STX1_BCLK_MST,
- JH7110_SYSCLK_I2STX_BCLK_EXT),
- JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK),
-- JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 0, 2,
- JH7110_SYSCLK_I2STX1_LRCK_MST,
- JH7110_SYSCLK_I2STX_LRCK_EXT),
- /* i2srx */
-@@ -300,11 +300,11 @@ static const struct jh71x0_clk_data jh71
- JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2,
- JH7110_SYSCLK_I2SRX_BCLK_MST_INV,
- JH7110_SYSCLK_I2SRX_BCLK_MST),
-- JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 0, 2,
- JH7110_SYSCLK_I2SRX_BCLK_MST,
- JH7110_SYSCLK_I2SRX_BCLK_EXT),
- JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK),
-- JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 0, 2,
- JH7110_SYSCLK_I2SRX_LRCK_MST,
- JH7110_SYSCLK_I2SRX_LRCK_EXT),
- /* pdm */
-@@ -314,7 +314,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0),
- JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0),
- JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK),
-- JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 2,
-+ JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 0, 2,
- JH7110_SYSCLK_TDM_INTERNAL,
- JH7110_SYSCLK_TDM_EXT),
- JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM),
---- a/drivers/clk/starfive/clk-starfive-jh71x0.h
-+++ b/drivers/clk/starfive/clk-starfive-jh71x0.h
-@@ -61,10 +61,10 @@ struct jh71x0_clk_data {
- .parents = { [0] = _parent }, \
- }
-
--#define JH71X0__MUX(_idx, _name, _nparents, ...) \
-+#define JH71X0__MUX(_idx, _name, _flags, _nparents, ...) \
- [_idx] = { \
- .name = _name, \
-- .flags = 0, \
-+ .flags = _flags, \
- .max = ((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT, \
- .parents = { __VA_ARGS__ }, \
- }
+++ /dev/null
-From 7dfed4b67bd6ba8c33caf90c01821b67cf3260dd Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Sat, 25 Mar 2023 23:04:31 +0100
-Subject: [PATCH 1007/1024] clk: starfive: jh7100: Add CLK_SET_RATE_PARENT to
- gmac_tx
-
-This is needed by the dwmac-starfive ethernet driver to set the clock
-for 1000, 100 and 10 Mbps links properly.
-
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
----
- drivers/clk/starfive/clk-starfive-jh7100.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/clk/starfive/clk-starfive-jh7100.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7100.c
-@@ -200,7 +200,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV),
- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
-- JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 0, 3,
-+ JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 3,
- JH7100_CLK_GMAC_GTX,
- JH7100_CLK_GMAC_TX_INV,
- JH7100_CLK_GMAC_RMII_TX),
+++ /dev/null
-From f8d08ec17674e56c7c689f5ca43c4dd3a4b76d13 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Thu, 14 Oct 2021 20:35:43 +0200
-Subject: [PATCH 1008/1024] clk: starfive: jh7100: Keep more clocks alive
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- drivers/clk/starfive/clk-starfive-jh7100.c | 37 +++++++++++-----------
- 1 file changed, 19 insertions(+), 18 deletions(-)
-
---- a/drivers/clk/starfive/clk-starfive-jh7100.c
-+++ b/drivers/clk/starfive/clk-starfive-jh7100.c
-@@ -94,9 +94,9 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GATE(JH7100_CLK_DMA2PNOC_AXI, "dma2pnoc_axi", 0, JH7100_CLK_CPU_AXI),
- JH71X0_GATE(JH7100_CLK_SGDMA2P_AHB, "sgdma2p_ahb", 0, JH7100_CLK_AHB_BUS),
- JH71X0__DIV(JH7100_CLK_DLA_BUS, "dla_bus", 4, JH7100_CLK_DLA_ROOT),
-- JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", 0, JH7100_CLK_DLA_BUS),
-- JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", 0, JH7100_CLK_DLA_BUS),
-- JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", 0, JH7100_CLK_APB1_BUS),
-+ JH71X0_GATE(JH7100_CLK_DLA_AXI, "dla_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DLA_BUS),
-+ JH71X0_GATE(JH7100_CLK_DLANOC_AXI, "dlanoc_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DLA_BUS),
-+ JH71X0_GATE(JH7100_CLK_DLA_APB, "dla_apb", CLK_IGNORE_UNUSED, JH7100_CLK_APB1_BUS),
- JH71X0_GDIV(JH7100_CLK_VP6_CORE, "vp6_core", 0, 4, JH7100_CLK_DSP_ROOT_DIV),
- JH71X0__DIV(JH7100_CLK_VP6BUS_SRC, "vp6bus_src", 4, JH7100_CLK_DSP_ROOT),
- JH71X0_GDIV(JH7100_CLK_VP6_AXI, "vp6_axi", 0, 4, JH7100_CLK_VP6BUS_SRC),
-@@ -160,11 +160,12 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GATE(JH7100_CLK_DMA1P_AXI, "dma1p_axi", 0, JH7100_CLK_SGDMA1P_BUS),
- JH71X0_GDIV(JH7100_CLK_X2C_AXI, "x2c_axi", CLK_IS_CRITICAL, 8, JH7100_CLK_CPUNBUS_ROOT_DIV),
- JH71X0__DIV(JH7100_CLK_USB_BUS, "usb_bus", 8, JH7100_CLK_CPUNBUS_ROOT_DIV),
-- JH71X0_GATE(JH7100_CLK_USB_AXI, "usb_axi", 0, JH7100_CLK_USB_BUS),
-- JH71X0_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", 0, JH7100_CLK_USB_BUS),
-+ JH71X0_GATE(JH7100_CLK_USB_AXI, "usb_axi", CLK_IGNORE_UNUSED, JH7100_CLK_USB_BUS),
-+ JH71X0_GATE(JH7100_CLK_USBNOC_AXI, "usbnoc_axi", CLK_IGNORE_UNUSED, JH7100_CLK_USB_BUS),
- JH71X0__DIV(JH7100_CLK_USBPHY_ROOTDIV, "usbphy_rootdiv", 4, JH7100_CLK_GMACUSB_ROOT),
-- JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV),
-- JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32,
-+ JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", CLK_IGNORE_UNUSED, 8,
-+ JH7100_CLK_USBPHY_ROOTDIV),
-+ JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", CLK_IGNORE_UNUSED, 32,
- JH7100_CLK_USBPHY_ROOTDIV),
- JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2,
- JH7100_CLK_OSC_SYS,
-@@ -183,23 +184,23 @@ static const struct jh71x0_clk_data jh71
- JH71X0__DIV(JH7100_CLK_VIN_BUS, "vin_bus", 8, JH7100_CLK_VIN_SRC),
- JH71X0_GATE(JH7100_CLK_VIN_AXI, "vin_axi", 0, JH7100_CLK_VIN_BUS),
- JH71X0_GATE(JH7100_CLK_VINNOC_AXI, "vinnoc_axi", 0, JH7100_CLK_VIN_BUS),
-- JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", 0, 4, JH7100_CLK_VOUT_ROOT),
-+ JH71X0_GDIV(JH7100_CLK_VOUT_SRC, "vout_src", CLK_IGNORE_UNUSED, 4, JH7100_CLK_VOUT_ROOT),
- JH71X0__DIV(JH7100_CLK_DISPBUS_SRC, "dispbus_src", 4, JH7100_CLK_VOUTBUS_ROOT),
- JH71X0__DIV(JH7100_CLK_DISP_BUS, "disp_bus", 4, JH7100_CLK_DISPBUS_SRC),
-- JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", 0, JH7100_CLK_DISP_BUS),
-- JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", 0, JH7100_CLK_DISP_BUS),
-+ JH71X0_GATE(JH7100_CLK_DISP_AXI, "disp_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DISP_BUS),
-+ JH71X0_GATE(JH7100_CLK_DISPNOC_AXI, "dispnoc_axi", CLK_IGNORE_UNUSED, JH7100_CLK_DISP_BUS),
- JH71X0_GATE(JH7100_CLK_SDIO0_AHB, "sdio0_ahb", 0, JH7100_CLK_AHB_BUS),
- JH71X0_GDIV(JH7100_CLK_SDIO0_CCLKINT, "sdio0_cclkint", 0, 24, JH7100_CLK_PERH0_SRC),
- JH71X0__INV(JH7100_CLK_SDIO0_CCLKINT_INV, "sdio0_cclkint_inv", JH7100_CLK_SDIO0_CCLKINT),
- JH71X0_GATE(JH7100_CLK_SDIO1_AHB, "sdio1_ahb", 0, JH7100_CLK_AHB_BUS),
- JH71X0_GDIV(JH7100_CLK_SDIO1_CCLKINT, "sdio1_cclkint", 0, 24, JH7100_CLK_PERH1_SRC),
- JH71X0__INV(JH7100_CLK_SDIO1_CCLKINT_INV, "sdio1_cclkint_inv", JH7100_CLK_SDIO1_CCLKINT),
-- JH71X0_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", 0, JH7100_CLK_AHB_BUS),
-+ JH71X0_GATE(JH7100_CLK_GMAC_AHB, "gmac_ahb", CLK_IGNORE_UNUSED, JH7100_CLK_AHB_BUS),
- JH71X0__DIV(JH7100_CLK_GMAC_ROOT_DIV, "gmac_root_div", 8, JH7100_CLK_GMACUSB_ROOT),
-- JH71X0_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", 0, 31, JH7100_CLK_GMAC_ROOT_DIV),
-- JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV),
-- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
-- JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
-+ JH71X0_GDIV(JH7100_CLK_GMAC_PTP_REF, "gmac_ptp_refclk", CLK_IGNORE_UNUSED, 31, JH7100_CLK_GMAC_ROOT_DIV),
-+ JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", CLK_IGNORE_UNUSED, 255, JH7100_CLK_GMAC_ROOT_DIV),
-+ JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", CLK_IGNORE_UNUSED, 8, JH7100_CLK_GMAC_RMII_REF),
-+ JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", CLK_IGNORE_UNUSED, 8, JH7100_CLK_GMAC_RMII_REF),
- JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 3,
- JH7100_CLK_GMAC_GTX,
- JH7100_CLK_GMAC_TX_INV,
-@@ -209,8 +210,8 @@ static const struct jh71x0_clk_data jh71
- JH7100_CLK_GMAC_GR_MII_RX,
- JH7100_CLK_GMAC_RMII_RX),
- JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE),
-- JH71X0_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", 0, JH7100_CLK_GMAC_RMII_REF),
-- JH71X0_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", 0, 127, JH7100_CLK_GMAC_ROOT_DIV),
-+ JH71X0_GATE(JH7100_CLK_GMAC_RMII, "gmac_rmii", CLK_IGNORE_UNUSED, JH7100_CLK_GMAC_RMII_REF),
-+ JH71X0_GDIV(JH7100_CLK_GMAC_TOPHYREF, "gmac_tophyref", CLK_IGNORE_UNUSED, 127, JH7100_CLK_GMAC_ROOT_DIV),
- JH71X0_GATE(JH7100_CLK_SPI2AHB_AHB, "spi2ahb_ahb", 0, JH7100_CLK_AHB_BUS),
- JH71X0_GDIV(JH7100_CLK_SPI2AHB_CORE, "spi2ahb_core", 0, 31, JH7100_CLK_PERH0_SRC),
- JH71X0_GATE(JH7100_CLK_EZMASTER_AHB, "ezmaster_ahb", 0, JH7100_CLK_AHB_BUS),
-@@ -223,7 +224,7 @@ static const struct jh71x0_clk_data jh71
- JH71X0_GATE(JH7100_CLK_AES, "aes_clk", 0, JH7100_CLK_SEC_AHB),
- JH71X0_GATE(JH7100_CLK_SHA, "sha_clk", 0, JH7100_CLK_SEC_AHB),
- JH71X0_GATE(JH7100_CLK_PKA, "pka_clk", 0, JH7100_CLK_SEC_AHB),
-- JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", 0, JH7100_CLK_APB1_BUS),
-+ JH71X0_GATE(JH7100_CLK_TRNG_APB, "trng_apb", CLK_IGNORE_UNUSED, JH7100_CLK_APB1_BUS),
- JH71X0_GATE(JH7100_CLK_OTP_APB, "otp_apb", 0, JH7100_CLK_APB1_BUS),
- JH71X0_GATE(JH7100_CLK_UART0_APB, "uart0_apb", 0, JH7100_CLK_APB1_BUS),
- JH71X0_GDIV(JH7100_CLK_UART0_CORE, "uart0_core", 0, 63, JH7100_CLK_PERH1_SRC),
+++ /dev/null
-From 980f1e9ef19d472e72c36e142db7fb4e224f0f3e Mon Sep 17 00:00:00 2001
-From: Matteo Croce <technoboy85@gmail.com>
-Date: Fri, 21 May 2021 03:26:38 +0200
-Subject: [PATCH 1009/1024] net: stmmac: use GFP_DMA32
-
-Signed-off-by: Matteo Croce <mcroce@microsoft.com>
----
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -1434,7 +1434,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;
-@@ -4687,7 +4687,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;
+++ /dev/null
-From 4989e7aa5ed5ef9bc2532b3a47ff381572f389b5 Mon Sep 17 00:00:00 2001
-From: Huan Feng <huan.feng@starfivetech.com>
-Date: Fri, 8 Jan 2021 03:35:42 +0800
-Subject: [PATCH 1010/1024] hwrng: Add StarFive JH7100 Random Number Generator
- driver
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- drivers/char/hw_random/Kconfig | 13 ++
- drivers/char/hw_random/Makefile | 1 +
- drivers/char/hw_random/starfive-vic-rng.c | 256 ++++++++++++++++++++++
- drivers/char/hw_random/starfive-vic-rng.h | 167 ++++++++++++++
- 4 files changed, 437 insertions(+)
- create mode 100644 drivers/char/hw_random/starfive-vic-rng.c
- create mode 100644 drivers/char/hw_random/starfive-vic-rng.h
-
---- a/drivers/char/hw_random/Kconfig
-+++ b/drivers/char/hw_random/Kconfig
-@@ -322,6 +322,19 @@ config HW_RANDOM_POWERNV
-
- If unsure, say Y.
-
-+config HW_RANDOM_STARFIVE_VIC
-+ tristate "Starfive VIC Random Number Generator support"
-+ depends on HW_RANDOM && (SOC_STARFIVE || COMPILE_TEST)
-+ default SOC_STARFIVE
-+ help
-+ This driver provides kernel-side support for the Random Number
-+ Generator hardware found on Starfive VIC SoC.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called starfive-vic-rng.
-+
-+ If unsure, say Y.
-+
- config HW_RANDOM_HISI
- tristate "Hisilicon Random Number Generator support"
- depends on ARCH_HISI || COMPILE_TEST
---- a/drivers/char/hw_random/Makefile
-+++ b/drivers/char/hw_random/Makefile
-@@ -28,6 +28,7 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon
- obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
- obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
- obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
-+obj-$(CONFIG_HW_RANDOM_STARFIVE_VIC) += starfive-vic-rng.o
- obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o
- obj-$(CONFIG_HW_RANDOM_HISTB) += histb-rng.o
- obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
---- /dev/null
-+++ b/drivers/char/hw_random/starfive-vic-rng.c
-@@ -0,0 +1,256 @@
-+/*
-+ ******************************************************************************
-+ * @file starfive-vic-rng.c
-+ * @author StarFive Technology
-+ * @version V1.0
-+ * @date 08/13/2020
-+ * @brief
-+ ******************************************************************************
-+ * @copy
-+ *
-+ * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
-+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
-+ * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
-+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
-+ * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
-+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
-+ *
-+ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
-+ */
-+#include <linux/err.h>
-+#include <linux/kernel.h>
-+#include <linux/hw_random.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/interrupt.h>
-+#include <linux/random.h>
-+
-+#include "starfive-vic-rng.h"
-+
-+#define to_vic_rng(p) container_of(p, struct vic_rng, rng)
-+
-+struct vic_rng {
-+ struct device *dev;
-+ void __iomem *base;
-+ struct hwrng rng;
-+};
-+
-+static inline void vic_wait_till_idle(struct vic_rng *hrng)
-+{
-+ while(readl(hrng->base + VIC_STAT) & VIC_STAT_BUSY)
-+ ;
-+}
-+
-+static inline void vic_rng_irq_mask_clear(struct vic_rng *hrng)
-+{
-+ // clear register: ISTAT
-+ u32 data = readl(hrng->base + VIC_ISTAT);
-+ writel(data, hrng->base + VIC_ISTAT);
-+ writel(0, hrng->base + VIC_ALARM);
-+}
-+
-+static int vic_trng_cmd(struct vic_rng *hrng, u32 cmd) {
-+ int res = 0;
-+ // wait till idle
-+ vic_wait_till_idle(hrng);
-+ switch (cmd) {
-+ case VIC_CTRL_CMD_NOP:
-+ case VIC_CTRL_CMD_GEN_NOISE:
-+ case VIC_CTRL_CMD_GEN_NONCE:
-+ case VIC_CTRL_CMD_CREATE_STATE:
-+ case VIC_CTRL_CMD_RENEW_STATE:
-+ case VIC_CTRL_CMD_REFRESH_ADDIN:
-+ case VIC_CTRL_CMD_GEN_RANDOM:
-+ case VIC_CTRL_CMD_ADVANCE_STATE:
-+ case VIC_CTRL_CMD_KAT:
-+ case VIC_CTRL_CMD_ZEROIZE:
-+ writel(cmd, hrng->base + VIC_CTRL);
-+ break;
-+ default:
-+ res = -1;
-+ break;
-+ }
-+
-+ return res;
-+}
-+
-+static int vic_rng_init(struct hwrng *rng)
-+{
-+ struct vic_rng *hrng = to_vic_rng(rng);
-+
-+ // wait till idle
-+
-+ // clear register: ISTAT
-+ vic_rng_irq_mask_clear(hrng);
-+
-+ // set mission mode
-+ writel(VIC_SMODE_SECURE_EN(1), hrng->base + VIC_SMODE);
-+
-+ vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE);
-+ vic_wait_till_idle(hrng);
-+
-+ // set interrupt
-+ writel(VIC_IE_ALL, hrng->base + VIC_IE);
-+
-+ // zeroize
-+ vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
-+
-+ vic_wait_till_idle(hrng);
-+
-+ return 0;
-+}
-+
-+static irqreturn_t vic_rng_irq(int irq, void *priv)
-+{
-+ u32 status, val;
-+ struct vic_rng *hrng = (struct vic_rng *)priv;
-+
-+ /*
-+ * clearing the interrupt will also clear the error register
-+ * read error and status before clearing
-+ */
-+ status = readl(hrng->base + VIC_ISTAT);
-+
-+ if (status & VIC_ISTAT_ALARMS) {
-+ writel(VIC_ISTAT_ALARMS, hrng->base + VIC_ISTAT);
-+ val = readl(hrng->base + VIC_ALARM);
-+ if (val & VIC_ALARM_ILLEGAL_CMD_SEQ) {
-+ writel(VIC_ALARM_ILLEGAL_CMD_SEQ, hrng->base + VIC_ALARM);
-+ //dev_info(hrng->dev, "ILLEGAL CMD SEQ: LAST_CMD=0x%x\r\n",
-+ //VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT)));
-+ } else {
-+ dev_info(hrng->dev, "Failed test: %x\r\n", val);
-+ }
-+ }
-+
-+ if (status & VIC_ISTAT_ZEROIZE) {
-+ writel(VIC_ISTAT_ZEROIZE, hrng->base + VIC_ISTAT);
-+ //dev_info(hrng->dev, "zeroized\r\n");
-+ }
-+
-+ if (status & VIC_ISTAT_KAT_COMPLETE) {
-+ writel(VIC_ISTAT_KAT_COMPLETE, hrng->base + VIC_ISTAT);
-+ //dev_info(hrng->dev, "kat_completed\r\n");
-+ }
-+
-+ if (status & VIC_ISTAT_NOISE_RDY) {
-+ writel(VIC_ISTAT_NOISE_RDY, hrng->base + VIC_ISTAT);
-+ //dev_info(hrng->dev, "noise_rdy\r\n");
-+ }
-+
-+ if (status & VIC_ISTAT_DONE) {
-+ writel(VIC_ISTAT_DONE, hrng->base + VIC_ISTAT);
-+ //dev_info(hrng->dev, "done\r\n");
-+ /*
-+ if (VIC_STAT_LAST_CMD(readl(hrng->base + VIC_STAT)) ==
-+ VIC_CTRL_CMD_GEN_RANDOM) {
-+ dev_info(hrng->dev, "Need Update Buffer\r\n");
-+ }
-+ */
-+ }
-+ vic_rng_irq_mask_clear(hrng);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void vic_rng_cleanup(struct hwrng *rng)
-+{
-+ struct vic_rng *hrng = to_vic_rng(rng);
-+
-+ writel(0, hrng->base + VIC_CTRL);
-+}
-+
-+static int vic_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
-+{
-+ struct vic_rng *hrng = to_vic_rng(rng);
-+
-+ vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
-+ vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_NOISE);
-+ vic_trng_cmd(hrng, VIC_CTRL_CMD_CREATE_STATE);
-+
-+ vic_wait_till_idle(hrng);
-+ max = min_t(size_t, max, (VIC_RAND_LEN * 4));
-+
-+ writel(0x0, hrng->base + VIC_MODE);
-+ vic_trng_cmd(hrng, VIC_CTRL_CMD_GEN_RANDOM);
-+
-+ vic_wait_till_idle(hrng);
-+ memcpy_fromio(buf, hrng->base + VIC_RAND0, max);
-+ vic_trng_cmd(hrng, VIC_CTRL_CMD_ZEROIZE);
-+
-+ vic_wait_till_idle(hrng);
-+ return max;
-+}
-+
-+static int vic_rng_probe(struct platform_device *pdev)
-+{
-+ int ret;
-+ int irq;
-+ struct vic_rng *rng;
-+ struct resource *res;
-+
-+ rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
-+ if (!rng){
-+ return -ENOMEM;
-+ }
-+
-+ platform_set_drvdata(pdev, rng);
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ rng->base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(rng->base)){
-+ return PTR_ERR(rng->base);
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq <= 0) {
-+ dev_err(&pdev->dev, "Couldn't get irq %d\n", irq);
-+ return irq;
-+ }
-+
-+ ret = devm_request_irq(&pdev->dev, irq, vic_rng_irq, 0, pdev->name,
-+ (void *)rng);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Can't get interrupt working.\n");
-+ return ret;
-+ }
-+
-+ rng->rng.name = pdev->name;
-+ rng->rng.init = vic_rng_init;
-+ rng->rng.cleanup = vic_rng_cleanup;
-+ rng->rng.read = vic_rng_read;
-+
-+ rng->dev = &pdev->dev;
-+
-+ ret = devm_hwrng_register(&pdev->dev, &rng->rng);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to register hwrng\n");
-+ return ret;
-+ }
-+
-+ dev_info(&pdev->dev, "Initialized\n");
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id vic_rng_dt_ids[] = {
-+ { .compatible = "starfive,vic-rng" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, vic_rng_dt_ids);
-+
-+static struct platform_driver vic_rng_driver = {
-+ .probe = vic_rng_probe,
-+ .driver = {
-+ .name = "vic-rng",
-+ .of_match_table = vic_rng_dt_ids,
-+ },
-+};
-+
-+module_platform_driver(vic_rng_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Huan Feng <huan.feng@starfivetech.com>");
-+MODULE_DESCRIPTION("Starfive VIC random number generator driver");
---- /dev/null
-+++ b/drivers/char/hw_random/starfive-vic-rng.h
-@@ -0,0 +1,167 @@
-+/*
-+ ******************************************************************************
-+ * @file starfive-vic-rng.h
-+ * @author StarFive Technology
-+ * @version V1.0
-+ * @date 08/13/2020
-+ * @brief
-+ ******************************************************************************
-+ * @copy
-+ *
-+ * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
-+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
-+ * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
-+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
-+ * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
-+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
-+ *
-+ * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd.
-+ */
-+
-+#define VIC_CTRL 0x00
-+#define VIC_MODE 0x04
-+#define VIC_SMODE 0x08
-+#define VIC_STAT 0x0C
-+#define VIC_IE 0x10
-+#define VIC_ISTAT 0x14
-+#define VIC_ALARM 0x18
-+#define VIC_BUILD_ID 0x1C
-+#define VIC_FEATURES 0x20
-+#define VIC_RAND0 0x24
-+#define VIC_NPA_DATA0 0x34
-+#define VIC_SEED0 0x74
-+#define VIC_IA_RDATA 0xA4
-+#define VIC_IA_WDATA 0xA8
-+#define VIC_IA_ADDR 0xAC
-+#define VIC_IA_CMD 0xB0
-+
-+/* CTRL */
-+#define VIC_CTRL_CMD_NOP 0
-+#define VIC_CTRL_CMD_GEN_NOISE 1
-+#define VIC_CTRL_CMD_GEN_NONCE 2
-+#define VIC_CTRL_CMD_CREATE_STATE 3
-+#define VIC_CTRL_CMD_RENEW_STATE 4
-+#define VIC_CTRL_CMD_REFRESH_ADDIN 5
-+#define VIC_CTRL_CMD_GEN_RANDOM 6
-+#define VIC_CTRL_CMD_ADVANCE_STATE 7
-+#define VIC_CTRL_CMD_KAT 8
-+#define VIC_CTRL_CMD_ZEROIZE 15
-+
-+/* MODE */
-+#define _VIC_MODE_ADDIN_PRESENT 4
-+#define _VIC_MODE_PRED_RESIST 3
-+#define _VIC_MODE_KAT_SEL 2
-+#define _VIC_MODE_KAT_VEC 1
-+#define _VIC_MODE_SEC_ALG 0
-+
-+#define VIC_MODE_ADDIN_PRESENT (1UL << _VIC_MODE_ADDIN_PRESENT)
-+#define VIC_MODE_PRED_RESIST (1UL << _VIC_MODE_PRED_RESIST)
-+#define VIC_MODE_KAT_SEL (1UL << _VIC_MODE_KAT_SEL)
-+#define VIC_MODE_KAT_VEC (1UL << _VIC_MODE_KAT_VEC)
-+#define VIC_MODE_SEC_ALG (1UL << _VIC_MODE_SEC_ALG)
-+
-+/* SMODE */
-+#define _VIC_SMODE_MAX_REJECTS 2
-+#define _VIC_SMODE_SECURE_EN 1
-+#define _VIC_SMODE_NONCE 0
-+
-+#define VIC_SMODE_MAX_REJECTS(x) ((x) << _VIC_SMODE_MAX_REJECTS)
-+#define VIC_SMODE_SECURE_EN(x) ((x) << _VIC_SMODE_SECURE_EN)
-+#define VIC_SMODE_NONCE (1UL << _VIC_SMODE_NONCE)
-+
-+/* STAT */
-+#define _VIC_STAT_BUSY 31
-+#define _VIC_STAT_DRBG_STATE 7
-+#define _VIC_STAT_SECURE 6
-+#define _VIC_STAT_NONCE_MODE 5
-+#define _VIC_STAT_SEC_ALG 4
-+#define _VIC_STAT_LAST_CMD 0
-+
-+#define VIC_STAT_BUSY (1UL << _VIC_STAT_BUSY)
-+#define VIC_STAT_DRBG_STATE (1UL << _VIC_STAT_DRBG_STATE)
-+#define VIC_STAT_SECURE (1UL << _VIC_STAT_SECURE)
-+#define VIC_STAT_NONCE_MODE (1UL << _VIC_STAT_NONCE_MODE)
-+#define VIC_STAT_SEC_ALG (1UL << _VIC_STAT_SEC_ALG)
-+#define VIC_STAT_LAST_CMD(x) (((x) >> _VIC_STAT_LAST_CMD) & 0xF)
-+
-+/* IE */
-+#define _VIC_IE_GLBL 31
-+#define _VIC_IE_DONE 4
-+#define _VIC_IE_ALARMS 3
-+#define _VIC_IE_NOISE_RDY 2
-+#define _VIC_IE_KAT_COMPLETE 1
-+#define _VIC_IE_ZEROIZE 0
-+
-+#define VIC_IE_GLBL (1UL << _VIC_IE_GLBL)
-+#define VIC_IE_DONE (1UL << _VIC_IE_DONE)
-+#define VIC_IE_ALARMS (1UL << _VIC_IE_ALARMS)
-+#define VIC_IE_NOISE_RDY (1UL << _VIC_IE_NOISE_RDY)
-+#define VIC_IE_KAT_COMPLETE (1UL << _VIC_IE_KAT_COMPLETE)
-+#define VIC_IE_ZEROIZE (1UL << _VIC_IE_ZEROIZE)
-+#define VIC_IE_ALL (VIC_IE_GLBL | VIC_IE_DONE | VIC_IE_ALARMS | \
-+ VIC_IE_NOISE_RDY | VIC_IE_KAT_COMPLETE | VIC_IE_ZEROIZE)
-+
-+/* ISTAT */
-+#define _VIC_ISTAT_DONE 4
-+#define _VIC_ISTAT_ALARMS 3
-+#define _VIC_ISTAT_NOISE_RDY 2
-+#define _VIC_ISTAT_KAT_COMPLETE 1
-+#define _VIC_ISTAT_ZEROIZE 0
-+
-+#define VIC_ISTAT_DONE (1UL << _VIC_ISTAT_DONE)
-+#define VIC_ISTAT_ALARMS (1UL << _VIC_ISTAT_ALARMS)
-+#define VIC_ISTAT_NOISE_RDY (1UL << _VIC_ISTAT_NOISE_RDY)
-+#define VIC_ISTAT_KAT_COMPLETE (1UL << _VIC_ISTAT_KAT_COMPLETE)
-+#define VIC_ISTAT_ZEROIZE (1UL << _VIC_ISTAT_ZEROIZE)
-+
-+/* ALARMS */
-+#define VIC_ALARM_ILLEGAL_CMD_SEQ (1UL << 4)
-+#define VIC_ALARM_FAILED_TEST_ID_OK 0
-+#define VIC_ALARM_FAILED_TEST_ID_KAT_STAT 1
-+#define VIC_ALARM_FAILED_TEST_ID_KAT 2
-+#define VIC_ALARM_FAILED_TEST_ID_MONOBIT 3
-+#define VIC_ALARM_FAILED_TEST_ID_RUN 4
-+#define VIC_ALARM_FAILED_TEST_ID_LONGRUN 5
-+#define VIC_ALARM_FAILED_TEST_ID_AUTOCORRELATION 6
-+#define VIC_ALARM_FAILED_TEST_ID_POKER 7
-+#define VIC_ALARM_FAILED_TEST_ID_REPETITION_COUNT 8
-+#define VIC_ALARM_FAILED_TEST_ID_ADAPATIVE_PROPORTION 9
-+
-+/* BUILD_ID */
-+#define VIC_BUILD_ID_STEPPING(x) (((x) >> 28) & 0xF)
-+#define VIC_BUILD_ID_EPN(x) ((x) & 0xFFFF)
-+
-+/* FEATURES */
-+#define VIC_FEATURES_AES_256(x) (((x) >> 9) & 1)
-+#define VIC_FEATURES_EXTRA_PS_PRESENT(x) (((x) >> 8) & 1)
-+#define VIC_FEATURES_DIAG_LEVEL_NS(x) (((x) >> 7) & 1)
-+#define VIC_FEATURES_DIAG_LEVEL_CLP800(x) (((x) >> 4) & 7)
-+#define VIC_FEATURES_DIAG_LEVEL_ST_HLT(x) (((x) >> 1) & 7)
-+#define VIC_FEATURES_SECURE_RST_STATE(x) ((x) & 1)
-+
-+/* IA_CMD */
-+#define VIC_IA_CMD_GO (1UL << 31)
-+#define VIC_IA_CMD_WR (1)
-+
-+#define _VIC_SMODE_MAX_REJECTS_MASK 255UL
-+#define _VIC_SMODE_SECURE_EN_MASK 1UL
-+#define _VIC_SMODE_NONCE_MASK 1UL
-+#define _VIC_MODE_SEC_ALG_MASK 1UL
-+#define _VIC_MODE_ADDIN_PRESENT_MASK 1UL
-+#define _VIC_MODE_PRED_RESIST_MASK 1UL
-+
-+#define VIC_SMODE_SET_MAX_REJECTS(y, x) (((y) & ~(_VIC_SMODE_MAX_REJECTS_MASK << _VIC_SMODE_MAX_REJECTS)) | ((x) << _VIC_SMODE_MAX_REJECTS))
-+#define VIC_SMODE_SET_SECURE_EN(y, x) (((y) & ~(_VIC_SMODE_SECURE_EN_MASK << _VIC_SMODE_SECURE_EN)) | ((x) << _VIC_SMODE_SECURE_EN))
-+#define VIC_SMODE_SET_NONCE(y, x) (((y) & ~(_VIC_SMODE_NONCE_MASK << _VIC_SMODE_NONCE)) | ((x) << _VIC_SMODE_NONCE))
-+#define VIC_SMODE_GET_MAX_REJECTS(x) (((x) >> _VIC_SMODE_MAX_REJECTS) & _VIC_SMODE_MAX_REJECTS_MASK)
-+#define VIC_SMODE_GET_SECURE_EN(x) (((x) >> _VIC_SMODE_SECURE_EN) & _VIC_SMODE_SECURE_EN_MASK)
-+#define VIC_SMODE_GET_NONCE(x) (((x) >> _VIC_SMODE_NONCE) & _VIC_SMODE_NONCE_MASK)
-+
-+#define VIC_MODE_SET_SEC_ALG(y, x) (((y) & ~(_VIC_MODE_SEC_ALG_MASK << _VIC_MODE_SEC_ALG)) | ((x) << _VIC_MODE_SEC_ALG))
-+#define VIC_MODE_SET_PRED_RESIST(y, x) (((y) & ~(_VIC_MODE_PRED_RESIST_MASK << _VIC_MODE_PRED_RESIST)) | ((x) << _VIC_MODE_PRED_RESIST))
-+#define VIC_MODE_SET_ADDIN_PRESENT(y, x) (((y) & ~(_VIC_MODE_ADDIN_PRESENT_MASK << _VIC_MODE_ADDIN_PRESENT)) | ((x) << _VIC_MODE_ADDIN_PRESENT))
-+#define VIC_MODE_GET_SEC_ALG(x) (((x) >> _VIC_MODE_SEC_ALG) & _VIC_MODE_SEC_ALG_MASK)
-+#define VIC_MODE_GET_PRED_RESIST(x) (((x) >> _VIC_MODE_PRED_RESIST) & _VIC_MODE_PRED_RESIST_MASK)
-+#define VIC_MODE_GET_ADDIN_PRESENT(x) (((x) >> _VIC_MODE_ADDIN_PRESENT) & _VIC_MODE_ADDIN_PRESENT_MASK)
-+
-+#define VIC_RAND_LEN 4
+++ /dev/null
-From 34fd7b7f92deef97f03c80d056e2f51bc08b7dc6 Mon Sep 17 00:00:00 2001
-From: Chenjieqin <Jessica.Chen@starfivetech.com>
-Date: Fri, 8 Jan 2021 03:56:54 +0800
-Subject: [PATCH 1011/1024] pwm: sifive-ptc: Add SiFive PWM PTC driver
-
-yiming.li: clear CNTR of PWM after setting period & duty_cycle
-Emil: cleanups, clock, reset and div_u64
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- drivers/pwm/Kconfig | 11 ++
- drivers/pwm/Makefile | 1 +
- drivers/pwm/pwm-sifive-ptc.c | 260 +++++++++++++++++++++++++++++++++++
- 3 files changed, 272 insertions(+)
- create mode 100644 drivers/pwm/pwm-sifive-ptc.c
-
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
-@@ -549,6 +549,17 @@ config PWM_SIFIVE
- To compile this driver as a module, choose M here: the module
- will be called pwm-sifive.
-
-+config PWM_SIFIVE_PTC
-+ tristate "SiFive PWM PTC support"
-+ depends on SOC_SIFIVE || SOC_STARFIVE || COMPILE_TEST
-+ depends on OF
-+ depends on COMMON_CLK
-+ help
-+ Generic PWM framework driver for SiFive SoCs.
-+
-+ To compile this driver as a module, choose M here: the module
-+ will be called pwm-sifive-ptc.
-+
- config PWM_SL28CPLD
- tristate "Kontron sl28cpld PWM support"
- depends on MFD_SL28CPLD || COMPILE_TEST
---- a/drivers/pwm/Makefile
-+++ b/drivers/pwm/Makefile
-@@ -50,6 +50,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockch
- obj-$(CONFIG_PWM_RZ_MTU3) += pwm-rz-mtu3.o
- obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
- obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
-+obj-$(CONFIG_PWM_SIFIVE_PTC) += pwm-sifive-ptc.o
- obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o
- obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
- obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o
---- /dev/null
-+++ b/drivers/pwm/pwm-sifive-ptc.c
-@@ -0,0 +1,260 @@
-+/*
-+ * Copyright (C) 2018 SiFive, Inc
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2, as published by
-+ * the Free Software Foundation.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/math64.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/pwm.h>
-+#include <linux/reset.h>
-+
-+#include <dt-bindings/pwm/pwm.h>
-+
-+/* max channel of pwm */
-+#define MAX_PWM 8
-+
-+/* PTC Register offsets */
-+#define REG_RPTC_CNTR 0x0
-+#define REG_RPTC_HRC 0x4
-+#define REG_RPTC_LRC 0x8
-+#define REG_RPTC_CTRL 0xC
-+
-+/* Bit for PWM clock */
-+#define BIT_PWM_CLOCK_EN 31
-+
-+/* Bit for clock gen soft reset */
-+#define BIT_CLK_GEN_SOFT_RESET 13
-+
-+#define NS_1 1000000000U
-+
-+/* Access PTC register (cntr hrc lrc and ctrl), need to replace PWM_BASE_ADDR */
-+#define REG_PTC_BASE_ADDR_SUB(base, N) \
-+ ((base) + (((N) > 3) ? (((N) - 4) * 0x10 + (1 << 15)) : ((N) * 0x10)))
-+#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N))
-+#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4)
-+#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8)
-+#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC)
-+
-+/* pwm ptc device */
-+struct sifive_pwm_ptc_device {
-+ struct pwm_chip chip;
-+ struct clk *clk;
-+ void __iomem *regs;
-+};
-+
-+static inline struct sifive_pwm_ptc_device *chip_to_sifive_ptc(struct pwm_chip *c)
-+{
-+ return container_of(c, struct sifive_pwm_ptc_device, chip);
-+}
-+
-+static int sifive_pwm_ptc_get_state(struct pwm_chip *chip, struct pwm_device *dev,
-+ struct pwm_state *state)
-+{
-+ struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip);
-+ u32 data_lrc;
-+ u32 data_hrc;
-+ u32 pwm_clk_ns = 0;
-+
-+ /* get lrc and hrc data from registe */
-+ data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm));
-+ data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm));
-+
-+ /* how many ns does apb clock elapse */
-+ pwm_clk_ns = NS_1 / clk_get_rate(pwm->clk);
-+
-+ /* pwm period(ns) */
-+ state->period = data_lrc * pwm_clk_ns;
-+
-+ /* duty cycle(ns) means high level eclapse ns if it is normal polarity */
-+ state->duty_cycle = data_hrc * pwm_clk_ns;
-+
-+ /* polarity, we don't use it now because it is not in dts */
-+ state->polarity = PWM_POLARITY_NORMAL;
-+
-+ /* enabled or not */
-+ state->enabled = 1;
-+
-+ dev_dbg(pwm->chip.dev, "%s: no:%d\n", __func__, dev->hwpwm);
-+ dev_dbg(pwm->chip.dev, "data_hrc:0x%x 0x%x\n", data_hrc, data_lrc);
-+ dev_dbg(pwm->chip.dev, "period:%llu\n", state->period);
-+ dev_dbg(pwm->chip.dev, "duty_cycle:%llu\n", state->duty_cycle);
-+ dev_dbg(pwm->chip.dev, "polarity:%d\n", state->polarity);
-+ dev_dbg(pwm->chip.dev, "enabled:%d\n", state->enabled);
-+
-+ return 0;
-+}
-+
-+static int sifive_pwm_ptc_apply(struct pwm_chip *chip, struct pwm_device *dev,
-+ const struct pwm_state *state)
-+{
-+ struct sifive_pwm_ptc_device *pwm = chip_to_sifive_ptc(chip);
-+ void __iomem *reg_addr;
-+ u32 pwm_clk_ns = 0;
-+ u32 data_hrc = 0;
-+ u32 data_lrc = 0;
-+ u32 period_data = 0;
-+ u32 duty_data = 0;
-+
-+ dev_dbg(pwm->chip.dev, "%s: no:%d\n", __func__, dev->hwpwm);
-+ dev_dbg(pwm->chip.dev, "period:%llu\n", state->period);
-+ dev_dbg(pwm->chip.dev, "duty_cycle:%llu\n", state->duty_cycle);
-+ dev_dbg(pwm->chip.dev, "polarity:%d\n", state->polarity);
-+ dev_dbg(pwm->chip.dev, "enabled:%d\n", state->enabled);
-+
-+ /* duty_cycle should be less or equal than period */
-+ if (state->duty_cycle > state->period)
-+ return -EINVAL;
-+
-+ /* calculate pwm real period (ns) */
-+ pwm_clk_ns = NS_1 / clk_get_rate(pwm->clk);
-+
-+ dev_dbg(pwm->chip.dev, "pwm_clk_ns:%u\n", pwm_clk_ns);
-+
-+ /* calculate period count */
-+ period_data = div_u64(state->period, pwm_clk_ns);
-+
-+ if (!state->enabled)
-+ /* if disabled, just set duty_data to 0, which means low level always */
-+ duty_data = 0;
-+ else
-+ /* calculate duty count */
-+ duty_data = div_u64(state->duty_cycle, pwm_clk_ns);
-+
-+ dev_dbg(pwm->chip.dev, "period_data:%u, duty_data:%u\n",
-+ period_data, duty_data);
-+
-+ if (state->polarity == PWM_POLARITY_NORMAL)
-+ /* calculate data_hrc */
-+ data_hrc = period_data - duty_data;
-+ else
-+ /* calculate data_hrc */
-+ data_hrc = duty_data;
-+
-+ data_lrc = period_data;
-+
-+ /* set hrc */
-+ reg_addr = REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm);
-+ dev_dbg(pwm->chip.dev, "%s: reg_addr:%p, data:%u\n",
-+ __func__, reg_addr, data_hrc);
-+
-+ iowrite32(data_hrc, reg_addr);
-+
-+ dev_dbg(pwm->chip.dev, "%s: hrc ok\n", __func__);
-+
-+ /* set lrc */
-+ reg_addr = REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm);
-+ dev_dbg(pwm->chip.dev, "%s: reg_addr:%p, data:%u\n",
-+ __func__, reg_addr, data_lrc);
-+
-+ iowrite32(data_lrc, reg_addr);
-+ dev_dbg(pwm->chip.dev, "%s: lrc ok\n", __func__);
-+
-+ /* Clear REG_RPTC_CNTR after setting period & duty_cycle */
-+ reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm);
-+ iowrite32(0, reg_addr);
-+ return 0;
-+}
-+
-+static const struct pwm_ops sifive_pwm_ptc_ops = {
-+ .get_state = sifive_pwm_ptc_get_state,
-+ .apply = sifive_pwm_ptc_apply,
-+ .owner = THIS_MODULE,
-+};
-+
-+static void sifive_pwm_ptc_disable_action(void *data)
-+{
-+ clk_disable_unprepare(data);
-+}
-+
-+static int sifive_pwm_ptc_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct device_node *node = pdev->dev.of_node;
-+ struct sifive_pwm_ptc_device *pwm;
-+ struct pwm_chip *chip;
-+ struct reset_control *rst;
-+ int ret;
-+
-+ pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
-+ if (!pwm)
-+ return -ENOMEM;
-+
-+ platform_set_drvdata(pdev, pwm);
-+
-+ chip = &pwm->chip;
-+ chip->dev = dev;
-+ chip->ops = &sifive_pwm_ptc_ops;
-+
-+ /* how many parameters can be transferred to ptc, need to fix */
-+ chip->of_pwm_n_cells = 3;
-+ chip->base = -1;
-+
-+ /* get pwm channels count, max value is 8 */
-+ ret = of_property_read_u32(node, "starfive,npwm", &chip->npwm);
-+ if (ret < 0 || chip->npwm > MAX_PWM)
-+ chip->npwm = MAX_PWM;
-+
-+ dev_dbg(dev, "%s: npwm:0x%x\n", __func__, chip->npwm);
-+
-+ /* get IO base address */
-+ pwm->regs = devm_platform_ioremap_resource(pdev, 0);
-+ if (IS_ERR(pwm->regs))
-+ return dev_err_probe(dev, PTR_ERR(pwm->regs),
-+ "Unable to map IO resources\n");
-+
-+ pwm->clk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(pwm->clk))
-+ return dev_err_probe(dev, PTR_ERR(pwm->clk),
-+ "Unable to get controller clock\n");
-+
-+ ret = clk_prepare_enable(pwm->clk);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Unable to enable clock\n");
-+
-+ ret = devm_add_action_or_reset(dev, sifive_pwm_ptc_disable_action, pwm->clk);
-+ if (ret)
-+ return ret;
-+
-+ rst = devm_reset_control_get_exclusive(dev, NULL);
-+ if (IS_ERR(rst))
-+ return dev_err_probe(dev, PTR_ERR(rst), "Unable to get reset\n");
-+
-+ ret = reset_control_deassert(rst);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Unable to deassert reset\n");
-+
-+ /*
-+ * after pwmchip_add it will show up as /sys/class/pwm/pwmchip0,
-+ * 0 is chip->base, pwm0 can be seen after running echo 0 > export
-+ */
-+ ret = devm_pwmchip_add(dev, chip);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "cannot register PTC: %d\n", ret);
-+
-+ dev_dbg(dev, "SiFive PWM PTC chip registered %d PWMs\n", chip->npwm);
-+ return 0;
-+}
-+
-+static const struct of_device_id sifive_pwm_ptc_of_match[] = {
-+ { .compatible = "starfive,pwm0" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, sifive_pwm_ptc_of_match);
-+
-+static struct platform_driver sifive_pwm_ptc_driver = {
-+ .probe = sifive_pwm_ptc_probe,
-+ .driver = {
-+ .name = "pwm-sifive-ptc",
-+ .of_match_table = sifive_pwm_ptc_of_match,
-+ },
-+};
-+module_platform_driver(sifive_pwm_ptc_driver);
-+
-+MODULE_DESCRIPTION("SiFive PWM PTC driver");
-+MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 4f3335c302b7f944b61f564095505b3c7a1b62ee Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Sat, 20 Nov 2021 19:29:25 +0100
-Subject: [PATCH 1012/1024] dt-bindings: reset: Add StarFive JH7100 audio reset
- definitions
-
-Add all resets for the StarFive JH7100 audio reset controller.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- .../dt-bindings/reset/starfive-jh7100-audio.h | 31 +++++++++++++++++++
- 1 file changed, 31 insertions(+)
- create mode 100644 include/dt-bindings/reset/starfive-jh7100-audio.h
-
---- /dev/null
-+++ b/include/dt-bindings/reset/starfive-jh7100-audio.h
-@@ -0,0 +1,31 @@
-+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
-+/*
-+ * Copyright (C) 2021 Emil Renner Berthing
-+ */
-+
-+#ifndef __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__
-+#define __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__
-+
-+#define JH7100_AUDRSTN_APB_BUS 0
-+#define JH7100_AUDRSTN_I2SADC_APB 1
-+#define JH7100_AUDRSTN_I2SADC_SRST 2
-+#define JH7100_AUDRSTN_PDM_APB 3
-+#define JH7100_AUDRSTN_I2SVAD_APB 4
-+#define JH7100_AUDRSTN_I2SVAD_SRST 5
-+#define JH7100_AUDRSTN_SPDIF_APB 6
-+#define JH7100_AUDRSTN_PWMDAC_APB 7
-+#define JH7100_AUDRSTN_I2SDAC_APB 8
-+#define JH7100_AUDRSTN_I2SDAC_SRST 9
-+#define JH7100_AUDRSTN_I2S1_APB 10
-+#define JH7100_AUDRSTN_I2S1_SRST 11
-+#define JH7100_AUDRSTN_I2SDAC16K_APB 12
-+#define JH7100_AUDRSTN_I2SDAC16K_SRST 13
-+#define JH7100_AUDRSTN_DMA1P_AHB 14
-+#define JH7100_AUDRSTN_USB_APB 15
-+#define JH7100_AUDRST_USB_AXI 16
-+#define JH7100_AUDRST_USB_PWRUP_RST_N 17
-+#define JH7100_AUDRST_USB_PONRST 18
-+
-+#define JH7100_AUDRSTN_END 19
-+
-+#endif /* __DT_BINDINGS_RESET_STARFIVE_JH7100_AUDIO_H__ */
+++ /dev/null
-From 1e428568e486b40f78febddf2958ba27289bd49f Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Tue, 7 Dec 2021 21:48:51 +0100
-Subject: [PATCH 1013/1024] dt-bindings: reset: Add starfive,jh7100-audrst
- bindings
-
-Add bindings for the audio reset controller on the StarFive JH7100
-RISC-V SoC.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- .../reset/starfive,jh7100-audrst.yaml | 38 +++++++++++++++++++
- 1 file changed, 38 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/reset/starfive,jh7100-audrst.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/reset/starfive,jh7100-audrst.yaml
-@@ -0,0 +1,38 @@
-+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/reset/starfive,jh7100-audrst.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: StarFive JH7100 SoC Audio Reset Controller Device Tree Bindings
-+
-+maintainers:
-+ - Emil Renner Berthing <kernel@esmil.dk>
-+
-+properties:
-+ compatible:
-+ enum:
-+ - starfive,jh7100-audrst
-+
-+ reg:
-+ maxItems: 1
-+
-+ "#reset-cells":
-+ const: 1
-+
-+required:
-+ - compatible
-+ - reg
-+ - "#reset-cells"
-+
-+additionalProperties: false
-+
-+examples:
-+ - |
-+ reset-controller@10490000 {
-+ compatible = "starfive,jh7100-audrst";
-+ reg = <0x10490000 0x10000>;
-+ #reset-cells = <1>;
-+ };
-+
-+...
+++ /dev/null
-From 91559ced47de9e6fb1e6dd65a5544fcc86dea806 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Sat, 20 Nov 2021 19:30:49 +0100
-Subject: [PATCH 1014/1024] reset: starfive: Add JH7100 audio reset driver
-
-The audio resets are almost identical to the system resets, there are
-just fewer of them. So factor out and export a generic probe function,
-so most of the reset controller implementation can be shared.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- MAINTAINERS | 2 +-
- drivers/reset/starfive/Kconfig | 7 ++
- drivers/reset/starfive/Makefile | 2 +
- .../starfive/reset-starfive-jh7100-audio.c | 66 +++++++++++++++++++
- .../reset/starfive/reset-starfive-jh7100.h | 16 +++++
- 5 files changed, 92 insertions(+), 1 deletion(-)
- create mode 100644 drivers/reset/starfive/reset-starfive-jh7100-audio.c
- create mode 100644 drivers/reset/starfive/reset-starfive-jh7100.h
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -20556,7 +20556,7 @@ STARFIVE JH71X0 RESET CONTROLLER DRIVERS
- M: Emil Renner Berthing <kernel@esmil.dk>
- M: Hal Feng <hal.feng@starfivetech.com>
- S: Maintained
--F: Documentation/devicetree/bindings/reset/starfive,jh7100-reset.yaml
-+F: Documentation/devicetree/bindings/reset/starfive,jh7100-*.yaml
- F: drivers/reset/starfive/reset-starfive-jh71*
- F: include/dt-bindings/reset/starfive?jh71*.h
-
---- a/drivers/reset/starfive/Kconfig
-+++ b/drivers/reset/starfive/Kconfig
-@@ -11,6 +11,13 @@ config RESET_STARFIVE_JH7100
- help
- This enables the reset controller driver for the StarFive JH7100 SoC.
-
-+config RESET_STARFIVE_JH7100_AUDIO
-+ tristate "StarFive JH7100 Audio Reset Driver"
-+ depends on RESET_STARFIVE_JH7100
-+ default m if SOC_STARFIVE
-+ help
-+ This enables the audio reset driver for the StarFive JH7100 SoC.
-+
- config RESET_STARFIVE_JH7110
- bool "StarFive JH7110 Reset Driver"
- depends on CLK_STARFIVE_JH7110_SYS
---- a/drivers/reset/starfive/Makefile
-+++ b/drivers/reset/starfive/Makefile
-@@ -2,4 +2,6 @@
- obj-$(CONFIG_RESET_STARFIVE_JH71X0) += reset-starfive-jh71x0.o
-
- obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o
-+obj-$(CONFIG_RESET_STARFIVE_JH7100_AUDIO) += reset-starfive-jh7100-audio.o
-+
- obj-$(CONFIG_RESET_STARFIVE_JH7110) += reset-starfive-jh7110.o
---- /dev/null
-+++ b/drivers/reset/starfive/reset-starfive-jh7100-audio.c
-@@ -0,0 +1,66 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Audio reset driver for the StarFive JH7100 SoC
-+ *
-+ * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
-+ */
-+
-+#include <linux/mod_devicetable.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+
-+#include "reset-starfive-jh71x0.h"
-+
-+#include <dt-bindings/reset/starfive-jh7100-audio.h>
-+
-+/* register offsets */
-+#define JH7100_AUDRST_ASSERT0 0x00
-+#define JH7100_AUDRST_STATUS0 0x04
-+
-+/*
-+ * Writing a 1 to the n'th bit of the ASSERT register asserts
-+ * line n, and writing a 0 deasserts the same line.
-+ * Most reset lines have their status inverted so a 0 bit in the STATUS
-+ * register means the line is asserted and a 1 means it's deasserted. A few
-+ * lines don't though, so store the expected value of the status registers when
-+ * all lines are asserted.
-+ */
-+static const u32 jh7100_audrst_asserted[1] = {
-+ BIT(JH7100_AUDRST_USB_AXI) |
-+ BIT(JH7100_AUDRST_USB_PWRUP_RST_N) |
-+ BIT(JH7100_AUDRST_USB_PONRST)
-+};
-+
-+static int jh7100_audrst_probe(struct platform_device *pdev)
-+{
-+ void __iomem *base = devm_platform_ioremap_resource(pdev, 0);
-+
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ return reset_starfive_jh71x0_register(&pdev->dev, pdev->dev.of_node,
-+ base + JH7100_AUDRST_ASSERT0,
-+ base + JH7100_AUDRST_STATUS0,
-+ jh7100_audrst_asserted,
-+ JH7100_AUDRSTN_END,
-+ THIS_MODULE);
-+}
-+
-+static const struct of_device_id jh7100_audrst_dt_ids[] = {
-+ { .compatible = "starfive,jh7100-audrst" },
-+ { /* sentinel */ }
-+};
-+MODULE_DEVICE_TABLE(of, jh7100_audrst_dt_ids);
-+
-+static struct platform_driver jh7100_audrst_driver = {
-+ .probe = jh7100_audrst_probe,
-+ .driver = {
-+ .name = "jh7100-reset-audio",
-+ .of_match_table = jh7100_audrst_dt_ids,
-+ },
-+};
-+module_platform_driver(jh7100_audrst_driver);
-+
-+MODULE_AUTHOR("Emil Renner Berthing");
-+MODULE_DESCRIPTION("StarFive JH7100 audio reset driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/reset/starfive/reset-starfive-jh7100.h
-@@ -0,0 +1,16 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
-+ */
-+
-+#ifndef _RESET_STARFIVE_JH7100_H_
-+#define _RESET_STARFIVE_JH7100_H_
-+
-+#include <linux/platform_device.h>
-+
-+int reset_starfive_jh7100_generic_probe(struct platform_device *pdev,
-+ const u32 *asserted,
-+ unsigned int status_offset,
-+ unsigned int nr_resets);
-+
-+#endif
+++ /dev/null
-From 418603fdce51212d4547aacfe2b4801fc5e61978 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Sat, 20 Nov 2021 21:33:08 +0100
-Subject: [PATCH 1015/1024] RISC-V: Add StarFive JH7100 audio reset node
-
-Add device tree node for the audio resets on the StarFive JH7100 RISC-V
-SoC.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
----
- arch/riscv/boot/dts/starfive/jh7100.dtsi | 6 ++++++
- 1 file changed, 6 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
-@@ -168,6 +168,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>;
+++ /dev/null
-From 8e090d271683d5869cdab0729f54a8af8c79c476 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Tue, 31 Oct 2023 15:14:44 +0100
-Subject: [PATCH 1016/1024] soc: sifive: ccache: Add StarFive JH7100 support
-
-This adds support for the StarFive JH7100 SoC which also features this
-SiFive cache controller.
-
-The JH7100 has non-coherent DMAs but predate the standard RISC-V Zicbom
-exension, so instead we need to use this cache controller for
-non-standard cache management operations.
-
-Unfortunately the interrupt for uncorrected data is broken on the JH7100
-and fires continuously, so add a quirk to not register a handler for it.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- drivers/soc/sifive/sifive_ccache.c | 62 +++++++++++++++++++++++++++++-
- 1 file changed, 60 insertions(+), 2 deletions(-)
-
---- a/drivers/soc/sifive/sifive_ccache.c
-+++ b/drivers/soc/sifive/sifive_ccache.c
-@@ -8,13 +8,16 @@
-
- #define pr_fmt(fmt) "CCACHE: " fmt
-
-+#include <linux/align.h>
- #include <linux/debugfs.h>
- #include <linux/interrupt.h>
- #include <linux/of_irq.h>
- #include <linux/of_address.h>
- #include <linux/device.h>
- #include <linux/bitfield.h>
-+#include <asm/cacheflush.h>
- #include <asm/cacheinfo.h>
-+#include <asm/dma-noncoherent.h>
- #include <soc/sifive/sifive_ccache.h>
-
- #define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100
-@@ -39,10 +42,14 @@
- #define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16)
- #define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24)
-
-+#define SIFIVE_CCACHE_FLUSH64 0x200
-+#define SIFIVE_CCACHE_FLUSH32 0x240
-+
- #define SIFIVE_CCACHE_WAYENABLE 0x08
- #define SIFIVE_CCACHE_ECCINJECTERR 0x40
-
- #define SIFIVE_CCACHE_MAX_ECCINTR 4
-+#define SIFIVE_CCACHE_LINE_SIZE 64
-
- static void __iomem *ccache_base;
- static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR];
-@@ -56,6 +63,11 @@ enum {
- DIR_UNCORR,
- };
-
-+enum {
-+ QUIRK_NONSTANDARD_CACHE_OPS = BIT(0),
-+ QUIRK_BROKEN_DATA_UNCORR = BIT(1),
-+};
-+
- #ifdef CONFIG_DEBUG_FS
- static struct dentry *sifive_test;
-
-@@ -106,6 +118,8 @@ static void ccache_config_read(void)
- static const struct of_device_id sifive_ccache_ids[] = {
- { .compatible = "sifive,fu540-c000-ccache" },
- { .compatible = "sifive,fu740-c000-ccache" },
-+ { .compatible = "starfive,jh7100-ccache",
-+ .data = (void *)(QUIRK_NONSTANDARD_CACHE_OPS | QUIRK_BROKEN_DATA_UNCORR) },
- { .compatible = "sifive,ccache0" },
- { /* end of table */ }
- };
-@@ -124,6 +138,34 @@ int unregister_sifive_ccache_error_notif
- }
- EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier);
-
-+#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
-+static void ccache_flush_range(phys_addr_t start, size_t len)
-+{
-+ phys_addr_t end = start + len;
-+ phys_addr_t line;
-+
-+ if (!len)
-+ return;
-+
-+ mb();
-+ for (line = ALIGN_DOWN(start, SIFIVE_CCACHE_LINE_SIZE); line < end;
-+ line += SIFIVE_CCACHE_LINE_SIZE) {
-+#ifdef CONFIG_32BIT
-+ writel(line >> 4, ccache_base + SIFIVE_CCACHE_FLUSH32);
-+#else
-+ writeq(line, ccache_base + SIFIVE_CCACHE_FLUSH64);
-+#endif
-+ mb();
-+ }
-+}
-+
-+static const struct riscv_nonstd_cache_ops ccache_mgmt_ops __initconst = {
-+ .wback = &ccache_flush_range,
-+ .inv = &ccache_flush_range,
-+ .wback_inv = &ccache_flush_range,
-+};
-+#endif /* CONFIG_RISCV_NONSTANDARD_CACHE_OPS */
-+
- static int ccache_largest_wayenabled(void)
- {
- return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF;
-@@ -210,11 +252,15 @@ static int __init sifive_ccache_init(voi
- struct device_node *np;
- struct resource res;
- int i, rc, intr_num;
-+ const struct of_device_id *match;
-+ unsigned long quirks;
-
-- np = of_find_matching_node(NULL, sifive_ccache_ids);
-+ np = of_find_matching_node_and_match(NULL, sifive_ccache_ids, &match);
- if (!np)
- return -ENODEV;
-
-+ quirks = (uintptr_t)match->data;
-+
- if (of_address_to_resource(np, 0, &res)) {
- rc = -ENODEV;
- goto err_node_put;
-@@ -240,6 +286,10 @@ static int __init sifive_ccache_init(voi
-
- for (i = 0; i < intr_num; i++) {
- g_irq[i] = irq_of_parse_and_map(np, i);
-+
-+ if (i == DATA_UNCORR && (quirks & QUIRK_BROKEN_DATA_UNCORR))
-+ continue;
-+
- rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc",
- NULL);
- if (rc) {
-@@ -249,6 +299,14 @@ static int __init sifive_ccache_init(voi
- }
- of_node_put(np);
-
-+#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
-+ if (quirks & QUIRK_NONSTANDARD_CACHE_OPS) {
-+ riscv_cbom_block_size = SIFIVE_CCACHE_LINE_SIZE;
-+ riscv_noncoherent_supported();
-+ riscv_noncoherent_register_cache_ops(&ccache_mgmt_ops);
-+ }
-+#endif
-+
- ccache_config_read();
-
- ccache_cache_ops.get_priv_group = ccache_get_priv_group;
-@@ -269,4 +327,4 @@ err_node_put:
- return rc;
- }
-
--device_initcall(sifive_ccache_init);
-+arch_initcall(sifive_ccache_init);
+++ /dev/null
-From 30fb5963f4cf3b7d114a8212358147615480685c Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Thu, 30 Nov 2023 16:19:25 +0100
-Subject: [PATCH 1017/1024] riscv: errata: Add StarFive JH7100 errata
-
-This not really an errata, but since the JH7100 was made before
-the standard Zicbom extension it needs the DMA_GLOBAL_POOL and
-RISCV_NONSTANDARD_CACHE_OPS enabled to work correctly.
-
-Acked-by: Conor Dooley <conor.dooley@microchip.com>
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com>
-Acked-by: Palmer Dabbelt <palmer@rivosinc.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- arch/riscv/Kconfig.errata | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
---- a/arch/riscv/Kconfig.errata
-+++ b/arch/riscv/Kconfig.errata
-@@ -53,6 +53,23 @@ config ERRATA_SIFIVE_CIP_1200
-
- If you don't know what to do here, say "Y".
-
-+config ERRATA_STARFIVE_JH7100
-+ bool "StarFive JH7100 support"
-+ depends on ARCH_STARFIVE && NONPORTABLE
-+ select DMA_GLOBAL_POOL
-+ select RISCV_DMA_NONCOHERENT
-+ select RISCV_NONSTANDARD_CACHE_OPS
-+ select SIFIVE_CCACHE
-+ default n
-+ help
-+ The StarFive JH7100 was a test chip for the JH7110 and has
-+ caches that are non-coherent with respect to peripheral DMAs.
-+ It was designed before the Zicbom extension so needs non-standard
-+ cache operations through the SiFive cache controller.
-+
-+ Say "Y" if you want to support the BeagleV Starlight and/or
-+ StarFive VisionFive V1 boards.
-+
- config ERRATA_THEAD
- bool "T-HEAD errata"
- depends on RISCV_ALTERNATIVE
+++ /dev/null
-From 29e4bc0fafd9add93acc967f3992948b3afe7176 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Thu, 30 Nov 2023 16:19:27 +0100
-Subject: [PATCH 1018/1024] riscv: dts: starfive: Mark the JH7100 as having
- non-coherent DMAs
-
-The StarFive JH7100 SoC has non-coherent device DMAs, so mark the
-soc bus as such.
-
-Link: https://github.com/starfive-tech/JH7100_Docs/blob/main/JH7100%20Cache%20Coherence%20V1.0.pdf
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- arch/riscv/boot/dts/starfive/jh7100.dtsi | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
-@@ -138,6 +138,7 @@
- interrupt-parent = <&plic>;
- #address-cells = <2>;
- #size-cells = <2>;
-+ dma-noncoherent;
- ranges;
-
- clint: clint@2000000 {
+++ /dev/null
-From e1918356dcc285eb7c50f271795e6fcc18d6c092 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Thu, 30 Nov 2023 16:19:28 +0100
-Subject: [PATCH 1019/1024] riscv: dts: starfive: Add JH7100 cache controller
-
-The StarFive JH7100 SoC also features the SiFive L2 cache controller,
-so add the device tree nodes for it.
-
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- arch/riscv/boot/dts/starfive/jh7100.dtsi | 13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
-@@ -32,6 +32,7 @@
- i-tlb-sets = <1>;
- i-tlb-size = <32>;
- mmu-type = "riscv,sv39";
-+ next-level-cache = <&ccache>;
- riscv,isa = "rv64imafdc";
- tlb-split;
-
-@@ -57,6 +58,7 @@
- i-tlb-sets = <1>;
- i-tlb-size = <32>;
- mmu-type = "riscv,sv39";
-+ next-level-cache = <&ccache>;
- riscv,isa = "rv64imafdc";
- tlb-split;
-
-@@ -148,6 +150,17 @@
- &cpu1_intc 3 &cpu1_intc 7>;
- };
-
-+ ccache: cache-controller@2010000 {
-+ compatible = "starfive,jh7100-ccache", "sifive,ccache0", "cache";
-+ reg = <0x0 0x2010000 0x0 0x1000>;
-+ interrupts = <128>, <130>, <131>, <129>;
-+ cache-block-size = <64>;
-+ cache-level = <2>;
-+ cache-sets = <2048>;
-+ cache-size = <2097152>;
-+ cache-unified;
-+ };
-+
- plic: interrupt-controller@c000000 {
- compatible = "starfive,jh7100-plic", "sifive,plic-1.0.0";
- reg = <0x0 0xc000000 0x0 0x4000000>;
+++ /dev/null
-From 3cbd661b811bda9a33253f65b5cf0c25b8c5447f Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Thu, 30 Nov 2023 16:19:29 +0100
-Subject: [PATCH 1020/1024] riscv: dts: starfive: Add pool for coherent DMA
- memory on JH7100 boards
-
-The StarFive JH7100 SoC has non-coherent device DMAs, but most drivers
-expect to be able to allocate coherent memory for DMA descriptors and
-such. However on the JH7100 DDR memory appears twice in the physical
-memory map, once cached and once uncached:
-
- 0x00_8000_0000 - 0x08_7fff_ffff : Off chip DDR memory, cached
- 0x10_0000_0000 - 0x17_ffff_ffff : Off chip DDR memory, uncached
-
-To use this uncached region we create a global DMA memory pool there and
-reserve the corresponding area in the cached region.
-
-However the uncached region is fully above the 32bit address limit, so add
-a dma-ranges map so the DMA address used for peripherals is still in the
-regular cached region below the limit.
-
-Link: https://github.com/starfive-tech/JH7100_Docs/blob/main/JH7100%20Data%20Sheet%20V01.01.04-EN%20(4-21-2021).pdf
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../boot/dts/starfive/jh7100-common.dtsi | 24 +++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
-@@ -39,6 +39,30 @@
- label = "ack";
- };
- };
-+
-+ reserved-memory {
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+ ranges;
-+
-+ dma-reserved@fa000000 {
-+ reg = <0x0 0xfa000000 0x0 0x1000000>;
-+ no-map;
-+ };
-+
-+ linux,dma@107a000000 {
-+ compatible = "shared-dma-pool";
-+ reg = <0x10 0x7a000000 0x0 0x1000000>;
-+ no-map;
-+ linux,dma-default;
-+ };
-+ };
-+
-+ soc {
-+ dma-ranges = <0x00 0x80000000 0x00 0x80000000 0x00 0x7a000000>,
-+ <0x00 0xfa000000 0x10 0x7a000000 0x00 0x01000000>,
-+ <0x00 0xfb000000 0x00 0xfb000000 0x07 0x85000000>;
-+ };
- };
-
- &gpio {
+++ /dev/null
-From 7be159c760aa8a1ece1354892af215b2f8c21152 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Thu, 30 Nov 2023 16:19:30 +0100
-Subject: [PATCH 1021/1024] riscv: dts: starfive: Add JH7100 MMC nodes
-
-Add device tree nodes for the Synopsis MMC controllers on the
-StarFive JH7100 SoC.
-
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- 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
-@@ -188,6 +188,32 @@
- #reset-cells = <1>;
- };
-
-+ sdio0: mmc@10000000 {
-+ compatible = "snps,dw-mshc";
-+ reg = <0x0 0x10000000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SDIO0_AHB>,
-+ <&clkgen JH7100_CLK_SDIO0_CCLKINT_INV>;
-+ clock-names = "biu", "ciu";
-+ interrupts = <4>;
-+ data-addr = <0>;
-+ fifo-depth = <32>;
-+ fifo-watermark-aligned;
-+ status = "disabled";
-+ };
-+
-+ sdio1: mmc@10010000 {
-+ compatible = "snps,dw-mshc";
-+ reg = <0x0 0x10010000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SDIO1_AHB>,
-+ <&clkgen JH7100_CLK_SDIO1_CCLKINT_INV>;
-+ clock-names = "biu", "ciu";
-+ interrupts = <5>;
-+ data-addr = <0>;
-+ fifo-depth = <32>;
-+ fifo-watermark-aligned;
-+ status = "disabled";
-+ };
-+
- clkgen: clock-controller@11800000 {
- compatible = "starfive,jh7100-clkgen";
- reg = <0x0 0x11800000 0x0 0x10000>;
+++ /dev/null
-From 015edaccef82200d913d5f1e99fd95641f526bc6 Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Thu, 30 Nov 2023 16:19:31 +0100
-Subject: [PATCH 1022/1024] riscv: dts: starfive: Enable SD-card on JH7100
- boards
-
-Add pinctrl and MMC device tree nodes for the SD-card on the
-BeagleV Starlight and StarFive VisionFive V1 boards.
-
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- .../boot/dts/starfive/jh7100-common.dtsi | 47 +++++++++++++++++++
- 1 file changed, 47 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
-@@ -12,6 +12,7 @@
-
- / {
- aliases {
-+ mmc0 = &sdio0;
- serial0 = &uart3;
- };
-
-@@ -108,6 +109,43 @@
- };
- };
-
-+ sdio0_pins: sdio0-0 {
-+ clk-pins {
-+ pinmux = <GPIOMUX(54, GPO_SDIO0_PAD_CCLK_OUT,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ sdio-pins {
-+ pinmux = <GPIOMUX(55, GPO_LOW, GPO_DISABLE,
-+ GPI_SDIO0_PAD_CARD_DETECT_N)>,
-+ <GPIOMUX(53,
-+ GPO_SDIO0_PAD_CCMD_OUT,
-+ GPO_SDIO0_PAD_CCMD_OEN,
-+ GPI_SDIO0_PAD_CCMD_IN)>,
-+ <GPIOMUX(49,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT0,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT0,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT0)>,
-+ <GPIOMUX(50,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT1,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT1,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT1)>,
-+ <GPIOMUX(51,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT2,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT2,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT2)>,
-+ <GPIOMUX(52,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT3,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT3,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT3)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
- uart3_pins: uart3-0 {
- rx-pins {
- pinmux = <GPIOMUX(13, GPO_LOW, GPO_DISABLE,
-@@ -178,6 +216,15 @@
- clock-frequency = <27000000>;
- };
-
-+&sdio0 {
-+ broken-cd;
-+ bus-width = <4>;
-+ cap-sd-highspeed;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdio0_pins>;
-+ status = "okay";
-+};
-+
- &uart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins>;
+++ /dev/null
-From 1e70a0772165dd552f82434c9072dabfaaaf4c2a Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Date: Fri, 15 Dec 2023 20:09:09 +0100
-Subject: [PATCH 1023/1024] riscv: errata: Make ERRATA_STARFIVE_JH7100 depend
- on !DMA_DIRECT_REMAP
-
-Similar to the Renesas RZ/Five[1] the JH7100 SoC needs the non-portable
-CONFIG_DMA_GLOBAL_POOL enabled which is incompatible with DMA_DIRECT_REMAP
-selected by RISCV_ISA_ZICBOM.
-
-[1]: commit 31b2daea0764 ("soc: renesas: Make RZ/Five depend on !DMA_DIRECT_REMAP")
-
-Link: https://lore.kernel.org/all/24942b4d-d16a-463f-b39a-f9dfcb89d742@infradead.org/
-Fixes: 64fc984a8a54 ("riscv: errata: Add StarFive JH7100 errata")
-Signed-off-by: Emil Renner Berthing <emil.renner.berthing@canonical.com>
-Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
----
- arch/riscv/Kconfig.errata | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
---- a/arch/riscv/Kconfig.errata
-+++ b/arch/riscv/Kconfig.errata
-@@ -55,7 +55,9 @@ config ERRATA_SIFIVE_CIP_1200
-
- config ERRATA_STARFIVE_JH7100
- bool "StarFive JH7100 support"
-- depends on ARCH_STARFIVE && NONPORTABLE
-+ depends on ARCH_STARFIVE
-+ depends on !DMA_DIRECT_REMAP
-+ depends on NONPORTABLE
- select DMA_GLOBAL_POOL
- select RISCV_DMA_NONCOHERENT
- select RISCV_NONSTANDARD_CACHE_OPS
+++ /dev/null
-From 782f99cc437d975c9ef5a1f351bb8fb83d50039b Mon Sep 17 00:00:00 2001
-From: Emil Renner Berthing <kernel@esmil.dk>
-Date: Sun, 1 Sep 2024 12:43:01 +0000
-Subject: [PATCH 1024/1024] riscv: dts: Add full JH7100, Starlight and
- VisionFive support
-
-Based on the device tree in https://github.com/starfive-tech/u-boot/
-with contributions from:
-yanhong.wang <yanhong.wang@starfivetech.com>
-Huan.Feng <huan.feng@starfivetech.com>
-ke.zhu <ke.zhu@starfivetech.com>
-yiming.li <yiming.li@starfivetech.com>
-jack.zhu <jack.zhu@starfivetech.com>
-Samin Guo <samin.guo@starfivetech.com>
-Chenjieqin <Jessica.Chen@starfivetech.com>
-bo.li <bo.li@starfivetech.com>
-
-Rearranged, cleanups, fixes, pins and resets added by Emil.
-Cleanups, fixes, clocks added by Geert.
-Cleanups and GPIO fixes from Drew.
-Thermal zone added by Stephen.
-PWM pins added by Jianlong.
-cpu-map added by Jonas.
-
-Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
-Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
-Signed-off-by: Stephen L Arnold <nerdboy@gentoo.org>
-Signed-off-by: Drew Fustini <drew@beagleboard.org>
-Signed-off-by: Jianlong Huang <jianlong.huang@starfivetech.com>
-Signed-off-by: Jonas Hahnfeld <hahnjo@hahnjo.de>
----
- .../dts/starfive/jh7100-beaglev-starlight.dts | 16 +
- .../boot/dts/starfive/jh7100-common.dtsi | 432 +++++++++++++++
- .../jh7100-starfive-visionfive-v1.dts | 19 +
- arch/riscv/boot/dts/starfive/jh7100.dtsi | 503 ++++++++++++++++++
- 4 files changed, 970 insertions(+)
-
---- a/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
-+++ b/arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
-@@ -6,8 +6,24 @@
-
- /dts-v1/;
- #include "jh7100-common.dtsi"
-+#include <dt-bindings/gpio/gpio.h>
-
- / {
- model = "BeagleV Starlight Beta";
- compatible = "beagle,beaglev-starlight-jh7100-r0", "starfive,jh7100";
- };
-+
-+&gmac {
-+ snps,reset-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
-+};
-+
-+&gpio {
-+ /* don't reset gpio mux for serial console on uart3 */
-+ starfive,keep-gpiomux = <13 14>;
-+};
-+
-+&mdio {
-+ phy: ethernet-phy@7 {
-+ reg = <7>;
-+ };
-+};
---- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
-@@ -14,6 +14,7 @@
- aliases {
- mmc0 = &sdio0;
- serial0 = &uart3;
-+ serial1 = &uart0;
- };
-
- chosen {
-@@ -64,9 +65,174 @@
- <0x00 0xfa000000 0x10 0x7a000000 0x00 0x01000000>,
- <0x00 0xfb000000 0x00 0xfb000000 0x07 0x85000000>;
- };
-+
-+ reserved-memory {
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+ ranges;
-+
-+ linux,cma {
-+ compatible = "shared-dma-pool";
-+ reusable;
-+ size = <0x0 0x28000000>;
-+ alignment = <0x0 0x1000>;
-+ alloc-ranges = <0x0 0xa0000000 0x0 0x28000000>;
-+ linux,cma-default;
-+ };
-+
-+ jpu_reserved: framebuffer@c9000000 {
-+ reg = <0x0 0xc9000000 0x0 0x4000000>;
-+ };
-+
-+ nvdla_reserved: framebuffer@d0000000 {
-+ no-map;
-+ reg = <0x0 0xd0000000 0x0 0x28000000>;
-+ };
-+
-+ vin_reserved: framebuffer@f9000000 {
-+ compatible = "shared-dma-pool";
-+ no-map;
-+ reg = <0x0 0xf9000000 0x0 0x1000000>;
-+ };
-+
-+ sffb_reserved: framebuffer@fb000000 {
-+ compatible = "shared-dma-pool";
-+ no-map;
-+ reg = <0x0 0xfb000000 0x0 0x2000000>;
-+ };
-+ };
-+
-+ wifi_pwrseq: wifi-pwrseq {
-+ compatible = "mmc-pwrseq-simple";
-+ reset-gpios = <&gpio 37 GPIO_ACTIVE_LOW>;
-+ };
-+};
-+
-+&display {
-+ memory-region = <&sffb_reserved>;
-+ status = "okay";
-+};
-+
-+&crtc {
-+ ddr-format = <4>; //<WIN_FMT_RGB565>;
-+ status = "okay";
-+
-+ port: port@0 {
-+ reg = <0>;
-+
-+ crtc_0_out: endpoint {
-+ remote-endpoint = <&hdmi_input0>;
-+ };
-+ };
-+};
-+
-+&encoder {
-+ encoder-type = <2>; // 2-TMDS, 3-LVDS, 6-DSI, 8-DPI
-+ status = "okay";
-+
-+ ports {
-+ port@0 {
-+ hdmi_out: endpoint {
-+ remote-endpoint = <&tda998x_0_input>;
-+ };
-+ };
-+
-+ port@1 {
-+ hdmi_input0: endpoint {
-+ remote-endpoint = <&crtc_0_out>;
-+ };
-+ };
-+
-+ };
-+};
-+
-+&gmac {
-+ starfive,gtxclk-dlychain = <4>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&gmac_pins>;
-+ phy-mode = "rgmii-txid";
-+ phy-handle = <&phy>;
-+ status = "okay";
-+
-+ mdio: mdio {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ compatible = "snps,dwmac-mdio";
-+ };
- };
-
- &gpio {
-+ gmac_pins: gmac-0 {
-+ gtxclk-pins {
-+ pins = <PAD_FUNC_SHARE(115)>;
-+ bias-pull-up;
-+ drive-strength = <35>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+ miitxclk-pins {
-+ pins = <PAD_FUNC_SHARE(116)>;
-+ bias-pull-up;
-+ drive-strength = <14>;
-+ input-enable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ tx-pins {
-+ pins = <PAD_FUNC_SHARE(117)>,
-+ <PAD_FUNC_SHARE(119)>,
-+ <PAD_FUNC_SHARE(120)>,
-+ <PAD_FUNC_SHARE(121)>,
-+ <PAD_FUNC_SHARE(122)>,
-+ <PAD_FUNC_SHARE(123)>,
-+ <PAD_FUNC_SHARE(124)>,
-+ <PAD_FUNC_SHARE(125)>,
-+ <PAD_FUNC_SHARE(126)>;
-+ bias-pull-up;
-+ drive-strength = <35>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ rxclk-pins {
-+ pins = <PAD_FUNC_SHARE(127)>;
-+ bias-pull-up;
-+ drive-strength = <14>;
-+ input-enable;
-+ input-schmitt-disable;
-+ slew-rate = <6>;
-+ };
-+ rxer-pins {
-+ pins = <PAD_FUNC_SHARE(129)>;
-+ bias-pull-up;
-+ drive-strength = <14>;
-+ input-enable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ rx-pins {
-+ pins = <PAD_FUNC_SHARE(128)>,
-+ <PAD_FUNC_SHARE(130)>,
-+ <PAD_FUNC_SHARE(131)>,
-+ <PAD_FUNC_SHARE(132)>,
-+ <PAD_FUNC_SHARE(133)>,
-+ <PAD_FUNC_SHARE(134)>,
-+ <PAD_FUNC_SHARE(135)>,
-+ <PAD_FUNC_SHARE(136)>,
-+ <PAD_FUNC_SHARE(137)>,
-+ <PAD_FUNC_SHARE(138)>,
-+ <PAD_FUNC_SHARE(139)>,
-+ <PAD_FUNC_SHARE(140)>,
-+ <PAD_FUNC_SHARE(141)>;
-+ bias-pull-up;
-+ drive-strength = <14>;
-+ input-enable;
-+ input-schmitt-enable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
- i2c0_pins: i2c0-0 {
- i2c-pins {
- pinmux = <GPIOMUX(62, GPO_LOW,
-@@ -146,6 +312,166 @@
- };
- };
-
-+ pwmdac_pins: pwmdac-0 {
-+ pwmdac-pins {
-+ pinmux = <GPIOMUX(23, GPO_PWMDAC_LEFT_OUT,
-+ GPO_ENABLE, GPI_NONE)>,
-+ <GPIOMUX(24, GPO_PWMDAC_RIGHT_OUT,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <35>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ pwm_pins: pwm-0 {
-+ pwm-pins {
-+ pinmux = <GPIOMUX(7,
-+ GPO_PWM_PAD_OUT_BIT0,
-+ GPO_PWM_PAD_OE_N_BIT0,
-+ GPI_NONE)>,
-+ <GPIOMUX(5,
-+ GPO_PWM_PAD_OUT_BIT1,
-+ GPO_PWM_PAD_OE_N_BIT1,
-+ GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <35>;
-+ input-disable;
-+ input-schmitt-disable;
-+ slew-rate = <0>;
-+ };
-+ };
-+
-+ sdio0_pins: sdio0-0 {
-+ clk-pins {
-+ pinmux = <GPIOMUX(54, GPO_SDIO0_PAD_CCLK_OUT,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ sdio-pins {
-+ pinmux = <GPIOMUX(55, GPO_LOW, GPO_DISABLE,
-+ GPI_SDIO0_PAD_CARD_DETECT_N)>,
-+ <GPIOMUX(53,
-+ GPO_SDIO0_PAD_CCMD_OUT,
-+ GPO_SDIO0_PAD_CCMD_OEN,
-+ GPI_SDIO0_PAD_CCMD_IN)>,
-+ <GPIOMUX(49,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT0,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT0,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT0)>,
-+ <GPIOMUX(50,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT1,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT1,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT1)>,
-+ <GPIOMUX(51,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT2,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT2,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT2)>,
-+ <GPIOMUX(52,
-+ GPO_SDIO0_PAD_CDATA_OUT_BIT3,
-+ GPO_SDIO0_PAD_CDATA_OEN_BIT3,
-+ GPI_SDIO0_PAD_CDATA_IN_BIT3)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ sdio1_pins: sdio1-0 {
-+ clk-pins {
-+ pinmux = <GPIOMUX(33, GPO_SDIO1_PAD_CCLK_OUT,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ sdio-pins {
-+ pinmux = <GPIOMUX(29,
-+ GPO_SDIO1_PAD_CCMD_OUT,
-+ GPO_SDIO1_PAD_CCMD_OEN,
-+ GPI_SDIO1_PAD_CCMD_IN)>,
-+ <GPIOMUX(36,
-+ GPO_SDIO1_PAD_CDATA_OUT_BIT0,
-+ GPO_SDIO1_PAD_CDATA_OEN_BIT0,
-+ GPI_SDIO1_PAD_CDATA_IN_BIT0)>,
-+ <GPIOMUX(30,
-+ GPO_SDIO1_PAD_CDATA_OUT_BIT1,
-+ GPO_SDIO1_PAD_CDATA_OEN_BIT1,
-+ GPI_SDIO1_PAD_CDATA_IN_BIT1)>,
-+ <GPIOMUX(34,
-+ GPO_SDIO1_PAD_CDATA_OUT_BIT2,
-+ GPO_SDIO1_PAD_CDATA_OEN_BIT2,
-+ GPI_SDIO1_PAD_CDATA_IN_BIT2)>,
-+ <GPIOMUX(31,
-+ GPO_SDIO1_PAD_CDATA_OUT_BIT3,
-+ GPO_SDIO1_PAD_CDATA_OEN_BIT3,
-+ GPI_SDIO1_PAD_CDATA_IN_BIT3)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ };
-+
-+ spi2_pins: spi2-0 {
-+ mosi-pins {
-+ pinmux = <GPIOMUX(18, GPO_SPI2_PAD_TXD,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ miso-pins {
-+ pinmux = <GPIOMUX(16, GPO_LOW, GPO_DISABLE,
-+ GPI_SPI2_PAD_RXD)>;
-+ bias-pull-up;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ sck-pins {
-+ pinmux = <GPIOMUX(12, GPO_SPI2_PAD_SCK_OUT,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ ss-pins {
-+ pinmux = <GPIOMUX(15, GPO_SPI2_PAD_SS_0_N,
-+ GPO_ENABLE, GPI_NONE)>,
-+ <GPIOMUX(11, GPO_SPI2_PAD_SS_1_N,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
-+ uart0_pins: uart0-0 {
-+ rx-pins {
-+ pinmux = <GPIOMUX(40, GPO_LOW, GPO_DISABLE,
-+ GPI_UART0_PAD_SIN)>,
-+ <GPIOMUX(39, GPO_LOW, GPO_DISABLE,
-+ GPI_UART0_PAD_CTSN)>;
-+ bias-pull-up;
-+ drive-strength = <14>;
-+ input-enable;
-+ input-schmitt-enable;
-+ };
-+ tx-pins {
-+ pinmux = <GPIOMUX(41, GPO_UART0_PAD_SOUT,
-+ GPO_ENABLE, GPI_NONE)>,
-+ <GPIOMUX(42, GPO_UART0_PAD_RTSN,
-+ GPO_ENABLE, GPI_NONE)>;
-+ bias-disable;
-+ drive-strength = <35>;
-+ input-disable;
-+ input-schmitt-disable;
-+ };
-+ };
-+
- uart3_pins: uart3-0 {
- rx-pins {
- pinmux = <GPIOMUX(13, GPO_LOW, GPO_DISABLE,
-@@ -186,6 +512,17 @@
- regulators {
- };
- };
-+
-+ tda998x@70 {
-+ compatible = "nxp,tda998x";
-+ reg = <0x70>;
-+
-+ port {
-+ tda998x_0_input: endpoint {
-+ remote-endpoint = <&hdmi_out>;
-+ };
-+ };
-+ };
- };
-
- &i2c1 {
-@@ -225,8 +562,104 @@
- status = "okay";
- };
-
-+&ptc {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwm_pins>;
-+ status = "okay";
-+};
-+
-+&pwmdac {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pwmdac_pins>;
-+ status = "okay";
-+};
-+
-+&qspi {
-+ nor_flash: nor-flash@0 {
-+ compatible = "spi-flash";
-+ reg = <0>;
-+ spi-max-frequency = <31250000>;
-+ page-size = <256>;
-+ block-size = <16>;
-+ cdns,read-delay = <4>;
-+ cdns,tshsl-ns = <1>;
-+ cdns,tsd2d-ns = <1>;
-+ cdns,tchsh-ns = <1>;
-+ cdns,tslch-ns = <1>;
-+ spi-tx-bus-width = <1>;
-+ spi-rx-bus-width = <1>;
-+ };
-+
-+ nand_flash: nand-flash@1 {
-+ compatible = "spi-flash-nand";
-+ reg = <1>;
-+ spi-max-frequency = <31250000>;
-+ page-size = <2048>;
-+ block-size = <17>;
-+ cdns,read-delay = <4>;
-+ cdns,tshsl-ns = <1>;
-+ cdns,tsd2d-ns = <1>;
-+ cdns,tchsh-ns = <1>;
-+ cdns,tslch-ns = <1>;
-+ spi-tx-bus-width = <1>;
-+ spi-rx-bus-width = <1>;
-+ };
-+};
-+
-+&sdio0 {
-+ broken-cd;
-+ bus-width = <4>;
-+ cap-sd-highspeed;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdio0_pins>;
-+ max-frequency = <10000000>;
-+ status = "okay";
-+};
-+
-+&sdio1 {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ bus-width = <4>;
-+ cap-sd-highspeed;
-+ cap-sdio-irq;
-+ cap-power-off-card;
-+ mmc-pwrseq = <&wifi_pwrseq>;
-+ non-removable;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&sdio1_pins>;
-+ status = "okay";
-+
-+ wifi@1 {
-+ compatible = "brcm,bcm4329-fmac";
-+ reg = <1>;
-+ };
-+};
-+
-+&spi2 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&spi2_pins>;
-+ status = "okay";
-+
-+ spi_dev0: spi@0 {
-+ compatible = "rohm,dh2228fv";
-+ spi-max-frequency = <10000000>;
-+ reg = <0>;
-+ };
-+};
-+
-+&uart0 {
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&uart0_pins>;
-+ status = "okay";
-+};
-+
- &uart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins>;
- status = "okay";
- };
-+
-+&usb3 {
-+ dr_mode = "host";
-+ status = "okay";
-+};
---- a/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts
-+++ b/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts
-@@ -18,3 +18,22 @@
- priority = <224>;
- };
- };
-+
-+&gpio {
-+ /* don't reset gpio mux for serial console and reset gpio */
-+ starfive,keep-gpiomux = <13 14 63>;
-+};
-+
-+&i2c0 {
-+ eeprom@50 {
-+ compatible = "atmel,24c04";
-+ reg = <0x50>;
-+ pagesize = <16>;
-+ };
-+};
-+
-+&mdio {
-+ phy: ethernet-phy@0 {
-+ reg = <0>;
-+ };
-+};
---- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
-+++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
-@@ -6,7 +6,9 @@
-
- /dts-v1/;
- #include <dt-bindings/clock/starfive-jh7100.h>
-+#include <dt-bindings/clock/starfive-jh7100-audio.h>
- #include <dt-bindings/reset/starfive-jh7100.h>
-+#include <dt-bindings/reset/starfive-jh7100-audio.h>
-
- / {
- compatible = "starfive,jh7100";
-@@ -135,6 +137,13 @@
- clock-frequency = <0>;
- };
-
-+ /* gmac device configuration */
-+ stmmac_axi_setup: stmmac-axi-config {
-+ snps,wr_osr_lmt = <0xf>;
-+ snps,rd_osr_lmt = <0xf>;
-+ snps,blen = <256 128 64 32 0 0 0>;
-+ };
-+
- soc {
- compatible = "simple-bus";
- interrupt-parent = <&plic>;
-@@ -143,6 +152,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>;
-@@ -172,6 +199,151 @@
- riscv,ndev = <133>;
- };
-
-+ gmac: ethernet@10020000 {
-+ compatible = "starfive,jh7100-dwmac", "snps,dwmac";
-+ reg = <0x0 0x10020000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_GMAC_ROOT_DIV>,
-+ <&clkgen JH7100_CLK_GMAC_AHB>,
-+ <&clkgen JH7100_CLK_GMAC_PTP_REF>,
-+ <&clkgen JH7100_CLK_GMAC_TX_INV>,
-+ <&clkgen JH7100_CLK_GMAC_GTX>;
-+ clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "gtx";
-+ resets = <&rstgen JH7100_RSTN_GMAC_AHB>;
-+ reset-names = "ahb";
-+ interrupts = <6>, <7>;
-+ interrupt-names = "macirq", "eth_wake_irq";
-+ max-frame-size = <9000>;
-+ snps,multicast-filter-bins = <0>;
-+ snps,perfect-filter-entries = <128>;
-+ starfive,syscon = <&sysmain 0x70 0>;
-+ rx-fifo-depth = <32768>;
-+ tx-fifo-depth = <16384>;
-+ snps,axi-config = <&stmmac_axi_setup>;
-+ snps,fixed-burst;
-+ /*snps,force_sf_dma_mode;*/
-+ snps,force_thresh_dma_mode;
-+ snps,no-pbl-x8;
-+ status = "disabled";
-+ };
-+
-+ dma2p: dma-controller@100b0000 {
-+ compatible = "starfive,jh7100-axi-dma";
-+ reg = <0x0 0x100b0000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SGDMA2P_AXI>,
-+ <&clkgen JH7100_CLK_SGDMA2P_AHB>;
-+ clock-names = "core-clk", "cfgr-clk";
-+ resets = <&rstgen JH7100_RSTN_SGDMA2P_AXI>,
-+ <&rstgen JH7100_RSTN_SGDMA2P_AHB>;
-+ reset-names = "axi", "ahb";
-+ interrupts = <2>;
-+ #dma-cells = <1>;
-+ dma-channels = <4>;
-+ snps,dma-masters = <1>;
-+ snps,data-width = <4>;
-+ snps,block-size = <4096 4096 4096 4096>;
-+ snps,priority = <0 1 2 3>;
-+ snps,axi-max-burst-len = <128>;
-+ dma-coherent;
-+ };
-+
-+ crypto: crypto@100d0000 {
-+ compatible = "starfive,vic-sec";
-+ reg = <0x0 0x100d0000 0x0 0x20000>,
-+ <0x0 0x11800234 0x0 0xc>;
-+ reg-names = "secmem", "secclk";
-+ clocks = <&clkgen JH7100_CLK_SEC_AHB>;
-+ interrupts = <31>;
-+ };
-+
-+ i2sadc0: i2sadc0@10400000 {
-+ compatible = "snps,designware-i2sadc0";
-+ reg = <0x0 0x10400000 0x0 0x1000>;
-+ clocks = <&clkgen JH7100_CLK_APB1_BUS>;
-+ clock-names = "i2sclk";
-+ interrupt-parent = <&plic>;
-+ #sound-dai-cells = <0>;
-+ dmas = <&dma2p 28>;
-+ dma-names = "rx";
-+ };
-+
-+ i2svad: i2svad@10420000 {
-+ compatible = "starfive,sf-i2svad";
-+ reg = <0x0 0x10420000 0x0 0x1000> ;
-+ clocks = <&audclk JH7100_AUDCLK_I2SVAD_APB>;
-+ clock-names = "i2svad_apb";
-+ resets = <&audrst JH7100_AUDRSTN_I2SVAD_APB>,
-+ <&audrst JH7100_AUDRSTN_I2SVAD_SRST>;
-+ reset-names = "apb_i2svad", "i2svad_srst";
-+ interrupts = <60>, <61>;
-+ interrupt-names = "spintr", "slintr";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ pwmdac: pwmdac@10440000 {
-+ compatible = "starfive,pwmdac";
-+ reg = <0x0 0x10440000 0x0 0x1000>;
-+ clocks = <&clkgen JH7100_CLK_AUDIO_ROOT>,
-+ <&clkgen JH7100_CLK_AUDIO_SRC>,
-+ <&clkgen JH7100_CLK_AUDIO_12288>,
-+ <&audclk JH7100_AUDCLK_DMA1P_AHB>,
-+ <&audclk JH7100_AUDCLK_PWMDAC_APB>,
-+ <&audclk JH7100_AUDCLK_DAC_MCLK>;
-+ clock-names = "audio_root",
-+ "audio_src",
-+ "audio_12288",
-+ "dma1p_ahb",
-+ "pwmdac_apb",
-+ "dac_mclk";
-+ resets = <&audrst JH7100_AUDRSTN_APB_BUS>,
-+ <&audrst JH7100_AUDRSTN_DMA1P_AHB>,
-+ <&audrst JH7100_AUDRSTN_PWMDAC_APB>;
-+ reset-names = "apb_bus", "dma1p_ahb", "apb_pwmdac";
-+ dmas = <&dma2p 23>;
-+ dma-names = "tx";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ i2sdac0: i2sdac0@10450000 {
-+ compatible = "snps,designware-i2sdac0";
-+ reg = <0x0 0x10450000 0x0 0x1000>;
-+ clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>,
-+ <&audclk JH7100_AUDCLK_I2SDAC_BCLK>,
-+ <&audclk JH7100_AUDCLK_I2SDAC_LRCLK>,
-+ <&audclk JH7100_AUDCLK_I2SDAC_APB>;
-+ clock-names = "dac_mclk", "i2sdac0_bclk", "i2sdac0_lrclk", "i2sdac_apb";
-+ resets = <&audrst JH7100_AUDRSTN_I2SDAC_APB>,
-+ <&audrst JH7100_AUDRSTN_I2SDAC_SRST>;
-+ reset-names = "apb_i2sdac", "i2sdac_srst";
-+ #sound-dai-cells = <0>;
-+ dmas = <&dma2p 30>;
-+ dma-names = "tx";
-+ };
-+
-+ i2sdac1: i2sdac1@10460000 {
-+ compatible = "snps,designware-i2sdac1";
-+ reg = <0x0 0x10460000 0x0 0x1000>;
-+ clocks = <&audclk JH7100_AUDCLK_DAC_MCLK>,
-+ <&audclk JH7100_AUDCLK_I2S1_BCLK>,
-+ <&audclk JH7100_AUDCLK_I2S1_LRCLK>,
-+ <&audclk JH7100_AUDCLK_I2S1_APB>;
-+ clock-names = "dac_mclk", "i2sdac1_bclk", "i2sdac1_lrclk", "i2s1_apb";
-+ resets = <&audrst JH7100_AUDRSTN_I2S1_APB>,
-+ <&audrst JH7100_AUDRSTN_I2S1_SRST>;
-+ #sound-dai-cells = <0>;
-+ dmas = <&dma2p 31>;
-+ dma-names = "tx";
-+ };
-+
-+ i2sdac16k: i2sdac16k@10470000 {
-+ compatible = "snps,designware-i2sdac16k";
-+ reg = <0x0 0x10470000 0x0 0x1000>;
-+ clocks = <&clkgen JH7100_CLK_APB1_BUS>;
-+ clock-names = "i2sclk";
-+ #sound-dai-cells = <0>;
-+ dmas = <&dma2p 29>;
-+ dma-names = "tx";
-+ };
-+
- audclk: clock-controller@10480000 {
- compatible = "starfive,jh7100-audclk";
- reg = <0x0 0x10480000 0x0 0x10000>;
-@@ -214,6 +386,82 @@
- status = "disabled";
- };
-
-+ spdif_transmitter: spdif-transmitter {
-+ compatible = "linux,spdif-dit";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ spdif_receiver: spdif-receiver {
-+ compatible = "linux,spdif-dir";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ pwmdac_codec: pwmdac-transmitter {
-+ compatible = "linux,pwmdac-dit";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ dmic_codec: dmic {
-+ compatible = "dmic-codec";
-+ #sound-dai-cells = <0>;
-+ };
-+
-+ sound: snd-card {
-+ compatible = "simple-audio-card";
-+ simple-audio-card,name = "Starfive-Multi-Sound-Card";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ /* pwmdac */
-+ simple-audio-card,dai-link@0 {
-+ reg = <0>;
-+ status = "okay";
-+ format = "left_j";
-+ bitclock-master = <&sndcpu0>;
-+ frame-master = <&sndcpu0>;
-+
-+ sndcpu0: cpu {
-+ sound-dai = <&pwmdac>;
-+ };
-+
-+ codec {
-+ sound-dai = <&pwmdac_codec>;
-+ };
-+ };
-+ };
-+
-+ usb3: usb@104c0000 {
-+ compatible = "cdns,usb3";
-+ reg = <0x0 0x104c0000 0x0 0x10000>, // memory area for HOST registers
-+ <0x0 0x104d0000 0x0 0x10000>, // memory area for DEVICE registers
-+ <0x0 0x104e0000 0x0 0x10000>; // memory area for OTG/DRD registers
-+ reg-names = "otg", "xhci", "dev";
-+ interrupts = <44>, <52>, <43>;
-+ interrupt-names = "host", "peripheral", "otg";
-+ phy-names = "cdns3,usb3-phy", "cdns3,usb2-phy";
-+ maximum-speed = "super-speed";
-+ status = "disabled";
-+ };
-+
-+ dma1p: dma-controller@10500000 {
-+ compatible = "starfive,jh7100-axi-dma";
-+ reg = <0x0 0x10500000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SGDMA1P_AXI>,
-+ <&clkgen JH7100_CLK_SGDMA1P_BUS>;
-+ clock-names = "core-clk", "cfgr-clk";
-+ resets = <&rstgen JH7100_RSTN_DMA1P_AXI>,
-+ <&rstgen JH7100_RSTN_SGDMA1P_AXI>;
-+ reset-names = "axi", "ahb";
-+ interrupts = <1>;
-+ #dma-cells = <1>;
-+ dma-channels = <16>;
-+ snps,dma-masters = <1>;
-+ snps,data-width = <3>;
-+ snps,block-size = <4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096 4096>;
-+ snps,priority = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
-+ snps,axi-max-burst-len = <64>;
-+ };
-+
- clkgen: clock-controller@11800000 {
- compatible = "starfive,jh7100-clkgen";
- reg = <0x0 0x11800000 0x0 0x10000>;
-@@ -222,12 +470,93 @@
- #clock-cells = <1>;
- };
-
-+ otp: otp@11810000 {
-+ compatible = "starfive,fu740-otp";
-+ reg = <0x0 0x11810000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_OTP_APB>;
-+ fuse-count = <0x200>;
-+ };
-+
- rstgen: reset-controller@11840000 {
- compatible = "starfive,jh7100-reset";
- reg = <0x0 0x11840000 0x0 0x10000>;
- #reset-cells = <1>;
- };
-
-+ sysmain: syscon@11850000 {
-+ compatible = "starfive,jh7100-sysmain", "syscon";
-+ reg = <0x0 0x11850000 0x0 0x10000>;
-+ };
-+
-+ qspi: spi@11860000 {
-+ compatible = "cdns,qspi-nor";
-+ reg = <0x0 0x11860000 0x0 0x10000>,
-+ <0x0 0x20000000 0x0 0x20000000>;
-+ clocks = <&clkgen JH7100_CLK_QSPI_AHB>;
-+ interrupts = <3>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ cdns,fifo-depth = <256>;
-+ cdns,fifo-width = <4>;
-+ cdns,trigger-address = <0x0>;
-+ spi-max-frequency = <250000000>;
-+ status = "disabled";
-+ };
-+
-+ uart0: serial@11870000 {
-+ compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart";
-+ reg = <0x0 0x11870000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_UART0_CORE>,
-+ <&clkgen JH7100_CLK_UART0_APB>;
-+ clock-names = "baudclk", "apb_pclk";
-+ resets = <&rstgen JH7100_RSTN_UART0_APB>;
-+ interrupts = <92>;
-+ reg-io-width = <4>;
-+ reg-shift = <2>;
-+ status = "disabled";
-+ };
-+
-+ uart1: serial@11880000 {
-+ compatible = "starfive,jh7100-hsuart", "snps,dw-apb-uart";
-+ reg = <0x0 0x11880000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_UART1_CORE>,
-+ <&clkgen JH7100_CLK_UART1_APB>;
-+ clock-names = "baudclk", "apb_pclk";
-+ resets = <&rstgen JH7100_RSTN_UART1_APB>;
-+ interrupts = <93>;
-+ reg-io-width = <4>;
-+ reg-shift = <2>;
-+ status = "disabled";
-+ };
-+
-+ spi0: spi@11890000 {
-+ compatible = "snps,dw-apb-ssi";
-+ reg = <0x0 0x11890000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SPI0_CORE>,
-+ <&clkgen JH7100_CLK_SPI0_APB>;
-+ clock-names = "ssi_clk", "pclk";
-+ resets = <&rstgen JH7100_RSTN_SPI0_APB>;
-+ reset-names = "spi";
-+ interrupts = <94>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi1: spi@118a0000 {
-+ compatible = "snps,dw-apb-ssi";
-+ reg = <0x0 0x118a0000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SPI1_CORE>,
-+ <&clkgen JH7100_CLK_SPI1_APB>;
-+ clock-names = "ssi_clk", "pclk";
-+ resets = <&rstgen JH7100_RSTN_SPI1_APB>;
-+ reset-names = "spi";
-+ interrupts = <95>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
- i2c0: i2c@118b0000 {
- compatible = "snps,designware-i2c";
- reg = <0x0 0x118b0000 0x0 0x10000>;
-@@ -254,6 +583,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>,
-@@ -268,6 +632,86 @@
- #interrupt-cells = <2>;
- };
-
-+ nvdla@11940000 {
-+ compatible = "nvidia,nvdla_os_initial";
-+ interrupts = <22>;
-+ memory-region = <&nvdla_reserved>;
-+ reg = <0x0 0x11940000 0x0 0x40000>;
-+ status = "okay";
-+ };
-+
-+ display: display-subsystem {
-+ compatible = "starfive,display-subsystem";
-+ dma-coherent;
-+ status = "disabled";
-+ };
-+
-+ encoder: display-encoder {
-+ compatible = "starfive,display-encoder";
-+ status = "disabled";
-+ };
-+
-+ crtc: crtc@12000000 {
-+ compatible = "starfive,jh7100-crtc";
-+ reg = <0x0 0x12000000 0x0 0x10000>,
-+ <0x0 0x12040000 0x0 0x10000>,
-+ <0x0 0x12080000 0x0 0x10000>,
-+ <0x0 0x120c0000 0x0 0x10000>,
-+ <0x0 0x12240000 0x0 0x10000>,
-+ <0x0 0x12250000 0x0 0x10000>,
-+ <0x0 0x12260000 0x0 0x10000>;
-+ reg-names = "lcdc", "vpp0", "vpp1", "vpp2", "clk", "rst", "sys";
-+ clocks = <&clkgen JH7100_CLK_DISP_AXI>, <&clkgen JH7100_CLK_VOUT_SRC>;
-+ clock-names = "disp_axi", "vout_src";
-+ resets = <&rstgen JH7100_RSTN_DISP_AXI>, <&rstgen JH7100_RSTN_VOUT_SRC>;
-+ reset-names = "disp_axi", "vout_src";
-+ interrupts = <101>, <103>;
-+ interrupt-names = "lcdc_irq", "vpp1_irq";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+
-+ pp1 {
-+ pp-id = <1>;
-+ fifo-out;
-+ //sys-bus-out;
-+ src-format = <11>; //<COLOR_RGB565>;
-+ src-width = <1920>;
-+ src-height = <1080>;
-+ dst-format = <7>; //<COLOR_RGB888_ARGB>;
-+ dst-width = <1920>;
-+ dst-height = <1080>;
-+ };
-+ };
-+
-+ spi2: spi@12410000 {
-+ compatible = "snps,dw-apb-ssi";
-+ reg = <0x0 0x12410000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SPI2_CORE>,
-+ <&clkgen JH7100_CLK_SPI2_APB>;
-+ clock-names = "ssi_clk", "pclk";
-+ resets = <&rstgen JH7100_RSTN_SPI2_APB>;
-+ reset-names = "spi";
-+ interrupts = <70>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ spi3: spi@12420000 {
-+ compatible = "snps,dw-apb-ssi";
-+ reg = <0x0 0x12420000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_SPI3_CORE>,
-+ <&clkgen JH7100_CLK_SPI3_APB>;
-+ clock-names = "ssi_clk", "pclk";
-+ resets = <&rstgen JH7100_RSTN_SPI3_APB>;
-+ reset-names = "spi";
-+ interrupts = <71>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
- uart2: serial@12430000 {
- compatible = "starfive,jh7100-uart", "snps,dw-apb-uart";
- reg = <0x0 0x12430000 0x0 0x10000>;
-@@ -341,5 +785,64 @@
- reset-names = "sense", "bus";
- #thermal-sensor-cells = <0>;
- };
-+
-+ ptc: pwm@12490000 {
-+ compatible = "starfive,pwm0";
-+ reg = <0x0 0x12490000 0x0 0x10000>;
-+ clocks = <&clkgen JH7100_CLK_PWM_APB>;
-+ resets = <&rstgen JH7100_RSTN_PWM_APB>;
-+ #pwm-cells = <3>;
-+ sifive,npwm = <8>;
-+ status = "disabled";
-+ };
-+
-+ thermal-zones {
-+ cpu-thermal {
-+ polling-delay-passive = <250>;
-+ polling-delay = <15000>;
-+
-+ thermal-sensors = <&sfctemp>;
-+
-+ cooling-maps {
-+ };
-+
-+ trips {
-+ cpu_alert0: cpu_alert0 {
-+ /* milliCelsius */
-+ temperature = <75000>;
-+ hysteresis = <2000>;
-+ type = "passive";
-+ };
-+
-+ cpu_crit: cpu_crit {
-+ /* milliCelsius */
-+ temperature = <90000>;
-+ hysteresis = <2000>;
-+ type = "critical";
-+ };
-+ };
-+ };
-+ };
-+
-+ xrp@f0000000 {
-+ compatible = "cdns,xrp";
-+ reg = <0x0 0xf0000000 0x0 0x01ffffff>,
-+ <0x10 0x72000000 0x0 0x00001000>,
-+ <0x10 0x72001000 0x0 0x00fff000>,
-+ <0x0 0x124b0000 0x0 0x00010000>;
-+ clocks = <&clkgen JH7100_CLK_VP6_CORE>;
-+ interrupts = <27>, <28>;
-+ firmware-name = "vp6_elf";
-+ dsp-irq = <19 20>;
-+ dsp-irq-src = <0x20 0x21>;
-+ intc-irq-mode = <1>;
-+ intc-irq = <0 1>;
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges = <0x40000000 0x0 0x40000000 0x01000000>,
-+ <0xb0000000 0x10 0x70000000 0x3000000>;
-+ dsp@0 {
-+ };
-+ };
- };
- };