From: Álvaro Fernández Rojas Date: Thu, 18 Feb 2021 17:04:33 +0000 (+0100) Subject: bcm27xx: import latest patches from the RPi foundation X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=f07e572f6447465d8938679533d604e402b0f066;p=openwrt%2Fstaging%2Fmkresin.git bcm27xx: import latest patches from the RPi foundation bcm2708: boot tested on RPi B+ v1.2 bcm2709: boot tested on RPi 3B v1.2 and RPi 4B v1.1 4G bcm2710: boot tested on RPi 3B v1.2 bcm2711: boot tested on RPi 4B v1.1 4G Signed-off-by: Álvaro Fernández Rojas --- diff --git a/target/linux/bcm27xx/bcm2708/config-5.4 b/target/linux/bcm27xx/bcm2708/config-5.4 index c560ff04ad..e7d384dded 100644 --- a/target/linux/bcm27xx/bcm2708/config-5.4 +++ b/target/linux/bcm27xx/bcm2708/config-5.4 @@ -4,21 +4,6 @@ CONFIG_ARCH_32BIT_OFF_T=y CONFIG_ARCH_BCM=y CONFIG_ARCH_BCM2835=y CONFIG_ARCH_CLOCKSOURCE_DATA=y -CONFIG_ARCH_HAS_BINFMT_FLAT=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_ARCH_HAS_KCOV=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_HAS_PHYS_TO_DMA=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y @@ -27,23 +12,16 @@ CONFIG_ARCH_MULTI_V6=y CONFIG_ARCH_MULTI_V6_V7=y CONFIG_ARCH_NR_GPIO=0 CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USE_BUILTIN_BSWAP=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_ARM=y CONFIG_ARM_AMBA=y -CONFIG_ARM_BCM2835_CPUFREQ=y +# CONFIG_ARM_BCM2835_CPUFREQ is not set CONFIG_ARM_CPU_SUSPEND=y CONFIG_ARM_ERRATA_411920=y CONFIG_ARM_HAS_SG_CHAIN=y CONFIG_ARM_L1_CACHE_SHIFT=5 CONFIG_ARM_PATCH_PHYS_VIRT=y -# CONFIG_ARM_RASPBERRYPI_CPUFREQ is not set +CONFIG_ARM_RASPBERRYPI_CPUFREQ=y # CONFIG_ARM_SCMI_PROTOCOL is not set CONFIG_ARM_THUMB=y CONFIG_ARM_TIMER_SP804=y @@ -76,7 +54,6 @@ CONFIG_BLK_PM=y CONFIG_BLK_SCSI_REQUEST=y CONFIG_BRCM_CHAR_DRIVERS=y # CONFIG_CACHE_L2X0 is not set -CONFIG_CC_HAS_KASAN_GENERIC=y CONFIG_CLKDEV_LOOKUP=y CONFIG_CLKSRC_MMIO=y CONFIG_CLK_BCM2835=y @@ -97,7 +74,8 @@ CONFIG_COMPAT_32BIT_TIME=y CONFIG_CONFIGFS_FS=y CONFIG_CONSOLE_TRANSLATIONS=y CONFIG_CONTIG_ALLOC=y -# CONFIG_CPUFREQ_DT is not set +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y CONFIG_CPU_32v6=y CONFIG_CPU_32v6K=y CONFIG_CPU_ABRT_EV6=y @@ -202,47 +180,13 @@ CONFIG_GENERIC_STRNLEN_USER=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_IRQCHIP=y # CONFIG_GPIO_BCM_VIRT is not set +# CONFIG_GPIO_FSM is not set CONFIG_GPIO_RASPBERRYPI_EXP=y CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_PFN_VALID=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_OPTPROBES=y -CONFIG_HAVE_PCI=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_PROC_CPU=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_UID16=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HW_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_BCM2835=y @@ -268,6 +212,7 @@ CONFIG_JBD2=y CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_XZ is not set CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y @@ -332,6 +277,7 @@ CONFIG_PM_CLK=y CONFIG_PM_GENERIC_DOMAINS=y CONFIG_PM_GENERIC_DOMAINS_OF=y CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_OPP=y CONFIG_PM_SLEEP=y CONFIG_POWER_SUPPLY=y CONFIG_PRINTK_TIME=y diff --git a/target/linux/bcm27xx/bcm2709/config-5.4 b/target/linux/bcm27xx/bcm2709/config-5.4 index 017f3eb0ad..98ac433752 100644 --- a/target/linux/bcm27xx/bcm2709/config-5.4 +++ b/target/linux/bcm27xx/bcm2709/config-5.4 @@ -6,26 +6,6 @@ CONFIG_ARCH_BCM2835=y # CONFIG_ARCH_BCM_HR2 is not set CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_DMA_ADDR_T_64BIT=y -CONFIG_ARCH_HAS_BINFMT_FLAT=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_ARCH_HAS_KCOV=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_HAS_PHYS_TO_DMA=y -CONFIG_ARCH_HAS_PTE_SPECIAL=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y -CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y -CONFIG_ARCH_HAS_TICK_BROADCAST=y -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y @@ -35,14 +15,7 @@ CONFIG_ARCH_MULTI_V7=y CONFIG_ARCH_NR_GPIO=0 CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USE_BUILTIN_BSWAP=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_ARM=y CONFIG_ARM_AMBA=y CONFIG_ARM_ARCH_TIMER=y @@ -96,7 +69,6 @@ CONFIG_BOUNCE=y CONFIG_BRCM_CHAR_DRIVERS=y CONFIG_BROADCOM_PHY=y # CONFIG_CACHE_L2X0 is not set -CONFIG_CC_HAS_KASAN_GENERIC=y CONFIG_CLKDEV_LOOKUP=y CONFIG_CLKSRC_MMIO=y CONFIG_CLK_BCM2835=y @@ -204,6 +176,7 @@ CONFIG_ENABLE_MUST_CHECK=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXTCON=y CONFIG_F2FS_FS=y CONFIG_FB=y CONFIG_FB_BCM2708=y @@ -254,9 +227,11 @@ CONFIG_GENERIC_SCHED_CLOCK=y CONFIG_GENERIC_SMP_IDLE_THREAD=y CONFIG_GENERIC_STRNCPY_FROM_USER=y CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_IRQCHIP=y CONFIG_GPIO_BCM_VIRT=y +# CONFIG_GPIO_FSM is not set CONFIG_GPIO_RASPBERRYPI_EXP=y CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_HARDEN_BRANCH_PREDICTOR=y @@ -264,49 +239,7 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAVE_ARCH_BITREVERSE=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_PFN_VALID=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y -CONFIG_HAVE_ARM_ARCH_TIMER=y -CONFIG_HAVE_ARM_SMCCC=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FAST_GUP=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_IDE=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_OPTPROBES=y -CONFIG_HAVE_PCI=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_PROC_CPU=y -CONFIG_HAVE_RCU_TABLE_FREE=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y CONFIG_HAVE_SMP=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_UID16=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HIGHMEM=y CONFIG_HIGHPTE=y CONFIG_HOTPLUG_CPU=y @@ -335,6 +268,7 @@ CONFIG_IRQ_WORK=y CONFIG_JBD2=y CONFIG_KEYS=y CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y @@ -381,6 +315,7 @@ CONFIG_NEON=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NLS=y CONFIG_NLS_ASCII=y +CONFIG_NOP_USB_XCEIV=y CONFIG_NO_HZ=y CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y @@ -498,10 +433,12 @@ CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_COMMON=y CONFIG_USB_DWCOTG=y +CONFIG_USB_GADGET=y CONFIG_USB_LAN78XX=y CONFIG_USB_NET_DRIVERS=y CONFIG_USB_NET_SMSC95XX=y CONFIG_USB_PCI=y +CONFIG_USB_PHY=y CONFIG_USB_STORAGE=y CONFIG_USB_SUPPORT=y CONFIG_USB_UAS=y diff --git a/target/linux/bcm27xx/bcm2710/config-5.4 b/target/linux/bcm27xx/bcm2710/config-5.4 index a011e2f213..5aaf021de9 100644 --- a/target/linux/bcm27xx/bcm2710/config-5.4 +++ b/target/linux/bcm27xx/bcm2710/config-5.4 @@ -3,59 +3,7 @@ CONFIG_64BIT=y CONFIG_ARCH_BCM2835=y CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_DMA_ADDR_T_64BIT=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y -CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y -CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_ARCH_HAS_FAST_MULTIPLIER=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_ARCH_HAS_GIGANTIC_PAGE=y -CONFIG_ARCH_HAS_KCOV=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_HAS_PTE_DEVMAP=y -CONFIG_ARCH_HAS_PTE_SPECIAL=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SET_DIRECT_MAP=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y -CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y -CONFIG_ARCH_HAS_TICK_BROADCAST=y -CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y -CONFIG_ARCH_INLINE_READ_LOCK=y -CONFIG_ARCH_INLINE_READ_LOCK_BH=y -CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y -CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y -CONFIG_ARCH_INLINE_READ_UNLOCK=y -CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y -CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y -CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y -CONFIG_ARCH_INLINE_SPIN_LOCK=y -CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y -CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y -CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y -CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y -CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y -CONFIG_ARCH_INLINE_WRITE_LOCK=y -CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y -CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y -CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_ARCH_MMAP_RND_BITS=18 CONFIG_ARCH_MMAP_RND_BITS_MAX=24 @@ -65,20 +13,7 @@ CONFIG_ARCH_PROC_KCORE_TEXT=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y -CONFIG_ARCH_SUPPORTS_INT128=y -CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y -CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y -CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_USE_MEMREMAP_PROT=y -CONFIG_ARCH_USE_QUEUED_RWLOCKS=y -CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_ARCH_WANT_FRAME_POINTERS=y -CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y CONFIG_ARM64=y CONFIG_ARM64_4K_PAGES=y CONFIG_ARM64_CNP=y @@ -153,7 +88,6 @@ CONFIG_CAVIUM_ERRATUM_22375=y CONFIG_CAVIUM_ERRATUM_23154=y CONFIG_CAVIUM_ERRATUM_27456=y CONFIG_CAVIUM_TX2_ERRATUM_219=y -CONFIG_CC_HAS_KASAN_GENERIC=y CONFIG_CLKDEV_LOOKUP=y CONFIG_CLKSRC_MMIO=y CONFIG_CLK_BCM2835=y @@ -242,11 +176,11 @@ CONFIG_DRM_RCAR_WRITEBACK=y CONFIG_DTC=y CONFIG_DUMMY_CONSOLE=y CONFIG_EDAC_SUPPORT=y -CONFIG_EFI_EARLYCON=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXTCON=y CONFIG_F2FS_FS=y CONFIG_FB=y CONFIG_FB_BCM2708=y @@ -305,6 +239,7 @@ CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_IRQCHIP=y CONFIG_GPIO_BCM_VIRT=y +# CONFIG_GPIO_FSM is not set CONFIG_GPIO_RASPBERRYPI_EXP=y CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_HARDEN_BRANCH_PREDICTOR=y @@ -312,59 +247,6 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y -CONFIG_HAVE_ARCH_AUDITSYSCALL=y -CONFIG_HAVE_ARCH_BITREVERSE=y -CONFIG_HAVE_ARCH_HUGE_VMAP=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y -CONFIG_HAVE_ARCH_KASAN=y -CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_PFN_VALID=y -CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y -CONFIG_HAVE_ARCH_SECCOMP_FILTER=y -CONFIG_HAVE_ARCH_STACKLEAK=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y -CONFIG_HAVE_ARCH_VMAP_STACK=y -CONFIG_HAVE_ARM_SMCCC=y -CONFIG_HAVE_ASM_MODVERSIONS=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_HAVE_CMPXCHG_DOUBLE=y -CONFIG_HAVE_CMPXCHG_LOCAL=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_BUGVERBOSE=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FAST_GUP=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y -CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_GENERIC_VDSO=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_MEMORY_PRESENT=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_PATA_PLATFORM=y -CONFIG_HAVE_PCI=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_RCU_TABLE_FREE=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HOLES_IN_ZONE=y CONFIG_HOTPLUG_CPU=y CONFIG_HW_CONSOLE=y @@ -379,26 +261,6 @@ CONFIG_I2C_BOARDINFO=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 -CONFIG_INLINE_READ_LOCK=y -CONFIG_INLINE_READ_LOCK_BH=y -CONFIG_INLINE_READ_LOCK_IRQ=y -CONFIG_INLINE_READ_LOCK_IRQSAVE=y -CONFIG_INLINE_READ_UNLOCK_BH=y -CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y -CONFIG_INLINE_SPIN_LOCK=y -CONFIG_INLINE_SPIN_LOCK_BH=y -CONFIG_INLINE_SPIN_LOCK_IRQ=y -CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y -CONFIG_INLINE_SPIN_TRYLOCK=y -CONFIG_INLINE_SPIN_TRYLOCK_BH=y -CONFIG_INLINE_SPIN_UNLOCK_BH=y -CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y -CONFIG_INLINE_WRITE_LOCK=y -CONFIG_INLINE_WRITE_LOCK_BH=y -CONFIG_INLINE_WRITE_LOCK_IRQ=y -CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y -CONFIG_INLINE_WRITE_UNLOCK_BH=y -CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y CONFIG_INPUT=y CONFIG_INPUT_MOUSEDEV=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set @@ -412,6 +274,7 @@ CONFIG_IRQ_WORK=y CONFIG_JBD2=y CONFIG_KEYS=y CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y diff --git a/target/linux/bcm27xx/bcm2711/config-5.4 b/target/linux/bcm27xx/bcm2711/config-5.4 index ee391ff5be..2ba8bfba3d 100644 --- a/target/linux/bcm27xx/bcm2711/config-5.4 +++ b/target/linux/bcm27xx/bcm2711/config-5.4 @@ -3,59 +3,7 @@ CONFIG_64BIT=y CONFIG_ARCH_BCM2835=y CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_DMA_ADDR_T_64BIT=y -CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y -CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y -CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_ARCH_HAS_FAST_MULTIPLIER=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_ARCH_HAS_GIGANTIC_PAGE=y -CONFIG_ARCH_HAS_KCOV=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_HAS_PTE_DEVMAP=y -CONFIG_ARCH_HAS_PTE_SPECIAL=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SET_DIRECT_MAP=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y -CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y -CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y -CONFIG_ARCH_HAS_TICK_BROADCAST=y -CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y -CONFIG_ARCH_INLINE_READ_LOCK=y -CONFIG_ARCH_INLINE_READ_LOCK_BH=y -CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y -CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y -CONFIG_ARCH_INLINE_READ_UNLOCK=y -CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y -CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y -CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y -CONFIG_ARCH_INLINE_SPIN_LOCK=y -CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y -CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y -CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y -CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y -CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y -CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y -CONFIG_ARCH_INLINE_WRITE_LOCK=y -CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y -CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y -CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y -CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_ARCH_MMAP_RND_BITS=18 CONFIG_ARCH_MMAP_RND_BITS_MAX=24 @@ -65,20 +13,7 @@ CONFIG_ARCH_PROC_KCORE_TEXT=y CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_SPARSEMEM_DEFAULT=y CONFIG_ARCH_SPARSEMEM_ENABLE=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y -CONFIG_ARCH_SUPPORTS_INT128=y -CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y -CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y -CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_USE_MEMREMAP_PROT=y -CONFIG_ARCH_USE_QUEUED_RWLOCKS=y -CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_ARCH_WANT_FRAME_POINTERS=y -CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y CONFIG_ARM64=y CONFIG_ARM64_4K_PAGES=y CONFIG_ARM64_CNP=y @@ -157,7 +92,6 @@ CONFIG_CAVIUM_ERRATUM_22375=y CONFIG_CAVIUM_ERRATUM_23154=y CONFIG_CAVIUM_ERRATUM_27456=y CONFIG_CAVIUM_TX2_ERRATUM_219=y -CONFIG_CC_HAS_KASAN_GENERIC=y CONFIG_CLKDEV_LOOKUP=y CONFIG_CLKSRC_MMIO=y CONFIG_CLK_BCM2835=y @@ -247,11 +181,11 @@ CONFIG_DRM_RCAR_WRITEBACK=y CONFIG_DTC=y CONFIG_DUMMY_CONSOLE=y CONFIG_EDAC_SUPPORT=y -CONFIG_EFI_EARLYCON=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXTCON=y CONFIG_F2FS_FS=y CONFIG_FB=y CONFIG_FB_BCM2708=y @@ -311,6 +245,7 @@ CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_IRQCHIP=y CONFIG_GPIO_BCM_VIRT=y +# CONFIG_GPIO_FSM is not set CONFIG_GPIO_RASPBERRYPI_EXP=y CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_HARDEN_BRANCH_PREDICTOR=y @@ -318,59 +253,6 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y -CONFIG_HAVE_ARCH_AUDITSYSCALL=y -CONFIG_HAVE_ARCH_BITREVERSE=y -CONFIG_HAVE_ARCH_HUGE_VMAP=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y -CONFIG_HAVE_ARCH_KASAN=y -CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_PFN_VALID=y -CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y -CONFIG_HAVE_ARCH_SECCOMP_FILTER=y -CONFIG_HAVE_ARCH_STACKLEAK=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y -CONFIG_HAVE_ARCH_VMAP_STACK=y -CONFIG_HAVE_ARM_SMCCC=y -CONFIG_HAVE_ASM_MODVERSIONS=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_HAVE_CMPXCHG_DOUBLE=y -CONFIG_HAVE_CMPXCHG_LOCAL=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_BUGVERBOSE=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FAST_GUP=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y -CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_GENERIC_VDSO=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_MEMORY_PRESENT=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_PATA_PLATFORM=y -CONFIG_HAVE_PCI=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_RCU_TABLE_FREE=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HOLES_IN_ZONE=y CONFIG_HOTPLUG_CPU=y CONFIG_HW_CONSOLE=y @@ -385,26 +267,6 @@ CONFIG_I2C_BOARDINFO=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 -CONFIG_INLINE_READ_LOCK=y -CONFIG_INLINE_READ_LOCK_BH=y -CONFIG_INLINE_READ_LOCK_IRQ=y -CONFIG_INLINE_READ_LOCK_IRQSAVE=y -CONFIG_INLINE_READ_UNLOCK_BH=y -CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y -CONFIG_INLINE_SPIN_LOCK=y -CONFIG_INLINE_SPIN_LOCK_BH=y -CONFIG_INLINE_SPIN_LOCK_IRQ=y -CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y -CONFIG_INLINE_SPIN_TRYLOCK=y -CONFIG_INLINE_SPIN_TRYLOCK_BH=y -CONFIG_INLINE_SPIN_UNLOCK_BH=y -CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y -CONFIG_INLINE_WRITE_LOCK=y -CONFIG_INLINE_WRITE_LOCK_BH=y -CONFIG_INLINE_WRITE_LOCK_IRQ=y -CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y -CONFIG_INLINE_WRITE_UNLOCK_BH=y -CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y CONFIG_INPUT=y CONFIG_INPUT_MOUSEDEV=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set @@ -418,6 +280,7 @@ CONFIG_IRQ_WORK=y CONFIG_JBD2=y CONFIG_KEYS=y CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_ACTPWR=y CONFIG_LEDS_TRIGGER_INPUT=y CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y @@ -462,6 +325,7 @@ CONFIG_NEED_SG_DMA_LENGTH=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NLS=y CONFIG_NLS_ASCII=y +CONFIG_NOP_USB_XCEIV=y CONFIG_NO_HZ=y CONFIG_NO_HZ_COMMON=y CONFIG_NO_HZ_IDLE=y @@ -584,7 +448,9 @@ CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_COMMON=y CONFIG_USB_DWCOTG=y +CONFIG_USB_GADGET=y CONFIG_USB_PCI=y +CONFIG_USB_PHY=y CONFIG_USB_STORAGE=y CONFIG_USB_SUPPORT=y CONFIG_USB_UAS=y diff --git a/target/linux/bcm27xx/modules/sound.mk b/target/linux/bcm27xx/modules/sound.mk index 8c6f1bf49c..dab31d8132 100644 --- a/target/linux/bcm27xx/modules/sound.mk +++ b/target/linux/bcm27xx/modules/sound.mk @@ -133,6 +133,28 @@ endef $(eval $(call KernelPackage,sound-soc-allo-boss-dac)) +define KernelPackage/sound-soc-allo-boss2-dac + TITLE:=Support for Allo Boss2 DAC + KCONFIG:= \ + CONFIG_SND_AUDIO_GRAPH_CARD \ + CONFIG_SND_BCM2708_SOC_ALLO_BOSS2_DAC + FILES:= \ + $(LINUX_DIR)/sound/soc/bcm/snd-soc-allo-boss2-dac.ko + AUTOLOAD:=$(call AutoLoad,68,snd-soc-allo-boss2-dac) + DEPENDS:= \ + kmod-sound-soc-bcm2835-i2s \ + +kmod-i2c-bcm2835 \ + +kmod-regmap-i2c + $(call AddDepends/sound) +endef + +define KernelPackage/sound-soc-allo-boss2-dac/description + This package contains support for Allo Boss2 DAC +endef + +$(eval $(call KernelPackage,sound-soc-allo-boss2-dac)) + + define KernelPackage/sound-soc-allo-digione TITLE:=Support for Allo Piano DigiOne KCONFIG:= \ @@ -825,6 +847,28 @@ endef $(eval $(call KernelPackage,sound-soc-justboom-digi)) +define KernelPackage/sound-soc-pifi-40-amp + TITLE:=Support for PiFi-40 amp + KCONFIG:= \ + CONFIG_SND_BCM2708_SOC_PIFI_40 \ + CONFIG_SND_PIFI_40 \ + CONFIG_SND_SOC_TAS571X + FILES:= \ + $(LINUX_DIR)/sound/soc/bcm/snd-soc-pifi-40.ko \ + $(LINUX_DIR)/sound/soc/codecs/snd-soc-tas571x.ko + AUTOLOAD:=$(call AutoLoad,68,snd-soc-tas571x) + DEPENDS:= \ + kmod-sound-soc-bcm2835-i2s + $(call AddDepends/sound) +endef + +define KernelPackage/sound-soc-pifi-40-amp/description + This package contains support for PiFi-40 amp +endef + +$(eval $(call KernelPackage,sound-soc-pifi-40-amp)) + + define KernelPackage/sound-soc-pisound TITLE:=Support for Blokas Labs PiSound KCONFIG:= \ diff --git a/target/linux/bcm27xx/patches-5.4/950-0134-spi-spi-bcm2835-Disable-forced-software-CS.patch b/target/linux/bcm27xx/patches-5.4/950-0134-spi-spi-bcm2835-Disable-forced-software-CS.patch new file mode 100644 index 0000000000..0abe5059c0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0134-spi-spi-bcm2835-Disable-forced-software-CS.patch @@ -0,0 +1,47 @@ +From dc1e3fefce7abd7532fbc74e26df61a8ced1dcd6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 15 Jan 2019 12:41:15 +0000 +Subject: [PATCH] spi: spi-bcm2835: Disable forced software CS + +With GPIO CS used by the DTBs, allow hardware CS to be selected by an +overlay. + +Signed-off-by: Phil Elwell +--- + drivers/spi/spi-bcm2835.c | 37 ------------------------------------- + 1 file changed, 37 deletions(-) + +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -1230,31 +1230,6 @@ static int bcm2835_spi_setup(struct spi_ + return -EINVAL; + } + +- /* +- * Translate native CS to GPIO +- * +- * FIXME: poking around in the gpiolib internals like this is +- * not very good practice. Find a way to locate the real problem +- * and fix it. Why is the GPIO descriptor in spi->cs_gpiod +- * sometimes not assigned correctly? Erroneous device trees? +- */ +- +- /* get the gpio chip for the base */ +- chip = gpiochip_find("pinctrl-bcm2835", chip_match_name); +- if (!chip) +- return 0; +- +- spi->cs_gpiod = gpiochip_request_own_desc(chip, 8 - spi->chip_select, +- DRV_NAME, +- GPIO_LOOKUP_FLAGS_DEFAULT, +- GPIOD_OUT_LOW); +- if (IS_ERR(spi->cs_gpiod)) +- return PTR_ERR(spi->cs_gpiod); +- +- /* and set up the "mode" and level */ +- dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n", +- spi->chip_select); +- + return 0; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0134-spi-spi-bcm2835-Re-enable-HW-CS.patch b/target/linux/bcm27xx/patches-5.4/950-0134-spi-spi-bcm2835-Re-enable-HW-CS.patch deleted file mode 100644 index 13dd356f93..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0134-spi-spi-bcm2835-Re-enable-HW-CS.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 33b150a792ccde6eded4240dea0e3ec784b07d7c Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 15 Jan 2019 12:39:50 +0000 -Subject: [PATCH] spi: spi-bcm2835: Re-enable HW CS - -Signed-off-by: Phil Elwell ---- - drivers/spi/spi-bcm2835.c | 53 +++++++++++++++++++++++++++++++++++++-- - 1 file changed, 51 insertions(+), 2 deletions(-) - ---- a/drivers/spi/spi-bcm2835.c -+++ b/drivers/spi/spi-bcm2835.c -@@ -1169,9 +1169,57 @@ static void bcm2835_spi_handle_err(struc - bcm2835_spi_reset_hw(ctlr); - } - --static int chip_match_name(struct gpio_chip *chip, void *data) -+static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level) - { -- return !strcmp(chip->label, data); -+ /* -+ * we can assume that we are "native" as per spi_set_cs -+ * calling us ONLY when cs_gpio is not set -+ * we can also assume that we are CS < 3 as per bcm2835_spi_setup -+ * we would not get called because of error handling there. -+ * the level passed is the electrical level not enabled/disabled -+ * so it has to get translated back to enable/disable -+ * see spi_set_cs in spi.c for the implementation -+ */ -+ -+ struct spi_master *master = spi->master; -+ struct bcm2835_spi *bs = spi_master_get_devdata(master); -+ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); -+ bool enable; -+ -+ /* calculate the enable flag from the passed gpio_level */ -+ enable = (spi->mode & SPI_CS_HIGH) ? gpio_level : !gpio_level; -+ -+ /* set flags for "reverse" polarity in the registers */ -+ if (spi->mode & SPI_CS_HIGH) { -+ /* set the correct CS-bits */ -+ cs |= BCM2835_SPI_CS_CSPOL; -+ cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select; -+ } else { -+ /* clean the CS-bits */ -+ cs &= ~BCM2835_SPI_CS_CSPOL; -+ cs &= ~(BCM2835_SPI_CS_CSPOL0 << spi->chip_select); -+ } -+ -+ /* select the correct chip_select depending on disabled/enabled */ -+ if (enable) { -+ /* set cs correctly */ -+ if (spi->mode & SPI_NO_CS) { -+ /* use the "undefined" chip-select */ -+ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; -+ } else { -+ /* set the chip select */ -+ cs &= ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01); -+ cs |= spi->chip_select; -+ } -+ } else { -+ /* disable CSPOL which puts HW-CS into deselected state */ -+ cs &= ~BCM2835_SPI_CS_CSPOL; -+ /* use the "undefined" chip-select as precaution */ -+ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; -+ } -+ -+ /* finally set the calculated flags in SPI_CS */ -+ bcm2835_wr(bs, BCM2835_SPI_CS, cs); - } - - static int bcm2835_spi_setup(struct spi_device *spi) -@@ -1276,6 +1324,7 @@ static int bcm2835_spi_probe(struct plat - ctlr->bits_per_word_mask = SPI_BPW_MASK(8); - ctlr->num_chipselect = BCM2835_SPI_NUM_CS; - ctlr->setup = bcm2835_spi_setup; -+ ctlr->set_cs = bcm2835_spi_set_cs; - ctlr->transfer_one = bcm2835_spi_transfer_one; - ctlr->handle_err = bcm2835_spi_handle_err; - ctlr->prepare_message = bcm2835_spi_prepare_message; diff --git a/target/linux/bcm27xx/patches-5.4/950-0135-Added-driver-for-the-HiFiBerry-DAC-ADC-2694.patch b/target/linux/bcm27xx/patches-5.4/950-0135-Added-driver-for-the-HiFiBerry-DAC-ADC-2694.patch new file mode 100644 index 0000000000..cc379f55e1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0135-Added-driver-for-the-HiFiBerry-DAC-ADC-2694.patch @@ -0,0 +1,464 @@ +From b6eb457e794f8c48b7004cc88aa82889bcd5f8e6 Mon Sep 17 00:00:00 2001 +From: HiFiBerry +Date: Mon, 8 Oct 2018 18:10:12 +0200 +Subject: [PATCH] Added driver for the HiFiBerry DAC+ ADC (#2694) + +Signed-off-by: Daniel Matuschek + +hifiberry_dacplusadc: switch to snd_soc_dai_set_bclk_ratio + +Signed-off-by: Matthias Reichl + +ASoC: hifiberry_dacplusadc: fix DAI link setup + +The driver only defines a single DAI link and the code that tries +to setup the second (non-existent) DAI link looks wrong - using dmic +as a CPU/platform driver doesn't make any sense. + +The DT overlay doesn't define a dmic property, so the code was never +executed (otherwise it would have resulted in a memory corruption). + +So drop the offending code to prevent issues if a dmic property +should be added to the DT overlay. + +Signed-off-by: Matthias Reichl + +ASoC: hifiberry_dacplusadc: use modern dai_link style + +Signed-off-by: Matthias Reichl +--- + sound/soc/bcm/Kconfig | 9 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/hifiberry_dacplusadc.c | 390 +++++++++++++++++++++++++++ + 3 files changed, 401 insertions(+) + create mode 100644 sound/soc/bcm/hifiberry_dacplusadc.c + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -41,6 +41,15 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + help + Say Y or M if you want to add support for HifiBerry DAC+. + ++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC ++ tristate "Support for HifiBerry DAC+ADC" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_PCM512x_I2C ++ select SND_SOC_DMIC ++ select COMMON_CLK_HIFIBERRY_DACPRO ++ help ++ Say Y or M if you want to add support for HifiBerry DAC+ADC. ++ + config SND_BCM2708_SOC_HIFIBERRY_DIGI + tristate "Support for HifiBerry Digi" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo + + # BCM2708 Machine Support + snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o ++snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o + snd-soc-justboom-dac-objs := justboom-dac.o + snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-proto-objs := rpi-proto.o +@@ -35,6 +36,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi + + obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_dacplusadc.c +@@ -0,0 +1,390 @@ ++/* ++ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC ++ * ++ * Author: Daniel Matuschek, Stuart MacLean ++ * Copyright 2014-2015 ++ * based on code by Florian Meier ++ * ADC added by Joerg Schambacher ++ * Copyright 2018 ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/pcm512x.h" ++ ++#define HIFIBERRY_DACPRO_NOCLOCK 0 ++#define HIFIBERRY_DACPRO_CLK44EN 1 ++#define HIFIBERRY_DACPRO_CLK48EN 2 ++ ++struct platform_device *dmic_codec_dev; ++ ++struct pcm512x_priv { ++ struct regmap *regmap; ++ struct clk *sclk; ++}; ++ ++/* Clock rate of CLK44EN attached to GPIO6 pin */ ++#define CLK_44EN_RATE 22579200UL ++/* Clock rate of CLK48EN attached to GPIO3 pin */ ++#define CLK_48EN_RATE 24576000UL ++ ++static bool slave; ++static bool snd_rpi_hifiberry_is_dacpro; ++static bool digital_gain_0db_limit = true; ++ ++static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component, ++ int clk_id) ++{ ++ switch (clk_id) { ++ case HIFIBERRY_DACPRO_NOCLOCK: ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00); ++ break; ++ case HIFIBERRY_DACPRO_CLK44EN: ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20); ++ break; ++ case HIFIBERRY_DACPRO_CLK48EN: ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04); ++ break; ++ } ++} ++ ++static void snd_rpi_hifiberry_dacplusadc_clk_gpio(struct snd_soc_component *component) ++{ ++ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24); ++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02); ++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02); ++} ++ ++static bool snd_rpi_hifiberry_dacplusadc_is_sclk(struct snd_soc_component *component) ++{ ++ unsigned int sck; ++ ++ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck); ++ return (!(sck & 0x40)); ++} ++ ++static bool snd_rpi_hifiberry_dacplusadc_is_sclk_sleep( ++ struct snd_soc_component *component) ++{ ++ msleep(2); ++ return snd_rpi_hifiberry_dacplusadc_is_sclk(component); ++} ++ ++static bool snd_rpi_hifiberry_dacplusadc_is_pro_card(struct snd_soc_component *component) ++{ ++ bool isClk44EN, isClk48En, isNoClk; ++ ++ snd_rpi_hifiberry_dacplusadc_clk_gpio(component); ++ ++ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK44EN); ++ isClk44EN = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component); ++ ++ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK); ++ isNoClk = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component); ++ ++ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK48EN); ++ isClk48En = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component); ++ ++ return (isClk44EN && isClk48En && !isNoClk); ++} ++ ++static int snd_rpi_hifiberry_dacplusadc_clk_for_rate(int sample_rate) ++{ ++ int type; ++ ++ switch (sample_rate) { ++ case 11025: ++ case 22050: ++ case 44100: ++ case 88200: ++ case 176400: ++ case 352800: ++ type = HIFIBERRY_DACPRO_CLK44EN; ++ break; ++ default: ++ type = HIFIBERRY_DACPRO_CLK48EN; ++ break; ++ } ++ return type; ++} ++ ++static void snd_rpi_hifiberry_dacplusadc_set_sclk(struct snd_soc_component *component, ++ int sample_rate) ++{ ++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); ++ ++ if (!IS_ERR(pcm512x->sclk)) { ++ int ctype; ++ ++ ctype = snd_rpi_hifiberry_dacplusadc_clk_for_rate(sample_rate); ++ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN) ++ ? CLK_44EN_RATE : CLK_48EN_RATE); ++ snd_rpi_hifiberry_dacplusadc_select_clk(component, ctype); ++ } ++} ++ ++static int snd_rpi_hifiberry_dacplusadc_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_component *component = rtd->codec_dai->component; ++ struct pcm512x_priv *priv; ++ ++ if (slave) ++ snd_rpi_hifiberry_is_dacpro = false; ++ else ++ snd_rpi_hifiberry_is_dacpro = ++ snd_rpi_hifiberry_dacplusadc_is_pro_card(component); ++ ++ if (snd_rpi_hifiberry_is_dacpro) { ++ struct snd_soc_dai_link *dai = rtd->dai_link; ++ ++ dai->name = "HiFiBerry ADCDAC+ Pro"; ++ dai->stream_name = "HiFiBerry ADCDAC+ Pro HiFi"; ++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM; ++ ++ snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11); ++ snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03); ++ snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63); ++ } else { ++ priv = snd_soc_component_get_drvdata(component); ++ priv->sclk = ERR_PTR(-ENOENT); ++ } ++ ++ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08); ++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ ++ if (digital_gain_0db_limit) { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ ++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_dacplusadc_update_rate_den( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *component = rtd->codec_dai->component; ++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); ++ struct snd_ratnum *rats_no_pll; ++ unsigned int num = 0, den = 0; ++ int err; ++ ++ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL); ++ if (!rats_no_pll) ++ return -ENOMEM; ++ ++ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64; ++ rats_no_pll->den_min = 1; ++ rats_no_pll->den_max = 128; ++ rats_no_pll->den_step = 1; ++ ++ err = snd_interval_ratnum(hw_param_interval(params, ++ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den); ++ if (err >= 0 && den) { ++ params->rate_num = num; ++ params->rate_den = den; ++ } ++ ++ devm_kfree(rtd->dev, rats_no_pll); ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_dacplusadc_hw_params( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ int ret = 0; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ int channels = params_channels(params); ++ int width = 32; ++ ++ if (snd_rpi_hifiberry_is_dacpro) { ++ struct snd_soc_component *component = rtd->codec_dai->component; ++ ++ width = snd_pcm_format_physical_width(params_format(params)); ++ ++ snd_rpi_hifiberry_dacplusadc_set_sclk(component, ++ params_rate(params)); ++ ++ ret = snd_rpi_hifiberry_dacplusadc_update_rate_den( ++ substream, params); ++ } ++ ++ ret = snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, channels * width); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_bclk_ratio(rtd->codec_dai, channels * width); ++ return ret; ++} ++ ++static int hifiberry_dacplusadc_LED_cnt; ++ ++static int snd_rpi_hifiberry_dacplusadc_startup( ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *component = rtd->codec_dai->component; ++ ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, ++ 0x08, 0x08); ++ hifiberry_dacplusadc_LED_cnt++; ++ return 0; ++} ++ ++static void snd_rpi_hifiberry_dacplusadc_shutdown( ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *component = rtd->codec_dai->component; ++ ++ hifiberry_dacplusadc_LED_cnt--; ++ if (!hifiberry_dacplusadc_LED_cnt) ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, ++ 0x08, 0x00); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_hifiberry_dacplusadc_ops = { ++ .hw_params = snd_rpi_hifiberry_dacplusadc_hw_params, ++ .startup = snd_rpi_hifiberry_dacplusadc_startup, ++ .shutdown = snd_rpi_hifiberry_dacplusadc_shutdown, ++}; ++ ++SND_SOC_DAILINK_DEFS(hifi, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"), ++ COMP_CODEC("dmic-codec", "dmic-hifi")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); ++ ++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadc_dai[] = { ++{ ++ .name = "HiFiBerry DAC+ADC", ++ .stream_name = "HiFiBerry DAC+ADC HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_hifiberry_dacplusadc_ops, ++ .init = snd_rpi_hifiberry_dacplusadc_init, ++ SND_SOC_DAILINK_REG(hifi), ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_hifiberry_dacplusadc = { ++ .name = "snd_rpi_hifiberry_dacplusadc", ++ .driver_name = "HifiberryDacpAdc", ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_hifiberry_dacplusadc_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadc_dai), ++}; ++ ++ ++static int snd_rpi_hifiberry_dacplusadc_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_hifiberry_dacplusadc.dev = &pdev->dev; ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai; ++ ++ dai = &snd_rpi_hifiberry_dacplusadc_dai[0]; ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->of_node = i2s_node; ++ dai->cpus->dai_name = NULL; ++ dai->platforms->name = NULL; ++ } ++ } ++ digital_gain_0db_limit = !of_property_read_bool( ++ pdev->dev.of_node, "hifiberry,24db_digital_gain"); ++ slave = of_property_read_bool(pdev->dev.of_node, ++ "hifiberry-dacplusadc,slave"); ++ ++ ret = devm_snd_soc_register_card(&pdev->dev, ++ &snd_rpi_hifiberry_dacplusadc); ++ if (ret && ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static const struct of_device_id snd_rpi_hifiberry_dacplusadc_of_match[] = { ++ { .compatible = "hifiberry,hifiberry-dacplusadc", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadc_of_match); ++ ++static struct platform_driver snd_rpi_hifiberry_dacplusadc_driver = { ++ .driver = { ++ .name = "snd-rpi-hifiberry-dacplusadc", ++ .owner = THIS_MODULE, ++ .of_match_table = snd_rpi_hifiberry_dacplusadc_of_match, ++ }, ++ .probe = snd_rpi_hifiberry_dacplusadc_probe, ++}; ++ ++static int __init hifiberry_dacplusadc_init(void) ++{ ++ int ret; ++ ++ dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL, ++ 0); ++ if (IS_ERR(dmic_codec_dev)) { ++ pr_err("%s: dmic-codec device registration failed\n", __func__); ++ return PTR_ERR(dmic_codec_dev); ++ } ++ ++ ret = platform_driver_register(&snd_rpi_hifiberry_dacplusadc_driver); ++ if (ret) { ++ pr_err("%s: platform driver registration failed\n", __func__); ++ platform_device_unregister(dmic_codec_dev); ++ } ++ ++ return ret; ++} ++module_init(hifiberry_dacplusadc_init); ++ ++static void __exit hifiberry_dacplusadc_exit(void) ++{ ++ platform_driver_unregister(&snd_rpi_hifiberry_dacplusadc_driver); ++ platform_device_unregister(dmic_codec_dev); ++} ++module_exit(hifiberry_dacplusadc_exit); ++ ++MODULE_AUTHOR("Joerg Schambacher "); ++MODULE_AUTHOR("Daniel Matuschek "); ++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0135-spi-spi-bcm2835-Disable-forced-software-CS.patch b/target/linux/bcm27xx/patches-5.4/950-0135-spi-spi-bcm2835-Disable-forced-software-CS.patch deleted file mode 100644 index 752464087f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0135-spi-spi-bcm2835-Disable-forced-software-CS.patch +++ /dev/null @@ -1,47 +0,0 @@ -From dc1e3fefce7abd7532fbc74e26df61a8ced1dcd6 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 15 Jan 2019 12:41:15 +0000 -Subject: [PATCH] spi: spi-bcm2835: Disable forced software CS - -With GPIO CS used by the DTBs, allow hardware CS to be selected by an -overlay. - -Signed-off-by: Phil Elwell ---- - drivers/spi/spi-bcm2835.c | 37 ------------------------------------- - 1 file changed, 37 deletions(-) - ---- a/drivers/spi/spi-bcm2835.c -+++ b/drivers/spi/spi-bcm2835.c -@@ -1278,31 +1278,6 @@ static int bcm2835_spi_setup(struct spi_ - return -EINVAL; - } - -- /* -- * Translate native CS to GPIO -- * -- * FIXME: poking around in the gpiolib internals like this is -- * not very good practice. Find a way to locate the real problem -- * and fix it. Why is the GPIO descriptor in spi->cs_gpiod -- * sometimes not assigned correctly? Erroneous device trees? -- */ -- -- /* get the gpio chip for the base */ -- chip = gpiochip_find("pinctrl-bcm2835", chip_match_name); -- if (!chip) -- return 0; -- -- spi->cs_gpiod = gpiochip_request_own_desc(chip, 8 - spi->chip_select, -- DRV_NAME, -- GPIO_LOOKUP_FLAGS_DEFAULT, -- GPIOD_OUT_LOW); -- if (IS_ERR(spi->cs_gpiod)) -- return PTR_ERR(spi->cs_gpiod); -- -- /* and set up the "mode" and level */ -- dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n", -- spi->chip_select); -- - return 0; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0136-Added-driver-for-the-HiFiBerry-DAC-ADC-2694.patch b/target/linux/bcm27xx/patches-5.4/950-0136-Added-driver-for-the-HiFiBerry-DAC-ADC-2694.patch deleted file mode 100644 index cc379f55e1..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0136-Added-driver-for-the-HiFiBerry-DAC-ADC-2694.patch +++ /dev/null @@ -1,464 +0,0 @@ -From b6eb457e794f8c48b7004cc88aa82889bcd5f8e6 Mon Sep 17 00:00:00 2001 -From: HiFiBerry -Date: Mon, 8 Oct 2018 18:10:12 +0200 -Subject: [PATCH] Added driver for the HiFiBerry DAC+ ADC (#2694) - -Signed-off-by: Daniel Matuschek - -hifiberry_dacplusadc: switch to snd_soc_dai_set_bclk_ratio - -Signed-off-by: Matthias Reichl - -ASoC: hifiberry_dacplusadc: fix DAI link setup - -The driver only defines a single DAI link and the code that tries -to setup the second (non-existent) DAI link looks wrong - using dmic -as a CPU/platform driver doesn't make any sense. - -The DT overlay doesn't define a dmic property, so the code was never -executed (otherwise it would have resulted in a memory corruption). - -So drop the offending code to prevent issues if a dmic property -should be added to the DT overlay. - -Signed-off-by: Matthias Reichl - -ASoC: hifiberry_dacplusadc: use modern dai_link style - -Signed-off-by: Matthias Reichl ---- - sound/soc/bcm/Kconfig | 9 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/hifiberry_dacplusadc.c | 390 +++++++++++++++++++++++++++ - 3 files changed, 401 insertions(+) - create mode 100644 sound/soc/bcm/hifiberry_dacplusadc.c - ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -41,6 +41,15 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - help - Say Y or M if you want to add support for HifiBerry DAC+. - -+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC -+ tristate "Support for HifiBerry DAC+ADC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_PCM512x_I2C -+ select SND_SOC_DMIC -+ select COMMON_CLK_HIFIBERRY_DACPRO -+ help -+ Say Y or M if you want to add support for HifiBerry DAC+ADC. -+ - config SND_BCM2708_SOC_HIFIBERRY_DIGI - tristate "Support for HifiBerry Digi" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo - - # BCM2708 Machine Support - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o -+snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o - snd-soc-justboom-dac-objs := justboom-dac.o - snd-soc-rpi-cirrus-objs := rpi-cirrus.o - snd-soc-rpi-proto-objs := rpi-proto.o -@@ -35,6 +36,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi - - obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o - obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o ---- /dev/null -+++ b/sound/soc/bcm/hifiberry_dacplusadc.c -@@ -0,0 +1,390 @@ -+/* -+ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC -+ * -+ * Author: Daniel Matuschek, Stuart MacLean -+ * Copyright 2014-2015 -+ * based on code by Florian Meier -+ * ADC added by Joerg Schambacher -+ * Copyright 2018 -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "../codecs/pcm512x.h" -+ -+#define HIFIBERRY_DACPRO_NOCLOCK 0 -+#define HIFIBERRY_DACPRO_CLK44EN 1 -+#define HIFIBERRY_DACPRO_CLK48EN 2 -+ -+struct platform_device *dmic_codec_dev; -+ -+struct pcm512x_priv { -+ struct regmap *regmap; -+ struct clk *sclk; -+}; -+ -+/* Clock rate of CLK44EN attached to GPIO6 pin */ -+#define CLK_44EN_RATE 22579200UL -+/* Clock rate of CLK48EN attached to GPIO3 pin */ -+#define CLK_48EN_RATE 24576000UL -+ -+static bool slave; -+static bool snd_rpi_hifiberry_is_dacpro; -+static bool digital_gain_0db_limit = true; -+ -+static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component, -+ int clk_id) -+{ -+ switch (clk_id) { -+ case HIFIBERRY_DACPRO_NOCLOCK: -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00); -+ break; -+ case HIFIBERRY_DACPRO_CLK44EN: -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20); -+ break; -+ case HIFIBERRY_DACPRO_CLK48EN: -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04); -+ break; -+ } -+} -+ -+static void snd_rpi_hifiberry_dacplusadc_clk_gpio(struct snd_soc_component *component) -+{ -+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24); -+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02); -+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02); -+} -+ -+static bool snd_rpi_hifiberry_dacplusadc_is_sclk(struct snd_soc_component *component) -+{ -+ unsigned int sck; -+ -+ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck); -+ return (!(sck & 0x40)); -+} -+ -+static bool snd_rpi_hifiberry_dacplusadc_is_sclk_sleep( -+ struct snd_soc_component *component) -+{ -+ msleep(2); -+ return snd_rpi_hifiberry_dacplusadc_is_sclk(component); -+} -+ -+static bool snd_rpi_hifiberry_dacplusadc_is_pro_card(struct snd_soc_component *component) -+{ -+ bool isClk44EN, isClk48En, isNoClk; -+ -+ snd_rpi_hifiberry_dacplusadc_clk_gpio(component); -+ -+ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK44EN); -+ isClk44EN = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component); -+ -+ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK); -+ isNoClk = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component); -+ -+ snd_rpi_hifiberry_dacplusadc_select_clk(component, HIFIBERRY_DACPRO_CLK48EN); -+ isClk48En = snd_rpi_hifiberry_dacplusadc_is_sclk_sleep(component); -+ -+ return (isClk44EN && isClk48En && !isNoClk); -+} -+ -+static int snd_rpi_hifiberry_dacplusadc_clk_for_rate(int sample_rate) -+{ -+ int type; -+ -+ switch (sample_rate) { -+ case 11025: -+ case 22050: -+ case 44100: -+ case 88200: -+ case 176400: -+ case 352800: -+ type = HIFIBERRY_DACPRO_CLK44EN; -+ break; -+ default: -+ type = HIFIBERRY_DACPRO_CLK48EN; -+ break; -+ } -+ return type; -+} -+ -+static void snd_rpi_hifiberry_dacplusadc_set_sclk(struct snd_soc_component *component, -+ int sample_rate) -+{ -+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); -+ -+ if (!IS_ERR(pcm512x->sclk)) { -+ int ctype; -+ -+ ctype = snd_rpi_hifiberry_dacplusadc_clk_for_rate(sample_rate); -+ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN) -+ ? CLK_44EN_RATE : CLK_48EN_RATE); -+ snd_rpi_hifiberry_dacplusadc_select_clk(component, ctype); -+ } -+} -+ -+static int snd_rpi_hifiberry_dacplusadc_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ struct pcm512x_priv *priv; -+ -+ if (slave) -+ snd_rpi_hifiberry_is_dacpro = false; -+ else -+ snd_rpi_hifiberry_is_dacpro = -+ snd_rpi_hifiberry_dacplusadc_is_pro_card(component); -+ -+ if (snd_rpi_hifiberry_is_dacpro) { -+ struct snd_soc_dai_link *dai = rtd->dai_link; -+ -+ dai->name = "HiFiBerry ADCDAC+ Pro"; -+ dai->stream_name = "HiFiBerry ADCDAC+ Pro HiFi"; -+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM; -+ -+ snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11); -+ snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03); -+ snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63); -+ } else { -+ priv = snd_soc_component_get_drvdata(component); -+ priv->sclk = ERR_PTR(-ENOENT); -+ } -+ -+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08); -+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ -+ if (digital_gain_0db_limit) { -+ int ret; -+ struct snd_soc_card *card = rtd->card; -+ -+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207); -+ if (ret < 0) -+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); -+ } -+ -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_dacplusadc_update_rate_den( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); -+ struct snd_ratnum *rats_no_pll; -+ unsigned int num = 0, den = 0; -+ int err; -+ -+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL); -+ if (!rats_no_pll) -+ return -ENOMEM; -+ -+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64; -+ rats_no_pll->den_min = 1; -+ rats_no_pll->den_max = 128; -+ rats_no_pll->den_step = 1; -+ -+ err = snd_interval_ratnum(hw_param_interval(params, -+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den); -+ if (err >= 0 && den) { -+ params->rate_num = num; -+ params->rate_den = den; -+ } -+ -+ devm_kfree(rtd->dev, rats_no_pll); -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_dacplusadc_hw_params( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) -+{ -+ int ret = 0; -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ int channels = params_channels(params); -+ int width = 32; -+ -+ if (snd_rpi_hifiberry_is_dacpro) { -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ -+ width = snd_pcm_format_physical_width(params_format(params)); -+ -+ snd_rpi_hifiberry_dacplusadc_set_sclk(component, -+ params_rate(params)); -+ -+ ret = snd_rpi_hifiberry_dacplusadc_update_rate_den( -+ substream, params); -+ } -+ -+ ret = snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, channels * width); -+ if (ret) -+ return ret; -+ ret = snd_soc_dai_set_bclk_ratio(rtd->codec_dai, channels * width); -+ return ret; -+} -+ -+static int hifiberry_dacplusadc_LED_cnt; -+ -+static int snd_rpi_hifiberry_dacplusadc_startup( -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, -+ 0x08, 0x08); -+ hifiberry_dacplusadc_LED_cnt++; -+ return 0; -+} -+ -+static void snd_rpi_hifiberry_dacplusadc_shutdown( -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ -+ hifiberry_dacplusadc_LED_cnt--; -+ if (!hifiberry_dacplusadc_LED_cnt) -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, -+ 0x08, 0x00); -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_hifiberry_dacplusadc_ops = { -+ .hw_params = snd_rpi_hifiberry_dacplusadc_hw_params, -+ .startup = snd_rpi_hifiberry_dacplusadc_startup, -+ .shutdown = snd_rpi_hifiberry_dacplusadc_shutdown, -+}; -+ -+SND_SOC_DAILINK_DEFS(hifi, -+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), -+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"), -+ COMP_CODEC("dmic-codec", "dmic-hifi")), -+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); -+ -+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadc_dai[] = { -+{ -+ .name = "HiFiBerry DAC+ADC", -+ .stream_name = "HiFiBerry DAC+ADC HiFi", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_hifiberry_dacplusadc_ops, -+ .init = snd_rpi_hifiberry_dacplusadc_init, -+ SND_SOC_DAILINK_REG(hifi), -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_hifiberry_dacplusadc = { -+ .name = "snd_rpi_hifiberry_dacplusadc", -+ .driver_name = "HifiberryDacpAdc", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_hifiberry_dacplusadc_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadc_dai), -+}; -+ -+ -+static int snd_rpi_hifiberry_dacplusadc_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_hifiberry_dacplusadc.dev = &pdev->dev; -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai; -+ -+ dai = &snd_rpi_hifiberry_dacplusadc_dai[0]; -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ if (i2s_node) { -+ dai->cpus->of_node = i2s_node; -+ dai->platforms->of_node = i2s_node; -+ dai->cpus->dai_name = NULL; -+ dai->platforms->name = NULL; -+ } -+ } -+ digital_gain_0db_limit = !of_property_read_bool( -+ pdev->dev.of_node, "hifiberry,24db_digital_gain"); -+ slave = of_property_read_bool(pdev->dev.of_node, -+ "hifiberry-dacplusadc,slave"); -+ -+ ret = devm_snd_soc_register_card(&pdev->dev, -+ &snd_rpi_hifiberry_dacplusadc); -+ if (ret && ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ -+ return ret; -+} -+ -+static const struct of_device_id snd_rpi_hifiberry_dacplusadc_of_match[] = { -+ { .compatible = "hifiberry,hifiberry-dacplusadc", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadc_of_match); -+ -+static struct platform_driver snd_rpi_hifiberry_dacplusadc_driver = { -+ .driver = { -+ .name = "snd-rpi-hifiberry-dacplusadc", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_hifiberry_dacplusadc_of_match, -+ }, -+ .probe = snd_rpi_hifiberry_dacplusadc_probe, -+}; -+ -+static int __init hifiberry_dacplusadc_init(void) -+{ -+ int ret; -+ -+ dmic_codec_dev = platform_device_register_simple("dmic-codec", -1, NULL, -+ 0); -+ if (IS_ERR(dmic_codec_dev)) { -+ pr_err("%s: dmic-codec device registration failed\n", __func__); -+ return PTR_ERR(dmic_codec_dev); -+ } -+ -+ ret = platform_driver_register(&snd_rpi_hifiberry_dacplusadc_driver); -+ if (ret) { -+ pr_err("%s: platform driver registration failed\n", __func__); -+ platform_device_unregister(dmic_codec_dev); -+ } -+ -+ return ret; -+} -+module_init(hifiberry_dacplusadc_init); -+ -+static void __exit hifiberry_dacplusadc_exit(void) -+{ -+ platform_driver_unregister(&snd_rpi_hifiberry_dacplusadc_driver); -+ platform_device_unregister(dmic_codec_dev); -+} -+module_exit(hifiberry_dacplusadc_exit); -+ -+MODULE_AUTHOR("Joerg Schambacher "); -+MODULE_AUTHOR("Daniel Matuschek "); -+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0136-configs-Enable-the-AD193x-codecs.patch b/target/linux/bcm27xx/patches-5.4/950-0136-configs-Enable-the-AD193x-codecs.patch new file mode 100644 index 0000000000..bbf7c5a634 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0136-configs-Enable-the-AD193x-codecs.patch @@ -0,0 +1,28 @@ +From 222008f7786438cc6be8c51fc330b69f910cb933 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 7 Feb 2019 18:16:25 +0000 +Subject: [PATCH] configs: Enable the AD193x codecs + +See: https://github.com/raspberrypi/linux/issues/2850 + +Signed-off-by: Phil Elwell +--- + sound/soc/codecs/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -320,11 +320,11 @@ config SND_SOC_AD193X + tristate + + config SND_SOC_AD193X_SPI +- tristate ++ tristate "Analog Devices AU193X CODEC - SPI" + select SND_SOC_AD193X + + config SND_SOC_AD193X_I2C +- tristate ++ tristate "Analog Devices AU193X CODEC - I2C" + select SND_SOC_AD193X + + config SND_SOC_AD1980 diff --git a/target/linux/bcm27xx/patches-5.4/950-0137-configs-Enable-the-AD193x-codecs.patch b/target/linux/bcm27xx/patches-5.4/950-0137-configs-Enable-the-AD193x-codecs.patch deleted file mode 100644 index bbf7c5a634..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0137-configs-Enable-the-AD193x-codecs.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 222008f7786438cc6be8c51fc330b69f910cb933 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 7 Feb 2019 18:16:25 +0000 -Subject: [PATCH] configs: Enable the AD193x codecs - -See: https://github.com/raspberrypi/linux/issues/2850 - -Signed-off-by: Phil Elwell ---- - sound/soc/codecs/Kconfig | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -320,11 +320,11 @@ config SND_SOC_AD193X - tristate - - config SND_SOC_AD193X_SPI -- tristate -+ tristate "Analog Devices AU193X CODEC - SPI" - select SND_SOC_AD193X - - config SND_SOC_AD193X_I2C -- tristate -+ tristate "Analog Devices AU193X CODEC - I2C" - select SND_SOC_AD193X - - config SND_SOC_AD1980 diff --git a/target/linux/bcm27xx/patches-5.4/950-0137-lan78xx-EEE-support-is-now-a-PHY-property.patch b/target/linux/bcm27xx/patches-5.4/950-0137-lan78xx-EEE-support-is-now-a-PHY-property.patch new file mode 100644 index 0000000000..2778f40a94 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0137-lan78xx-EEE-support-is-now-a-PHY-property.patch @@ -0,0 +1,26 @@ +From d6e7ddb03b509147af9d21b0d544f76f014e4b92 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 5 Mar 2019 09:51:22 +0000 +Subject: [PATCH] lan78xx: EEE support is now a PHY property + +Now that EEE support is a property of the PHY, use the PHY's DT node +when querying the EEE-related properties. + +See: https://github.com/raspberrypi/linux/issues/2882 + +Signed-off-by: Phil Elwell +--- + drivers/net/usb/lan78xx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/usb/lan78xx.c ++++ b/drivers/net/usb/lan78xx.c +@@ -2180,7 +2180,7 @@ static int lan78xx_phy_init(struct lan78 + mii_adv_to_linkmode_adv_t(fc, mii_adv); + linkmode_or(phydev->advertising, fc, phydev->advertising); + +- if (of_property_read_bool(dev->udev->dev.of_node, ++ if (of_property_read_bool(phydev->mdio.dev.of_node, + "microchip,eee-enabled")) { + struct ethtool_eee edata; + memset(&edata, 0, sizeof(edata)); diff --git a/target/linux/bcm27xx/patches-5.4/950-0138-Revert-staging-vchiq-delete-vchiq_killable.h.patch b/target/linux/bcm27xx/patches-5.4/950-0138-Revert-staging-vchiq-delete-vchiq_killable.h.patch new file mode 100644 index 0000000000..0e314ec396 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0138-Revert-staging-vchiq-delete-vchiq_killable.h.patch @@ -0,0 +1,124 @@ +From 74204b27dbadce0bbf1e9bf58db7cac813a14dc6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 6 Mar 2019 16:28:09 +0000 +Subject: [PATCH] Revert "staging: vchiq: delete vchiq_killable.h" + +This reverts commit 2da56630b1cc422f58408033102b8f91ae97bc91. +--- + .../interface/vchiq_arm/vchiq_2835_arm.c | 1 + + .../interface/vchiq_arm/vchiq_arm.c | 1 + + .../interface/vchiq_arm/vchiq_connected.c | 1 + + .../interface/vchiq_arm/vchiq_core.c | 1 + + .../interface/vchiq_arm/vchiq_killable.h | 55 +++++++++++++++++++ + .../interface/vchiq_arm/vchiq_util.c | 1 + + 6 files changed, 60 insertions(+) + create mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +@@ -19,6 +19,7 @@ + + #include "vchiq_arm.h" + #include "vchiq_connected.h" ++#include "vchiq_killable.h" + #include "vchiq_pagelist.h" + + #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2) +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -28,6 +28,7 @@ + #include "vchiq_ioctl.h" + #include "vchiq_arm.h" + #include "vchiq_debugfs.h" ++#include "vchiq_killable.h" + + #define DEVICE_NAME "vchiq" + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c +@@ -3,6 +3,7 @@ + + #include "vchiq_connected.h" + #include "vchiq_core.h" ++#include "vchiq_killable.h" + #include + #include + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +@@ -2,6 +2,7 @@ + /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ + + #include "vchiq_core.h" ++#include "vchiq_killable.h" + + #define VCHIQ_SLOT_HANDLER_STACK 8192 + +--- /dev/null ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h +@@ -0,0 +1,55 @@ ++/** ++ * Copyright (c) 2010-2012 Broadcom. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2, as published by the Free ++ * Software Foundation. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef VCHIQ_KILLABLE_H ++#define VCHIQ_KILLABLE_H ++ ++#include ++#include ++ ++#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTRAP) | sigmask(SIGSTOP) | sigmask(SIGCONT)) ++ ++static inline int __must_check down_interruptible_killable(struct semaphore *sem) ++{ ++ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */ ++ int ret; ++ sigset_t blocked, oldset; ++ siginitsetinv(&blocked, SHUTDOWN_SIGS); ++ sigprocmask(SIG_SETMASK, &blocked, &oldset); ++ ret = down_interruptible(sem); ++ sigprocmask(SIG_SETMASK, &oldset, NULL); ++ return ret; ++} ++#define down_interruptible down_interruptible_killable ++ ++#endif +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c +@@ -2,6 +2,7 @@ + /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ + + #include "vchiq_util.h" ++#include "vchiq_killable.h" + + static inline int is_pow2(int i) + { diff --git a/target/linux/bcm27xx/patches-5.4/950-0138-lan78xx-EEE-support-is-now-a-PHY-property.patch b/target/linux/bcm27xx/patches-5.4/950-0138-lan78xx-EEE-support-is-now-a-PHY-property.patch deleted file mode 100644 index 2778f40a94..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0138-lan78xx-EEE-support-is-now-a-PHY-property.patch +++ /dev/null @@ -1,26 +0,0 @@ -From d6e7ddb03b509147af9d21b0d544f76f014e4b92 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 5 Mar 2019 09:51:22 +0000 -Subject: [PATCH] lan78xx: EEE support is now a PHY property - -Now that EEE support is a property of the PHY, use the PHY's DT node -when querying the EEE-related properties. - -See: https://github.com/raspberrypi/linux/issues/2882 - -Signed-off-by: Phil Elwell ---- - drivers/net/usb/lan78xx.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/usb/lan78xx.c -+++ b/drivers/net/usb/lan78xx.c -@@ -2180,7 +2180,7 @@ static int lan78xx_phy_init(struct lan78 - mii_adv_to_linkmode_adv_t(fc, mii_adv); - linkmode_or(phydev->advertising, fc, phydev->advertising); - -- if (of_property_read_bool(dev->udev->dev.of_node, -+ if (of_property_read_bool(phydev->mdio.dev.of_node, - "microchip,eee-enabled")) { - struct ethtool_eee edata; - memset(&edata, 0, sizeof(edata)); diff --git a/target/linux/bcm27xx/patches-5.4/950-0139-Revert-staging-bcm2835-audio-Drop-DT-dependency.patch b/target/linux/bcm27xx/patches-5.4/950-0139-Revert-staging-bcm2835-audio-Drop-DT-dependency.patch new file mode 100644 index 0000000000..09bfb7acad --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0139-Revert-staging-bcm2835-audio-Drop-DT-dependency.patch @@ -0,0 +1,96 @@ +From 6259d03df45a2fd245f6799a83a491edad07c80d Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 15 Mar 2019 21:11:10 +0000 +Subject: [PATCH] Revert "staging: bcm2835-audio: Drop DT dependency" + +This reverts commit b7491a9fca2dc2535b9dc922550a37c5baae9d3d. +--- + .../vc04_services/bcm2835-audio/bcm2835.c | 31 +++++++++++++------ + 1 file changed, 22 insertions(+), 9 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c ++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c +@@ -6,13 +6,13 @@ + #include + #include + #include ++#include + + #include "bcm2835.h" + + static bool enable_hdmi; + static bool enable_headphones; + static bool enable_compat_alsa = true; +-static int num_channels = MAX_SUBSTREAMS; + + module_param(enable_hdmi, bool, 0444); + MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device"); +@@ -21,8 +21,6 @@ MODULE_PARM_DESC(enable_headphones, "Ena + module_param(enable_compat_alsa, bool, 0444); + MODULE_PARM_DESC(enable_compat_alsa, + "Enables ALSA compatibility virtual audio device"); +-module_param(num_channels, int, 0644); +-MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)"); + + static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res) + { +@@ -296,19 +294,28 @@ static int snd_add_child_devices(struct + static int snd_bcm2835_alsa_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ u32 numchans; + int err; + +- if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) { +- num_channels = MAX_SUBSTREAMS; +- dev_warn(dev, "Illegal num_channels value, will use %u\n", +- num_channels); ++ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels", ++ &numchans); ++ if (err) { ++ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'"); ++ return err; ++ } ++ ++ if (numchans == 0 || numchans > MAX_SUBSTREAMS) { ++ numchans = MAX_SUBSTREAMS; ++ dev_warn(dev, ++ "Illegal 'brcm,pwm-channels' value, will use %u\n", ++ numchans); + } + + err = bcm2835_devm_add_vchi_ctx(dev); + if (err) + return err; + +- err = snd_add_child_devices(dev, num_channels); ++ err = snd_add_child_devices(dev, numchans); + if (err) + return err; + +@@ -330,6 +337,12 @@ static int snd_bcm2835_alsa_resume(struc + + #endif + ++static const struct of_device_id snd_bcm2835_of_match_table[] = { ++ { .compatible = "brcm,bcm2835-audio",}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table); ++ + static struct platform_driver bcm2835_alsa_driver = { + .probe = snd_bcm2835_alsa_probe, + #ifdef CONFIG_PM +@@ -338,6 +351,7 @@ static struct platform_driver bcm2835_al + #endif + .driver = { + .name = "bcm2835_audio", ++ .of_match_table = snd_bcm2835_of_match_table, + }, + }; + module_platform_driver(bcm2835_alsa_driver); +@@ -345,4 +359,3 @@ module_platform_driver(bcm2835_alsa_driv + MODULE_AUTHOR("Dom Cobley"); + MODULE_DESCRIPTION("Alsa driver for BCM2835 chip"); + MODULE_LICENSE("GPL"); +-MODULE_ALIAS("platform:bcm2835_audio"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0139-Revert-staging-vchiq-delete-vchiq_killable.h.patch b/target/linux/bcm27xx/patches-5.4/950-0139-Revert-staging-vchiq-delete-vchiq_killable.h.patch deleted file mode 100644 index 0e314ec396..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0139-Revert-staging-vchiq-delete-vchiq_killable.h.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 74204b27dbadce0bbf1e9bf58db7cac813a14dc6 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 6 Mar 2019 16:28:09 +0000 -Subject: [PATCH] Revert "staging: vchiq: delete vchiq_killable.h" - -This reverts commit 2da56630b1cc422f58408033102b8f91ae97bc91. ---- - .../interface/vchiq_arm/vchiq_2835_arm.c | 1 + - .../interface/vchiq_arm/vchiq_arm.c | 1 + - .../interface/vchiq_arm/vchiq_connected.c | 1 + - .../interface/vchiq_arm/vchiq_core.c | 1 + - .../interface/vchiq_arm/vchiq_killable.h | 55 +++++++++++++++++++ - .../interface/vchiq_arm/vchiq_util.c | 1 + - 6 files changed, 60 insertions(+) - create mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -@@ -19,6 +19,7 @@ - - #include "vchiq_arm.h" - #include "vchiq_connected.h" -+#include "vchiq_killable.h" - #include "vchiq_pagelist.h" - - #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2) ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -28,6 +28,7 @@ - #include "vchiq_ioctl.h" - #include "vchiq_arm.h" - #include "vchiq_debugfs.h" -+#include "vchiq_killable.h" - - #define DEVICE_NAME "vchiq" - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c -@@ -3,6 +3,7 @@ - - #include "vchiq_connected.h" - #include "vchiq_core.h" -+#include "vchiq_killable.h" - #include - #include - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c -@@ -2,6 +2,7 @@ - /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - - #include "vchiq_core.h" -+#include "vchiq_killable.h" - - #define VCHIQ_SLOT_HANDLER_STACK 8192 - ---- /dev/null -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_killable.h -@@ -0,0 +1,55 @@ -+/** -+ * Copyright (c) 2010-2012 Broadcom. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions, and the following disclaimer, -+ * without modification. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The names of the above-listed copyright holders may not be used -+ * to endorse or promote products derived from this software without -+ * specific prior written permission. -+ * -+ * ALTERNATIVELY, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2, as published by the Free -+ * Software Foundation. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#ifndef VCHIQ_KILLABLE_H -+#define VCHIQ_KILLABLE_H -+ -+#include -+#include -+ -+#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTRAP) | sigmask(SIGSTOP) | sigmask(SIGCONT)) -+ -+static inline int __must_check down_interruptible_killable(struct semaphore *sem) -+{ -+ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */ -+ int ret; -+ sigset_t blocked, oldset; -+ siginitsetinv(&blocked, SHUTDOWN_SIGS); -+ sigprocmask(SIG_SETMASK, &blocked, &oldset); -+ ret = down_interruptible(sem); -+ sigprocmask(SIG_SETMASK, &oldset, NULL); -+ return ret; -+} -+#define down_interruptible down_interruptible_killable -+ -+#endif ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c -@@ -2,6 +2,7 @@ - /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - - #include "vchiq_util.h" -+#include "vchiq_killable.h" - - static inline int is_pow2(int i) - { diff --git a/target/linux/bcm27xx/patches-5.4/950-0140-Revert-staging-bcm2835-audio-Drop-DT-dependency.patch b/target/linux/bcm27xx/patches-5.4/950-0140-Revert-staging-bcm2835-audio-Drop-DT-dependency.patch deleted file mode 100644 index 09bfb7acad..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0140-Revert-staging-bcm2835-audio-Drop-DT-dependency.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 6259d03df45a2fd245f6799a83a491edad07c80d Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 15 Mar 2019 21:11:10 +0000 -Subject: [PATCH] Revert "staging: bcm2835-audio: Drop DT dependency" - -This reverts commit b7491a9fca2dc2535b9dc922550a37c5baae9d3d. ---- - .../vc04_services/bcm2835-audio/bcm2835.c | 31 +++++++++++++------ - 1 file changed, 22 insertions(+), 9 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -@@ -6,13 +6,13 @@ - #include - #include - #include -+#include - - #include "bcm2835.h" - - static bool enable_hdmi; - static bool enable_headphones; - static bool enable_compat_alsa = true; --static int num_channels = MAX_SUBSTREAMS; - - module_param(enable_hdmi, bool, 0444); - MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device"); -@@ -21,8 +21,6 @@ MODULE_PARM_DESC(enable_headphones, "Ena - module_param(enable_compat_alsa, bool, 0444); - MODULE_PARM_DESC(enable_compat_alsa, - "Enables ALSA compatibility virtual audio device"); --module_param(num_channels, int, 0644); --MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)"); - - static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res) - { -@@ -296,19 +294,28 @@ static int snd_add_child_devices(struct - static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -+ u32 numchans; - int err; - -- if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) { -- num_channels = MAX_SUBSTREAMS; -- dev_warn(dev, "Illegal num_channels value, will use %u\n", -- num_channels); -+ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels", -+ &numchans); -+ if (err) { -+ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'"); -+ return err; -+ } -+ -+ if (numchans == 0 || numchans > MAX_SUBSTREAMS) { -+ numchans = MAX_SUBSTREAMS; -+ dev_warn(dev, -+ "Illegal 'brcm,pwm-channels' value, will use %u\n", -+ numchans); - } - - err = bcm2835_devm_add_vchi_ctx(dev); - if (err) - return err; - -- err = snd_add_child_devices(dev, num_channels); -+ err = snd_add_child_devices(dev, numchans); - if (err) - return err; - -@@ -330,6 +337,12 @@ static int snd_bcm2835_alsa_resume(struc - - #endif - -+static const struct of_device_id snd_bcm2835_of_match_table[] = { -+ { .compatible = "brcm,bcm2835-audio",}, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table); -+ - static struct platform_driver bcm2835_alsa_driver = { - .probe = snd_bcm2835_alsa_probe, - #ifdef CONFIG_PM -@@ -338,6 +351,7 @@ static struct platform_driver bcm2835_al - #endif - .driver = { - .name = "bcm2835_audio", -+ .of_match_table = snd_bcm2835_of_match_table, - }, - }; - module_platform_driver(bcm2835_alsa_driver); -@@ -345,4 +359,3 @@ module_platform_driver(bcm2835_alsa_driv - MODULE_AUTHOR("Dom Cobley"); - MODULE_DESCRIPTION("Alsa driver for BCM2835 chip"); - MODULE_LICENSE("GPL"); --MODULE_ALIAS("platform:bcm2835_audio"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0140-gpu-vc4_firmware_kms-Fix-up-64-bit-compile-warnings.patch b/target/linux/bcm27xx/patches-5.4/950-0140-gpu-vc4_firmware_kms-Fix-up-64-bit-compile-warnings.patch new file mode 100644 index 0000000000..288281916c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0140-gpu-vc4_firmware_kms-Fix-up-64-bit-compile-warnings.patch @@ -0,0 +1,66 @@ +From b1a1e864164d0cde517b85c2ac2cb6f6ceaa78b4 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 28 Jan 2019 14:40:16 +0000 +Subject: [PATCH] gpu: vc4_firmware_kms: Fix up 64 bit compile + warnings. + +Resolve two build warnings with regard using incorrectly +sized parameters in logging messages on 64 bit builds. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -161,14 +161,14 @@ static void vc4_primary_plane_atomic_upd + WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]); + } + +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%08x/%d\n", ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n", + plane->base.id, plane->name, + state->crtc_w, + state->crtc_h, + bpp, + state->crtc_x, + state->crtc_y, +- bo->paddr + fb->offsets[0], ++ &fbinfo->base, + fb->pitches[0]); + + ret = rpi_firmware_transaction(vc4->firmware, +@@ -198,6 +198,7 @@ static void vc4_cursor_plane_atomic_upda + struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); ++ dma_addr_t addr = bo->paddr + fb->offsets[0]; + int ret; + u32 packet_state[] = { + state->crtc->state->active, +@@ -207,13 +208,13 @@ static void vc4_cursor_plane_atomic_upda + }; + WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4); + +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%08x/%d)", ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)", + plane->base.id, plane->name, + state->crtc_w, + state->crtc_h, + state->crtc_x, + state->crtc_y, +- bo->paddr + fb->offsets[0], ++ &addr, + fb->pitches[0]); + + /* add on the top/left offsets when overscan is active */ +@@ -239,7 +240,7 @@ static void vc4_cursor_plane_atomic_upda + fb != old_state->fb) { + u32 packet_info[] = { state->crtc_w, state->crtc_h, + 0, /* unused */ +- bo->paddr + fb->offsets[0], ++ addr, + 0, 0, /* hotx, hoty */}; + + ret = rpi_firmware_property(vc4->firmware, diff --git a/target/linux/bcm27xx/patches-5.4/950-0141-bcm2835-dma-Add-support-for-per-channel-flags.patch b/target/linux/bcm27xx/patches-5.4/950-0141-bcm2835-dma-Add-support-for-per-channel-flags.patch new file mode 100644 index 0000000000..8f68768588 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0141-bcm2835-dma-Add-support-for-per-channel-flags.patch @@ -0,0 +1,48 @@ +From d70a417420f9d10e86031ec24da68b71668aa833 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 20 Jul 2018 22:03:41 +0100 +Subject: [PATCH] bcm2835-dma: Add support for per-channel flags + +Add the ability to interpret the high bits of the dreq specifier as +flags to be included in the DMA_CS register. The motivation for this +change is the ability to set the DISDEBUG flag for SD card transfers +to avoid corruption when using the VPU debugger. + +Signed-off-by: Phil Elwell +--- + drivers/dma/bcm2835-dma.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/dma/bcm2835-dma.c ++++ b/drivers/dma/bcm2835-dma.c +@@ -141,6 +141,10 @@ struct bcm2835_desc { + #define BCM2835_DMA_S_DREQ BIT(10) /* enable SREQ for source */ + #define BCM2835_DMA_S_IGNORE BIT(11) /* ignore source reads - read 0 */ + #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12) ++#define BCM2835_DMA_CS_FLAGS(x) (x & (BCM2835_DMA_PRIORITY(15) | \ ++ BCM2835_DMA_PANIC_PRIORITY(15) | \ ++ BCM2835_DMA_WAIT_FOR_WRITES | \ ++ BCM2835_DMA_DIS_DEBUG)) + #define BCM2835_DMA_PER_MAP(x) ((x & 31) << 16) /* REQ source */ + #define BCM2835_DMA_WAIT(x) ((x & 31) << 21) /* add DMA-wait cycles */ + #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */ +@@ -454,7 +458,8 @@ static void bcm2835_dma_start_desc(struc + c->desc = d = to_bcm2835_dma_desc(&vd->tx); + + writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); +- writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); ++ writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq), ++ c->chan_base + BCM2835_DMA_CS); + } + + static irqreturn_t bcm2835_dma_callback(int irq, void *data) +@@ -481,7 +486,8 @@ static irqreturn_t bcm2835_dma_callback( + * if this IRQ handler is threaded.) If the channel is finished, it + * will remain idle despite the ACTIVE flag being set. + */ +- writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE, ++ writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | ++ BCM2835_DMA_CS_FLAGS(c->dreq), + c->chan_base + BCM2835_DMA_CS); + + d = c->desc; diff --git a/target/linux/bcm27xx/patches-5.4/950-0141-gpu-vc4_firmware_kms-Fix-up-64-bit-compile-warnings.patch b/target/linux/bcm27xx/patches-5.4/950-0141-gpu-vc4_firmware_kms-Fix-up-64-bit-compile-warnings.patch deleted file mode 100644 index 288281916c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0141-gpu-vc4_firmware_kms-Fix-up-64-bit-compile-warnings.patch +++ /dev/null @@ -1,66 +0,0 @@ -From b1a1e864164d0cde517b85c2ac2cb6f6ceaa78b4 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 28 Jan 2019 14:40:16 +0000 -Subject: [PATCH] gpu: vc4_firmware_kms: Fix up 64 bit compile - warnings. - -Resolve two build warnings with regard using incorrectly -sized parameters in logging messages on 64 bit builds. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -161,14 +161,14 @@ static void vc4_primary_plane_atomic_upd - WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]); - } - -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%08x/%d\n", -+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n", - plane->base.id, plane->name, - state->crtc_w, - state->crtc_h, - bpp, - state->crtc_x, - state->crtc_y, -- bo->paddr + fb->offsets[0], -+ &fbinfo->base, - fb->pitches[0]); - - ret = rpi_firmware_transaction(vc4->firmware, -@@ -198,6 +198,7 @@ static void vc4_cursor_plane_atomic_upda - struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); - struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); -+ dma_addr_t addr = bo->paddr + fb->offsets[0]; - int ret; - u32 packet_state[] = { - state->crtc->state->active, -@@ -207,13 +208,13 @@ static void vc4_cursor_plane_atomic_upda - }; - WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4); - -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%08x/%d)", -+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)", - plane->base.id, plane->name, - state->crtc_w, - state->crtc_h, - state->crtc_x, - state->crtc_y, -- bo->paddr + fb->offsets[0], -+ &addr, - fb->pitches[0]); - - /* add on the top/left offsets when overscan is active */ -@@ -239,7 +240,7 @@ static void vc4_cursor_plane_atomic_upda - fb != old_state->fb) { - u32 packet_info[] = { state->crtc_w, state->crtc_h, - 0, /* unused */ -- bo->paddr + fb->offsets[0], -+ addr, - 0, 0, /* hotx, hoty */}; - - ret = rpi_firmware_property(vc4->firmware, diff --git a/target/linux/bcm27xx/patches-5.4/950-0142-bcm2835-dma-Add-support-for-per-channel-flags.patch b/target/linux/bcm27xx/patches-5.4/950-0142-bcm2835-dma-Add-support-for-per-channel-flags.patch deleted file mode 100644 index 8f68768588..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0142-bcm2835-dma-Add-support-for-per-channel-flags.patch +++ /dev/null @@ -1,48 +0,0 @@ -From d70a417420f9d10e86031ec24da68b71668aa833 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 20 Jul 2018 22:03:41 +0100 -Subject: [PATCH] bcm2835-dma: Add support for per-channel flags - -Add the ability to interpret the high bits of the dreq specifier as -flags to be included in the DMA_CS register. The motivation for this -change is the ability to set the DISDEBUG flag for SD card transfers -to avoid corruption when using the VPU debugger. - -Signed-off-by: Phil Elwell ---- - drivers/dma/bcm2835-dma.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - ---- a/drivers/dma/bcm2835-dma.c -+++ b/drivers/dma/bcm2835-dma.c -@@ -141,6 +141,10 @@ struct bcm2835_desc { - #define BCM2835_DMA_S_DREQ BIT(10) /* enable SREQ for source */ - #define BCM2835_DMA_S_IGNORE BIT(11) /* ignore source reads - read 0 */ - #define BCM2835_DMA_BURST_LENGTH(x) ((x & 15) << 12) -+#define BCM2835_DMA_CS_FLAGS(x) (x & (BCM2835_DMA_PRIORITY(15) | \ -+ BCM2835_DMA_PANIC_PRIORITY(15) | \ -+ BCM2835_DMA_WAIT_FOR_WRITES | \ -+ BCM2835_DMA_DIS_DEBUG)) - #define BCM2835_DMA_PER_MAP(x) ((x & 31) << 16) /* REQ source */ - #define BCM2835_DMA_WAIT(x) ((x & 31) << 21) /* add DMA-wait cycles */ - #define BCM2835_DMA_NO_WIDE_BURSTS BIT(26) /* no 2 beat write bursts */ -@@ -454,7 +458,8 @@ static void bcm2835_dma_start_desc(struc - c->desc = d = to_bcm2835_dma_desc(&vd->tx); - - writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); -- writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); -+ writel(BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq), -+ c->chan_base + BCM2835_DMA_CS); - } - - static irqreturn_t bcm2835_dma_callback(int irq, void *data) -@@ -481,7 +486,8 @@ static irqreturn_t bcm2835_dma_callback( - * if this IRQ handler is threaded.) If the channel is finished, it - * will remain idle despite the ACTIVE flag being set. - */ -- writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE, -+ writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | -+ BCM2835_DMA_CS_FLAGS(c->dreq), - c->chan_base + BCM2835_DMA_CS); - - d = c->desc; diff --git a/target/linux/bcm27xx/patches-5.4/950-0142-drm-vc4-Programming-the-CTM-is-conditional-on-runnin.patch b/target/linux/bcm27xx/patches-5.4/950-0142-drm-vc4-Programming-the-CTM-is-conditional-on-runnin.patch new file mode 100644 index 0000000000..0ec79adb27 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0142-drm-vc4-Programming-the-CTM-is-conditional-on-runnin.patch @@ -0,0 +1,26 @@ +From 973ca1329ac445e55135e01874118d4e28392ea7 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 19 Feb 2019 15:18:25 +0000 +Subject: [PATCH] drm: vc4: Programming the CTM is conditional on + running full KMS + +vc4_ctm_commit writes to HVS registers, so this is only applicable +when in full KMS mode, not in firmware KMS mode. Add this conditional. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -166,7 +166,8 @@ vc4_atomic_complete_commit(struct drm_at + + drm_atomic_helper_commit_modeset_disables(dev, state); + +- vc4_ctm_commit(vc4, state); ++ if (!vc4->firmware_kms) ++ vc4_ctm_commit(vc4, state); + + drm_atomic_helper_commit_planes(dev, state, 0); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0143-drm-vc4-Programming-the-CTM-is-conditional-on-runnin.patch b/target/linux/bcm27xx/patches-5.4/950-0143-drm-vc4-Programming-the-CTM-is-conditional-on-runnin.patch deleted file mode 100644 index 0ec79adb27..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0143-drm-vc4-Programming-the-CTM-is-conditional-on-runnin.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 973ca1329ac445e55135e01874118d4e28392ea7 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 19 Feb 2019 15:18:25 +0000 -Subject: [PATCH] drm: vc4: Programming the CTM is conditional on - running full KMS - -vc4_ctm_commit writes to HVS registers, so this is only applicable -when in full KMS mode, not in firmware KMS mode. Add this conditional. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_kms.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -166,7 +166,8 @@ vc4_atomic_complete_commit(struct drm_at - - drm_atomic_helper_commit_modeset_disables(dev, state); - -- vc4_ctm_commit(vc4, state); -+ if (!vc4->firmware_kms) -+ vc4_ctm_commit(vc4, state); - - drm_atomic_helper_commit_planes(dev, state, 0); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0143-rtc-rv3028-Add-backup-switchover-mode-support.patch b/target/linux/bcm27xx/patches-5.4/950-0143-rtc-rv3028-Add-backup-switchover-mode-support.patch new file mode 100644 index 0000000000..375bd6e6b7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0143-rtc-rv3028-Add-backup-switchover-mode-support.patch @@ -0,0 +1,50 @@ +From c91a8597734d13ebb5ac7393fa6f100d70f15664 Mon Sep 17 00:00:00 2001 +From: Phil Howard +Date: Fri, 29 Mar 2019 10:53:14 +0000 +Subject: [PATCH] rtc: rv3028: Add backup switchover mode support + +Signed-off-by: Phil Howard +--- + drivers/rtc/rtc-rv3028.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/drivers/rtc/rtc-rv3028.c ++++ b/drivers/rtc/rtc-rv3028.c +@@ -73,6 +73,7 @@ + + #define RV3028_BACKUP_TCE BIT(5) + #define RV3028_BACKUP_TCR_MASK GENMASK(1,0) ++#define RV3028_BACKUP_BSM_MASK 0x0C + + #define OFFSET_STEP_PPT 953674 + +@@ -600,6 +601,7 @@ static int rv3028_probe(struct i2c_clien + struct rv3028_data *rv3028; + int ret, status; + u32 ohms; ++ u8 bsm; + struct nvmem_config nvmem_cfg = { + .name = "rv3028_nvram", + .word_size = 1, +@@ -671,6 +673,21 @@ static int rv3028_probe(struct i2c_clien + if (ret) + return ret; + ++ /* setup backup switchover mode */ ++ if (!device_property_read_u8(&client->dev, "backup-switchover-mode", ++ &bsm)) { ++ if (bsm <= 3) { ++ ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP, ++ RV3028_BACKUP_BSM_MASK, ++ (bsm & 0x03) << 2); ++ ++ if (ret) ++ return ret; ++ } else { ++ dev_warn(&client->dev, "invalid backup switchover mode value\n"); ++ } ++ } ++ + /* setup trickle charger */ + if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", + &ohms)) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0144-Audiophonics-I-Sabre-9038Q2M-DAC-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0144-Audiophonics-I-Sabre-9038Q2M-DAC-driver.patch new file mode 100644 index 0000000000..501e81092e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0144-Audiophonics-I-Sabre-9038Q2M-DAC-driver.patch @@ -0,0 +1,695 @@ +From bae79599259f1e09e362368335febe2a3c9c019b Mon Sep 17 00:00:00 2001 +From: FERHAT Nicolas +Date: Fri, 5 Apr 2019 13:06:42 +0100 +Subject: [PATCH] Audiophonics I-Sabre 9038Q2M DAC driver + +Signed-off-by: Audiophonics + +ASoC: i-sabre-q2m: use modern dai_link style + +Signed-off-by: Hui Wang +--- + sound/soc/bcm/Kconfig | 7 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/i-sabre-q2m.c | 158 +++++++++++++ + sound/soc/codecs/Kconfig | 5 + + sound/soc/codecs/Makefile | 2 + + sound/soc/codecs/i-sabre-codec.c | 392 +++++++++++++++++++++++++++++++ + sound/soc/codecs/i-sabre-codec.h | 42 ++++ + 7 files changed, 608 insertions(+) + create mode 100644 sound/soc/bcm/i-sabre-q2m.c + create mode 100644 sound/soc/codecs/i-sabre-codec.c + create mode 100644 sound/soc/codecs/i-sabre-codec.h + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -119,6 +119,13 @@ config SND_BCM2708_SOC_IQAUDIO_DIGI + help + Say Y or M if you want to add support for IQAudIO Digital IO board. + ++config SND_BCM2708_SOC_I_SABRE_Q2M ++ tristate "Support for Audiophonics I-Sabre Q2M DAC" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_I_SABRE_CODEC ++ help ++ Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC ++ + config SND_BCM2708_SOC_ADAU1977_ADC + tristate "Support for ADAU1977 ADC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -19,6 +19,7 @@ snd-soc-justboom-dac-objs := justboom-da + snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-proto-objs := rpi-proto.o + snd-soc-iqaudio-dac-objs := iqaudio-dac.o ++ snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o + snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o + snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o + snd-soc-audiosense-pi-objs := audiosense-pi.o +@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DA + obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o + obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o ++ obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o + obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o + obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o + obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o +--- /dev/null ++++ b/sound/soc/bcm/i-sabre-q2m.c +@@ -0,0 +1,158 @@ ++/* ++ * ASoC Driver for I-Sabre Q2M ++ * ++ * Author: Satoru Kawase ++ * Modified by: Xiao Qingyong ++ * Update kernel v4.18+ by : Audiophonics ++ * Copyright 2018 Audiophonics ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/i-sabre-codec.h" ++ ++ ++static int snd_rpi_i_sabre_q2m_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_component *component = rtd->codec_dai->component; ++ unsigned int value; ++ ++ /* Device ID */ ++ value = snd_soc_component_read32(component, ISABRECODEC_REG_01); ++ dev_info(component->card->dev, "Audiophonics Device ID : %02X\n", value); ++ ++ /* API revision */ ++ value = snd_soc_component_read32(component, ISABRECODEC_REG_02); ++ dev_info(component->card->dev, "Audiophonics API revision : %02X\n", value); ++ ++ return 0; ++} ++ ++static int snd_rpi_i_sabre_q2m_hw_params( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ int bclk_ratio; ++ ++ bclk_ratio = snd_pcm_format_physical_width( ++ params_format(params)) * params_channels(params); ++ return snd_soc_dai_set_bclk_ratio(cpu_dai, bclk_ratio); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_i_sabre_q2m_ops = { ++ .hw_params = snd_rpi_i_sabre_q2m_hw_params, ++}; ++ ++SND_SOC_DAILINK_DEFS(rpi_i_sabre_q2m, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("i-sabre-codec-i2c.1-0048", "i-sabre-codec-dai")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); ++ ++static struct snd_soc_dai_link snd_rpi_i_sabre_q2m_dai[] = { ++ { ++ .name = "I-Sabre Q2M", ++ .stream_name = "I-Sabre Q2M DAC", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBS_CFS, ++ .init = snd_rpi_i_sabre_q2m_init, ++ .ops = &snd_rpi_i_sabre_q2m_ops, ++ SND_SOC_DAILINK_REG(rpi_i_sabre_q2m), ++ } ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_i_sabre_q2m = { ++ .name = "I-Sabre Q2M DAC", ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_i_sabre_q2m_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_i_sabre_q2m_dai) ++}; ++ ++ ++static int snd_rpi_i_sabre_q2m_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_i_sabre_q2m.dev = &pdev->dev; ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai; ++ ++ dai = &snd_rpi_i_sabre_q2m_dai[0]; ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; ++ } else { ++ dev_err(&pdev->dev, ++ "Property 'i2s-controller' missing or invalid\n"); ++ return (-EINVAL); ++ } ++ ++ dai->name = "I-Sabre Q2M"; ++ dai->stream_name = "I-Sabre Q2M DAC"; ++ dai->dai_fmt = SND_SOC_DAIFMT_I2S ++ | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBS_CFS; ++ } ++ ++ /* Wait for registering codec driver */ ++ mdelay(50); ++ ++ ret = snd_soc_register_card(&snd_rpi_i_sabre_q2m); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ } ++ ++ return ret; ++} ++ ++static int snd_rpi_i_sabre_q2m_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_i_sabre_q2m); ++} ++ ++static const struct of_device_id snd_rpi_i_sabre_q2m_of_match[] = { ++ { .compatible = "audiophonics,i-sabre-q2m", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, snd_rpi_i_sabre_q2m_of_match); ++ ++static struct platform_driver snd_rpi_i_sabre_q2m_driver = { ++ .driver = { ++ .name = "snd-rpi-i-sabre-q2m", ++ .owner = THIS_MODULE, ++ .of_match_table = snd_rpi_i_sabre_q2m_of_match, ++ }, ++ .probe = snd_rpi_i_sabre_q2m_probe, ++ .remove = snd_rpi_i_sabre_q2m_remove, ++}; ++module_platform_driver(snd_rpi_i_sabre_q2m_driver); ++ ++MODULE_DESCRIPTION("ASoC Driver for I-Sabre Q2M"); ++MODULE_AUTHOR("Audiophonics "); ++MODULE_LICENSE("GPL"); +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -97,6 +97,7 @@ config SND_SOC_ALL_CODECS + select SND_SOC_ICS43432 + select SND_SOC_INNO_RK3036 + select SND_SOC_ISABELLE if I2C ++ select SND_SOC_I_SABRE_CODEC if I2C + select SND_SOC_JZ4740_CODEC + select SND_SOC_JZ4725B_CODEC + select SND_SOC_LM4857 if I2C +@@ -1497,4 +1498,8 @@ config SND_SOC_TPA6130A2 + tristate "Texas Instruments TPA6130A2 headphone amplifier" + depends on I2C + ++config SND_SOC_I_SABRE_CODEC ++ tristate "Audiophonics I-SABRE Codec" ++ depends on I2C ++ + endmenu +--- a/sound/soc/codecs/Makefile ++++ b/sound/soc/codecs/Makefile +@@ -92,6 +92,7 @@ snd-soc-hdac-hda-objs := hdac_hda.o + snd-soc-ics43432-objs := ics43432.o + snd-soc-inno-rk3036-objs := inno_rk3036.o + snd-soc-isabelle-objs := isabelle.o ++snd-soc-i-sabre-codec-objs := i-sabre-codec.o + snd-soc-jz4740-codec-objs := jz4740.o + snd-soc-jz4725b-codec-objs := jz4725b.o + snd-soc-l3-objs := l3.o +@@ -378,6 +379,7 @@ obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-so + obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o + obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o + obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o ++obj-$(CONFIG_SND_SOC_I_SABRE_CODEC) += snd-soc-i-sabre-codec.o + obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o + obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o + obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o +--- /dev/null ++++ b/sound/soc/codecs/i-sabre-codec.c +@@ -0,0 +1,392 @@ ++/* ++ * Driver for I-Sabre Q2M ++ * ++ * Author: Satoru Kawase ++ * Modified by: Xiao Qingyong ++ * Modified by: JC BARBAUD (Mute) ++ * Update kernel v4.18+ by : Audiophonics ++ * Copyright 2018 Audiophonics ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "i-sabre-codec.h" ++ ++ ++/* I-Sabre Q2M Codec Private Data */ ++struct i_sabre_codec_priv { ++ struct regmap *regmap; ++ unsigned int fmt; ++}; ++ ++ ++/* I-Sabre Q2M Codec Default Register Value */ ++static const struct reg_default i_sabre_codec_reg_defaults[] = { ++ { ISABRECODEC_REG_10, 0x00 }, ++ { ISABRECODEC_REG_20, 0x00 }, ++ { ISABRECODEC_REG_21, 0x00 }, ++ { ISABRECODEC_REG_22, 0x00 }, ++ { ISABRECODEC_REG_24, 0x00 }, ++}; ++ ++ ++static bool i_sabre_codec_writeable(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case ISABRECODEC_REG_10: ++ case ISABRECODEC_REG_20: ++ case ISABRECODEC_REG_21: ++ case ISABRECODEC_REG_22: ++ case ISABRECODEC_REG_24: ++ return true; ++ ++ default: ++ return false; ++ } ++} ++ ++static bool i_sabre_codec_readable(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case ISABRECODEC_REG_01: ++ case ISABRECODEC_REG_02: ++ case ISABRECODEC_REG_10: ++ case ISABRECODEC_REG_20: ++ case ISABRECODEC_REG_21: ++ case ISABRECODEC_REG_22: ++ case ISABRECODEC_REG_24: ++ return true; ++ ++ default: ++ return false; ++ } ++} ++ ++static bool i_sabre_codec_volatile(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case ISABRECODEC_REG_01: ++ case ISABRECODEC_REG_02: ++ return true; ++ ++ default: ++ return false; ++ } ++} ++ ++ ++/* Volume Scale */ ++static const DECLARE_TLV_DB_SCALE(volume_tlv, -10000, 100, 0); ++ ++ ++/* Filter Type */ ++static const char * const fir_filter_type_texts[] = { ++ "brick wall", ++ "corrected minimum phase fast", ++ "minimum phase slow", ++ "minimum phase fast", ++ "linear phase slow", ++ "linear phase fast", ++ "apodizing fast", ++}; ++ ++static SOC_ENUM_SINGLE_DECL(i_sabre_fir_filter_type_enum, ++ ISABRECODEC_REG_22, 0, fir_filter_type_texts); ++ ++ ++/* I2S / SPDIF Select */ ++static const char * const iis_spdif_sel_texts[] = { ++ "I2S", ++ "SPDIF", ++}; ++ ++static SOC_ENUM_SINGLE_DECL(i_sabre_iis_spdif_sel_enum, ++ ISABRECODEC_REG_24, 0, iis_spdif_sel_texts); ++ ++ ++/* Control */ ++static const struct snd_kcontrol_new i_sabre_codec_controls[] = { ++SOC_SINGLE_RANGE_TLV("Digital Playback Volume", ISABRECODEC_REG_20, 0, 0, 100, 1, volume_tlv), ++SOC_SINGLE("Digital Playback Switch", ISABRECODEC_REG_21, 0, 1, 1), ++SOC_ENUM("FIR Filter Type", i_sabre_fir_filter_type_enum), ++SOC_ENUM("I2S/SPDIF Select", i_sabre_iis_spdif_sel_enum), ++}; ++ ++ ++static const u32 i_sabre_codec_dai_rates_slave[] = { ++ 8000, 11025, 16000, 22050, 32000, ++ 44100, 48000, 64000, 88200, 96000, ++ 176400, 192000, 352800, 384000, ++ 705600, 768000, 1411200, 1536000 ++}; ++ ++static const struct snd_pcm_hw_constraint_list constraints_slave = { ++ .list = i_sabre_codec_dai_rates_slave, ++ .count = ARRAY_SIZE(i_sabre_codec_dai_rates_slave), ++}; ++ ++static int i_sabre_codec_dai_startup_slave( ++ struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ int ret; ++ ++ ret = snd_pcm_hw_constraint_list(substream->runtime, ++ 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_slave); ++ if (ret != 0) { ++ dev_err(component->card->dev, "Failed to setup rates constraints: %d\n", ret); ++ } ++ ++ return ret; ++} ++ ++static int i_sabre_codec_dai_startup( ++ struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct i_sabre_codec_priv *i_sabre_codec ++ = snd_soc_component_get_drvdata(component); ++ ++ switch (i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBS_CFS: ++ return i_sabre_codec_dai_startup_slave(substream, dai); ++ ++ default: ++ return (-EINVAL); ++ } ++} ++ ++static int i_sabre_codec_hw_params( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct i_sabre_codec_priv *i_sabre_codec ++ = snd_soc_component_get_drvdata(component); ++ unsigned int daifmt; ++ int format_width; ++ ++ dev_dbg(component->card->dev, "hw_params %u Hz, %u channels\n", ++ params_rate(params), params_channels(params)); ++ ++ /* Check I2S Format (Bit Size) */ ++ format_width = snd_pcm_format_width(params_format(params)); ++ if ((format_width != 32) && (format_width != 16)) { ++ dev_err(component->card->dev, "Bad frame size: %d\n", ++ snd_pcm_format_width(params_format(params))); ++ return (-EINVAL); ++ } ++ ++ /* Check Slave Mode */ ++ daifmt = i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK; ++ if (daifmt != SND_SOC_DAIFMT_CBS_CFS) { ++ return (-EINVAL); ++ } ++ ++ /* Notify Sampling Frequency */ ++ switch (params_rate(params)) ++ { ++ case 44100: ++ case 48000: ++ case 88200: ++ case 96000: ++ case 176400: ++ case 192000: ++ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x00); ++ break; ++ ++ case 352800: ++ case 384000: ++ case 705600: ++ case 768000: ++ case 1411200: ++ case 1536000: ++ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x01); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int i_sabre_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct i_sabre_codec_priv *i_sabre_codec ++ = snd_soc_component_get_drvdata(component); ++ ++ /* interface format */ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ break; ++ ++ case SND_SOC_DAIFMT_RIGHT_J: ++ case SND_SOC_DAIFMT_LEFT_J: ++ default: ++ return (-EINVAL); ++ } ++ ++ /* clock inversion */ ++ if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { ++ return (-EINVAL); ++ } ++ ++ /* Set Audio Data Format */ ++ i_sabre_codec->fmt = fmt; ++ ++ return 0; ++} ++ ++static int i_sabre_codec_dac_mute(struct snd_soc_dai *dai, int mute) ++{ ++ struct snd_soc_component *component = dai->component; ++ ++ if (mute) { ++ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x01); ++ } else { ++ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x00); ++ } ++ ++ return 0; ++} ++ ++ ++static const struct snd_soc_dai_ops i_sabre_codec_dai_ops = { ++ .startup = i_sabre_codec_dai_startup, ++ .hw_params = i_sabre_codec_hw_params, ++ .set_fmt = i_sabre_codec_set_fmt, ++ .digital_mute = i_sabre_codec_dac_mute, ++}; ++ ++static struct snd_soc_dai_driver i_sabre_codec_dai = { ++ .name = "i-sabre-codec-dai", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS, ++ .rate_min = 8000, ++ .rate_max = 1536000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE ++ | SNDRV_PCM_FMTBIT_S32_LE, ++ }, ++ .ops = &i_sabre_codec_dai_ops, ++}; ++ ++static struct snd_soc_component_driver i_sabre_codec_codec_driver = { ++ .controls = i_sabre_codec_controls, ++ .num_controls = ARRAY_SIZE(i_sabre_codec_controls), ++}; ++ ++ ++static const struct regmap_config i_sabre_codec_regmap = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = ISABRECODEC_MAX_REG, ++ ++ .reg_defaults = i_sabre_codec_reg_defaults, ++ .num_reg_defaults = ARRAY_SIZE(i_sabre_codec_reg_defaults), ++ ++ .writeable_reg = i_sabre_codec_writeable, ++ .readable_reg = i_sabre_codec_readable, ++ .volatile_reg = i_sabre_codec_volatile, ++ ++ .cache_type = REGCACHE_RBTREE, ++}; ++ ++ ++static int i_sabre_codec_probe(struct device *dev, struct regmap *regmap) ++{ ++ struct i_sabre_codec_priv *i_sabre_codec; ++ int ret; ++ ++ i_sabre_codec = devm_kzalloc(dev, sizeof(*i_sabre_codec), GFP_KERNEL); ++ if (!i_sabre_codec) { ++ dev_err(dev, "devm_kzalloc"); ++ return (-ENOMEM); ++ } ++ ++ i_sabre_codec->regmap = regmap; ++ ++ dev_set_drvdata(dev, i_sabre_codec); ++ ++ ret = snd_soc_register_component(dev, ++ &i_sabre_codec_codec_driver, &i_sabre_codec_dai, 1); ++ if (ret != 0) { ++ dev_err(dev, "Failed to register CODEC: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void i_sabre_codec_remove(struct device *dev) ++{ ++ snd_soc_unregister_component(dev); ++} ++ ++ ++static int i_sabre_codec_i2c_probe( ++ struct i2c_client *i2c, const struct i2c_device_id *id) ++{ ++ struct regmap *regmap; ++ ++ regmap = devm_regmap_init_i2c(i2c, &i_sabre_codec_regmap); ++ if (IS_ERR(regmap)) { ++ return PTR_ERR(regmap); ++ } ++ ++ return i_sabre_codec_probe(&i2c->dev, regmap); ++} ++ ++static int i_sabre_codec_i2c_remove(struct i2c_client *i2c) ++{ ++ i_sabre_codec_remove(&i2c->dev); ++ ++ return 0; ++} ++ ++ ++static const struct i2c_device_id i_sabre_codec_i2c_id[] = { ++ { "i-sabre-codec", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, i_sabre_codec_i2c_id); ++ ++static const struct of_device_id i_sabre_codec_of_match[] = { ++ { .compatible = "audiophonics,i-sabre-codec", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, i_sabre_codec_of_match); ++ ++static struct i2c_driver i_sabre_codec_i2c_driver = { ++ .driver = { ++ .name = "i-sabre-codec-i2c", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(i_sabre_codec_of_match), ++ }, ++ .probe = i_sabre_codec_i2c_probe, ++ .remove = i_sabre_codec_i2c_remove, ++ .id_table = i_sabre_codec_i2c_id, ++}; ++module_i2c_driver(i_sabre_codec_i2c_driver); ++ ++ ++MODULE_DESCRIPTION("ASoC I-Sabre Q2M codec driver"); ++MODULE_AUTHOR("Audiophonics "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/sound/soc/codecs/i-sabre-codec.h +@@ -0,0 +1,42 @@ ++/* ++ * Driver for I-Sabre Q2M ++ * ++ * Author: Satoru Kawase ++ * Modified by: Xiao Qingyong ++ * Copyright 2018 Audiophonics ++ * ++ * 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. ++ * ++ * 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. ++ */ ++ ++#ifndef _SND_SOC_ISABRECODEC ++#define _SND_SOC_ISABRECODEC ++ ++ ++/* ISABRECODEC Register Address */ ++#define ISABRECODEC_REG_01 0x01 /* Virtual Device ID : 0x01 = es9038q2m */ ++#define ISABRECODEC_REG_02 0x02 /* API revision : 0x01 = Revision 01 */ ++#define ISABRECODEC_REG_10 0x10 /* 0x01 = above 192kHz, 0x00 = otherwise */ ++#define ISABRECODEC_REG_20 0x20 /* 0 - 100 (decimal value, 0 = min., 100 = max.) */ ++#define ISABRECODEC_REG_21 0x21 /* 0x00 = Mute OFF, 0x01 = Mute ON */ ++#define ISABRECODEC_REG_22 0x22 ++/* ++ 0x00 = brick wall, ++ 0x01 = corrected minimum phase fast, ++ 0x02 = minimum phase slow, ++ 0x03 = minimum phase fast, ++ 0x04 = linear phase slow, ++ 0x05 = linear phase fast, ++ 0x06 = apodizing fast, ++*/ ++//#define ISABRECODEC_REG_23 0x23 /* reserved */ ++#define ISABRECODEC_REG_24 0x24 /* 0x00 = I2S, 0x01 = SPDIF */ ++#define ISABRECODEC_MAX_REG 0x24 /* Maximum Register Number */ ++ ++#endif /* _SND_SOC_ISABRECODEC */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0144-rtc-rv3028-Add-backup-switchover-mode-support.patch b/target/linux/bcm27xx/patches-5.4/950-0144-rtc-rv3028-Add-backup-switchover-mode-support.patch deleted file mode 100644 index 375bd6e6b7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0144-rtc-rv3028-Add-backup-switchover-mode-support.patch +++ /dev/null @@ -1,50 +0,0 @@ -From c91a8597734d13ebb5ac7393fa6f100d70f15664 Mon Sep 17 00:00:00 2001 -From: Phil Howard -Date: Fri, 29 Mar 2019 10:53:14 +0000 -Subject: [PATCH] rtc: rv3028: Add backup switchover mode support - -Signed-off-by: Phil Howard ---- - drivers/rtc/rtc-rv3028.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - ---- a/drivers/rtc/rtc-rv3028.c -+++ b/drivers/rtc/rtc-rv3028.c -@@ -73,6 +73,7 @@ - - #define RV3028_BACKUP_TCE BIT(5) - #define RV3028_BACKUP_TCR_MASK GENMASK(1,0) -+#define RV3028_BACKUP_BSM_MASK 0x0C - - #define OFFSET_STEP_PPT 953674 - -@@ -600,6 +601,7 @@ static int rv3028_probe(struct i2c_clien - struct rv3028_data *rv3028; - int ret, status; - u32 ohms; -+ u8 bsm; - struct nvmem_config nvmem_cfg = { - .name = "rv3028_nvram", - .word_size = 1, -@@ -671,6 +673,21 @@ static int rv3028_probe(struct i2c_clien - if (ret) - return ret; - -+ /* setup backup switchover mode */ -+ if (!device_property_read_u8(&client->dev, "backup-switchover-mode", -+ &bsm)) { -+ if (bsm <= 3) { -+ ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP, -+ RV3028_BACKUP_BSM_MASK, -+ (bsm & 0x03) << 2); -+ -+ if (ret) -+ return ret; -+ } else { -+ dev_warn(&client->dev, "invalid backup switchover mode value\n"); -+ } -+ } -+ - /* setup trickle charger */ - if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms", - &ohms)) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0145-Audiophonics-I-Sabre-9038Q2M-DAC-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0145-Audiophonics-I-Sabre-9038Q2M-DAC-driver.patch deleted file mode 100644 index 501e81092e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0145-Audiophonics-I-Sabre-9038Q2M-DAC-driver.patch +++ /dev/null @@ -1,695 +0,0 @@ -From bae79599259f1e09e362368335febe2a3c9c019b Mon Sep 17 00:00:00 2001 -From: FERHAT Nicolas -Date: Fri, 5 Apr 2019 13:06:42 +0100 -Subject: [PATCH] Audiophonics I-Sabre 9038Q2M DAC driver - -Signed-off-by: Audiophonics - -ASoC: i-sabre-q2m: use modern dai_link style - -Signed-off-by: Hui Wang ---- - sound/soc/bcm/Kconfig | 7 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/i-sabre-q2m.c | 158 +++++++++++++ - sound/soc/codecs/Kconfig | 5 + - sound/soc/codecs/Makefile | 2 + - sound/soc/codecs/i-sabre-codec.c | 392 +++++++++++++++++++++++++++++++ - sound/soc/codecs/i-sabre-codec.h | 42 ++++ - 7 files changed, 608 insertions(+) - create mode 100644 sound/soc/bcm/i-sabre-q2m.c - create mode 100644 sound/soc/codecs/i-sabre-codec.c - create mode 100644 sound/soc/codecs/i-sabre-codec.h - ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -119,6 +119,13 @@ config SND_BCM2708_SOC_IQAUDIO_DIGI - help - Say Y or M if you want to add support for IQAudIO Digital IO board. - -+config SND_BCM2708_SOC_I_SABRE_Q2M -+ tristate "Support for Audiophonics I-Sabre Q2M DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_I_SABRE_CODEC -+ help -+ Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC -+ - config SND_BCM2708_SOC_ADAU1977_ADC - tristate "Support for ADAU1977 ADC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -19,6 +19,7 @@ snd-soc-justboom-dac-objs := justboom-da - snd-soc-rpi-cirrus-objs := rpi-cirrus.o - snd-soc-rpi-proto-objs := rpi-proto.o - snd-soc-iqaudio-dac-objs := iqaudio-dac.o -+ snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o - snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o - snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o - snd-soc-audiosense-pi-objs := audiosense-pi.o -@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DA - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o - obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o -+ obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o - obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o - obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o - obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o ---- /dev/null -+++ b/sound/soc/bcm/i-sabre-q2m.c -@@ -0,0 +1,158 @@ -+/* -+ * ASoC Driver for I-Sabre Q2M -+ * -+ * Author: Satoru Kawase -+ * Modified by: Xiao Qingyong -+ * Update kernel v4.18+ by : Audiophonics -+ * Copyright 2018 Audiophonics -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../codecs/i-sabre-codec.h" -+ -+ -+static int snd_rpi_i_sabre_q2m_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ unsigned int value; -+ -+ /* Device ID */ -+ value = snd_soc_component_read32(component, ISABRECODEC_REG_01); -+ dev_info(component->card->dev, "Audiophonics Device ID : %02X\n", value); -+ -+ /* API revision */ -+ value = snd_soc_component_read32(component, ISABRECODEC_REG_02); -+ dev_info(component->card->dev, "Audiophonics API revision : %02X\n", value); -+ -+ return 0; -+} -+ -+static int snd_rpi_i_sabre_q2m_hw_params( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ int bclk_ratio; -+ -+ bclk_ratio = snd_pcm_format_physical_width( -+ params_format(params)) * params_channels(params); -+ return snd_soc_dai_set_bclk_ratio(cpu_dai, bclk_ratio); -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_i_sabre_q2m_ops = { -+ .hw_params = snd_rpi_i_sabre_q2m_hw_params, -+}; -+ -+SND_SOC_DAILINK_DEFS(rpi_i_sabre_q2m, -+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), -+ DAILINK_COMP_ARRAY(COMP_CODEC("i-sabre-codec-i2c.1-0048", "i-sabre-codec-dai")), -+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); -+ -+static struct snd_soc_dai_link snd_rpi_i_sabre_q2m_dai[] = { -+ { -+ .name = "I-Sabre Q2M", -+ .stream_name = "I-Sabre Q2M DAC", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBS_CFS, -+ .init = snd_rpi_i_sabre_q2m_init, -+ .ops = &snd_rpi_i_sabre_q2m_ops, -+ SND_SOC_DAILINK_REG(rpi_i_sabre_q2m), -+ } -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_i_sabre_q2m = { -+ .name = "I-Sabre Q2M DAC", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_i_sabre_q2m_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_i_sabre_q2m_dai) -+}; -+ -+ -+static int snd_rpi_i_sabre_q2m_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_i_sabre_q2m.dev = &pdev->dev; -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai; -+ -+ dai = &snd_rpi_i_sabre_q2m_dai[0]; -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ if (i2s_node) { -+ dai->cpus->dai_name = NULL; -+ dai->cpus->of_node = i2s_node; -+ dai->platforms->name = NULL; -+ dai->platforms->of_node = i2s_node; -+ } else { -+ dev_err(&pdev->dev, -+ "Property 'i2s-controller' missing or invalid\n"); -+ return (-EINVAL); -+ } -+ -+ dai->name = "I-Sabre Q2M"; -+ dai->stream_name = "I-Sabre Q2M DAC"; -+ dai->dai_fmt = SND_SOC_DAIFMT_I2S -+ | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBS_CFS; -+ } -+ -+ /* Wait for registering codec driver */ -+ mdelay(50); -+ -+ ret = snd_soc_register_card(&snd_rpi_i_sabre_q2m); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+static int snd_rpi_i_sabre_q2m_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_i_sabre_q2m); -+} -+ -+static const struct of_device_id snd_rpi_i_sabre_q2m_of_match[] = { -+ { .compatible = "audiophonics,i-sabre-q2m", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, snd_rpi_i_sabre_q2m_of_match); -+ -+static struct platform_driver snd_rpi_i_sabre_q2m_driver = { -+ .driver = { -+ .name = "snd-rpi-i-sabre-q2m", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_i_sabre_q2m_of_match, -+ }, -+ .probe = snd_rpi_i_sabre_q2m_probe, -+ .remove = snd_rpi_i_sabre_q2m_remove, -+}; -+module_platform_driver(snd_rpi_i_sabre_q2m_driver); -+ -+MODULE_DESCRIPTION("ASoC Driver for I-Sabre Q2M"); -+MODULE_AUTHOR("Audiophonics "); -+MODULE_LICENSE("GPL"); ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -97,6 +97,7 @@ config SND_SOC_ALL_CODECS - select SND_SOC_ICS43432 - select SND_SOC_INNO_RK3036 - select SND_SOC_ISABELLE if I2C -+ select SND_SOC_I_SABRE_CODEC if I2C - select SND_SOC_JZ4740_CODEC - select SND_SOC_JZ4725B_CODEC - select SND_SOC_LM4857 if I2C -@@ -1497,4 +1498,8 @@ config SND_SOC_TPA6130A2 - tristate "Texas Instruments TPA6130A2 headphone amplifier" - depends on I2C - -+config SND_SOC_I_SABRE_CODEC -+ tristate "Audiophonics I-SABRE Codec" -+ depends on I2C -+ - endmenu ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -92,6 +92,7 @@ snd-soc-hdac-hda-objs := hdac_hda.o - snd-soc-ics43432-objs := ics43432.o - snd-soc-inno-rk3036-objs := inno_rk3036.o - snd-soc-isabelle-objs := isabelle.o -+snd-soc-i-sabre-codec-objs := i-sabre-codec.o - snd-soc-jz4740-codec-objs := jz4740.o - snd-soc-jz4725b-codec-objs := jz4725b.o - snd-soc-l3-objs := l3.o -@@ -378,6 +379,7 @@ obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-so - obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o - obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o - obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o -+obj-$(CONFIG_SND_SOC_I_SABRE_CODEC) += snd-soc-i-sabre-codec.o - obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o - obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o - obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o ---- /dev/null -+++ b/sound/soc/codecs/i-sabre-codec.c -@@ -0,0 +1,392 @@ -+/* -+ * Driver for I-Sabre Q2M -+ * -+ * Author: Satoru Kawase -+ * Modified by: Xiao Qingyong -+ * Modified by: JC BARBAUD (Mute) -+ * Update kernel v4.18+ by : Audiophonics -+ * Copyright 2018 Audiophonics -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "i-sabre-codec.h" -+ -+ -+/* I-Sabre Q2M Codec Private Data */ -+struct i_sabre_codec_priv { -+ struct regmap *regmap; -+ unsigned int fmt; -+}; -+ -+ -+/* I-Sabre Q2M Codec Default Register Value */ -+static const struct reg_default i_sabre_codec_reg_defaults[] = { -+ { ISABRECODEC_REG_10, 0x00 }, -+ { ISABRECODEC_REG_20, 0x00 }, -+ { ISABRECODEC_REG_21, 0x00 }, -+ { ISABRECODEC_REG_22, 0x00 }, -+ { ISABRECODEC_REG_24, 0x00 }, -+}; -+ -+ -+static bool i_sabre_codec_writeable(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case ISABRECODEC_REG_10: -+ case ISABRECODEC_REG_20: -+ case ISABRECODEC_REG_21: -+ case ISABRECODEC_REG_22: -+ case ISABRECODEC_REG_24: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool i_sabre_codec_readable(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case ISABRECODEC_REG_01: -+ case ISABRECODEC_REG_02: -+ case ISABRECODEC_REG_10: -+ case ISABRECODEC_REG_20: -+ case ISABRECODEC_REG_21: -+ case ISABRECODEC_REG_22: -+ case ISABRECODEC_REG_24: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+static bool i_sabre_codec_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case ISABRECODEC_REG_01: -+ case ISABRECODEC_REG_02: -+ return true; -+ -+ default: -+ return false; -+ } -+} -+ -+ -+/* Volume Scale */ -+static const DECLARE_TLV_DB_SCALE(volume_tlv, -10000, 100, 0); -+ -+ -+/* Filter Type */ -+static const char * const fir_filter_type_texts[] = { -+ "brick wall", -+ "corrected minimum phase fast", -+ "minimum phase slow", -+ "minimum phase fast", -+ "linear phase slow", -+ "linear phase fast", -+ "apodizing fast", -+}; -+ -+static SOC_ENUM_SINGLE_DECL(i_sabre_fir_filter_type_enum, -+ ISABRECODEC_REG_22, 0, fir_filter_type_texts); -+ -+ -+/* I2S / SPDIF Select */ -+static const char * const iis_spdif_sel_texts[] = { -+ "I2S", -+ "SPDIF", -+}; -+ -+static SOC_ENUM_SINGLE_DECL(i_sabre_iis_spdif_sel_enum, -+ ISABRECODEC_REG_24, 0, iis_spdif_sel_texts); -+ -+ -+/* Control */ -+static const struct snd_kcontrol_new i_sabre_codec_controls[] = { -+SOC_SINGLE_RANGE_TLV("Digital Playback Volume", ISABRECODEC_REG_20, 0, 0, 100, 1, volume_tlv), -+SOC_SINGLE("Digital Playback Switch", ISABRECODEC_REG_21, 0, 1, 1), -+SOC_ENUM("FIR Filter Type", i_sabre_fir_filter_type_enum), -+SOC_ENUM("I2S/SPDIF Select", i_sabre_iis_spdif_sel_enum), -+}; -+ -+ -+static const u32 i_sabre_codec_dai_rates_slave[] = { -+ 8000, 11025, 16000, 22050, 32000, -+ 44100, 48000, 64000, 88200, 96000, -+ 176400, 192000, 352800, 384000, -+ 705600, 768000, 1411200, 1536000 -+}; -+ -+static const struct snd_pcm_hw_constraint_list constraints_slave = { -+ .list = i_sabre_codec_dai_rates_slave, -+ .count = ARRAY_SIZE(i_sabre_codec_dai_rates_slave), -+}; -+ -+static int i_sabre_codec_dai_startup_slave( -+ struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ int ret; -+ -+ ret = snd_pcm_hw_constraint_list(substream->runtime, -+ 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_slave); -+ if (ret != 0) { -+ dev_err(component->card->dev, "Failed to setup rates constraints: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+static int i_sabre_codec_dai_startup( -+ struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct i_sabre_codec_priv *i_sabre_codec -+ = snd_soc_component_get_drvdata(component); -+ -+ switch (i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBS_CFS: -+ return i_sabre_codec_dai_startup_slave(substream, dai); -+ -+ default: -+ return (-EINVAL); -+ } -+} -+ -+static int i_sabre_codec_hw_params( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct i_sabre_codec_priv *i_sabre_codec -+ = snd_soc_component_get_drvdata(component); -+ unsigned int daifmt; -+ int format_width; -+ -+ dev_dbg(component->card->dev, "hw_params %u Hz, %u channels\n", -+ params_rate(params), params_channels(params)); -+ -+ /* Check I2S Format (Bit Size) */ -+ format_width = snd_pcm_format_width(params_format(params)); -+ if ((format_width != 32) && (format_width != 16)) { -+ dev_err(component->card->dev, "Bad frame size: %d\n", -+ snd_pcm_format_width(params_format(params))); -+ return (-EINVAL); -+ } -+ -+ /* Check Slave Mode */ -+ daifmt = i_sabre_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK; -+ if (daifmt != SND_SOC_DAIFMT_CBS_CFS) { -+ return (-EINVAL); -+ } -+ -+ /* Notify Sampling Frequency */ -+ switch (params_rate(params)) -+ { -+ case 44100: -+ case 48000: -+ case 88200: -+ case 96000: -+ case 176400: -+ case 192000: -+ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x00); -+ break; -+ -+ case 352800: -+ case 384000: -+ case 705600: -+ case 768000: -+ case 1411200: -+ case 1536000: -+ snd_soc_component_update_bits(component, ISABRECODEC_REG_10, 0x01, 0x01); -+ break; -+ } -+ -+ return 0; -+} -+ -+static int i_sabre_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -+{ -+ struct snd_soc_component *component = dai->component; -+ struct i_sabre_codec_priv *i_sabre_codec -+ = snd_soc_component_get_drvdata(component); -+ -+ /* interface format */ -+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: -+ break; -+ -+ case SND_SOC_DAIFMT_RIGHT_J: -+ case SND_SOC_DAIFMT_LEFT_J: -+ default: -+ return (-EINVAL); -+ } -+ -+ /* clock inversion */ -+ if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { -+ return (-EINVAL); -+ } -+ -+ /* Set Audio Data Format */ -+ i_sabre_codec->fmt = fmt; -+ -+ return 0; -+} -+ -+static int i_sabre_codec_dac_mute(struct snd_soc_dai *dai, int mute) -+{ -+ struct snd_soc_component *component = dai->component; -+ -+ if (mute) { -+ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x01); -+ } else { -+ snd_soc_component_update_bits(component, ISABRECODEC_REG_21, 0x01, 0x00); -+ } -+ -+ return 0; -+} -+ -+ -+static const struct snd_soc_dai_ops i_sabre_codec_dai_ops = { -+ .startup = i_sabre_codec_dai_startup, -+ .hw_params = i_sabre_codec_hw_params, -+ .set_fmt = i_sabre_codec_set_fmt, -+ .digital_mute = i_sabre_codec_dac_mute, -+}; -+ -+static struct snd_soc_dai_driver i_sabre_codec_dai = { -+ .name = "i-sabre-codec-dai", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_CONTINUOUS, -+ .rate_min = 8000, -+ .rate_max = 1536000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE -+ | SNDRV_PCM_FMTBIT_S32_LE, -+ }, -+ .ops = &i_sabre_codec_dai_ops, -+}; -+ -+static struct snd_soc_component_driver i_sabre_codec_codec_driver = { -+ .controls = i_sabre_codec_controls, -+ .num_controls = ARRAY_SIZE(i_sabre_codec_controls), -+}; -+ -+ -+static const struct regmap_config i_sabre_codec_regmap = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = ISABRECODEC_MAX_REG, -+ -+ .reg_defaults = i_sabre_codec_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(i_sabre_codec_reg_defaults), -+ -+ .writeable_reg = i_sabre_codec_writeable, -+ .readable_reg = i_sabre_codec_readable, -+ .volatile_reg = i_sabre_codec_volatile, -+ -+ .cache_type = REGCACHE_RBTREE, -+}; -+ -+ -+static int i_sabre_codec_probe(struct device *dev, struct regmap *regmap) -+{ -+ struct i_sabre_codec_priv *i_sabre_codec; -+ int ret; -+ -+ i_sabre_codec = devm_kzalloc(dev, sizeof(*i_sabre_codec), GFP_KERNEL); -+ if (!i_sabre_codec) { -+ dev_err(dev, "devm_kzalloc"); -+ return (-ENOMEM); -+ } -+ -+ i_sabre_codec->regmap = regmap; -+ -+ dev_set_drvdata(dev, i_sabre_codec); -+ -+ ret = snd_soc_register_component(dev, -+ &i_sabre_codec_codec_driver, &i_sabre_codec_dai, 1); -+ if (ret != 0) { -+ dev_err(dev, "Failed to register CODEC: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void i_sabre_codec_remove(struct device *dev) -+{ -+ snd_soc_unregister_component(dev); -+} -+ -+ -+static int i_sabre_codec_i2c_probe( -+ struct i2c_client *i2c, const struct i2c_device_id *id) -+{ -+ struct regmap *regmap; -+ -+ regmap = devm_regmap_init_i2c(i2c, &i_sabre_codec_regmap); -+ if (IS_ERR(regmap)) { -+ return PTR_ERR(regmap); -+ } -+ -+ return i_sabre_codec_probe(&i2c->dev, regmap); -+} -+ -+static int i_sabre_codec_i2c_remove(struct i2c_client *i2c) -+{ -+ i_sabre_codec_remove(&i2c->dev); -+ -+ return 0; -+} -+ -+ -+static const struct i2c_device_id i_sabre_codec_i2c_id[] = { -+ { "i-sabre-codec", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, i_sabre_codec_i2c_id); -+ -+static const struct of_device_id i_sabre_codec_of_match[] = { -+ { .compatible = "audiophonics,i-sabre-codec", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, i_sabre_codec_of_match); -+ -+static struct i2c_driver i_sabre_codec_i2c_driver = { -+ .driver = { -+ .name = "i-sabre-codec-i2c", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(i_sabre_codec_of_match), -+ }, -+ .probe = i_sabre_codec_i2c_probe, -+ .remove = i_sabre_codec_i2c_remove, -+ .id_table = i_sabre_codec_i2c_id, -+}; -+module_i2c_driver(i_sabre_codec_i2c_driver); -+ -+ -+MODULE_DESCRIPTION("ASoC I-Sabre Q2M codec driver"); -+MODULE_AUTHOR("Audiophonics "); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/sound/soc/codecs/i-sabre-codec.h -@@ -0,0 +1,42 @@ -+/* -+ * Driver for I-Sabre Q2M -+ * -+ * Author: Satoru Kawase -+ * Modified by: Xiao Qingyong -+ * Copyright 2018 Audiophonics -+ * -+ * 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. -+ * -+ * 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. -+ */ -+ -+#ifndef _SND_SOC_ISABRECODEC -+#define _SND_SOC_ISABRECODEC -+ -+ -+/* ISABRECODEC Register Address */ -+#define ISABRECODEC_REG_01 0x01 /* Virtual Device ID : 0x01 = es9038q2m */ -+#define ISABRECODEC_REG_02 0x02 /* API revision : 0x01 = Revision 01 */ -+#define ISABRECODEC_REG_10 0x10 /* 0x01 = above 192kHz, 0x00 = otherwise */ -+#define ISABRECODEC_REG_20 0x20 /* 0 - 100 (decimal value, 0 = min., 100 = max.) */ -+#define ISABRECODEC_REG_21 0x21 /* 0x00 = Mute OFF, 0x01 = Mute ON */ -+#define ISABRECODEC_REG_22 0x22 -+/* -+ 0x00 = brick wall, -+ 0x01 = corrected minimum phase fast, -+ 0x02 = minimum phase slow, -+ 0x03 = minimum phase fast, -+ 0x04 = linear phase slow, -+ 0x05 = linear phase fast, -+ 0x06 = apodizing fast, -+*/ -+//#define ISABRECODEC_REG_23 0x23 /* reserved */ -+#define ISABRECODEC_REG_24 0x24 /* 0x00 = I2S, 0x01 = SPDIF */ -+#define ISABRECODEC_MAX_REG 0x24 /* Maximum Register Number */ -+ -+#endif /* _SND_SOC_ISABRECODEC */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0145-lan78xx-use-default-alignment-for-rx-buffers.patch b/target/linux/bcm27xx/patches-5.4/950-0145-lan78xx-use-default-alignment-for-rx-buffers.patch new file mode 100644 index 0000000000..1c2daad764 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0145-lan78xx-use-default-alignment-for-rx-buffers.patch @@ -0,0 +1,23 @@ +From c4fb99ee7aac2b979f729d4641d0e22fb5c08cc1 Mon Sep 17 00:00:00 2001 +From: P33M +Date: Thu, 2 May 2019 11:53:45 +0100 +Subject: [PATCH] lan78xx: use default alignment for rx buffers + +The lan78xx uses a 12-byte hardware rx header, so there is no need +to allocate SKBs with NET_IP_ALIGN set. Removes alignment faults +in both dwc_otg and in ipv6 processing. +--- + drivers/net/usb/lan78xx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/usb/lan78xx.c ++++ b/drivers/net/usb/lan78xx.c +@@ -3169,7 +3169,7 @@ static int rx_submit(struct lan78xx_net + size_t size = dev->rx_urb_size; + int ret = 0; + +- skb = netdev_alloc_skb_ip_align(dev->net, size); ++ skb = netdev_alloc_skb(dev->net, size); + if (!skb) { + usb_free_urb(urb); + return -ENOMEM; diff --git a/target/linux/bcm27xx/patches-5.4/950-0146-Added-IQaudIO-Pi-Codec-board-support-2969.patch b/target/linux/bcm27xx/patches-5.4/950-0146-Added-IQaudIO-Pi-Codec-board-support-2969.patch new file mode 100644 index 0000000000..2e4039c6b1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0146-Added-IQaudIO-Pi-Codec-board-support-2969.patch @@ -0,0 +1,332 @@ +From 1f912d3042032514c33736723300b3ed618ddd08 Mon Sep 17 00:00:00 2001 +From: IQaudIO +Date: Mon, 13 May 2019 21:53:05 +0100 +Subject: [PATCH] Added IQaudIO Pi-Codec board support (#2969) + +Add support for the IQaudIO Pi-Codec board. + +Signed-off-by: Gordon + +Fixed 48k timing issue + +ASoC: iqaudio-codec: use modern dai_link style + +Signed-off-by: Hui Wang +--- + sound/soc/bcm/Kconfig | 7 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/iqaudio-codec.c | 274 ++++++++++++++++++++++++++++++++++ + 3 files changed, 283 insertions(+) + create mode 100644 sound/soc/bcm/iqaudio-codec.c + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -104,6 +104,13 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI + help + Say Y or M if you want to add support for JustBoom Digi. + ++config SND_BCM2708_SOC_IQAUDIO_CODEC ++ tristate "Support for IQaudIO-CODEC" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_DA7213 ++ help ++ Say Y or M if you want to add support for IQaudIO-CODEC. ++ + config SND_BCM2708_SOC_IQAUDIO_DAC + tristate "Support for IQaudIO-DAC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -18,6 +18,7 @@ snd-soc-hifiberry-dacplusadc-objs := hif + snd-soc-justboom-dac-objs := justboom-dac.o + snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-proto-objs := rpi-proto.o ++snd-soc-iqaudio-codec-objs := iqaudio-codec.o + snd-soc-iqaudio-dac-objs := iqaudio-dac.o + snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o + snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o +@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o ++obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o + obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o + obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o +--- /dev/null ++++ b/sound/soc/bcm/iqaudio-codec.c +@@ -0,0 +1,274 @@ ++/* ++ * ASoC Driver for IQaudIO Raspberry Pi Codec board ++ * ++ * Author: Gordon Garrity ++ * (C) Copyright IQaudio Limited, 2017-2019 ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include "../codecs/da7213.h" ++ ++static int pll_out = DA7213_PLL_FREQ_OUT_90316800; ++ ++static int snd_rpi_iqaudio_pll_control(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *k, int event) ++{ ++ int ret = 0; ++ struct snd_soc_dapm_context *dapm = w->dapm; ++ struct snd_soc_card *card = dapm->card; ++ struct snd_soc_pcm_runtime *rtd = ++ snd_soc_get_pcm_runtime(card, card->dai_link[0].name); ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ ++ if (SND_SOC_DAPM_EVENT_OFF(event)) { ++ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_MCLK, 0, ++ 0); ++ if (ret) ++ dev_err(card->dev, "Failed to bypass PLL: %d\n", ret); ++ /* Allow PLL time to bypass */ ++ msleep(100); ++ } else if (SND_SOC_DAPM_EVENT_ON(event)) { ++ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0, ++ pll_out); ++ if (ret) ++ dev_err(card->dev, "Failed to enable PLL: %d\n", ret); ++ /* Allow PLL time to lock */ ++ msleep(100); ++ } ++ ++ return ret; ++} ++ ++static int snd_rpi_iqaudio_post_dapm_event(struct snd_soc_dapm_widget *w, ++ struct snd_kcontrol *kcontrol, ++ int event) ++{ ++ switch (event) { ++ case SND_SOC_DAPM_POST_PMU: ++ /* Delay for mic bias ramp */ ++ msleep(1000); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static const struct snd_kcontrol_new dapm_controls[] = { ++ SOC_DAPM_PIN_SWITCH("HP Jack"), ++ SOC_DAPM_PIN_SWITCH("MIC Jack"), ++ SOC_DAPM_PIN_SWITCH("Onboard MIC"), ++ SOC_DAPM_PIN_SWITCH("AUX Jack"), ++}; ++ ++static const struct snd_soc_dapm_widget dapm_widgets[] = { ++ SND_SOC_DAPM_HP("HP Jack", NULL), ++ SND_SOC_DAPM_MIC("MIC Jack", NULL), ++ SND_SOC_DAPM_MIC("Onboard MIC", NULL), ++ SND_SOC_DAPM_LINE("AUX Jack", NULL), ++ SND_SOC_DAPM_SUPPLY("PLL Control", SND_SOC_NOPM, 0, 0, ++ snd_rpi_iqaudio_pll_control, ++ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), ++ SND_SOC_DAPM_POST("Post Power Up Event", snd_rpi_iqaudio_post_dapm_event), ++}; ++ ++static const struct snd_soc_dapm_route audio_map[] = { ++ {"HP Jack", NULL, "HPL"}, ++ {"HP Jack", NULL, "HPR"}, ++ {"HP Jack", NULL, "PLL Control"}, ++ ++ {"AUXR", NULL, "AUX Jack"}, ++ {"AUXL", NULL, "AUX Jack"}, ++ {"AUX Jack", NULL, "PLL Control"}, ++ ++ /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */ ++ {"MIC1", NULL, "MIC Jack"}, ++ {"MIC Jack", NULL, "PLL Control"}, ++ {"MIC2", NULL, "Onboard MIC"}, ++ {"Onboard MIC", NULL, "PLL Control"}, ++}; ++ ++/* machine stream operations */ ++ ++static int snd_rpi_iqaudio_codec_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ int ret; ++ ++ /* ++ * Disable AUX Jack Pin by default to prevent PLL being enabled at ++ * startup. This avoids holding the PLL to a fixed SR config for ++ * subsequent streams. ++ * ++ * This pin can still be enabled later, as required by user-space. ++ */ ++ snd_soc_dapm_disable_pin(&rtd->card->dapm, "AUX Jack"); ++ snd_soc_dapm_sync(&rtd->card->dapm); ++ ++ /* Set bclk ratio to align with codec's BCLK rate */ ++ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64); ++ if (ret) { ++ dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n"); ++ return ret; ++ } ++ ++ /* Set MCLK frequency to codec, onboard 11.2896MHz clock */ ++ return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600, ++ SND_SOC_CLOCK_OUT); ++} ++ ++static int snd_rpi_iqaudio_codec_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ unsigned int samplerate = params_rate(params); ++ ++ switch (samplerate) { ++ case 8000: ++ case 16000: ++ case 32000: ++ case 48000: ++ case 96000: ++ pll_out = DA7213_PLL_FREQ_OUT_98304000; ++ return 0; ++ case 44100: ++ case 88200: ++ pll_out = DA7213_PLL_FREQ_OUT_90316800; ++ return 0; ++ default: ++ dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate); ++ return -EINVAL; ++ } ++} ++ ++static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = { ++ .hw_params = snd_rpi_iqaudio_codec_hw_params, ++}; ++ ++SND_SOC_DAILINK_DEFS(rpi_iqaudio, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("da7213.1-001a", "da7213-hifi")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0"))); ++ ++static struct snd_soc_dai_link snd_rpi_iqaudio_codec_dai[] = { ++{ ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM, ++ .init = snd_rpi_iqaudio_codec_init, ++ .ops = &snd_rpi_iqaudio_codec_ops, ++ .symmetric_rates = 1, ++ .symmetric_channels = 1, ++ .symmetric_samplebits = 1, ++ SND_SOC_DAILINK_REG(rpi_iqaudio), ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_iqaudio_codec = { ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_iqaudio_codec_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai), ++ .controls = dapm_controls, ++ .num_controls = ARRAY_SIZE(dapm_controls), ++ .dapm_widgets = dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(dapm_widgets), ++ .dapm_routes = audio_map, ++ .num_dapm_routes = ARRAY_SIZE(audio_map), ++}; ++ ++static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_iqaudio_codec.dev = &pdev->dev; ++ ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_card *card = &snd_rpi_iqaudio_codec; ++ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_codec_dai[0]; ++ ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; ++ } ++ ++ if (of_property_read_string(pdev->dev.of_node, "card_name", ++ &card->name)) ++ card->name = "IQaudIOCODEC"; ++ ++ if (of_property_read_string(pdev->dev.of_node, "dai_name", ++ &dai->name)) ++ dai->name = "IQaudIO CODEC"; ++ ++ if (of_property_read_string(pdev->dev.of_node, ++ "dai_stream_name", &dai->stream_name)) ++ dai->stream_name = "IQaudIO CODEC HiFi v1.2"; ++ ++ } ++ ++ ret = snd_soc_register_card(&snd_rpi_iqaudio_codec); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_iqaudio_codec); ++} ++ ++static const struct of_device_id iqaudio_of_match[] = { ++ { .compatible = "iqaudio,iqaudio-codec", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, iqaudio_of_match); ++ ++static struct platform_driver snd_rpi_iqaudio_codec_driver = { ++ .driver = { ++ .name = "snd-rpi-iqaudio-codec", ++ .owner = THIS_MODULE, ++ .of_match_table = iqaudio_of_match, ++ }, ++ .probe = snd_rpi_iqaudio_codec_probe, ++ .remove = snd_rpi_iqaudio_codec_remove, ++}; ++ ++ ++ ++module_platform_driver(snd_rpi_iqaudio_codec_driver); ++ ++MODULE_AUTHOR("Gordon Garrity "); ++MODULE_DESCRIPTION("ASoC Driver for IQaudIO CODEC"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0146-lan78xx-use-default-alignment-for-rx-buffers.patch b/target/linux/bcm27xx/patches-5.4/950-0146-lan78xx-use-default-alignment-for-rx-buffers.patch deleted file mode 100644 index 1c2daad764..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0146-lan78xx-use-default-alignment-for-rx-buffers.patch +++ /dev/null @@ -1,23 +0,0 @@ -From c4fb99ee7aac2b979f729d4641d0e22fb5c08cc1 Mon Sep 17 00:00:00 2001 -From: P33M -Date: Thu, 2 May 2019 11:53:45 +0100 -Subject: [PATCH] lan78xx: use default alignment for rx buffers - -The lan78xx uses a 12-byte hardware rx header, so there is no need -to allocate SKBs with NET_IP_ALIGN set. Removes alignment faults -in both dwc_otg and in ipv6 processing. ---- - drivers/net/usb/lan78xx.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/usb/lan78xx.c -+++ b/drivers/net/usb/lan78xx.c -@@ -3169,7 +3169,7 @@ static int rx_submit(struct lan78xx_net - size_t size = dev->rx_urb_size; - int ret = 0; - -- skb = netdev_alloc_skb_ip_align(dev->net, size); -+ skb = netdev_alloc_skb(dev->net, size); - if (!skb) { - usb_free_urb(urb); - return -ENOMEM; diff --git a/target/linux/bcm27xx/patches-5.4/950-0147-Added-IQaudIO-Pi-Codec-board-support-2969.patch b/target/linux/bcm27xx/patches-5.4/950-0147-Added-IQaudIO-Pi-Codec-board-support-2969.patch deleted file mode 100644 index 2e4039c6b1..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0147-Added-IQaudIO-Pi-Codec-board-support-2969.patch +++ /dev/null @@ -1,332 +0,0 @@ -From 1f912d3042032514c33736723300b3ed618ddd08 Mon Sep 17 00:00:00 2001 -From: IQaudIO -Date: Mon, 13 May 2019 21:53:05 +0100 -Subject: [PATCH] Added IQaudIO Pi-Codec board support (#2969) - -Add support for the IQaudIO Pi-Codec board. - -Signed-off-by: Gordon - -Fixed 48k timing issue - -ASoC: iqaudio-codec: use modern dai_link style - -Signed-off-by: Hui Wang ---- - sound/soc/bcm/Kconfig | 7 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/iqaudio-codec.c | 274 ++++++++++++++++++++++++++++++++++ - 3 files changed, 283 insertions(+) - create mode 100644 sound/soc/bcm/iqaudio-codec.c - ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -104,6 +104,13 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI - help - Say Y or M if you want to add support for JustBoom Digi. - -+config SND_BCM2708_SOC_IQAUDIO_CODEC -+ tristate "Support for IQaudIO-CODEC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_DA7213 -+ help -+ Say Y or M if you want to add support for IQaudIO-CODEC. -+ - config SND_BCM2708_SOC_IQAUDIO_DAC - tristate "Support for IQaudIO-DAC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -18,6 +18,7 @@ snd-soc-hifiberry-dacplusadc-objs := hif - snd-soc-justboom-dac-objs := justboom-dac.o - snd-soc-rpi-cirrus-objs := rpi-cirrus.o - snd-soc-rpi-proto-objs := rpi-proto.o -+snd-soc-iqaudio-codec-objs := iqaudio-codec.o - snd-soc-iqaudio-dac-objs := iqaudio-dac.o - snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o - snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o -@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D - obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o -+obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o - obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o - obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o ---- /dev/null -+++ b/sound/soc/bcm/iqaudio-codec.c -@@ -0,0 +1,274 @@ -+/* -+ * ASoC Driver for IQaudIO Raspberry Pi Codec board -+ * -+ * Author: Gordon Garrity -+ * (C) Copyright IQaudio Limited, 2017-2019 -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "../codecs/da7213.h" -+ -+static int pll_out = DA7213_PLL_FREQ_OUT_90316800; -+ -+static int snd_rpi_iqaudio_pll_control(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *k, int event) -+{ -+ int ret = 0; -+ struct snd_soc_dapm_context *dapm = w->dapm; -+ struct snd_soc_card *card = dapm->card; -+ struct snd_soc_pcm_runtime *rtd = -+ snd_soc_get_pcm_runtime(card, card->dai_link[0].name); -+ struct snd_soc_dai *codec_dai = rtd->codec_dai; -+ -+ if (SND_SOC_DAPM_EVENT_OFF(event)) { -+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_MCLK, 0, -+ 0); -+ if (ret) -+ dev_err(card->dev, "Failed to bypass PLL: %d\n", ret); -+ /* Allow PLL time to bypass */ -+ msleep(100); -+ } else if (SND_SOC_DAPM_EVENT_ON(event)) { -+ ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0, -+ pll_out); -+ if (ret) -+ dev_err(card->dev, "Failed to enable PLL: %d\n", ret); -+ /* Allow PLL time to lock */ -+ msleep(100); -+ } -+ -+ return ret; -+} -+ -+static int snd_rpi_iqaudio_post_dapm_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, -+ int event) -+{ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ /* Delay for mic bias ramp */ -+ msleep(1000); -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static const struct snd_kcontrol_new dapm_controls[] = { -+ SOC_DAPM_PIN_SWITCH("HP Jack"), -+ SOC_DAPM_PIN_SWITCH("MIC Jack"), -+ SOC_DAPM_PIN_SWITCH("Onboard MIC"), -+ SOC_DAPM_PIN_SWITCH("AUX Jack"), -+}; -+ -+static const struct snd_soc_dapm_widget dapm_widgets[] = { -+ SND_SOC_DAPM_HP("HP Jack", NULL), -+ SND_SOC_DAPM_MIC("MIC Jack", NULL), -+ SND_SOC_DAPM_MIC("Onboard MIC", NULL), -+ SND_SOC_DAPM_LINE("AUX Jack", NULL), -+ SND_SOC_DAPM_SUPPLY("PLL Control", SND_SOC_NOPM, 0, 0, -+ snd_rpi_iqaudio_pll_control, -+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), -+ SND_SOC_DAPM_POST("Post Power Up Event", snd_rpi_iqaudio_post_dapm_event), -+}; -+ -+static const struct snd_soc_dapm_route audio_map[] = { -+ {"HP Jack", NULL, "HPL"}, -+ {"HP Jack", NULL, "HPR"}, -+ {"HP Jack", NULL, "PLL Control"}, -+ -+ {"AUXR", NULL, "AUX Jack"}, -+ {"AUXL", NULL, "AUX Jack"}, -+ {"AUX Jack", NULL, "PLL Control"}, -+ -+ /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */ -+ {"MIC1", NULL, "MIC Jack"}, -+ {"MIC Jack", NULL, "PLL Control"}, -+ {"MIC2", NULL, "Onboard MIC"}, -+ {"Onboard MIC", NULL, "PLL Control"}, -+}; -+ -+/* machine stream operations */ -+ -+static int snd_rpi_iqaudio_codec_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_dai *codec_dai = rtd->codec_dai; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ int ret; -+ -+ /* -+ * Disable AUX Jack Pin by default to prevent PLL being enabled at -+ * startup. This avoids holding the PLL to a fixed SR config for -+ * subsequent streams. -+ * -+ * This pin can still be enabled later, as required by user-space. -+ */ -+ snd_soc_dapm_disable_pin(&rtd->card->dapm, "AUX Jack"); -+ snd_soc_dapm_sync(&rtd->card->dapm); -+ -+ /* Set bclk ratio to align with codec's BCLK rate */ -+ ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64); -+ if (ret) { -+ dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n"); -+ return ret; -+ } -+ -+ /* Set MCLK frequency to codec, onboard 11.2896MHz clock */ -+ return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600, -+ SND_SOC_CLOCK_OUT); -+} -+ -+static int snd_rpi_iqaudio_codec_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ unsigned int samplerate = params_rate(params); -+ -+ switch (samplerate) { -+ case 8000: -+ case 16000: -+ case 32000: -+ case 48000: -+ case 96000: -+ pll_out = DA7213_PLL_FREQ_OUT_98304000; -+ return 0; -+ case 44100: -+ case 88200: -+ pll_out = DA7213_PLL_FREQ_OUT_90316800; -+ return 0; -+ default: -+ dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate); -+ return -EINVAL; -+ } -+} -+ -+static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = { -+ .hw_params = snd_rpi_iqaudio_codec_hw_params, -+}; -+ -+SND_SOC_DAILINK_DEFS(rpi_iqaudio, -+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), -+ DAILINK_COMP_ARRAY(COMP_CODEC("da7213.1-001a", "da7213-hifi")), -+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0"))); -+ -+static struct snd_soc_dai_link snd_rpi_iqaudio_codec_dai[] = { -+{ -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBM_CFM, -+ .init = snd_rpi_iqaudio_codec_init, -+ .ops = &snd_rpi_iqaudio_codec_ops, -+ .symmetric_rates = 1, -+ .symmetric_channels = 1, -+ .symmetric_samplebits = 1, -+ SND_SOC_DAILINK_REG(rpi_iqaudio), -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_iqaudio_codec = { -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_iqaudio_codec_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai), -+ .controls = dapm_controls, -+ .num_controls = ARRAY_SIZE(dapm_controls), -+ .dapm_widgets = dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(dapm_widgets), -+ .dapm_routes = audio_map, -+ .num_dapm_routes = ARRAY_SIZE(audio_map), -+}; -+ -+static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_iqaudio_codec.dev = &pdev->dev; -+ -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_card *card = &snd_rpi_iqaudio_codec; -+ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_codec_dai[0]; -+ -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ if (i2s_node) { -+ dai->cpus->dai_name = NULL; -+ dai->cpus->of_node = i2s_node; -+ dai->platforms->name = NULL; -+ dai->platforms->of_node = i2s_node; -+ } -+ -+ if (of_property_read_string(pdev->dev.of_node, "card_name", -+ &card->name)) -+ card->name = "IQaudIOCODEC"; -+ -+ if (of_property_read_string(pdev->dev.of_node, "dai_name", -+ &dai->name)) -+ dai->name = "IQaudIO CODEC"; -+ -+ if (of_property_read_string(pdev->dev.of_node, -+ "dai_stream_name", &dai->stream_name)) -+ dai->stream_name = "IQaudIO CODEC HiFi v1.2"; -+ -+ } -+ -+ ret = snd_soc_register_card(&snd_rpi_iqaudio_codec); -+ if (ret) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_iqaudio_codec); -+} -+ -+static const struct of_device_id iqaudio_of_match[] = { -+ { .compatible = "iqaudio,iqaudio-codec", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, iqaudio_of_match); -+ -+static struct platform_driver snd_rpi_iqaudio_codec_driver = { -+ .driver = { -+ .name = "snd-rpi-iqaudio-codec", -+ .owner = THIS_MODULE, -+ .of_match_table = iqaudio_of_match, -+ }, -+ .probe = snd_rpi_iqaudio_codec_probe, -+ .remove = snd_rpi_iqaudio_codec_remove, -+}; -+ -+ -+ -+module_platform_driver(snd_rpi_iqaudio_codec_driver); -+ -+MODULE_AUTHOR("Gordon Garrity "); -+MODULE_DESCRIPTION("ASoC Driver for IQaudIO CODEC"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0147-sound-pcm512x-codec-Adding-352.8kHz-samplerate-suppo.patch b/target/linux/bcm27xx/patches-5.4/950-0147-sound-pcm512x-codec-Adding-352.8kHz-samplerate-suppo.patch new file mode 100644 index 0000000000..838508559e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0147-sound-pcm512x-codec-Adding-352.8kHz-samplerate-suppo.patch @@ -0,0 +1,21 @@ +From 59f91d9880013a36b1257dd8ce4b9412dec4132c Mon Sep 17 00:00:00 2001 +From: Klaus Schulz +Date: Thu, 16 May 2019 13:35:32 +0200 +Subject: [PATCH] sound: pcm512x-codec: Adding 352.8kHz samplerate + support + +--- + sound/soc/codecs/pcm512x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/soc/codecs/pcm512x.c ++++ b/sound/soc/codecs/pcm512x.c +@@ -534,7 +534,7 @@ static unsigned long pcm512x_ncp_target( + + static const u32 pcm512x_dai_rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, +- 88200, 96000, 176400, 192000, 384000, ++ 88200, 96000, 176400, 192000, 352800, 384000, + }; + + static const struct snd_pcm_hw_constraint_list constraints_slave = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0148-media-ov5647-Add-set_fmt-and-get_fmt-calls.patch b/target/linux/bcm27xx/patches-5.4/950-0148-media-ov5647-Add-set_fmt-and-get_fmt-calls.patch new file mode 100644 index 0000000000..6b5aa2b664 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0148-media-ov5647-Add-set_fmt-and-get_fmt-calls.patch @@ -0,0 +1,47 @@ +From 380d116f08c6ebca53234cba682b7e9e37bbab94 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:55:37 +0000 +Subject: [PATCH] media: ov5647: Add set_fmt and get_fmt calls. + +There's no way to query the subdevice for the supported +resolutions. +Add set_fmt and get_fmt implementations. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -463,8 +463,30 @@ static int ov5647_enum_mbus_code(struct + return 0; + } + ++static int ov5647_set_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ ++ if (format->pad != 0) ++ return -EINVAL; ++ ++ /* Only one format is supported, so return that */ ++ memset(fmt, 0, sizeof(*fmt)); ++ fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; ++ fmt->colorspace = V4L2_COLORSPACE_SRGB; ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->width = 640; ++ fmt->height = 480; ++ ++ return 0; ++} ++ + static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = { + .enum_mbus_code = ov5647_enum_mbus_code, ++ .set_fmt = ov5647_set_get_fmt, ++ .get_fmt = ov5647_set_get_fmt, + }; + + static const struct v4l2_subdev_ops ov5647_subdev_ops = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0148-sound-pcm512x-codec-Adding-352.8kHz-samplerate-suppo.patch b/target/linux/bcm27xx/patches-5.4/950-0148-sound-pcm512x-codec-Adding-352.8kHz-samplerate-suppo.patch deleted file mode 100644 index 838508559e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0148-sound-pcm512x-codec-Adding-352.8kHz-samplerate-suppo.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 59f91d9880013a36b1257dd8ce4b9412dec4132c Mon Sep 17 00:00:00 2001 -From: Klaus Schulz -Date: Thu, 16 May 2019 13:35:32 +0200 -Subject: [PATCH] sound: pcm512x-codec: Adding 352.8kHz samplerate - support - ---- - sound/soc/codecs/pcm512x.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/sound/soc/codecs/pcm512x.c -+++ b/sound/soc/codecs/pcm512x.c -@@ -534,7 +534,7 @@ static unsigned long pcm512x_ncp_target( - - static const u32 pcm512x_dai_rates[] = { - 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, -- 88200, 96000, 176400, 192000, 384000, -+ 88200, 96000, 176400, 192000, 352800, 384000, - }; - - static const struct snd_pcm_hw_constraint_list constraints_slave = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0149-media-Documentation-DT-add-device-tree-for-PWDN-cont.patch b/target/linux/bcm27xx/patches-5.4/950-0149-media-Documentation-DT-add-device-tree-for-PWDN-cont.patch new file mode 100644 index 0000000000..6d2cd03daa --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0149-media-Documentation-DT-add-device-tree-for-PWDN-cont.patch @@ -0,0 +1,33 @@ +From 574d071603ed49ed9c05a898763869b0e75344bb Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:55:59 +0000 +Subject: [PATCH] Documentation: DT: add device tree for PWDN + control + +Add optional GPIO pwdn to connect to the PWDN line on the sensor. + +Signed-off-by: Dave Stevenson +--- + Documentation/devicetree/bindings/media/i2c/ov5647.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/devicetree/bindings/media/i2c/ov5647.txt ++++ b/Documentation/devicetree/bindings/media/i2c/ov5647.txt +@@ -10,6 +10,9 @@ Required properties: + - reg : I2C slave address of the sensor. + - clocks : Reference to the xclk clock. + ++Optional Properties: ++- pwdn-gpios: reference to the GPIO connected to the pwdn pin, if any. ++ + The common video interfaces bindings (see video-interfaces.txt) should be + used to specify link to the image data receiver. The OV5647 device + node should contain one 'port' child node with an 'endpoint' subnode. +@@ -26,6 +29,7 @@ Example: + compatible = "ovti,ov5647"; + reg = <0x36>; + clocks = <&camera_clk>; ++ pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>; + port { + camera_1: endpoint { + remote-endpoint = <&csi1_ep1>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0149-media-ov5647-Add-set_fmt-and-get_fmt-calls.patch b/target/linux/bcm27xx/patches-5.4/950-0149-media-ov5647-Add-set_fmt-and-get_fmt-calls.patch deleted file mode 100644 index 6b5aa2b664..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0149-media-ov5647-Add-set_fmt-and-get_fmt-calls.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 380d116f08c6ebca53234cba682b7e9e37bbab94 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:55:37 +0000 -Subject: [PATCH] media: ov5647: Add set_fmt and get_fmt calls. - -There's no way to query the subdevice for the supported -resolutions. -Add set_fmt and get_fmt implementations. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/ov5647.c | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - ---- a/drivers/media/i2c/ov5647.c -+++ b/drivers/media/i2c/ov5647.c -@@ -463,8 +463,30 @@ static int ov5647_enum_mbus_code(struct - return 0; - } - -+static int ov5647_set_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct v4l2_mbus_framefmt *fmt = &format->format; -+ -+ if (format->pad != 0) -+ return -EINVAL; -+ -+ /* Only one format is supported, so return that */ -+ memset(fmt, 0, sizeof(*fmt)); -+ fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; -+ fmt->colorspace = V4L2_COLORSPACE_SRGB; -+ fmt->field = V4L2_FIELD_NONE; -+ fmt->width = 640; -+ fmt->height = 480; -+ -+ return 0; -+} -+ - static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = { - .enum_mbus_code = ov5647_enum_mbus_code, -+ .set_fmt = ov5647_set_get_fmt, -+ .get_fmt = ov5647_set_get_fmt, - }; - - static const struct v4l2_subdev_ops ov5647_subdev_ops = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0150-media-Documentation-DT-add-device-tree-for-PWDN-cont.patch b/target/linux/bcm27xx/patches-5.4/950-0150-media-Documentation-DT-add-device-tree-for-PWDN-cont.patch deleted file mode 100644 index 6d2cd03daa..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0150-media-Documentation-DT-add-device-tree-for-PWDN-cont.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 574d071603ed49ed9c05a898763869b0e75344bb Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:55:59 +0000 -Subject: [PATCH] Documentation: DT: add device tree for PWDN - control - -Add optional GPIO pwdn to connect to the PWDN line on the sensor. - -Signed-off-by: Dave Stevenson ---- - Documentation/devicetree/bindings/media/i2c/ov5647.txt | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/Documentation/devicetree/bindings/media/i2c/ov5647.txt -+++ b/Documentation/devicetree/bindings/media/i2c/ov5647.txt -@@ -10,6 +10,9 @@ Required properties: - - reg : I2C slave address of the sensor. - - clocks : Reference to the xclk clock. - -+Optional Properties: -+- pwdn-gpios: reference to the GPIO connected to the pwdn pin, if any. -+ - The common video interfaces bindings (see video-interfaces.txt) should be - used to specify link to the image data receiver. The OV5647 device - node should contain one 'port' child node with an 'endpoint' subnode. -@@ -26,6 +29,7 @@ Example: - compatible = "ovti,ov5647"; - reg = <0x36>; - clocks = <&camera_clk>; -+ pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>; - port { - camera_1: endpoint { - remote-endpoint = <&csi1_ep1>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0150-media-ov5647-Add-support-for-PWDN-GPIO.patch b/target/linux/bcm27xx/patches-5.4/950-0150-media-ov5647-Add-support-for-PWDN-GPIO.patch new file mode 100644 index 0000000000..24b678f858 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0150-media-ov5647-Add-support-for-PWDN-GPIO.patch @@ -0,0 +1,92 @@ +From 877bbff2bf6d53104efd1da9caf1e9cfff6f6ef4 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:56:33 +0000 +Subject: [PATCH] media: ov5647: Add support for PWDN GPIO. + +Add support for an optional GPIO connected to PWDN on the sensor. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -21,6 +21,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -35,6 +36,13 @@ + + #define SENSOR_NAME "ov5647" + ++/* ++ * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes ++ * high if reset is inserted after PWDN goes high, host can access sensor's ++ * SCCB to initialize sensor." ++ */ ++#define PWDN_ACTIVE_DELAY_MS 20 ++ + #define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5) + #define MIPI_CTRL00_BUS_IDLE BIT(2) + #define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0) +@@ -86,6 +94,7 @@ struct ov5647 { + unsigned int height; + int power_count; + struct clk *xclk; ++ struct gpio_desc *pwdn; + }; + + static inline struct ov5647 *to_state(struct v4l2_subdev *sd) +@@ -355,6 +364,11 @@ static int ov5647_sensor_power(struct v4 + if (on && !ov5647->power_count) { + dev_dbg(&client->dev, "OV5647 power on\n"); + ++ if (ov5647->pwdn) { ++ gpiod_set_value(ov5647->pwdn, 0); ++ msleep(PWDN_ACTIVE_DELAY_MS); ++ } ++ + ret = clk_prepare_enable(ov5647->xclk); + if (ret < 0) { + dev_err(&client->dev, "clk prepare enable failed\n"); +@@ -392,6 +406,8 @@ static int ov5647_sensor_power(struct v4 + dev_dbg(&client->dev, "soft stby failed\n"); + + clk_disable_unprepare(ov5647->xclk); ++ ++ gpiod_set_value(ov5647->pwdn, 1); + } + + /* Update the power count. */ +@@ -603,6 +619,10 @@ static int ov5647_probe(struct i2c_clien + return -EINVAL; + } + ++ /* Request the power down GPIO asserted */ ++ sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn", ++ GPIOD_OUT_HIGH); ++ + mutex_init(&sensor->lock); + + sd = &sensor->sd; +@@ -616,7 +636,15 @@ static int ov5647_probe(struct i2c_clien + if (ret < 0) + goto mutex_remove; + ++ if (sensor->pwdn) { ++ gpiod_set_value(sensor->pwdn, 0); ++ msleep(PWDN_ACTIVE_DELAY_MS); ++ } ++ + ret = ov5647_detect(sd); ++ ++ gpiod_set_value(sensor->pwdn, 1); ++ + if (ret < 0) + goto error; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0151-media-ov5647-Add-support-for-PWDN-GPIO.patch b/target/linux/bcm27xx/patches-5.4/950-0151-media-ov5647-Add-support-for-PWDN-GPIO.patch deleted file mode 100644 index 24b678f858..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0151-media-ov5647-Add-support-for-PWDN-GPIO.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 877bbff2bf6d53104efd1da9caf1e9cfff6f6ef4 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:56:33 +0000 -Subject: [PATCH] media: ov5647: Add support for PWDN GPIO. - -Add support for an optional GPIO connected to PWDN on the sensor. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/ov5647.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - ---- a/drivers/media/i2c/ov5647.c -+++ b/drivers/media/i2c/ov5647.c -@@ -21,6 +21,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -35,6 +36,13 @@ - - #define SENSOR_NAME "ov5647" - -+/* -+ * From the datasheet, "20ms after PWDN goes low or 20ms after RESETB goes -+ * high if reset is inserted after PWDN goes high, host can access sensor's -+ * SCCB to initialize sensor." -+ */ -+#define PWDN_ACTIVE_DELAY_MS 20 -+ - #define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5) - #define MIPI_CTRL00_BUS_IDLE BIT(2) - #define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0) -@@ -86,6 +94,7 @@ struct ov5647 { - unsigned int height; - int power_count; - struct clk *xclk; -+ struct gpio_desc *pwdn; - }; - - static inline struct ov5647 *to_state(struct v4l2_subdev *sd) -@@ -355,6 +364,11 @@ static int ov5647_sensor_power(struct v4 - if (on && !ov5647->power_count) { - dev_dbg(&client->dev, "OV5647 power on\n"); - -+ if (ov5647->pwdn) { -+ gpiod_set_value(ov5647->pwdn, 0); -+ msleep(PWDN_ACTIVE_DELAY_MS); -+ } -+ - ret = clk_prepare_enable(ov5647->xclk); - if (ret < 0) { - dev_err(&client->dev, "clk prepare enable failed\n"); -@@ -392,6 +406,8 @@ static int ov5647_sensor_power(struct v4 - dev_dbg(&client->dev, "soft stby failed\n"); - - clk_disable_unprepare(ov5647->xclk); -+ -+ gpiod_set_value(ov5647->pwdn, 1); - } - - /* Update the power count. */ -@@ -603,6 +619,10 @@ static int ov5647_probe(struct i2c_clien - return -EINVAL; - } - -+ /* Request the power down GPIO asserted */ -+ sensor->pwdn = devm_gpiod_get_optional(&client->dev, "pwdn", -+ GPIOD_OUT_HIGH); -+ - mutex_init(&sensor->lock); - - sd = &sensor->sd; -@@ -616,7 +636,15 @@ static int ov5647_probe(struct i2c_clien - if (ret < 0) - goto mutex_remove; - -+ if (sensor->pwdn) { -+ gpiod_set_value(sensor->pwdn, 0); -+ msleep(PWDN_ACTIVE_DELAY_MS); -+ } -+ - ret = ov5647_detect(sd); -+ -+ gpiod_set_value(sensor->pwdn, 1); -+ - if (ret < 0) - goto error; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0151-media-ov5647-Add-support-for-non-continuous-clock-mo.patch b/target/linux/bcm27xx/patches-5.4/950-0151-media-ov5647-Add-support-for-non-continuous-clock-mo.patch new file mode 100644 index 0000000000..0fc4fa3420 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0151-media-ov5647-Add-support-for-non-continuous-clock-mo.patch @@ -0,0 +1,79 @@ +From fd539af952dfb820dc3d285a4f1311ee17bdbc79 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:56:47 +0000 +Subject: [PATCH] media: ov5647: Add support for non-continuous clock + mode + +The driver was only supporting continuous clock mode +although this was not stated anywhere. +Non-continuous clock saves a small amount of power and +on some SoCs is easier to interface with. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -44,6 +44,7 @@ + #define PWDN_ACTIVE_DELAY_MS 20 + + #define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5) ++#define MIPI_CTRL00_LINE_SYNC_ENABLE BIT(4) + #define MIPI_CTRL00_BUS_IDLE BIT(2) + #define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0) + +@@ -95,6 +96,7 @@ struct ov5647 { + int power_count; + struct clk *xclk; + struct gpio_desc *pwdn; ++ unsigned int flags; + }; + + static inline struct ov5647 *to_state(struct v4l2_subdev *sd) +@@ -269,9 +271,15 @@ static int ov5647_set_virtual_channel(st + + static int ov5647_stream_on(struct v4l2_subdev *sd) + { ++ struct ov5647 *ov5647 = to_state(sd); ++ u8 val = MIPI_CTRL00_BUS_IDLE; + int ret; + +- ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE); ++ if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) ++ val |= MIPI_CTRL00_CLOCK_LANE_GATE | ++ MIPI_CTRL00_LINE_SYNC_ENABLE; ++ ++ ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, val); + if (ret < 0) + return ret; + +@@ -568,7 +576,7 @@ static const struct v4l2_subdev_internal + .open = ov5647_open, + }; + +-static int ov5647_parse_dt(struct device_node *np) ++static int ov5647_parse_dt(struct device_node *np, struct ov5647 *sensor) + { + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; + struct device_node *ep; +@@ -581,6 +589,9 @@ static int ov5647_parse_dt(struct device + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); + ++ if (!ret) ++ sensor->flags = bus_cfg.bus.mipi_csi2.flags; ++ + of_node_put(ep); + return ret; + } +@@ -599,7 +610,7 @@ static int ov5647_probe(struct i2c_clien + return -ENOMEM; + + if (IS_ENABLED(CONFIG_OF) && np) { +- ret = ov5647_parse_dt(np); ++ ret = ov5647_parse_dt(np, sensor); + if (ret) { + dev_err(dev, "DT parsing error: %d\n", ret); + return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0152-media-ov5647-Add-support-for-non-continuous-clock-mo.patch b/target/linux/bcm27xx/patches-5.4/950-0152-media-ov5647-Add-support-for-non-continuous-clock-mo.patch deleted file mode 100644 index 0fc4fa3420..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0152-media-ov5647-Add-support-for-non-continuous-clock-mo.patch +++ /dev/null @@ -1,79 +0,0 @@ -From fd539af952dfb820dc3d285a4f1311ee17bdbc79 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:56:47 +0000 -Subject: [PATCH] media: ov5647: Add support for non-continuous clock - mode - -The driver was only supporting continuous clock mode -although this was not stated anywhere. -Non-continuous clock saves a small amount of power and -on some SoCs is easier to interface with. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/ov5647.c | 17 ++++++++++++++--- - 1 file changed, 14 insertions(+), 3 deletions(-) - ---- a/drivers/media/i2c/ov5647.c -+++ b/drivers/media/i2c/ov5647.c -@@ -44,6 +44,7 @@ - #define PWDN_ACTIVE_DELAY_MS 20 - - #define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5) -+#define MIPI_CTRL00_LINE_SYNC_ENABLE BIT(4) - #define MIPI_CTRL00_BUS_IDLE BIT(2) - #define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0) - -@@ -95,6 +96,7 @@ struct ov5647 { - int power_count; - struct clk *xclk; - struct gpio_desc *pwdn; -+ unsigned int flags; - }; - - static inline struct ov5647 *to_state(struct v4l2_subdev *sd) -@@ -269,9 +271,15 @@ static int ov5647_set_virtual_channel(st - - static int ov5647_stream_on(struct v4l2_subdev *sd) - { -+ struct ov5647 *ov5647 = to_state(sd); -+ u8 val = MIPI_CTRL00_BUS_IDLE; - int ret; - -- ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE); -+ if (ov5647->flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) -+ val |= MIPI_CTRL00_CLOCK_LANE_GATE | -+ MIPI_CTRL00_LINE_SYNC_ENABLE; -+ -+ ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, val); - if (ret < 0) - return ret; - -@@ -568,7 +576,7 @@ static const struct v4l2_subdev_internal - .open = ov5647_open, - }; - --static int ov5647_parse_dt(struct device_node *np) -+static int ov5647_parse_dt(struct device_node *np, struct ov5647 *sensor) - { - struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; - struct device_node *ep; -@@ -581,6 +589,9 @@ static int ov5647_parse_dt(struct device - - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); - -+ if (!ret) -+ sensor->flags = bus_cfg.bus.mipi_csi2.flags; -+ - of_node_put(ep); - return ret; - } -@@ -599,7 +610,7 @@ static int ov5647_probe(struct i2c_clien - return -ENOMEM; - - if (IS_ENABLED(CONFIG_OF) && np) { -- ret = ov5647_parse_dt(np); -+ ret = ov5647_parse_dt(np, sensor); - if (ret) { - dev_err(dev, "DT parsing error: %d\n", ret); - return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0152-media-tc358743-Increase-FIFO-level-to-374.patch b/target/linux/bcm27xx/patches-5.4/950-0152-media-tc358743-Increase-FIFO-level-to-374.patch new file mode 100644 index 0000000000..8ec643f102 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0152-media-tc358743-Increase-FIFO-level-to-374.patch @@ -0,0 +1,31 @@ +From e9d49d1b54bb1f202ac8d4a42c5ebb9a9237da17 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:56:59 +0000 +Subject: [PATCH] media: tc358743: Increase FIFO level to 374. + +The existing fixed value of 16 worked for UYVY 720P60 over +2 lanes at 594MHz, or UYVY 1080P60 over 4 lanes. (RGB888 +1080P60 needs 6 lanes at 594MHz). +It doesn't allow for lower resolutions to work as the FIFO +underflows. + +374 is required for 1080P24-30 UYVY over 2 lanes @ 972Mbit/s, but +>374 means that the FIFO underflows on 1080P50 UYVY over 2 lanes +@ 972Mbit/s. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/tc358743.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -1949,7 +1949,7 @@ static int tc358743_probe_of(struct tc35 + state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; + state->pdata.enable_hdcp = false; + /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ +- state->pdata.fifo_level = 16; ++ state->pdata.fifo_level = 374; + /* + * The PLL input clock is obtained by dividing refclk by pll_prd. + * It must be between 6 MHz and 40 MHz, lower frequency is better. diff --git a/target/linux/bcm27xx/patches-5.4/950-0153-media-tc358743-Increase-FIFO-level-to-374.patch b/target/linux/bcm27xx/patches-5.4/950-0153-media-tc358743-Increase-FIFO-level-to-374.patch deleted file mode 100644 index 8ec643f102..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0153-media-tc358743-Increase-FIFO-level-to-374.patch +++ /dev/null @@ -1,31 +0,0 @@ -From e9d49d1b54bb1f202ac8d4a42c5ebb9a9237da17 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:56:59 +0000 -Subject: [PATCH] media: tc358743: Increase FIFO level to 374. - -The existing fixed value of 16 worked for UYVY 720P60 over -2 lanes at 594MHz, or UYVY 1080P60 over 4 lanes. (RGB888 -1080P60 needs 6 lanes at 594MHz). -It doesn't allow for lower resolutions to work as the FIFO -underflows. - -374 is required for 1080P24-30 UYVY over 2 lanes @ 972Mbit/s, but ->374 means that the FIFO underflows on 1080P50 UYVY over 2 lanes -@ 972Mbit/s. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/tc358743.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/media/i2c/tc358743.c -+++ b/drivers/media/i2c/tc358743.c -@@ -1949,7 +1949,7 @@ static int tc358743_probe_of(struct tc35 - state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; - state->pdata.enable_hdcp = false; - /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ -- state->pdata.fifo_level = 16; -+ state->pdata.fifo_level = 374; - /* - * The PLL input clock is obtained by dividing refclk by pll_prd. - * It must be between 6 MHz and 40 MHz, lower frequency is better. diff --git a/target/linux/bcm27xx/patches-5.4/950-0153-media-tc358743-fix-connected-active-CSI-2-lane-repor.patch b/target/linux/bcm27xx/patches-5.4/950-0153-media-tc358743-fix-connected-active-CSI-2-lane-repor.patch new file mode 100644 index 0000000000..2357c878d7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0153-media-tc358743-fix-connected-active-CSI-2-lane-repor.patch @@ -0,0 +1,74 @@ +From d318c95f164150bee4dbd875c3d9354665738f17 Mon Sep 17 00:00:00 2001 +From: Philipp Zabel +Date: Thu, 21 Sep 2017 17:30:24 +0200 +Subject: [PATCH] media: tc358743: fix connected/active CSI-2 lane + reporting + +g_mbus_config was supposed to indicate all supported lane numbers, not +only the number of those currently in active use. Since the TC358743 +can dynamically reduce the number of active lanes if the required +bandwidth allows for it, report all lane numbers up to the connected +number of lanes as supported in pdata mode. +In device tree mode, do not report lane count and clock mode at all, as +the receiver driver can determine these from the device tree. + +To allow communicating the number of currently active lanes, add a new +bitfield to the v4l2_mbus_config flags. This is a temporary fix, to be +used only until a better solution is found. + +Signed-off-by: Philipp Zabel +--- + drivers/media/i2c/tc358743.c | 14 ++++++++++++-- + include/media/v4l2-mediabus.h | 8 ++++++++ + 2 files changed, 20 insertions(+), 2 deletions(-) + +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -1608,11 +1608,20 @@ static int tc358743_g_mbus_config(struct + struct v4l2_mbus_config *cfg) + { + struct tc358743_state *state = to_state(sd); ++ const u32 mask = V4L2_MBUS_CSI2_LANE_MASK; ++ ++ if (state->csi_lanes_in_use > state->bus.num_data_lanes) ++ return -EINVAL; + + cfg->type = V4L2_MBUS_CSI2_DPHY; ++ cfg->flags = (state->csi_lanes_in_use << __ffs(mask)) & mask; ++ ++ /* In DT mode, only report the number of active lanes */ ++ if (sd->dev->of_node) ++ return 0; + +- /* Support for non-continuous CSI-2 clock is missing in the driver */ +- cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ /* Support for non-continuous CSI-2 clock is missing in pdate mode */ ++ cfg->flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + switch (state->csi_lanes_in_use) { + case 1: +@@ -2054,6 +2063,7 @@ static int tc358743_probe(struct i2c_cli + if (pdata) { + state->pdata = *pdata; + state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ state->bus.num_data_lanes = 4; + } else { + err = tc358743_probe_of(state); + if (err == -ENODEV) +--- a/include/media/v4l2-mediabus.h ++++ b/include/media/v4l2-mediabus.h +@@ -67,6 +67,14 @@ + V4L2_MBUS_CSI2_CHANNEL_1 | \ + V4L2_MBUS_CSI2_CHANNEL_2 | \ + V4L2_MBUS_CSI2_CHANNEL_3) ++/* ++ * Number of lanes in use, 0 == use all available lanes (default) ++ * ++ * This is a temporary fix for devices that need to reduce the number of active ++ * lanes for certain modes, until g_mbus_config() can be replaced with a better ++ * solution. ++ */ ++#define V4L2_MBUS_CSI2_LANE_MASK (0xf << 10) + + /** + * enum v4l2_mbus_type - media bus type diff --git a/target/linux/bcm27xx/patches-5.4/950-0154-media-tc358743-Add-support-for-972Mbit-s-link-freq.patch b/target/linux/bcm27xx/patches-5.4/950-0154-media-tc358743-Add-support-for-972Mbit-s-link-freq.patch new file mode 100644 index 0000000000..18ee169b1c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0154-media-tc358743-Add-support-for-972Mbit-s-link-freq.patch @@ -0,0 +1,79 @@ +From 9a379dd76a0369c09f1b613bdd869b6b0354a0f3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:57:21 +0000 +Subject: [PATCH] media: tc358743: Add support for 972Mbit/s link freq. + +Adds register setups for running the CSI lanes at 972Mbit/s, +which allows 1080P50 UYVY down 2 lanes. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/tc358743.c | 47 +++++++++++++++++++++++++----------- + 1 file changed, 33 insertions(+), 14 deletions(-) + +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -1978,6 +1978,7 @@ static int tc358743_probe_of(struct tc35 + /* + * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. + * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. ++ * 972 Mbps allows 1080P50 UYVY over 2-lane. + */ + bps_pr_lane = 2 * endpoint.link_frequencies[0]; + if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { +@@ -1990,23 +1991,41 @@ static int tc358743_probe_of(struct tc35 + state->pdata.refclk_hz * state->pdata.pll_prd; + + /* +- * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz +- * link frequency). In principle it should be possible to calculate ++ * FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane ++ * (297 MHz or 486 MHz link frequency). ++ * In principle it should be possible to calculate + * them based on link frequency and resolution. + */ +- if (bps_pr_lane != 594000000U) ++ switch (bps_pr_lane) { ++ default: + dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); +- state->pdata.lineinitcnt = 0xe80; +- state->pdata.lptxtimecnt = 0x003; +- /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ +- state->pdata.tclk_headercnt = 0x1403; +- state->pdata.tclk_trailcnt = 0x00; +- /* ths-preparecnt: 3, ths-zerocnt: 1 */ +- state->pdata.ths_headercnt = 0x0103; +- state->pdata.twakeup = 0x4882; +- state->pdata.tclk_postcnt = 0x008; +- state->pdata.ths_trailcnt = 0x2; +- state->pdata.hstxvregcnt = 0; ++ case 594000000U: ++ state->pdata.lineinitcnt = 0xe80; ++ state->pdata.lptxtimecnt = 0x003; ++ /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ ++ state->pdata.tclk_headercnt = 0x1403; ++ state->pdata.tclk_trailcnt = 0x00; ++ /* ths-preparecnt: 3, ths-zerocnt: 1 */ ++ state->pdata.ths_headercnt = 0x0103; ++ state->pdata.twakeup = 0x4882; ++ state->pdata.tclk_postcnt = 0x008; ++ state->pdata.ths_trailcnt = 0x2; ++ state->pdata.hstxvregcnt = 0; ++ break; ++ case 972000000U: ++ state->pdata.lineinitcnt = 0x1b58; ++ state->pdata.lptxtimecnt = 0x007; ++ /* tclk-preparecnt: 6, tclk-zerocnt: 40 */ ++ state->pdata.tclk_headercnt = 0x2806; ++ state->pdata.tclk_trailcnt = 0x00; ++ /* ths-preparecnt: 6, ths-zerocnt: 8 */ ++ state->pdata.ths_headercnt = 0x0806; ++ state->pdata.twakeup = 0x4268; ++ state->pdata.tclk_postcnt = 0x008; ++ state->pdata.ths_trailcnt = 0x5; ++ state->pdata.hstxvregcnt = 0; ++ break; ++ } + + state->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); diff --git a/target/linux/bcm27xx/patches-5.4/950-0154-media-tc358743-fix-connected-active-CSI-2-lane-repor.patch b/target/linux/bcm27xx/patches-5.4/950-0154-media-tc358743-fix-connected-active-CSI-2-lane-repor.patch deleted file mode 100644 index 2357c878d7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0154-media-tc358743-fix-connected-active-CSI-2-lane-repor.patch +++ /dev/null @@ -1,74 +0,0 @@ -From d318c95f164150bee4dbd875c3d9354665738f17 Mon Sep 17 00:00:00 2001 -From: Philipp Zabel -Date: Thu, 21 Sep 2017 17:30:24 +0200 -Subject: [PATCH] media: tc358743: fix connected/active CSI-2 lane - reporting - -g_mbus_config was supposed to indicate all supported lane numbers, not -only the number of those currently in active use. Since the TC358743 -can dynamically reduce the number of active lanes if the required -bandwidth allows for it, report all lane numbers up to the connected -number of lanes as supported in pdata mode. -In device tree mode, do not report lane count and clock mode at all, as -the receiver driver can determine these from the device tree. - -To allow communicating the number of currently active lanes, add a new -bitfield to the v4l2_mbus_config flags. This is a temporary fix, to be -used only until a better solution is found. - -Signed-off-by: Philipp Zabel ---- - drivers/media/i2c/tc358743.c | 14 ++++++++++++-- - include/media/v4l2-mediabus.h | 8 ++++++++ - 2 files changed, 20 insertions(+), 2 deletions(-) - ---- a/drivers/media/i2c/tc358743.c -+++ b/drivers/media/i2c/tc358743.c -@@ -1608,11 +1608,20 @@ static int tc358743_g_mbus_config(struct - struct v4l2_mbus_config *cfg) - { - struct tc358743_state *state = to_state(sd); -+ const u32 mask = V4L2_MBUS_CSI2_LANE_MASK; -+ -+ if (state->csi_lanes_in_use > state->bus.num_data_lanes) -+ return -EINVAL; - - cfg->type = V4L2_MBUS_CSI2_DPHY; -+ cfg->flags = (state->csi_lanes_in_use << __ffs(mask)) & mask; -+ -+ /* In DT mode, only report the number of active lanes */ -+ if (sd->dev->of_node) -+ return 0; - -- /* Support for non-continuous CSI-2 clock is missing in the driver */ -- cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; -+ /* Support for non-continuous CSI-2 clock is missing in pdate mode */ -+ cfg->flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - - switch (state->csi_lanes_in_use) { - case 1: -@@ -2054,6 +2063,7 @@ static int tc358743_probe(struct i2c_cli - if (pdata) { - state->pdata = *pdata; - state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; -+ state->bus.num_data_lanes = 4; - } else { - err = tc358743_probe_of(state); - if (err == -ENODEV) ---- a/include/media/v4l2-mediabus.h -+++ b/include/media/v4l2-mediabus.h -@@ -67,6 +67,14 @@ - V4L2_MBUS_CSI2_CHANNEL_1 | \ - V4L2_MBUS_CSI2_CHANNEL_2 | \ - V4L2_MBUS_CSI2_CHANNEL_3) -+/* -+ * Number of lanes in use, 0 == use all available lanes (default) -+ * -+ * This is a temporary fix for devices that need to reduce the number of active -+ * lanes for certain modes, until g_mbus_config() can be replaced with a better -+ * solution. -+ */ -+#define V4L2_MBUS_CSI2_LANE_MASK (0xf << 10) - - /** - * enum v4l2_mbus_type - media bus type diff --git a/target/linux/bcm27xx/patches-5.4/950-0155-media-tc358743-Add-support-for-972Mbit-s-link-freq.patch b/target/linux/bcm27xx/patches-5.4/950-0155-media-tc358743-Add-support-for-972Mbit-s-link-freq.patch deleted file mode 100644 index 18ee169b1c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0155-media-tc358743-Add-support-for-972Mbit-s-link-freq.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 9a379dd76a0369c09f1b613bdd869b6b0354a0f3 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:57:21 +0000 -Subject: [PATCH] media: tc358743: Add support for 972Mbit/s link freq. - -Adds register setups for running the CSI lanes at 972Mbit/s, -which allows 1080P50 UYVY down 2 lanes. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/tc358743.c | 47 +++++++++++++++++++++++++----------- - 1 file changed, 33 insertions(+), 14 deletions(-) - ---- a/drivers/media/i2c/tc358743.c -+++ b/drivers/media/i2c/tc358743.c -@@ -1978,6 +1978,7 @@ static int tc358743_probe_of(struct tc35 - /* - * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. - * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. -+ * 972 Mbps allows 1080P50 UYVY over 2-lane. - */ - bps_pr_lane = 2 * endpoint.link_frequencies[0]; - if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { -@@ -1990,23 +1991,41 @@ static int tc358743_probe_of(struct tc35 - state->pdata.refclk_hz * state->pdata.pll_prd; - - /* -- * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz -- * link frequency). In principle it should be possible to calculate -+ * FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane -+ * (297 MHz or 486 MHz link frequency). -+ * In principle it should be possible to calculate - * them based on link frequency and resolution. - */ -- if (bps_pr_lane != 594000000U) -+ switch (bps_pr_lane) { -+ default: - dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); -- state->pdata.lineinitcnt = 0xe80; -- state->pdata.lptxtimecnt = 0x003; -- /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ -- state->pdata.tclk_headercnt = 0x1403; -- state->pdata.tclk_trailcnt = 0x00; -- /* ths-preparecnt: 3, ths-zerocnt: 1 */ -- state->pdata.ths_headercnt = 0x0103; -- state->pdata.twakeup = 0x4882; -- state->pdata.tclk_postcnt = 0x008; -- state->pdata.ths_trailcnt = 0x2; -- state->pdata.hstxvregcnt = 0; -+ case 594000000U: -+ state->pdata.lineinitcnt = 0xe80; -+ state->pdata.lptxtimecnt = 0x003; -+ /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ -+ state->pdata.tclk_headercnt = 0x1403; -+ state->pdata.tclk_trailcnt = 0x00; -+ /* ths-preparecnt: 3, ths-zerocnt: 1 */ -+ state->pdata.ths_headercnt = 0x0103; -+ state->pdata.twakeup = 0x4882; -+ state->pdata.tclk_postcnt = 0x008; -+ state->pdata.ths_trailcnt = 0x2; -+ state->pdata.hstxvregcnt = 0; -+ break; -+ case 972000000U: -+ state->pdata.lineinitcnt = 0x1b58; -+ state->pdata.lptxtimecnt = 0x007; -+ /* tclk-preparecnt: 6, tclk-zerocnt: 40 */ -+ state->pdata.tclk_headercnt = 0x2806; -+ state->pdata.tclk_trailcnt = 0x00; -+ /* ths-preparecnt: 6, ths-zerocnt: 8 */ -+ state->pdata.ths_headercnt = 0x0806; -+ state->pdata.twakeup = 0x4268; -+ state->pdata.tclk_postcnt = 0x008; -+ state->pdata.ths_trailcnt = 0x5; -+ state->pdata.hstxvregcnt = 0; -+ break; -+ } - - state->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_LOW); diff --git a/target/linux/bcm27xx/patches-5.4/950-0155-media-tc358743-Check-I2C-succeeded-during-probe.patch b/target/linux/bcm27xx/patches-5.4/950-0155-media-tc358743-Check-I2C-succeeded-during-probe.patch new file mode 100644 index 0000000000..653602b306 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0155-media-tc358743-Check-I2C-succeeded-during-probe.patch @@ -0,0 +1,98 @@ +From f83a4396237e96da7a2aa3bfc2de1c928b128e6c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:57:34 +0000 +Subject: [PATCH] media: tc358743: Check I2C succeeded during probe. + +The probe for the TC358743 reads the CHIPID register from +the device and compares it to the expected value of 0. +If the I2C request fails then that also returns 0, so +the driver loads thinking that the device is there. + +Generally I2C communications are reliable so there is +limited need to check the return value on every transfer, +therefore only amend the one read during probe to check +for I2C errors. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/tc358743.c | 27 +++++++++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) + +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -110,7 +110,7 @@ static inline struct tc358743_state *to_ + + /* --------------- I2C --------------- */ + +-static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) ++static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) + { + struct tc358743_state *state = to_state(sd); + struct i2c_client *client = state->i2c_client; +@@ -136,6 +136,7 @@ static void i2c_rd(struct v4l2_subdev *s + v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", + __func__, reg, client->addr); + } ++ return err != ARRAY_SIZE(msgs); + } + + static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) +@@ -192,15 +193,24 @@ static void i2c_wr(struct v4l2_subdev *s + } + } + +-static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) ++static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n, ++ int *err) + { ++ int error; + __le32 val = 0; + +- i2c_rd(sd, reg, (u8 __force *)&val, n); ++ error = i2c_rd(sd, reg, (u8 __force *)&val, n); ++ if (err) ++ *err = error; + + return le32_to_cpu(val); + } + ++static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) ++{ ++ return i2c_rdreg_err(sd, reg, n, NULL); ++} ++ + static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) + { + __le32 raw = cpu_to_le32(val); +@@ -229,6 +239,13 @@ static u16 i2c_rd16(struct v4l2_subdev * + return i2c_rdreg(sd, reg, 2); + } + ++static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value) ++{ ++ int err; ++ *value = i2c_rdreg_err(sd, reg, 2, &err); ++ return err; ++} ++ + static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) + { + i2c_wrreg(sd, reg, val, 2); +@@ -2064,6 +2081,7 @@ static int tc358743_probe(struct i2c_cli + struct tc358743_platform_data *pdata = client->dev.platform_data; + struct v4l2_subdev *sd; + u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; ++ u16 chipid; + int err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) +@@ -2096,7 +2114,8 @@ static int tc358743_probe(struct i2c_cli + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + + /* i2c access */ +- if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { ++ if (i2c_rd16_err(sd, CHIPID, &chipid) || ++ (chipid & MASK_CHIPID) != 0) { + v4l2_info(sd, "not a TC358743 on address 0x%x\n", + client->addr << 1); + return -ENODEV; diff --git a/target/linux/bcm27xx/patches-5.4/950-0156-media-adv7180-Default-to-the-first-valid-input.patch b/target/linux/bcm27xx/patches-5.4/950-0156-media-adv7180-Default-to-the-first-valid-input.patch new file mode 100644 index 0000000000..7e2066b211 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0156-media-adv7180-Default-to-the-first-valid-input.patch @@ -0,0 +1,45 @@ +From b1d3f1c74057db79c45a11ed9ce0fc1e24d67401 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:57:46 +0000 +Subject: [PATCH] media: adv7180: Default to the first valid input + +The hardware default is differential CVBS on AIN1 & 2, which +isn't very useful. + +Select the first input that is defined as valid for the +chip variant (typically CVBS_AIN1). + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/adv7180.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/media/i2c/adv7180.c ++++ b/drivers/media/i2c/adv7180.c +@@ -1246,6 +1246,7 @@ static const struct adv7180_chip_info ad + static int init_device(struct adv7180_state *state) + { + int ret; ++ int i; + + mutex_lock(&state->mutex); + +@@ -1292,6 +1293,18 @@ static int init_device(struct adv7180_st + goto out_unlock; + } + ++ /* Select first valid input */ ++ for (i = 0; i < 32; i++) { ++ if (BIT(i) & state->chip_info->valid_input_mask) { ++ ret = state->chip_info->select_input(state, i); ++ ++ if (ret == 0) { ++ state->input = i; ++ break; ++ } ++ } ++ } ++ + out_unlock: + mutex_unlock(&state->mutex); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0156-media-tc358743-Check-I2C-succeeded-during-probe.patch b/target/linux/bcm27xx/patches-5.4/950-0156-media-tc358743-Check-I2C-succeeded-during-probe.patch deleted file mode 100644 index 653602b306..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0156-media-tc358743-Check-I2C-succeeded-during-probe.patch +++ /dev/null @@ -1,98 +0,0 @@ -From f83a4396237e96da7a2aa3bfc2de1c928b128e6c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:57:34 +0000 -Subject: [PATCH] media: tc358743: Check I2C succeeded during probe. - -The probe for the TC358743 reads the CHIPID register from -the device and compares it to the expected value of 0. -If the I2C request fails then that also returns 0, so -the driver loads thinking that the device is there. - -Generally I2C communications are reliable so there is -limited need to check the return value on every transfer, -therefore only amend the one read during probe to check -for I2C errors. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/tc358743.c | 27 +++++++++++++++++++++++---- - 1 file changed, 23 insertions(+), 4 deletions(-) - ---- a/drivers/media/i2c/tc358743.c -+++ b/drivers/media/i2c/tc358743.c -@@ -110,7 +110,7 @@ static inline struct tc358743_state *to_ - - /* --------------- I2C --------------- */ - --static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) -+static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) - { - struct tc358743_state *state = to_state(sd); - struct i2c_client *client = state->i2c_client; -@@ -136,6 +136,7 @@ static void i2c_rd(struct v4l2_subdev *s - v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", - __func__, reg, client->addr); - } -+ return err != ARRAY_SIZE(msgs); - } - - static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) -@@ -192,15 +193,24 @@ static void i2c_wr(struct v4l2_subdev *s - } - } - --static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) -+static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n, -+ int *err) - { -+ int error; - __le32 val = 0; - -- i2c_rd(sd, reg, (u8 __force *)&val, n); -+ error = i2c_rd(sd, reg, (u8 __force *)&val, n); -+ if (err) -+ *err = error; - - return le32_to_cpu(val); - } - -+static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) -+{ -+ return i2c_rdreg_err(sd, reg, n, NULL); -+} -+ - static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) - { - __le32 raw = cpu_to_le32(val); -@@ -229,6 +239,13 @@ static u16 i2c_rd16(struct v4l2_subdev * - return i2c_rdreg(sd, reg, 2); - } - -+static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value) -+{ -+ int err; -+ *value = i2c_rdreg_err(sd, reg, 2, &err); -+ return err; -+} -+ - static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) - { - i2c_wrreg(sd, reg, val, 2); -@@ -2064,6 +2081,7 @@ static int tc358743_probe(struct i2c_cli - struct tc358743_platform_data *pdata = client->dev.platform_data; - struct v4l2_subdev *sd; - u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; -+ u16 chipid; - int err; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) -@@ -2096,7 +2114,8 @@ static int tc358743_probe(struct i2c_cli - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; - - /* i2c access */ -- if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { -+ if (i2c_rd16_err(sd, CHIPID, &chipid) || -+ (chipid & MASK_CHIPID) != 0) { - v4l2_info(sd, "not a TC358743 on address 0x%x\n", - client->addr << 1); - return -ENODEV; diff --git a/target/linux/bcm27xx/patches-5.4/950-0157-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch b/target/linux/bcm27xx/patches-5.4/950-0157-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch new file mode 100644 index 0000000000..75323fceb2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0157-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch @@ -0,0 +1,24 @@ +From b1a4a23406727f112b9a296b0231ec4d1b99d6e0 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:57:56 +0000 +Subject: [PATCH] media: adv7180: Add YPrPb support for ADV7282M + +The ADV7282M can support YPbPr on AIN1-3, but this was +not selectable from the driver. Add it to the list of +supported input modes. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/adv7180.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/media/i2c/adv7180.c ++++ b/drivers/media/i2c/adv7180.c +@@ -1235,6 +1235,7 @@ static const struct adv7180_chip_info ad + BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | + BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | + BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | ++ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | + BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), diff --git a/target/linux/bcm27xx/patches-5.4/950-0157-media-adv7180-Default-to-the-first-valid-input.patch b/target/linux/bcm27xx/patches-5.4/950-0157-media-adv7180-Default-to-the-first-valid-input.patch deleted file mode 100644 index 7e2066b211..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0157-media-adv7180-Default-to-the-first-valid-input.patch +++ /dev/null @@ -1,45 +0,0 @@ -From b1d3f1c74057db79c45a11ed9ce0fc1e24d67401 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:57:46 +0000 -Subject: [PATCH] media: adv7180: Default to the first valid input - -The hardware default is differential CVBS on AIN1 & 2, which -isn't very useful. - -Select the first input that is defined as valid for the -chip variant (typically CVBS_AIN1). - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/adv7180.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - ---- a/drivers/media/i2c/adv7180.c -+++ b/drivers/media/i2c/adv7180.c -@@ -1246,6 +1246,7 @@ static const struct adv7180_chip_info ad - static int init_device(struct adv7180_state *state) - { - int ret; -+ int i; - - mutex_lock(&state->mutex); - -@@ -1292,6 +1293,18 @@ static int init_device(struct adv7180_st - goto out_unlock; - } - -+ /* Select first valid input */ -+ for (i = 0; i < 32; i++) { -+ if (BIT(i) & state->chip_info->valid_input_mask) { -+ ret = state->chip_info->select_input(state, i); -+ -+ if (ret == 0) { -+ state->input = i; -+ break; -+ } -+ } -+ } -+ - out_unlock: - mutex_unlock(&state->mutex); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0158-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch b/target/linux/bcm27xx/patches-5.4/950-0158-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch deleted file mode 100644 index 75323fceb2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0158-media-adv7180-Add-YPrPb-support-for-ADV7282M.patch +++ /dev/null @@ -1,24 +0,0 @@ -From b1a4a23406727f112b9a296b0231ec4d1b99d6e0 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:57:56 +0000 -Subject: [PATCH] media: adv7180: Add YPrPb support for ADV7282M - -The ADV7282M can support YPbPr on AIN1-3, but this was -not selectable from the driver. Add it to the list of -supported input modes. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/adv7180.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/media/i2c/adv7180.c -+++ b/drivers/media/i2c/adv7180.c -@@ -1235,6 +1235,7 @@ static const struct adv7180_chip_info ad - BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | - BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | - BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | -+ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | - BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | - BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | - BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), diff --git a/target/linux/bcm27xx/patches-5.4/950-0158-media-videodev2-Add-helper-defines-for-printing-FOUR.patch b/target/linux/bcm27xx/patches-5.4/950-0158-media-videodev2-Add-helper-defines-for-printing-FOUR.patch new file mode 100644 index 0000000000..683e5611e1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0158-media-videodev2-Add-helper-defines-for-printing-FOUR.patch @@ -0,0 +1,28 @@ +From be9b0a589271cd3e998e6851900323443f94ef17 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:58:08 +0000 +Subject: [PATCH] media: videodev2: Add helper defines for printing + FOURCCs + +New helper defines that allow printing of a FOURCC using +printf(V4L2_FOURCC_CONV, V4L2_FOURCC_CONV_ARGS(fourcc)); + +Signed-off-by: Dave Stevenson +--- + include/uapi/linux/videodev2.h | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -82,6 +82,11 @@ + ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) + #define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1U << 31)) + ++#define V4L2_FOURCC_CONV "%c%c%c%c%s" ++#define V4L2_FOURCC_CONV_ARGS(fourcc) \ ++ (fourcc) & 0x7f, ((fourcc) >> 8) & 0x7f, ((fourcc) >> 16) & 0x7f, \ ++ ((fourcc) >> 24) & 0x7f, (fourcc) & BIT(31) ? "-BE" : "" ++ + /* + * E N U M S + */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0159-dt-bindings-Document-BCM283x-CSI2-CCP2-receiver.patch b/target/linux/bcm27xx/patches-5.4/950-0159-dt-bindings-Document-BCM283x-CSI2-CCP2-receiver.patch new file mode 100644 index 0000000000..d091a14bc5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0159-dt-bindings-Document-BCM283x-CSI2-CCP2-receiver.patch @@ -0,0 +1,103 @@ +From a9fd19f2fc9c3f067ea32e53f84c9e83b8f910c5 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:59:06 +0000 +Subject: [PATCH] dt-bindings: Document BCM283x CSI2/CCP2 receiver + +Document the DT bindings for the CSI2/CCP2 receiver peripheral +(known as Unicam) on BCM283x SoCs. + +Signed-off-by: Dave Stevenson +Acked-by: Rob Herring +--- + .../bindings/media/bcm2835-unicam.txt | 85 +++++++++++++++++++ + 1 file changed, 85 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/bcm2835-unicam.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/bcm2835-unicam.txt +@@ -0,0 +1,85 @@ ++Broadcom BCM283x Camera Interface (Unicam) ++------------------------------------------ ++ ++The Unicam block on BCM283x SoCs is the receiver for either ++CSI-2 or CCP2 data from image sensors or similar devices. ++ ++The main platform using this SoC is the Raspberry Pi family of boards. ++On the Pi the VideoCore firmware can also control this hardware block, ++and driving it from two different processors will cause issues. ++To avoid this, the firmware checks the device tree configuration ++during boot. If it finds device tree nodes called csi0 or csi1 then ++it will stop the firmware accessing the block, and it can then ++safely be used via the device tree binding. ++ ++Required properties: ++=================== ++- compatible : must be "brcm,bcm2835-unicam". ++- reg : physical base address and length of the register sets for the ++ device. ++- interrupts : should contain the IRQ line for this Unicam instance. ++- clocks : list of clock specifiers, corresponding to entries in ++ clock-names property. ++- clock-names : must contain an "lp" entry, matching entries in the ++ clocks property. ++ ++Unicam supports a single port node. It should contain one 'port' child node ++with child 'endpoint' node. Please refer to the bindings defined in ++Documentation/devicetree/bindings/media/video-interfaces.txt. ++ ++Within the endpoint node the "remote-endpoint" and "data-lanes" properties ++are mandatory. ++Data lane reordering is not supported so the data lanes must be in order, ++starting at 1. The number of data lanes should represent the number of ++usable lanes for the hardware block. That may be limited by either the SoC or ++how the platform presents the interface, and the lower value must be used. ++ ++Lane reordering is not supported on the clock lane either, so the optional ++property "clock-lane" will implicitly be <0>. ++Similarly lane inversion is not supported, therefore "lane-polarities" will ++implicitly be <0 0 0 0 0>. ++Neither of these values will be checked. ++ ++Example: ++ csi1: csi1@7e801000 { ++ compatible = "brcm,bcm2835-unicam"; ++ reg = <0x7e801000 0x800>, ++ <0x7e802004 0x4>; ++ interrupts = <2 7>; ++ clocks = <&clocks BCM2835_CLOCK_CAM1>; ++ clock-names = "lp"; ++ ++ port { ++ csi1_ep: endpoint { ++ remote-endpoint = <&tc358743_0>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ }; ++ ++ i2c0: i2c@7e205000 { ++ tc358743: csi-hdmi-bridge@0f { ++ compatible = "toshiba,tc358743"; ++ reg = <0x0f>; ++ ++ clocks = <&tc358743_clk>; ++ clock-names = "refclk"; ++ ++ tc358743_clk: bridge-clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <27000000>; ++ }; ++ ++ port { ++ tc358743_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = ++ /bits/ 64 <297000000>; ++ }; ++ }; ++ }; ++ }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0159-media-videodev2-Add-helper-defines-for-printing-FOUR.patch b/target/linux/bcm27xx/patches-5.4/950-0159-media-videodev2-Add-helper-defines-for-printing-FOUR.patch deleted file mode 100644 index 683e5611e1..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0159-media-videodev2-Add-helper-defines-for-printing-FOUR.patch +++ /dev/null @@ -1,28 +0,0 @@ -From be9b0a589271cd3e998e6851900323443f94ef17 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:58:08 +0000 -Subject: [PATCH] media: videodev2: Add helper defines for printing - FOURCCs - -New helper defines that allow printing of a FOURCC using -printf(V4L2_FOURCC_CONV, V4L2_FOURCC_CONV_ARGS(fourcc)); - -Signed-off-by: Dave Stevenson ---- - include/uapi/linux/videodev2.h | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/include/uapi/linux/videodev2.h -+++ b/include/uapi/linux/videodev2.h -@@ -82,6 +82,11 @@ - ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) - #define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1U << 31)) - -+#define V4L2_FOURCC_CONV "%c%c%c%c%s" -+#define V4L2_FOURCC_CONV_ARGS(fourcc) \ -+ (fourcc) & 0x7f, ((fourcc) >> 8) & 0x7f, ((fourcc) >> 16) & 0x7f, \ -+ ((fourcc) >> 24) & 0x7f, (fourcc) & BIT(31) ? "-BE" : "" -+ - /* - * E N U M S - */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0160-MAINTAINERS-Add-entry-for-BCM2835-Unicam-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0160-MAINTAINERS-Add-entry-for-BCM2835-Unicam-driver.patch new file mode 100644 index 0000000000..4b8b3aa431 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0160-MAINTAINERS-Add-entry-for-BCM2835-Unicam-driver.patch @@ -0,0 +1,28 @@ +From daa92f5f17a45cbe99afc4d655768f3564fff5f1 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 31 Oct 2018 14:59:40 +0000 +Subject: [PATCH] MAINTAINERS: Add entry for BCM2835 Unicam driver + +Adds entry for the new BCM2835 Unicam (CSI-2 receiver) driver + +Signed-off-by: Dave Stevenson +--- + MAINTAINERS | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3198,6 +3198,13 @@ N: bcm2711 + N: bcm2835 + F: drivers/staging/vc04_services + ++BROADCOM BCM2835 CAMERA DRIVER ++M: Dave Stevenson ++L: linux-media@vger.kernel.org ++S: Maintained ++F: drivers/media/platform/bcm2835/ ++F: Documentation/devicetree/bindings/media/bcm2835-unicam.txt ++ + BROADCOM BCM47XX MIPS ARCHITECTURE + M: Hauke Mehrtens + M: Rafał Miłecki diff --git a/target/linux/bcm27xx/patches-5.4/950-0160-dt-bindings-Document-BCM283x-CSI2-CCP2-receiver.patch b/target/linux/bcm27xx/patches-5.4/950-0160-dt-bindings-Document-BCM283x-CSI2-CCP2-receiver.patch deleted file mode 100644 index d091a14bc5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0160-dt-bindings-Document-BCM283x-CSI2-CCP2-receiver.patch +++ /dev/null @@ -1,103 +0,0 @@ -From a9fd19f2fc9c3f067ea32e53f84c9e83b8f910c5 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:59:06 +0000 -Subject: [PATCH] dt-bindings: Document BCM283x CSI2/CCP2 receiver - -Document the DT bindings for the CSI2/CCP2 receiver peripheral -(known as Unicam) on BCM283x SoCs. - -Signed-off-by: Dave Stevenson -Acked-by: Rob Herring ---- - .../bindings/media/bcm2835-unicam.txt | 85 +++++++++++++++++++ - 1 file changed, 85 insertions(+) - create mode 100644 Documentation/devicetree/bindings/media/bcm2835-unicam.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/bcm2835-unicam.txt -@@ -0,0 +1,85 @@ -+Broadcom BCM283x Camera Interface (Unicam) -+------------------------------------------ -+ -+The Unicam block on BCM283x SoCs is the receiver for either -+CSI-2 or CCP2 data from image sensors or similar devices. -+ -+The main platform using this SoC is the Raspberry Pi family of boards. -+On the Pi the VideoCore firmware can also control this hardware block, -+and driving it from two different processors will cause issues. -+To avoid this, the firmware checks the device tree configuration -+during boot. If it finds device tree nodes called csi0 or csi1 then -+it will stop the firmware accessing the block, and it can then -+safely be used via the device tree binding. -+ -+Required properties: -+=================== -+- compatible : must be "brcm,bcm2835-unicam". -+- reg : physical base address and length of the register sets for the -+ device. -+- interrupts : should contain the IRQ line for this Unicam instance. -+- clocks : list of clock specifiers, corresponding to entries in -+ clock-names property. -+- clock-names : must contain an "lp" entry, matching entries in the -+ clocks property. -+ -+Unicam supports a single port node. It should contain one 'port' child node -+with child 'endpoint' node. Please refer to the bindings defined in -+Documentation/devicetree/bindings/media/video-interfaces.txt. -+ -+Within the endpoint node the "remote-endpoint" and "data-lanes" properties -+are mandatory. -+Data lane reordering is not supported so the data lanes must be in order, -+starting at 1. The number of data lanes should represent the number of -+usable lanes for the hardware block. That may be limited by either the SoC or -+how the platform presents the interface, and the lower value must be used. -+ -+Lane reordering is not supported on the clock lane either, so the optional -+property "clock-lane" will implicitly be <0>. -+Similarly lane inversion is not supported, therefore "lane-polarities" will -+implicitly be <0 0 0 0 0>. -+Neither of these values will be checked. -+ -+Example: -+ csi1: csi1@7e801000 { -+ compatible = "brcm,bcm2835-unicam"; -+ reg = <0x7e801000 0x800>, -+ <0x7e802004 0x4>; -+ interrupts = <2 7>; -+ clocks = <&clocks BCM2835_CLOCK_CAM1>; -+ clock-names = "lp"; -+ -+ port { -+ csi1_ep: endpoint { -+ remote-endpoint = <&tc358743_0>; -+ data-lanes = <1 2>; -+ }; -+ }; -+ }; -+ -+ i2c0: i2c@7e205000 { -+ tc358743: csi-hdmi-bridge@0f { -+ compatible = "toshiba,tc358743"; -+ reg = <0x0f>; -+ -+ clocks = <&tc358743_clk>; -+ clock-names = "refclk"; -+ -+ tc358743_clk: bridge-clk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <27000000>; -+ }; -+ -+ port { -+ tc358743_0: endpoint { -+ remote-endpoint = <&csi1_ep>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ clock-noncontinuous; -+ link-frequencies = -+ /bits/ 64 <297000000>; -+ }; -+ }; -+ }; -+ }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0161-MAINTAINERS-Add-entry-for-BCM2835-Unicam-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0161-MAINTAINERS-Add-entry-for-BCM2835-Unicam-driver.patch deleted file mode 100644 index 4b8b3aa431..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0161-MAINTAINERS-Add-entry-for-BCM2835-Unicam-driver.patch +++ /dev/null @@ -1,28 +0,0 @@ -From daa92f5f17a45cbe99afc4d655768f3564fff5f1 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 31 Oct 2018 14:59:40 +0000 -Subject: [PATCH] MAINTAINERS: Add entry for BCM2835 Unicam driver - -Adds entry for the new BCM2835 Unicam (CSI-2 receiver) driver - -Signed-off-by: Dave Stevenson ---- - MAINTAINERS | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -3198,6 +3198,13 @@ N: bcm2711 - N: bcm2835 - F: drivers/staging/vc04_services - -+BROADCOM BCM2835 CAMERA DRIVER -+M: Dave Stevenson -+L: linux-media@vger.kernel.org -+S: Maintained -+F: drivers/media/platform/bcm2835/ -+F: Documentation/devicetree/bindings/media/bcm2835-unicam.txt -+ - BROADCOM BCM47XX MIPS ARCHITECTURE - M: Hauke Mehrtens - M: Rafał Miłecki diff --git a/target/linux/bcm27xx/patches-5.4/950-0161-media-tc358743-Return-an-appropriate-colorspace-from.patch b/target/linux/bcm27xx/patches-5.4/950-0161-media-tc358743-Return-an-appropriate-colorspace-from.patch new file mode 100644 index 0000000000..b5b9105f4f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0161-media-tc358743-Return-an-appropriate-colorspace-from.patch @@ -0,0 +1,98 @@ +From 929b5ddd10bc0ca10a7b815e40ac35092c5b812f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 22 Nov 2018 17:31:06 +0000 +Subject: [PATCH] media: tc358743: Return an appropriate colorspace + from tc358743_set_fmt + +When calling tc358743_set_fmt, the code was calling tc358743_get_fmt +to choose a valid format. However that sets the colorspace +based on what was read back from the chip. When you set the format, +then the driver would choose and program the colorspace based +on the format code. + +The result was that if you called try or set format for UYVY +when the current format was RGB3 then you would get told sRGB, +and try RGB3 when current was UYVY and you would get told +SMPTE170M. + +The value programmed into the chip is determined by this driver, +therefore there is no need to read back the value. Return the +colorspace based on the format set/tried instead. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/tc358743.c | 40 +++++++++++++----------------------- + 1 file changed, 14 insertions(+), 26 deletions(-) + +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -1690,12 +1690,23 @@ static int tc358743_enum_mbus_code(struc + return 0; + } + ++static u32 tc358743_g_colorspace(u32 code) ++{ ++ switch (code) { ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ return V4L2_COLORSPACE_SRGB; ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ return V4L2_COLORSPACE_SMPTE170M; ++ default: ++ return 0; ++ } ++} ++ + static int tc358743_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) + { + struct tc358743_state *state = to_state(sd); +- u8 vi_rep = i2c_rd8(sd, VI_REP); + + if (format->pad != 0) + return -EINVAL; +@@ -1705,23 +1716,7 @@ static int tc358743_get_fmt(struct v4l2_ + format->format.height = state->timings.bt.height; + format->format.field = V4L2_FIELD_NONE; + +- switch (vi_rep & MASK_VOUT_COLOR_SEL) { +- case MASK_VOUT_COLOR_RGB_FULL: +- case MASK_VOUT_COLOR_RGB_LIMITED: +- format->format.colorspace = V4L2_COLORSPACE_SRGB; +- break; +- case MASK_VOUT_COLOR_601_YCBCR_LIMITED: +- case MASK_VOUT_COLOR_601_YCBCR_FULL: +- format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; +- break; +- case MASK_VOUT_COLOR_709_YCBCR_FULL: +- case MASK_VOUT_COLOR_709_YCBCR_LIMITED: +- format->format.colorspace = V4L2_COLORSPACE_REC709; +- break; +- default: +- format->format.colorspace = 0; +- break; +- } ++ format->format.colorspace = tc358743_g_colorspace(format->format.code); + + return 0; + } +@@ -1736,18 +1731,11 @@ static int tc358743_set_fmt(struct v4l2_ + int ret = tc358743_get_fmt(sd, cfg, format); + + format->format.code = code; ++ format->format.colorspace = tc358743_g_colorspace(code); + + if (ret) + return ret; + +- switch (code) { +- case MEDIA_BUS_FMT_RGB888_1X24: +- case MEDIA_BUS_FMT_UYVY8_1X16: +- break; +- default: +- return -EINVAL; +- } +- + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0162-media-tc358743-Return-an-appropriate-colorspace-from.patch b/target/linux/bcm27xx/patches-5.4/950-0162-media-tc358743-Return-an-appropriate-colorspace-from.patch deleted file mode 100644 index b5b9105f4f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0162-media-tc358743-Return-an-appropriate-colorspace-from.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 929b5ddd10bc0ca10a7b815e40ac35092c5b812f Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 22 Nov 2018 17:31:06 +0000 -Subject: [PATCH] media: tc358743: Return an appropriate colorspace - from tc358743_set_fmt - -When calling tc358743_set_fmt, the code was calling tc358743_get_fmt -to choose a valid format. However that sets the colorspace -based on what was read back from the chip. When you set the format, -then the driver would choose and program the colorspace based -on the format code. - -The result was that if you called try or set format for UYVY -when the current format was RGB3 then you would get told sRGB, -and try RGB3 when current was UYVY and you would get told -SMPTE170M. - -The value programmed into the chip is determined by this driver, -therefore there is no need to read back the value. Return the -colorspace based on the format set/tried instead. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/tc358743.c | 40 +++++++++++++----------------------- - 1 file changed, 14 insertions(+), 26 deletions(-) - ---- a/drivers/media/i2c/tc358743.c -+++ b/drivers/media/i2c/tc358743.c -@@ -1690,12 +1690,23 @@ static int tc358743_enum_mbus_code(struc - return 0; - } - -+static u32 tc358743_g_colorspace(u32 code) -+{ -+ switch (code) { -+ case MEDIA_BUS_FMT_RGB888_1X24: -+ return V4L2_COLORSPACE_SRGB; -+ case MEDIA_BUS_FMT_UYVY8_1X16: -+ return V4L2_COLORSPACE_SMPTE170M; -+ default: -+ return 0; -+ } -+} -+ - static int tc358743_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) - { - struct tc358743_state *state = to_state(sd); -- u8 vi_rep = i2c_rd8(sd, VI_REP); - - if (format->pad != 0) - return -EINVAL; -@@ -1705,23 +1716,7 @@ static int tc358743_get_fmt(struct v4l2_ - format->format.height = state->timings.bt.height; - format->format.field = V4L2_FIELD_NONE; - -- switch (vi_rep & MASK_VOUT_COLOR_SEL) { -- case MASK_VOUT_COLOR_RGB_FULL: -- case MASK_VOUT_COLOR_RGB_LIMITED: -- format->format.colorspace = V4L2_COLORSPACE_SRGB; -- break; -- case MASK_VOUT_COLOR_601_YCBCR_LIMITED: -- case MASK_VOUT_COLOR_601_YCBCR_FULL: -- format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; -- break; -- case MASK_VOUT_COLOR_709_YCBCR_FULL: -- case MASK_VOUT_COLOR_709_YCBCR_LIMITED: -- format->format.colorspace = V4L2_COLORSPACE_REC709; -- break; -- default: -- format->format.colorspace = 0; -- break; -- } -+ format->format.colorspace = tc358743_g_colorspace(format->format.code); - - return 0; - } -@@ -1736,18 +1731,11 @@ static int tc358743_set_fmt(struct v4l2_ - int ret = tc358743_get_fmt(sd, cfg, format); - - format->format.code = code; -+ format->format.colorspace = tc358743_g_colorspace(code); - - if (ret) - return ret; - -- switch (code) { -- case MEDIA_BUS_FMT_RGB888_1X24: -- case MEDIA_BUS_FMT_UYVY8_1X16: -- break; -- default: -- return -EINVAL; -- } -- - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0162-staging-bcm2835-camera-Fix-logical-continuation-spli.patch b/target/linux/bcm27xx/patches-5.4/950-0162-staging-bcm2835-camera-Fix-logical-continuation-spli.patch new file mode 100644 index 0000000000..c1cbff5671 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0162-staging-bcm2835-camera-Fix-logical-continuation-spli.patch @@ -0,0 +1,27 @@ +From 88e3479406637f8461fd026196f7bc5d4bf81cf9 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 21 Feb 2018 15:48:54 +0000 +Subject: [PATCH] staging: bcm2835-camera: Fix logical continuation + splits + +Fix checkpatch errors for "Logical continuations should be +on the previous line". + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c ++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +@@ -1114,8 +1114,8 @@ static int mmal_setup_components(struct + + ret = vchiq_mmal_port_set_format(dev->instance, camera_port); + +- if (!ret +- && camera_port == ++ if (!ret && ++ camera_port == + &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) { + bool overlay_enabled = + !!dev->component[COMP_PREVIEW]->enabled; diff --git a/target/linux/bcm27xx/patches-5.4/950-0163-staging-bcm2835-camera-Ensure-timestamps-never-go-ba.patch b/target/linux/bcm27xx/patches-5.4/950-0163-staging-bcm2835-camera-Ensure-timestamps-never-go-ba.patch new file mode 100644 index 0000000000..c9e18874ab --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0163-staging-bcm2835-camera-Ensure-timestamps-never-go-ba.patch @@ -0,0 +1,38 @@ +From fd3a6710bbcf875c85e6a2f3513c6eb4c46adeaa Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 24 Jul 2018 12:08:29 +0100 +Subject: [PATCH] staging: bcm2835-camera: Ensure timestamps never go + backwards. + +There is an awkward situation with H264 header bytes. Currently +they are returned with a PTS of 0 because they aren't associated +with a timestamped frame to encode. These are handled by either +returning the timestamp of the last buffer to have been received, +or in the case of the first buffer the timestamp taken at +start_streaming. +This results in a race where the current frame may have started +before we take the start time, which results in the first encoded +frame having an earlier timestamp than the header bytes. + +Ensure that we never return a negative delta to the user by checking +against the previous timestamp. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c ++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +@@ -380,6 +380,11 @@ static void buffer_cb(struct vchiq_mmal_ + ktime_to_ns(dev->capture.kernel_start_ts), + dev->capture.vc_start_timestamp, pts, + ktime_to_ns(timestamp)); ++ if (timestamp < dev->capture.last_timestamp) { ++ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, ++ "Negative delta - using last time\n"); ++ timestamp = dev->capture.last_timestamp; ++ } + buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp); + } else { + if (dev->capture.last_timestamp) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0164-staging-bcm2835-camera-Fix-logical-continuation-spli.patch b/target/linux/bcm27xx/patches-5.4/950-0164-staging-bcm2835-camera-Fix-logical-continuation-spli.patch deleted file mode 100644 index c1cbff5671..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0164-staging-bcm2835-camera-Fix-logical-continuation-spli.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 88e3479406637f8461fd026196f7bc5d4bf81cf9 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 21 Feb 2018 15:48:54 +0000 -Subject: [PATCH] staging: bcm2835-camera: Fix logical continuation - splits - -Fix checkpatch errors for "Logical continuations should be -on the previous line". - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -@@ -1114,8 +1114,8 @@ static int mmal_setup_components(struct - - ret = vchiq_mmal_port_set_format(dev->instance, camera_port); - -- if (!ret -- && camera_port == -+ if (!ret && -+ camera_port == - &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) { - bool overlay_enabled = - !!dev->component[COMP_PREVIEW]->enabled; diff --git a/target/linux/bcm27xx/patches-5.4/950-0164-staging-vc04_services-Split-vchiq-mmal-into-a-module.patch b/target/linux/bcm27xx/patches-5.4/950-0164-staging-vc04_services-Split-vchiq-mmal-into-a-module.patch new file mode 100644 index 0000000000..278d57b1bd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0164-staging-vc04_services-Split-vchiq-mmal-into-a-module.patch @@ -0,0 +1,7518 @@ +From 85961f2d8f646488acb86f996c78a1f9ad57cb0a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 24 Sep 2018 16:30:37 +0100 +Subject: [PATCH] staging: vc04_services: Split vchiq-mmal into a + module + +In preparation for adding a video codec V4L2 module which also +wants to use vchiq-mmal functions, split it out into an +independent module. +The minimum number of changes have been made to achieve this +(eg straight moves where possible) so existing checkpatch +errors will still be present. + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/Kconfig | 1 + + drivers/staging/vc04_services/Makefile | 1 + + .../vc04_services/bcm2835-camera/Kconfig | 2 +- + .../vc04_services/bcm2835-camera/Makefile | 5 +++-- + .../staging/vc04_services/vchiq-mmal/Kconfig | 7 ++++++ + .../staging/vc04_services/vchiq-mmal/Makefile | 8 +++++++ + .../mmal-common.h | 0 + .../mmal-encodings.h | 0 + .../mmal-msg-common.h | 0 + .../mmal-msg-format.h | 0 + .../mmal-msg-port.h | 0 + .../{bcm2835-camera => vchiq-mmal}/mmal-msg.h | 0 + .../mmal-parameters.h | 0 + .../mmal-vchiq.c | 22 +++++++++++++++++++ + .../mmal-vchiq.h | 0 + 15 files changed, 43 insertions(+), 3 deletions(-) + create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Kconfig + create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Makefile + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-common.h (100%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-encodings.h (100%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-common.h (100%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-format.h (100%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-port.h (100%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg.h (100%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-parameters.h (100%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.c (98%) + rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.h (100%) + +--- a/drivers/staging/vc04_services/Kconfig ++++ b/drivers/staging/vc04_services/Kconfig +@@ -22,6 +22,7 @@ config BCM2835_VCHIQ + source "drivers/staging/vc04_services/bcm2835-audio/Kconfig" + + source "drivers/staging/vc04_services/bcm2835-camera/Kconfig" ++source "drivers/staging/vc04_services/vchiq-mmal/Kconfig" + + endif + +--- a/drivers/staging/vc04_services/Makefile ++++ b/drivers/staging/vc04_services/Makefile +@@ -12,6 +12,7 @@ vchiq-objs := \ + + obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ + obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ ++obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ + + ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000 + +--- a/drivers/staging/vc04_services/bcm2835-camera/Kconfig ++++ b/drivers/staging/vc04_services/bcm2835-camera/Kconfig +@@ -3,7 +3,7 @@ config VIDEO_BCM2835 + tristate "BCM2835 Camera" + depends on MEDIA_SUPPORT + depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) +- select BCM2835_VCHIQ ++ select BCM2835_VCHIQ_MMAL + select VIDEOBUF2_VMALLOC + select BTREE + help +--- a/drivers/staging/vc04_services/bcm2835-camera/Makefile ++++ b/drivers/staging/vc04_services/bcm2835-camera/Makefile +@@ -1,11 +1,12 @@ + # SPDX-License-Identifier: GPL-2.0 + bcm2835-v4l2-$(CONFIG_VIDEO_BCM2835) := \ + bcm2835-camera.o \ +- controls.o \ +- mmal-vchiq.o ++ controls.o + + obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v4l2.o + + ccflags-y += \ + -I $(srctree)/$(src)/.. \ ++ -Idrivers/staging/vc04_services \ ++ -Idrivers/staging/vc04_services/vchiq-mmal \ + -D__VCCOREVER__=0x04000000 +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig +@@ -0,0 +1,7 @@ ++config BCM2835_VCHIQ_MMAL ++ tristate "BCM2835 MMAL VCHIQ service" ++ depends on (ARCH_BCM2835 || COMPILE_TEST) ++ select BCM2835_VCHIQ ++ help ++ Enables the MMAL API over VCHIQ as used for the ++ majority of the multimedia services on VideoCore. +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0 ++bcm2835-mmal-vchiq-objs := mmal-vchiq.o ++ ++obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += bcm2835-mmal-vchiq.o ++ ++ccflags-y += \ ++ -Idrivers/staging/vc04_services \ ++ -D__VCCOREVER__=0x04000000 +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c ++++ /dev/null +@@ -1,1891 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- * +- * V4L2 driver MMAL vchiq interface code +- */ +- +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "mmal-common.h" +-#include "mmal-vchiq.h" +-#include "mmal-msg.h" +- +-#define USE_VCHIQ_ARM +-#include "interface/vchi/vchi.h" +- +-/* maximum number of components supported */ +-#define VCHIQ_MMAL_MAX_COMPONENTS 4 +- +-/*#define FULL_MSG_DUMP 1*/ +- +-#ifdef DEBUG +-static const char *const msg_type_names[] = { +- "UNKNOWN", +- "QUIT", +- "SERVICE_CLOSED", +- "GET_VERSION", +- "COMPONENT_CREATE", +- "COMPONENT_DESTROY", +- "COMPONENT_ENABLE", +- "COMPONENT_DISABLE", +- "PORT_INFO_GET", +- "PORT_INFO_SET", +- "PORT_ACTION", +- "BUFFER_FROM_HOST", +- "BUFFER_TO_HOST", +- "GET_STATS", +- "PORT_PARAMETER_SET", +- "PORT_PARAMETER_GET", +- "EVENT_TO_HOST", +- "GET_CORE_STATS_FOR_PORT", +- "OPAQUE_ALLOCATOR", +- "CONSUME_MEM", +- "LMK", +- "OPAQUE_ALLOCATOR_DESC", +- "DRM_GET_LHS32", +- "DRM_GET_TIME", +- "BUFFER_FROM_HOST_ZEROLEN", +- "PORT_FLUSH", +- "HOST_LOG", +-}; +-#endif +- +-static const char *const port_action_type_names[] = { +- "UNKNOWN", +- "ENABLE", +- "DISABLE", +- "FLUSH", +- "CONNECT", +- "DISCONNECT", +- "SET_REQUIREMENTS", +-}; +- +-#if defined(DEBUG) +-#if defined(FULL_MSG_DUMP) +-#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \ +- do { \ +- pr_debug(TITLE" type:%s(%d) length:%d\n", \ +- msg_type_names[(MSG)->h.type], \ +- (MSG)->h.type, (MSG_LEN)); \ +- print_hex_dump(KERN_DEBUG, "<h.type], \ +- (MSG)->h.type, (MSG_LEN)); \ +- } +-#endif +-#else +-#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) +-#endif +- +-struct vchiq_mmal_instance; +- +-/* normal message context */ +-struct mmal_msg_context { +- struct vchiq_mmal_instance *instance; +- +- /* Index in the context_map idr so that we can find the +- * mmal_msg_context again when servicing the VCHI reply. +- */ +- int handle; +- +- union { +- struct { +- /* work struct for buffer_cb callback */ +- struct work_struct work; +- /* work struct for deferred callback */ +- struct work_struct buffer_to_host_work; +- /* mmal instance */ +- struct vchiq_mmal_instance *instance; +- /* mmal port */ +- struct vchiq_mmal_port *port; +- /* actual buffer used to store bulk reply */ +- struct mmal_buffer *buffer; +- /* amount of buffer used */ +- unsigned long buffer_used; +- /* MMAL buffer flags */ +- u32 mmal_flags; +- /* Presentation and Decode timestamps */ +- s64 pts; +- s64 dts; +- +- int status; /* context status */ +- +- } bulk; /* bulk data */ +- +- struct { +- /* message handle to release */ +- struct vchi_held_msg msg_handle; +- /* pointer to received message */ +- struct mmal_msg *msg; +- /* received message length */ +- u32 msg_len; +- /* completion upon reply */ +- struct completion cmplt; +- } sync; /* synchronous response */ +- } u; +- +-}; +- +-struct vchiq_mmal_instance { +- VCHI_SERVICE_HANDLE_T handle; +- +- /* ensure serialised access to service */ +- struct mutex vchiq_mutex; +- +- /* vmalloc page to receive scratch bulk xfers into */ +- void *bulk_scratch; +- +- struct idr context_map; +- /* protect accesses to context_map */ +- struct mutex context_map_lock; +- +- /* component to use next */ +- int component_idx; +- struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS]; +- +- /* ordered workqueue to process all bulk operations */ +- struct workqueue_struct *bulk_wq; +-}; +- +-static struct mmal_msg_context * +-get_msg_context(struct vchiq_mmal_instance *instance) +-{ +- struct mmal_msg_context *msg_context; +- int handle; +- +- /* todo: should this be allocated from a pool to avoid kzalloc */ +- msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL); +- +- if (!msg_context) +- return ERR_PTR(-ENOMEM); +- +- /* Create an ID that will be passed along with our message so +- * that when we service the VCHI reply, we can look up what +- * message is being replied to. +- */ +- mutex_lock(&instance->context_map_lock); +- handle = idr_alloc(&instance->context_map, msg_context, +- 0, 0, GFP_KERNEL); +- mutex_unlock(&instance->context_map_lock); +- +- if (handle < 0) { +- kfree(msg_context); +- return ERR_PTR(handle); +- } +- +- msg_context->instance = instance; +- msg_context->handle = handle; +- +- return msg_context; +-} +- +-static struct mmal_msg_context * +-lookup_msg_context(struct vchiq_mmal_instance *instance, int handle) +-{ +- return idr_find(&instance->context_map, handle); +-} +- +-static void +-release_msg_context(struct mmal_msg_context *msg_context) +-{ +- struct vchiq_mmal_instance *instance = msg_context->instance; +- +- mutex_lock(&instance->context_map_lock); +- idr_remove(&instance->context_map, msg_context->handle); +- mutex_unlock(&instance->context_map_lock); +- kfree(msg_context); +-} +- +-/* deals with receipt of event to host message */ +-static void event_to_host_cb(struct vchiq_mmal_instance *instance, +- struct mmal_msg *msg, u32 msg_len) +-{ +- pr_debug("unhandled event\n"); +- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n", +- msg->u.event_to_host.client_component, +- msg->u.event_to_host.port_type, +- msg->u.event_to_host.port_num, +- msg->u.event_to_host.cmd, msg->u.event_to_host.length); +-} +- +-/* workqueue scheduled callback +- * +- * we do this because it is important we do not call any other vchiq +- * sync calls from witin the message delivery thread +- */ +-static void buffer_work_cb(struct work_struct *work) +-{ +- struct mmal_msg_context *msg_context = +- container_of(work, struct mmal_msg_context, u.bulk.work); +- +- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); +- +- msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, +- msg_context->u.bulk.port, +- msg_context->u.bulk.status, +- msg_context->u.bulk.buffer, +- msg_context->u.bulk.buffer_used, +- msg_context->u.bulk.mmal_flags, +- msg_context->u.bulk.dts, +- msg_context->u.bulk.pts); +-} +- +-/* workqueue scheduled callback to handle receiving buffers +- * +- * VCHI will allow up to 4 bulk receives to be scheduled before blocking. +- * If we block in the service_callback context then we can't process the +- * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked +- * vchi_bulk_queue_receive() call to complete. +- */ +-static void buffer_to_host_work_cb(struct work_struct *work) +-{ +- struct mmal_msg_context *msg_context = +- container_of(work, struct mmal_msg_context, +- u.bulk.buffer_to_host_work); +- struct vchiq_mmal_instance *instance = msg_context->instance; +- unsigned long len = msg_context->u.bulk.buffer_used; +- int ret; +- +- if (!len) +- /* Dummy receive to ensure the buffers remain in order */ +- len = 8; +- /* queue the bulk submission */ +- vchi_service_use(instance->handle); +- ret = vchi_bulk_queue_receive(instance->handle, +- msg_context->u.bulk.buffer->buffer, +- /* Actual receive needs to be a multiple +- * of 4 bytes +- */ +- (len + 3) & ~3, +- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | +- VCHI_FLAGS_BLOCK_UNTIL_QUEUED, +- msg_context); +- +- vchi_service_release(instance->handle); +- +- if (ret != 0) +- pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n", +- __func__, msg_context, ret); +-} +- +-/* enqueue a bulk receive for a given message context */ +-static int bulk_receive(struct vchiq_mmal_instance *instance, +- struct mmal_msg *msg, +- struct mmal_msg_context *msg_context) +-{ +- unsigned long rd_len; +- +- rd_len = msg->u.buffer_from_host.buffer_header.length; +- +- if (!msg_context->u.bulk.buffer) { +- pr_err("bulk.buffer not configured - error in buffer_from_host\n"); +- +- /* todo: this is a serious error, we should never have +- * committed a buffer_to_host operation to the mmal +- * port without the buffer to back it up (underflow +- * handling) and there is no obvious way to deal with +- * this - how is the mmal servie going to react when +- * we fail to do the xfer and reschedule a buffer when +- * it arrives? perhaps a starved flag to indicate a +- * waiting bulk receive? +- */ +- +- return -EINVAL; +- } +- +- /* ensure we do not overrun the available buffer */ +- if (rd_len > msg_context->u.bulk.buffer->buffer_size) { +- rd_len = msg_context->u.bulk.buffer->buffer_size; +- pr_warn("short read as not enough receive buffer space\n"); +- /* todo: is this the correct response, what happens to +- * the rest of the message data? +- */ +- } +- +- /* store length */ +- msg_context->u.bulk.buffer_used = rd_len; +- msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts; +- msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts; +- +- queue_work(msg_context->instance->bulk_wq, +- &msg_context->u.bulk.buffer_to_host_work); +- +- return 0; +-} +- +-/* data in message, memcpy from packet into output buffer */ +-static int inline_receive(struct vchiq_mmal_instance *instance, +- struct mmal_msg *msg, +- struct mmal_msg_context *msg_context) +-{ +- memcpy(msg_context->u.bulk.buffer->buffer, +- msg->u.buffer_from_host.short_data, +- msg->u.buffer_from_host.payload_in_message); +- +- msg_context->u.bulk.buffer_used = +- msg->u.buffer_from_host.payload_in_message; +- +- return 0; +-} +- +-/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */ +-static int +-buffer_from_host(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, struct mmal_buffer *buf) +-{ +- struct mmal_msg_context *msg_context; +- struct mmal_msg m; +- int ret; +- +- if (!port->enabled) +- return -EINVAL; +- +- pr_debug("instance:%p buffer:%p\n", instance->handle, buf); +- +- /* get context */ +- if (!buf->msg_context) { +- pr_err("%s: msg_context not allocated, buf %p\n", __func__, +- buf); +- return -EINVAL; +- } +- msg_context = buf->msg_context; +- +- /* store bulk message context for when data arrives */ +- msg_context->u.bulk.instance = instance; +- msg_context->u.bulk.port = port; +- msg_context->u.bulk.buffer = buf; +- msg_context->u.bulk.buffer_used = 0; +- +- /* initialise work structure ready to schedule callback */ +- INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb); +- INIT_WORK(&msg_context->u.bulk.buffer_to_host_work, +- buffer_to_host_work_cb); +- +- atomic_inc(&port->buffers_with_vpu); +- +- /* prep the buffer from host message */ +- memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */ +- +- m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST; +- m.h.magic = MMAL_MAGIC; +- m.h.context = msg_context->handle; +- m.h.status = 0; +- +- /* drvbuf is our private data passed back */ +- m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC; +- m.u.buffer_from_host.drvbuf.component_handle = port->component->handle; +- m.u.buffer_from_host.drvbuf.port_handle = port->handle; +- m.u.buffer_from_host.drvbuf.client_context = msg_context->handle; +- +- /* buffer header */ +- m.u.buffer_from_host.buffer_header.cmd = 0; +- m.u.buffer_from_host.buffer_header.data = +- (u32)(unsigned long)buf->buffer; +- m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; +- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */ +- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */ +- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */ +- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; +- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; +- +- /* clear buffer type sepecific data */ +- memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, +- sizeof(m.u.buffer_from_host.buffer_header_type_specific)); +- +- /* no payload in message */ +- m.u.buffer_from_host.payload_in_message = 0; +- +- vchi_service_use(instance->handle); +- +- ret = vchi_queue_kernel_message(instance->handle, +- &m, +- sizeof(struct mmal_msg_header) + +- sizeof(m.u.buffer_from_host)); +- +- vchi_service_release(instance->handle); +- +- return ret; +-} +- +-/* deals with receipt of buffer to host message */ +-static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, +- struct mmal_msg *msg, u32 msg_len) +-{ +- struct mmal_msg_context *msg_context; +- u32 handle; +- +- pr_debug("%s: instance:%p msg:%p msg_len:%d\n", +- __func__, instance, msg, msg_len); +- +- if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) { +- handle = msg->u.buffer_from_host.drvbuf.client_context; +- msg_context = lookup_msg_context(instance, handle); +- +- if (!msg_context) { +- pr_err("drvbuf.client_context(%u) is invalid\n", +- handle); +- return; +- } +- } else { +- pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n"); +- return; +- } +- +- msg_context->u.bulk.mmal_flags = +- msg->u.buffer_from_host.buffer_header.flags; +- +- if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) { +- /* message reception had an error */ +- pr_warn("error %d in reply\n", msg->h.status); +- +- msg_context->u.bulk.status = msg->h.status; +- +- } else if (msg->u.buffer_from_host.buffer_header.length == 0) { +- /* empty buffer */ +- if (msg->u.buffer_from_host.buffer_header.flags & +- MMAL_BUFFER_HEADER_FLAG_EOS) { +- msg_context->u.bulk.status = +- bulk_receive(instance, msg, msg_context); +- if (msg_context->u.bulk.status == 0) +- return; /* successful bulk submission, bulk +- * completion will trigger callback +- */ +- } else { +- /* do callback with empty buffer - not EOS though */ +- msg_context->u.bulk.status = 0; +- msg_context->u.bulk.buffer_used = 0; +- } +- } else if (msg->u.buffer_from_host.payload_in_message == 0) { +- /* data is not in message, queue a bulk receive */ +- msg_context->u.bulk.status = +- bulk_receive(instance, msg, msg_context); +- if (msg_context->u.bulk.status == 0) +- return; /* successful bulk submission, bulk +- * completion will trigger callback +- */ +- +- /* failed to submit buffer, this will end badly */ +- pr_err("error %d on bulk submission\n", +- msg_context->u.bulk.status); +- +- } else if (msg->u.buffer_from_host.payload_in_message <= +- MMAL_VC_SHORT_DATA) { +- /* data payload within message */ +- msg_context->u.bulk.status = inline_receive(instance, msg, +- msg_context); +- } else { +- pr_err("message with invalid short payload\n"); +- +- /* signal error */ +- msg_context->u.bulk.status = -EINVAL; +- msg_context->u.bulk.buffer_used = +- msg->u.buffer_from_host.payload_in_message; +- } +- +- /* schedule the port callback */ +- schedule_work(&msg_context->u.bulk.work); +-} +- +-static void bulk_receive_cb(struct vchiq_mmal_instance *instance, +- struct mmal_msg_context *msg_context) +-{ +- msg_context->u.bulk.status = 0; +- +- /* schedule the port callback */ +- schedule_work(&msg_context->u.bulk.work); +-} +- +-static void bulk_abort_cb(struct vchiq_mmal_instance *instance, +- struct mmal_msg_context *msg_context) +-{ +- pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context); +- +- msg_context->u.bulk.status = -EINTR; +- +- schedule_work(&msg_context->u.bulk.work); +-} +- +-/* incoming event service callback */ +-static void service_callback(void *param, +- const VCHI_CALLBACK_REASON_T reason, +- void *bulk_ctx) +-{ +- struct vchiq_mmal_instance *instance = param; +- int status; +- u32 msg_len; +- struct mmal_msg *msg; +- struct vchi_held_msg msg_handle; +- struct mmal_msg_context *msg_context; +- +- if (!instance) { +- pr_err("Message callback passed NULL instance\n"); +- return; +- } +- +- switch (reason) { +- case VCHI_CALLBACK_MSG_AVAILABLE: +- status = vchi_msg_hold(instance->handle, (void **)&msg, +- &msg_len, VCHI_FLAGS_NONE, &msg_handle); +- if (status) { +- pr_err("Unable to dequeue a message (%d)\n", status); +- break; +- } +- +- DBG_DUMP_MSG(msg, msg_len, "<<< reply message"); +- +- /* handling is different for buffer messages */ +- switch (msg->h.type) { +- case MMAL_MSG_TYPE_BUFFER_FROM_HOST: +- vchi_held_msg_release(&msg_handle); +- break; +- +- case MMAL_MSG_TYPE_EVENT_TO_HOST: +- event_to_host_cb(instance, msg, msg_len); +- vchi_held_msg_release(&msg_handle); +- +- break; +- +- case MMAL_MSG_TYPE_BUFFER_TO_HOST: +- buffer_to_host_cb(instance, msg, msg_len); +- vchi_held_msg_release(&msg_handle); +- break; +- +- default: +- /* messages dependent on header context to complete */ +- if (!msg->h.context) { +- pr_err("received message context was null!\n"); +- vchi_held_msg_release(&msg_handle); +- break; +- } +- +- msg_context = lookup_msg_context(instance, +- msg->h.context); +- if (!msg_context) { +- pr_err("received invalid message context %u!\n", +- msg->h.context); +- vchi_held_msg_release(&msg_handle); +- break; +- } +- +- /* fill in context values */ +- msg_context->u.sync.msg_handle = msg_handle; +- msg_context->u.sync.msg = msg; +- msg_context->u.sync.msg_len = msg_len; +- +- /* todo: should this check (completion_done() +- * == 1) for no one waiting? or do we need a +- * flag to tell us the completion has been +- * interrupted so we can free the message and +- * its context. This probably also solves the +- * message arriving after interruption todo +- * below +- */ +- +- /* complete message so caller knows it happened */ +- complete(&msg_context->u.sync.cmplt); +- break; +- } +- +- break; +- +- case VCHI_CALLBACK_BULK_RECEIVED: +- bulk_receive_cb(instance, bulk_ctx); +- break; +- +- case VCHI_CALLBACK_BULK_RECEIVE_ABORTED: +- bulk_abort_cb(instance, bulk_ctx); +- break; +- +- case VCHI_CALLBACK_SERVICE_CLOSED: +- /* TODO: consider if this requires action if received when +- * driver is not explicitly closing the service +- */ +- break; +- +- default: +- pr_err("Received unhandled message reason %d\n", reason); +- break; +- } +-} +- +-static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, +- struct mmal_msg *msg, +- unsigned int payload_len, +- struct mmal_msg **msg_out, +- struct vchi_held_msg *msg_handle_out) +-{ +- struct mmal_msg_context *msg_context; +- int ret; +- unsigned long timeout; +- +- /* payload size must not cause message to exceed max size */ +- if (payload_len > +- (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) { +- pr_err("payload length %d exceeds max:%d\n", payload_len, +- (int)(MMAL_MSG_MAX_SIZE - +- sizeof(struct mmal_msg_header))); +- return -EINVAL; +- } +- +- msg_context = get_msg_context(instance); +- if (IS_ERR(msg_context)) +- return PTR_ERR(msg_context); +- +- init_completion(&msg_context->u.sync.cmplt); +- +- msg->h.magic = MMAL_MAGIC; +- msg->h.context = msg_context->handle; +- msg->h.status = 0; +- +- DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len), +- ">>> sync message"); +- +- vchi_service_use(instance->handle); +- +- ret = vchi_queue_kernel_message(instance->handle, +- msg, +- sizeof(struct mmal_msg_header) + +- payload_len); +- +- vchi_service_release(instance->handle); +- +- if (ret) { +- pr_err("error %d queuing message\n", ret); +- release_msg_context(msg_context); +- return ret; +- } +- +- timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt, +- 3 * HZ); +- if (timeout == 0) { +- pr_err("timed out waiting for sync completion\n"); +- ret = -ETIME; +- /* todo: what happens if the message arrives after aborting */ +- release_msg_context(msg_context); +- return ret; +- } +- +- *msg_out = msg_context->u.sync.msg; +- *msg_handle_out = msg_context->u.sync.msg_handle; +- release_msg_context(msg_context); +- +- return 0; +-} +- +-static void dump_port_info(struct vchiq_mmal_port *port) +-{ +- pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled); +- +- pr_debug("buffer minimum num:%d size:%d align:%d\n", +- port->minimum_buffer.num, +- port->minimum_buffer.size, port->minimum_buffer.alignment); +- +- pr_debug("buffer recommended num:%d size:%d align:%d\n", +- port->recommended_buffer.num, +- port->recommended_buffer.size, +- port->recommended_buffer.alignment); +- +- pr_debug("buffer current values num:%d size:%d align:%d\n", +- port->current_buffer.num, +- port->current_buffer.size, port->current_buffer.alignment); +- +- pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n", +- port->format.type, +- port->format.encoding, port->format.encoding_variant); +- +- pr_debug(" bitrate:%d flags:0x%x\n", +- port->format.bitrate, port->format.flags); +- +- if (port->format.type == MMAL_ES_TYPE_VIDEO) { +- pr_debug +- ("es video format: width:%d height:%d colourspace:0x%x\n", +- port->es.video.width, port->es.video.height, +- port->es.video.color_space); +- +- pr_debug(" : crop xywh %d,%d,%d,%d\n", +- port->es.video.crop.x, +- port->es.video.crop.y, +- port->es.video.crop.width, port->es.video.crop.height); +- pr_debug(" : framerate %d/%d aspect %d/%d\n", +- port->es.video.frame_rate.num, +- port->es.video.frame_rate.den, +- port->es.video.par.num, port->es.video.par.den); +- } +-} +- +-static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p) +-{ +- /* todo do readonly fields need setting at all? */ +- p->type = port->type; +- p->index = port->index; +- p->index_all = 0; +- p->is_enabled = port->enabled; +- p->buffer_num_min = port->minimum_buffer.num; +- p->buffer_size_min = port->minimum_buffer.size; +- p->buffer_alignment_min = port->minimum_buffer.alignment; +- p->buffer_num_recommended = port->recommended_buffer.num; +- p->buffer_size_recommended = port->recommended_buffer.size; +- +- /* only three writable fields in a port */ +- p->buffer_num = port->current_buffer.num; +- p->buffer_size = port->current_buffer.size; +- p->userdata = (u32)(unsigned long)port; +-} +- +-static int port_info_set(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- pr_debug("setting port info port %p\n", port); +- if (!port) +- return -1; +- dump_port_info(port); +- +- m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET; +- +- m.u.port_info_set.component_handle = port->component->handle; +- m.u.port_info_set.port_type = port->type; +- m.u.port_info_set.port_index = port->index; +- +- port_to_mmal_msg(port, &m.u.port_info_set.port); +- +- /* elementary stream format setup */ +- m.u.port_info_set.format.type = port->format.type; +- m.u.port_info_set.format.encoding = port->format.encoding; +- m.u.port_info_set.format.encoding_variant = +- port->format.encoding_variant; +- m.u.port_info_set.format.bitrate = port->format.bitrate; +- m.u.port_info_set.format.flags = port->format.flags; +- +- memcpy(&m.u.port_info_set.es, &port->es, +- sizeof(union mmal_es_specific_format)); +- +- m.u.port_info_set.format.extradata_size = port->format.extradata_size; +- memcpy(&m.u.port_info_set.extradata, port->format.extradata, +- port->format.extradata_size); +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.port_info_set), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- /* return operation status */ +- ret = -rmsg->u.port_info_get_reply.status; +- +- pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret, +- port->component->handle, port->handle); +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* use port info get message to retrieve port information */ +-static int port_info_get(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- /* port info time */ +- m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET; +- m.u.port_info_get.component_handle = port->component->handle; +- m.u.port_info_get.port_type = port->type; +- m.u.port_info_get.index = port->index; +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.port_info_get), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- /* return operation status */ +- ret = -rmsg->u.port_info_get_reply.status; +- if (ret != MMAL_MSG_STATUS_SUCCESS) +- goto release_msg; +- +- if (rmsg->u.port_info_get_reply.port.is_enabled == 0) +- port->enabled = 0; +- else +- port->enabled = 1; +- +- /* copy the values out of the message */ +- port->handle = rmsg->u.port_info_get_reply.port_handle; +- +- /* port type and index cached to use on port info set because +- * it does not use a port handle +- */ +- port->type = rmsg->u.port_info_get_reply.port_type; +- port->index = rmsg->u.port_info_get_reply.port_index; +- +- port->minimum_buffer.num = +- rmsg->u.port_info_get_reply.port.buffer_num_min; +- port->minimum_buffer.size = +- rmsg->u.port_info_get_reply.port.buffer_size_min; +- port->minimum_buffer.alignment = +- rmsg->u.port_info_get_reply.port.buffer_alignment_min; +- +- port->recommended_buffer.alignment = +- rmsg->u.port_info_get_reply.port.buffer_alignment_min; +- port->recommended_buffer.num = +- rmsg->u.port_info_get_reply.port.buffer_num_recommended; +- +- port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num; +- port->current_buffer.size = +- rmsg->u.port_info_get_reply.port.buffer_size; +- +- /* stream format */ +- port->format.type = rmsg->u.port_info_get_reply.format.type; +- port->format.encoding = rmsg->u.port_info_get_reply.format.encoding; +- port->format.encoding_variant = +- rmsg->u.port_info_get_reply.format.encoding_variant; +- port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate; +- port->format.flags = rmsg->u.port_info_get_reply.format.flags; +- +- /* elementary stream format */ +- memcpy(&port->es, +- &rmsg->u.port_info_get_reply.es, +- sizeof(union mmal_es_specific_format)); +- port->format.es = &port->es; +- +- port->format.extradata_size = +- rmsg->u.port_info_get_reply.format.extradata_size; +- memcpy(port->format.extradata, +- rmsg->u.port_info_get_reply.extradata, +- port->format.extradata_size); +- +- pr_debug("received port info\n"); +- dump_port_info(port); +- +-release_msg: +- +- pr_debug("%s:result:%d component:0x%x port:%d\n", +- __func__, ret, port->component->handle, port->handle); +- +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* create comonent on vc */ +-static int create_component(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component, +- const char *name) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- /* build component create message */ +- m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE; +- m.u.component_create.client_component = (u32)(unsigned long)component; +- strncpy(m.u.component_create.name, name, +- sizeof(m.u.component_create.name)); +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.component_create), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != m.h.type) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.component_create_reply.status; +- if (ret != MMAL_MSG_STATUS_SUCCESS) +- goto release_msg; +- +- /* a valid component response received */ +- component->handle = rmsg->u.component_create_reply.component_handle; +- component->inputs = rmsg->u.component_create_reply.input_num; +- component->outputs = rmsg->u.component_create_reply.output_num; +- component->clocks = rmsg->u.component_create_reply.clock_num; +- +- pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n", +- component->handle, +- component->inputs, component->outputs, component->clocks); +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* destroys a component on vc */ +-static int destroy_component(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY; +- m.u.component_destroy.component_handle = component->handle; +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.component_destroy), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != m.h.type) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.component_destroy_reply.status; +- +-release_msg: +- +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* enable a component on vc */ +-static int enable_component(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE; +- m.u.component_enable.component_handle = component->handle; +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.component_enable), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != m.h.type) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.component_enable_reply.status; +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* disable a component on vc */ +-static int disable_component(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE; +- m.u.component_disable.component_handle = component->handle; +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.component_disable), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != m.h.type) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.component_disable_reply.status; +- +-release_msg: +- +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* get version of mmal implementation */ +-static int get_version(struct vchiq_mmal_instance *instance, +- u32 *major_out, u32 *minor_out) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_GET_VERSION; +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.version), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != m.h.type) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- *major_out = rmsg->u.version.major; +- *minor_out = rmsg->u.version.minor; +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* do a port action with a port as a parameter */ +-static int port_action_port(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- enum mmal_msg_port_action_type action_type) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_PORT_ACTION; +- m.u.port_action_port.component_handle = port->component->handle; +- m.u.port_action_port.port_handle = port->handle; +- m.u.port_action_port.action = action_type; +- +- port_to_mmal_msg(port, &m.u.port_action_port.port); +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.port_action_port), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.port_action_reply.status; +- +- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n", +- __func__, +- ret, port->component->handle, port->handle, +- port_action_type_names[action_type], action_type); +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* do a port action with handles as parameters */ +-static int port_action_handle(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- enum mmal_msg_port_action_type action_type, +- u32 connect_component_handle, +- u32 connect_port_handle) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_PORT_ACTION; +- +- m.u.port_action_handle.component_handle = port->component->handle; +- m.u.port_action_handle.port_handle = port->handle; +- m.u.port_action_handle.action = action_type; +- +- m.u.port_action_handle.connect_component_handle = +- connect_component_handle; +- m.u.port_action_handle.connect_port_handle = connect_port_handle; +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(m.u.port_action_handle), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.port_action_reply.status; +- +- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n", +- __func__, +- ret, port->component->handle, port->handle, +- port_action_type_names[action_type], +- action_type, connect_component_handle, connect_port_handle); +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-static int port_parameter_set(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- u32 parameter_id, void *value, u32 value_size) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET; +- +- m.u.port_parameter_set.component_handle = port->component->handle; +- m.u.port_parameter_set.port_handle = port->handle; +- m.u.port_parameter_set.id = parameter_id; +- m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size; +- memcpy(&m.u.port_parameter_set.value, value, value_size); +- +- ret = send_synchronous_mmal_msg(instance, &m, +- (4 * sizeof(u32)) + value_size, +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) { +- /* got an unexpected message type in reply */ +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.port_parameter_set_reply.status; +- +- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", +- __func__, +- ret, port->component->handle, port->handle, parameter_id); +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-static int port_parameter_get(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- u32 parameter_id, void *value, u32 *value_size) +-{ +- int ret; +- struct mmal_msg m; +- struct mmal_msg *rmsg; +- struct vchi_held_msg rmsg_handle; +- +- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET; +- +- m.u.port_parameter_get.component_handle = port->component->handle; +- m.u.port_parameter_get.port_handle = port->handle; +- m.u.port_parameter_get.id = parameter_id; +- m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size; +- +- ret = send_synchronous_mmal_msg(instance, &m, +- sizeof(struct +- mmal_msg_port_parameter_get), +- &rmsg, &rmsg_handle); +- if (ret) +- return ret; +- +- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) { +- /* got an unexpected message type in reply */ +- pr_err("Incorrect reply type %d\n", rmsg->h.type); +- ret = -EINVAL; +- goto release_msg; +- } +- +- ret = -rmsg->u.port_parameter_get_reply.status; +- /* port_parameter_get_reply.size includes the header, +- * whilst *value_size doesn't. +- */ +- rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32)); +- +- if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) { +- /* Copy only as much as we have space for +- * but report true size of parameter +- */ +- memcpy(value, &rmsg->u.port_parameter_get_reply.value, +- *value_size); +- *value_size = rmsg->u.port_parameter_get_reply.size; +- } else { +- memcpy(value, &rmsg->u.port_parameter_get_reply.value, +- rmsg->u.port_parameter_get_reply.size); +- } +- +- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, +- ret, port->component->handle, port->handle, parameter_id); +- +-release_msg: +- vchi_held_msg_release(&rmsg_handle); +- +- return ret; +-} +- +-/* disables a port and drains buffers from it */ +-static int port_disable(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port) +-{ +- int ret; +- struct list_head *q, *buf_head; +- unsigned long flags = 0; +- +- if (!port->enabled) +- return 0; +- +- port->enabled = 0; +- +- ret = port_action_port(instance, port, +- MMAL_MSG_PORT_ACTION_TYPE_DISABLE); +- if (ret == 0) { +- /* +- * Drain all queued buffers on port. This should only +- * apply to buffers that have been queued before the port +- * has been enabled. If the port has been enabled and buffers +- * passed, then the buffers should have been removed from this +- * list, and we should get the relevant callbacks via VCHIQ +- * to release the buffers. +- */ +- spin_lock_irqsave(&port->slock, flags); +- +- list_for_each_safe(buf_head, q, &port->buffers) { +- struct mmal_buffer *mmalbuf; +- +- mmalbuf = list_entry(buf_head, struct mmal_buffer, +- list); +- list_del(buf_head); +- if (port->buffer_cb) +- port->buffer_cb(instance, +- port, 0, mmalbuf, 0, 0, +- MMAL_TIME_UNKNOWN, +- MMAL_TIME_UNKNOWN); +- } +- +- spin_unlock_irqrestore(&port->slock, flags); +- +- ret = port_info_get(instance, port); +- } +- +- return ret; +-} +- +-/* enable a port */ +-static int port_enable(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port) +-{ +- unsigned int hdr_count; +- struct list_head *q, *buf_head; +- int ret; +- +- if (port->enabled) +- return 0; +- +- ret = port_action_port(instance, port, +- MMAL_MSG_PORT_ACTION_TYPE_ENABLE); +- if (ret) +- goto done; +- +- port->enabled = 1; +- +- if (port->buffer_cb) { +- /* send buffer headers to videocore */ +- hdr_count = 1; +- list_for_each_safe(buf_head, q, &port->buffers) { +- struct mmal_buffer *mmalbuf; +- +- mmalbuf = list_entry(buf_head, struct mmal_buffer, +- list); +- ret = buffer_from_host(instance, port, mmalbuf); +- if (ret) +- goto done; +- +- list_del(buf_head); +- hdr_count++; +- if (hdr_count > port->current_buffer.num) +- break; +- } +- } +- +- ret = port_info_get(instance, port); +- +-done: +- return ret; +-} +- +-/* ------------------------------------------------------------------ +- * Exported API +- *------------------------------------------------------------------ +- */ +- +-int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- ret = port_info_set(instance, port); +- if (ret) +- goto release_unlock; +- +- /* read what has actually been set */ +- ret = port_info_get(instance, port); +- +-release_unlock: +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- u32 parameter, void *value, u32 value_size) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- ret = port_parameter_set(instance, port, parameter, value, value_size); +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- u32 parameter, void *value, u32 *value_size) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- ret = port_parameter_get(instance, port, parameter, value, value_size); +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-/* enable a port +- * +- * enables a port and queues buffers for satisfying callbacks if we +- * provide a callback handler +- */ +-int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- vchiq_mmal_buffer_cb buffer_cb) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- /* already enabled - noop */ +- if (port->enabled) { +- ret = 0; +- goto unlock; +- } +- +- port->buffer_cb = buffer_cb; +- +- ret = port_enable(instance, port); +- +-unlock: +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- if (!port->enabled) { +- mutex_unlock(&instance->vchiq_mutex); +- return 0; +- } +- +- ret = port_disable(instance, port); +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-/* ports will be connected in a tunneled manner so data buffers +- * are not handled by client. +- */ +-int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *src, +- struct vchiq_mmal_port *dst) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- /* disconnect ports if connected */ +- if (src->connected) { +- ret = port_disable(instance, src); +- if (ret) { +- pr_err("failed disabling src port(%d)\n", ret); +- goto release_unlock; +- } +- +- /* do not need to disable the destination port as they +- * are connected and it is done automatically +- */ +- +- ret = port_action_handle(instance, src, +- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, +- src->connected->component->handle, +- src->connected->handle); +- if (ret < 0) { +- pr_err("failed disconnecting src port\n"); +- goto release_unlock; +- } +- src->connected->enabled = 0; +- src->connected = NULL; +- } +- +- if (!dst) { +- /* do not make new connection */ +- ret = 0; +- pr_debug("not making new connection\n"); +- goto release_unlock; +- } +- +- /* copy src port format to dst */ +- dst->format.encoding = src->format.encoding; +- dst->es.video.width = src->es.video.width; +- dst->es.video.height = src->es.video.height; +- dst->es.video.crop.x = src->es.video.crop.x; +- dst->es.video.crop.y = src->es.video.crop.y; +- dst->es.video.crop.width = src->es.video.crop.width; +- dst->es.video.crop.height = src->es.video.crop.height; +- dst->es.video.frame_rate.num = src->es.video.frame_rate.num; +- dst->es.video.frame_rate.den = src->es.video.frame_rate.den; +- +- /* set new format */ +- ret = port_info_set(instance, dst); +- if (ret) { +- pr_debug("setting port info failed\n"); +- goto release_unlock; +- } +- +- /* read what has actually been set */ +- ret = port_info_get(instance, dst); +- if (ret) { +- pr_debug("read back port info failed\n"); +- goto release_unlock; +- } +- +- /* connect two ports together */ +- ret = port_action_handle(instance, src, +- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, +- dst->component->handle, dst->handle); +- if (ret < 0) { +- pr_debug("connecting port %d:%d to %d:%d failed\n", +- src->component->handle, src->handle, +- dst->component->handle, dst->handle); +- goto release_unlock; +- } +- src->connected = dst; +- +-release_unlock: +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- struct mmal_buffer *buffer) +-{ +- unsigned long flags = 0; +- int ret; +- +- ret = buffer_from_host(instance, port, buffer); +- if (ret == -EINVAL) { +- /* Port is disabled. Queue for when it is enabled. */ +- spin_lock_irqsave(&port->slock, flags); +- list_add_tail(&buffer->list, &port->buffers); +- spin_unlock_irqrestore(&port->slock, flags); +- } +- +- return 0; +-} +- +-int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, +- struct mmal_buffer *buf) +-{ +- struct mmal_msg_context *msg_context = get_msg_context(instance); +- +- if (IS_ERR(msg_context)) +- return (PTR_ERR(msg_context)); +- +- buf->msg_context = msg_context; +- return 0; +-} +- +-int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) +-{ +- struct mmal_msg_context *msg_context = buf->msg_context; +- +- if (msg_context) +- release_msg_context(msg_context); +- buf->msg_context = NULL; +- +- return 0; +-} +- +-/* Initialise a mmal component and its ports +- * +- */ +-int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, +- const char *name, +- struct vchiq_mmal_component **component_out) +-{ +- int ret; +- int idx; /* port index */ +- struct vchiq_mmal_component *component; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) { +- ret = -EINVAL; /* todo is this correct error? */ +- goto unlock; +- } +- +- component = &instance->component[instance->component_idx]; +- +- ret = create_component(instance, component, name); +- if (ret < 0) { +- pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", +- __func__, ret); +- goto unlock; +- } +- +- /* ports info needs gathering */ +- component->control.type = MMAL_PORT_TYPE_CONTROL; +- component->control.index = 0; +- component->control.component = component; +- spin_lock_init(&component->control.slock); +- INIT_LIST_HEAD(&component->control.buffers); +- ret = port_info_get(instance, &component->control); +- if (ret < 0) +- goto release_component; +- +- for (idx = 0; idx < component->inputs; idx++) { +- component->input[idx].type = MMAL_PORT_TYPE_INPUT; +- component->input[idx].index = idx; +- component->input[idx].component = component; +- spin_lock_init(&component->input[idx].slock); +- INIT_LIST_HEAD(&component->input[idx].buffers); +- ret = port_info_get(instance, &component->input[idx]); +- if (ret < 0) +- goto release_component; +- } +- +- for (idx = 0; idx < component->outputs; idx++) { +- component->output[idx].type = MMAL_PORT_TYPE_OUTPUT; +- component->output[idx].index = idx; +- component->output[idx].component = component; +- spin_lock_init(&component->output[idx].slock); +- INIT_LIST_HEAD(&component->output[idx].buffers); +- ret = port_info_get(instance, &component->output[idx]); +- if (ret < 0) +- goto release_component; +- } +- +- for (idx = 0; idx < component->clocks; idx++) { +- component->clock[idx].type = MMAL_PORT_TYPE_CLOCK; +- component->clock[idx].index = idx; +- component->clock[idx].component = component; +- spin_lock_init(&component->clock[idx].slock); +- INIT_LIST_HEAD(&component->clock[idx].buffers); +- ret = port_info_get(instance, &component->clock[idx]); +- if (ret < 0) +- goto release_component; +- } +- +- instance->component_idx++; +- +- *component_out = component; +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return 0; +- +-release_component: +- destroy_component(instance, component); +-unlock: +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-/* +- * cause a mmal component to be destroyed +- */ +-int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- if (component->enabled) +- ret = disable_component(instance, component); +- +- ret = destroy_component(instance, component); +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-/* +- * cause a mmal component to be enabled +- */ +-int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- if (component->enabled) { +- mutex_unlock(&instance->vchiq_mutex); +- return 0; +- } +- +- ret = enable_component(instance, component); +- if (ret == 0) +- component->enabled = true; +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-/* +- * cause a mmal component to be enabled +- */ +-int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- if (!component->enabled) { +- mutex_unlock(&instance->vchiq_mutex); +- return 0; +- } +- +- ret = disable_component(instance, component); +- if (ret == 0) +- component->enabled = 0; +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-int vchiq_mmal_version(struct vchiq_mmal_instance *instance, +- u32 *major_out, u32 *minor_out) +-{ +- int ret; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- ret = get_version(instance, major_out, minor_out); +- +- mutex_unlock(&instance->vchiq_mutex); +- +- return ret; +-} +- +-int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance) +-{ +- int status = 0; +- +- if (!instance) +- return -EINVAL; +- +- if (mutex_lock_interruptible(&instance->vchiq_mutex)) +- return -EINTR; +- +- vchi_service_use(instance->handle); +- +- status = vchi_service_close(instance->handle); +- if (status != 0) +- pr_err("mmal-vchiq: VCHIQ close failed\n"); +- +- mutex_unlock(&instance->vchiq_mutex); +- +- flush_workqueue(instance->bulk_wq); +- destroy_workqueue(instance->bulk_wq); +- +- vfree(instance->bulk_scratch); +- +- idr_destroy(&instance->context_map); +- +- kfree(instance); +- +- return status; +-} +- +-int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) +-{ +- int status; +- struct vchiq_mmal_instance *instance; +- static VCHI_INSTANCE_T vchi_instance; +- struct service_creation params = { +- .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER), +- .service_id = VC_MMAL_SERVER_NAME, +- .callback = service_callback, +- .callback_param = NULL, +- }; +- +- /* compile time checks to ensure structure size as they are +- * directly (de)serialised from memory. +- */ +- +- /* ensure the header structure has packed to the correct size */ +- BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24); +- +- /* ensure message structure does not exceed maximum length */ +- BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE); +- +- /* mmal port struct is correct size */ +- BUILD_BUG_ON(sizeof(struct mmal_port) != 64); +- +- /* create a vchi instance */ +- status = vchi_initialise(&vchi_instance); +- if (status) { +- pr_err("Failed to initialise VCHI instance (status=%d)\n", +- status); +- return -EIO; +- } +- +- status = vchi_connect(vchi_instance); +- if (status) { +- pr_err("Failed to connect VCHI instance (status=%d)\n", status); +- return -EIO; +- } +- +- instance = kzalloc(sizeof(*instance), GFP_KERNEL); +- +- if (!instance) +- return -ENOMEM; +- +- mutex_init(&instance->vchiq_mutex); +- +- instance->bulk_scratch = vmalloc(PAGE_SIZE); +- +- mutex_init(&instance->context_map_lock); +- idr_init_base(&instance->context_map, 1); +- +- params.callback_param = instance; +- +- instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq", +- WQ_MEM_RECLAIM); +- if (!instance->bulk_wq) +- goto err_free; +- +- status = vchi_service_open(vchi_instance, ¶ms, &instance->handle); +- if (status) { +- pr_err("Failed to open VCHI service connection (status=%d)\n", +- status); +- goto err_close_services; +- } +- +- vchi_service_release(instance->handle); +- +- *out_instance = instance; +- +- return 0; +- +-err_close_services: +- vchi_service_close(instance->handle); +- destroy_workqueue(instance->bulk_wq); +-err_free: +- vfree(instance->bulk_scratch); +- kfree(instance); +- return -ENODEV; +-} +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -0,0 +1,1913 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ * ++ * V4L2 driver MMAL vchiq interface code ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mmal-common.h" ++#include "mmal-vchiq.h" ++#include "mmal-msg.h" ++ ++#define USE_VCHIQ_ARM ++#include "interface/vchi/vchi.h" ++ ++MODULE_DESCRIPTION("BCM2835 MMAL VCHIQ interface"); ++MODULE_AUTHOR("Dave Stevenson, "); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("0.0.1"); ++ ++/* maximum number of components supported */ ++#define VCHIQ_MMAL_MAX_COMPONENTS 4 ++ ++/*#define FULL_MSG_DUMP 1*/ ++ ++#ifdef DEBUG ++static const char *const msg_type_names[] = { ++ "UNKNOWN", ++ "QUIT", ++ "SERVICE_CLOSED", ++ "GET_VERSION", ++ "COMPONENT_CREATE", ++ "COMPONENT_DESTROY", ++ "COMPONENT_ENABLE", ++ "COMPONENT_DISABLE", ++ "PORT_INFO_GET", ++ "PORT_INFO_SET", ++ "PORT_ACTION", ++ "BUFFER_FROM_HOST", ++ "BUFFER_TO_HOST", ++ "GET_STATS", ++ "PORT_PARAMETER_SET", ++ "PORT_PARAMETER_GET", ++ "EVENT_TO_HOST", ++ "GET_CORE_STATS_FOR_PORT", ++ "OPAQUE_ALLOCATOR", ++ "CONSUME_MEM", ++ "LMK", ++ "OPAQUE_ALLOCATOR_DESC", ++ "DRM_GET_LHS32", ++ "DRM_GET_TIME", ++ "BUFFER_FROM_HOST_ZEROLEN", ++ "PORT_FLUSH", ++ "HOST_LOG", ++}; ++#endif ++ ++static const char *const port_action_type_names[] = { ++ "UNKNOWN", ++ "ENABLE", ++ "DISABLE", ++ "FLUSH", ++ "CONNECT", ++ "DISCONNECT", ++ "SET_REQUIREMENTS", ++}; ++ ++#if defined(DEBUG) ++#if defined(FULL_MSG_DUMP) ++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \ ++ do { \ ++ pr_debug(TITLE" type:%s(%d) length:%d\n", \ ++ msg_type_names[(MSG)->h.type], \ ++ (MSG)->h.type, (MSG_LEN)); \ ++ print_hex_dump(KERN_DEBUG, "<h.type], \ ++ (MSG)->h.type, (MSG_LEN)); \ ++ } ++#endif ++#else ++#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) ++#endif ++ ++struct vchiq_mmal_instance; ++ ++/* normal message context */ ++struct mmal_msg_context { ++ struct vchiq_mmal_instance *instance; ++ ++ /* Index in the context_map idr so that we can find the ++ * mmal_msg_context again when servicing the VCHI reply. ++ */ ++ int handle; ++ ++ union { ++ struct { ++ /* work struct for buffer_cb callback */ ++ struct work_struct work; ++ /* work struct for deferred callback */ ++ struct work_struct buffer_to_host_work; ++ /* mmal instance */ ++ struct vchiq_mmal_instance *instance; ++ /* mmal port */ ++ struct vchiq_mmal_port *port; ++ /* actual buffer used to store bulk reply */ ++ struct mmal_buffer *buffer; ++ /* amount of buffer used */ ++ unsigned long buffer_used; ++ /* MMAL buffer flags */ ++ u32 mmal_flags; ++ /* Presentation and Decode timestamps */ ++ s64 pts; ++ s64 dts; ++ ++ int status; /* context status */ ++ ++ } bulk; /* bulk data */ ++ ++ struct { ++ /* message handle to release */ ++ struct vchi_held_msg msg_handle; ++ /* pointer to received message */ ++ struct mmal_msg *msg; ++ /* received message length */ ++ u32 msg_len; ++ /* completion upon reply */ ++ struct completion cmplt; ++ } sync; /* synchronous response */ ++ } u; ++ ++}; ++ ++struct vchiq_mmal_instance { ++ VCHI_SERVICE_HANDLE_T handle; ++ ++ /* ensure serialised access to service */ ++ struct mutex vchiq_mutex; ++ ++ /* vmalloc page to receive scratch bulk xfers into */ ++ void *bulk_scratch; ++ ++ struct idr context_map; ++ /* protect accesses to context_map */ ++ struct mutex context_map_lock; ++ ++ /* component to use next */ ++ int component_idx; ++ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS]; ++ ++ /* ordered workqueue to process all bulk operations */ ++ struct workqueue_struct *bulk_wq; ++}; ++ ++static struct mmal_msg_context * ++get_msg_context(struct vchiq_mmal_instance *instance) ++{ ++ struct mmal_msg_context *msg_context; ++ int handle; ++ ++ /* todo: should this be allocated from a pool to avoid kzalloc */ ++ msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL); ++ ++ if (!msg_context) ++ return ERR_PTR(-ENOMEM); ++ ++ /* Create an ID that will be passed along with our message so ++ * that when we service the VCHI reply, we can look up what ++ * message is being replied to. ++ */ ++ mutex_lock(&instance->context_map_lock); ++ handle = idr_alloc(&instance->context_map, msg_context, ++ 0, 0, GFP_KERNEL); ++ mutex_unlock(&instance->context_map_lock); ++ ++ if (handle < 0) { ++ kfree(msg_context); ++ return ERR_PTR(handle); ++ } ++ ++ msg_context->instance = instance; ++ msg_context->handle = handle; ++ ++ return msg_context; ++} ++ ++static struct mmal_msg_context * ++lookup_msg_context(struct vchiq_mmal_instance *instance, int handle) ++{ ++ return idr_find(&instance->context_map, handle); ++} ++ ++static void ++release_msg_context(struct mmal_msg_context *msg_context) ++{ ++ struct vchiq_mmal_instance *instance = msg_context->instance; ++ ++ mutex_lock(&instance->context_map_lock); ++ idr_remove(&instance->context_map, msg_context->handle); ++ mutex_unlock(&instance->context_map_lock); ++ kfree(msg_context); ++} ++ ++/* deals with receipt of event to host message */ ++static void event_to_host_cb(struct vchiq_mmal_instance *instance, ++ struct mmal_msg *msg, u32 msg_len) ++{ ++ pr_debug("unhandled event\n"); ++ pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n", ++ msg->u.event_to_host.client_component, ++ msg->u.event_to_host.port_type, ++ msg->u.event_to_host.port_num, ++ msg->u.event_to_host.cmd, msg->u.event_to_host.length); ++} ++ ++/* workqueue scheduled callback ++ * ++ * we do this because it is important we do not call any other vchiq ++ * sync calls from witin the message delivery thread ++ */ ++static void buffer_work_cb(struct work_struct *work) ++{ ++ struct mmal_msg_context *msg_context = ++ container_of(work, struct mmal_msg_context, u.bulk.work); ++ ++ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); ++ ++ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, ++ msg_context->u.bulk.port, ++ msg_context->u.bulk.status, ++ msg_context->u.bulk.buffer, ++ msg_context->u.bulk.buffer_used, ++ msg_context->u.bulk.mmal_flags, ++ msg_context->u.bulk.dts, ++ msg_context->u.bulk.pts); ++} ++ ++/* workqueue scheduled callback to handle receiving buffers ++ * ++ * VCHI will allow up to 4 bulk receives to be scheduled before blocking. ++ * If we block in the service_callback context then we can't process the ++ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked ++ * vchi_bulk_queue_receive() call to complete. ++ */ ++static void buffer_to_host_work_cb(struct work_struct *work) ++{ ++ struct mmal_msg_context *msg_context = ++ container_of(work, struct mmal_msg_context, ++ u.bulk.buffer_to_host_work); ++ struct vchiq_mmal_instance *instance = msg_context->instance; ++ unsigned long len = msg_context->u.bulk.buffer_used; ++ int ret; ++ ++ if (!len) ++ /* Dummy receive to ensure the buffers remain in order */ ++ len = 8; ++ /* queue the bulk submission */ ++ vchi_service_use(instance->handle); ++ ret = vchi_bulk_queue_receive(instance->handle, ++ msg_context->u.bulk.buffer->buffer, ++ /* Actual receive needs to be a multiple ++ * of 4 bytes ++ */ ++ (len + 3) & ~3, ++ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, ++ msg_context); ++ ++ vchi_service_release(instance->handle); ++ ++ if (ret != 0) ++ pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n", ++ __func__, msg_context, ret); ++} ++ ++/* enqueue a bulk receive for a given message context */ ++static int bulk_receive(struct vchiq_mmal_instance *instance, ++ struct mmal_msg *msg, ++ struct mmal_msg_context *msg_context) ++{ ++ unsigned long rd_len; ++ ++ rd_len = msg->u.buffer_from_host.buffer_header.length; ++ ++ if (!msg_context->u.bulk.buffer) { ++ pr_err("bulk.buffer not configured - error in buffer_from_host\n"); ++ ++ /* todo: this is a serious error, we should never have ++ * committed a buffer_to_host operation to the mmal ++ * port without the buffer to back it up (underflow ++ * handling) and there is no obvious way to deal with ++ * this - how is the mmal servie going to react when ++ * we fail to do the xfer and reschedule a buffer when ++ * it arrives? perhaps a starved flag to indicate a ++ * waiting bulk receive? ++ */ ++ ++ return -EINVAL; ++ } ++ ++ /* ensure we do not overrun the available buffer */ ++ if (rd_len > msg_context->u.bulk.buffer->buffer_size) { ++ rd_len = msg_context->u.bulk.buffer->buffer_size; ++ pr_warn("short read as not enough receive buffer space\n"); ++ /* todo: is this the correct response, what happens to ++ * the rest of the message data? ++ */ ++ } ++ ++ /* store length */ ++ msg_context->u.bulk.buffer_used = rd_len; ++ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts; ++ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts; ++ ++ queue_work(msg_context->instance->bulk_wq, ++ &msg_context->u.bulk.buffer_to_host_work); ++ ++ return 0; ++} ++ ++/* data in message, memcpy from packet into output buffer */ ++static int inline_receive(struct vchiq_mmal_instance *instance, ++ struct mmal_msg *msg, ++ struct mmal_msg_context *msg_context) ++{ ++ memcpy(msg_context->u.bulk.buffer->buffer, ++ msg->u.buffer_from_host.short_data, ++ msg->u.buffer_from_host.payload_in_message); ++ ++ msg_context->u.bulk.buffer_used = ++ msg->u.buffer_from_host.payload_in_message; ++ ++ return 0; ++} ++ ++/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */ ++static int ++buffer_from_host(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, struct mmal_buffer *buf) ++{ ++ struct mmal_msg_context *msg_context; ++ struct mmal_msg m; ++ int ret; ++ ++ if (!port->enabled) ++ return -EINVAL; ++ ++ pr_debug("instance:%p buffer:%p\n", instance->handle, buf); ++ ++ /* get context */ ++ if (!buf->msg_context) { ++ pr_err("%s: msg_context not allocated, buf %p\n", __func__, ++ buf); ++ return -EINVAL; ++ } ++ msg_context = buf->msg_context; ++ ++ /* store bulk message context for when data arrives */ ++ msg_context->u.bulk.instance = instance; ++ msg_context->u.bulk.port = port; ++ msg_context->u.bulk.buffer = buf; ++ msg_context->u.bulk.buffer_used = 0; ++ ++ /* initialise work structure ready to schedule callback */ ++ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb); ++ INIT_WORK(&msg_context->u.bulk.buffer_to_host_work, ++ buffer_to_host_work_cb); ++ ++ atomic_inc(&port->buffers_with_vpu); ++ ++ /* prep the buffer from host message */ ++ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */ ++ ++ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST; ++ m.h.magic = MMAL_MAGIC; ++ m.h.context = msg_context->handle; ++ m.h.status = 0; ++ ++ /* drvbuf is our private data passed back */ ++ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC; ++ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle; ++ m.u.buffer_from_host.drvbuf.port_handle = port->handle; ++ m.u.buffer_from_host.drvbuf.client_context = msg_context->handle; ++ ++ /* buffer header */ ++ m.u.buffer_from_host.buffer_header.cmd = 0; ++ m.u.buffer_from_host.buffer_header.data = ++ (u32)(unsigned long)buf->buffer; ++ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; ++ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */ ++ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */ ++ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */ ++ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; ++ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; ++ ++ /* clear buffer type sepecific data */ ++ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, ++ sizeof(m.u.buffer_from_host.buffer_header_type_specific)); ++ ++ /* no payload in message */ ++ m.u.buffer_from_host.payload_in_message = 0; ++ ++ vchi_service_use(instance->handle); ++ ++ ret = vchi_queue_kernel_message(instance->handle, ++ &m, ++ sizeof(struct mmal_msg_header) + ++ sizeof(m.u.buffer_from_host)); ++ ++ vchi_service_release(instance->handle); ++ ++ return ret; ++} ++ ++/* deals with receipt of buffer to host message */ ++static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, ++ struct mmal_msg *msg, u32 msg_len) ++{ ++ struct mmal_msg_context *msg_context; ++ u32 handle; ++ ++ pr_debug("%s: instance:%p msg:%p msg_len:%d\n", ++ __func__, instance, msg, msg_len); ++ ++ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) { ++ handle = msg->u.buffer_from_host.drvbuf.client_context; ++ msg_context = lookup_msg_context(instance, handle); ++ ++ if (!msg_context) { ++ pr_err("drvbuf.client_context(%u) is invalid\n", ++ handle); ++ return; ++ } ++ } else { ++ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n"); ++ return; ++ } ++ ++ msg_context->u.bulk.mmal_flags = ++ msg->u.buffer_from_host.buffer_header.flags; ++ ++ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) { ++ /* message reception had an error */ ++ pr_warn("error %d in reply\n", msg->h.status); ++ ++ msg_context->u.bulk.status = msg->h.status; ++ ++ } else if (msg->u.buffer_from_host.buffer_header.length == 0) { ++ /* empty buffer */ ++ if (msg->u.buffer_from_host.buffer_header.flags & ++ MMAL_BUFFER_HEADER_FLAG_EOS) { ++ msg_context->u.bulk.status = ++ bulk_receive(instance, msg, msg_context); ++ if (msg_context->u.bulk.status == 0) ++ return; /* successful bulk submission, bulk ++ * completion will trigger callback ++ */ ++ } else { ++ /* do callback with empty buffer - not EOS though */ ++ msg_context->u.bulk.status = 0; ++ msg_context->u.bulk.buffer_used = 0; ++ } ++ } else if (msg->u.buffer_from_host.payload_in_message == 0) { ++ /* data is not in message, queue a bulk receive */ ++ msg_context->u.bulk.status = ++ bulk_receive(instance, msg, msg_context); ++ if (msg_context->u.bulk.status == 0) ++ return; /* successful bulk submission, bulk ++ * completion will trigger callback ++ */ ++ ++ /* failed to submit buffer, this will end badly */ ++ pr_err("error %d on bulk submission\n", ++ msg_context->u.bulk.status); ++ ++ } else if (msg->u.buffer_from_host.payload_in_message <= ++ MMAL_VC_SHORT_DATA) { ++ /* data payload within message */ ++ msg_context->u.bulk.status = inline_receive(instance, msg, ++ msg_context); ++ } else { ++ pr_err("message with invalid short payload\n"); ++ ++ /* signal error */ ++ msg_context->u.bulk.status = -EINVAL; ++ msg_context->u.bulk.buffer_used = ++ msg->u.buffer_from_host.payload_in_message; ++ } ++ ++ /* schedule the port callback */ ++ schedule_work(&msg_context->u.bulk.work); ++} ++ ++static void bulk_receive_cb(struct vchiq_mmal_instance *instance, ++ struct mmal_msg_context *msg_context) ++{ ++ msg_context->u.bulk.status = 0; ++ ++ /* schedule the port callback */ ++ schedule_work(&msg_context->u.bulk.work); ++} ++ ++static void bulk_abort_cb(struct vchiq_mmal_instance *instance, ++ struct mmal_msg_context *msg_context) ++{ ++ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context); ++ ++ msg_context->u.bulk.status = -EINTR; ++ ++ schedule_work(&msg_context->u.bulk.work); ++} ++ ++/* incoming event service callback */ ++static void service_callback(void *param, ++ const VCHI_CALLBACK_REASON_T reason, ++ void *bulk_ctx) ++{ ++ struct vchiq_mmal_instance *instance = param; ++ int status; ++ u32 msg_len; ++ struct mmal_msg *msg; ++ struct vchi_held_msg msg_handle; ++ struct mmal_msg_context *msg_context; ++ ++ if (!instance) { ++ pr_err("Message callback passed NULL instance\n"); ++ return; ++ } ++ ++ switch (reason) { ++ case VCHI_CALLBACK_MSG_AVAILABLE: ++ status = vchi_msg_hold(instance->handle, (void **)&msg, ++ &msg_len, VCHI_FLAGS_NONE, &msg_handle); ++ if (status) { ++ pr_err("Unable to dequeue a message (%d)\n", status); ++ break; ++ } ++ ++ DBG_DUMP_MSG(msg, msg_len, "<<< reply message"); ++ ++ /* handling is different for buffer messages */ ++ switch (msg->h.type) { ++ case MMAL_MSG_TYPE_BUFFER_FROM_HOST: ++ vchi_held_msg_release(&msg_handle); ++ break; ++ ++ case MMAL_MSG_TYPE_EVENT_TO_HOST: ++ event_to_host_cb(instance, msg, msg_len); ++ vchi_held_msg_release(&msg_handle); ++ ++ break; ++ ++ case MMAL_MSG_TYPE_BUFFER_TO_HOST: ++ buffer_to_host_cb(instance, msg, msg_len); ++ vchi_held_msg_release(&msg_handle); ++ break; ++ ++ default: ++ /* messages dependent on header context to complete */ ++ if (!msg->h.context) { ++ pr_err("received message context was null!\n"); ++ vchi_held_msg_release(&msg_handle); ++ break; ++ } ++ ++ msg_context = lookup_msg_context(instance, ++ msg->h.context); ++ if (!msg_context) { ++ pr_err("received invalid message context %u!\n", ++ msg->h.context); ++ vchi_held_msg_release(&msg_handle); ++ break; ++ } ++ ++ /* fill in context values */ ++ msg_context->u.sync.msg_handle = msg_handle; ++ msg_context->u.sync.msg = msg; ++ msg_context->u.sync.msg_len = msg_len; ++ ++ /* todo: should this check (completion_done() ++ * == 1) for no one waiting? or do we need a ++ * flag to tell us the completion has been ++ * interrupted so we can free the message and ++ * its context. This probably also solves the ++ * message arriving after interruption todo ++ * below ++ */ ++ ++ /* complete message so caller knows it happened */ ++ complete(&msg_context->u.sync.cmplt); ++ break; ++ } ++ ++ break; ++ ++ case VCHI_CALLBACK_BULK_RECEIVED: ++ bulk_receive_cb(instance, bulk_ctx); ++ break; ++ ++ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED: ++ bulk_abort_cb(instance, bulk_ctx); ++ break; ++ ++ case VCHI_CALLBACK_SERVICE_CLOSED: ++ /* TODO: consider if this requires action if received when ++ * driver is not explicitly closing the service ++ */ ++ break; ++ ++ default: ++ pr_err("Received unhandled message reason %d\n", reason); ++ break; ++ } ++} ++ ++static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, ++ struct mmal_msg *msg, ++ unsigned int payload_len, ++ struct mmal_msg **msg_out, ++ struct vchi_held_msg *msg_handle_out) ++{ ++ struct mmal_msg_context *msg_context; ++ int ret; ++ unsigned long timeout; ++ ++ /* payload size must not cause message to exceed max size */ ++ if (payload_len > ++ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) { ++ pr_err("payload length %d exceeds max:%d\n", payload_len, ++ (int)(MMAL_MSG_MAX_SIZE - ++ sizeof(struct mmal_msg_header))); ++ return -EINVAL; ++ } ++ ++ msg_context = get_msg_context(instance); ++ if (IS_ERR(msg_context)) ++ return PTR_ERR(msg_context); ++ ++ init_completion(&msg_context->u.sync.cmplt); ++ ++ msg->h.magic = MMAL_MAGIC; ++ msg->h.context = msg_context->handle; ++ msg->h.status = 0; ++ ++ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len), ++ ">>> sync message"); ++ ++ vchi_service_use(instance->handle); ++ ++ ret = vchi_queue_kernel_message(instance->handle, ++ msg, ++ sizeof(struct mmal_msg_header) + ++ payload_len); ++ ++ vchi_service_release(instance->handle); ++ ++ if (ret) { ++ pr_err("error %d queuing message\n", ret); ++ release_msg_context(msg_context); ++ return ret; ++ } ++ ++ timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt, ++ 3 * HZ); ++ if (timeout == 0) { ++ pr_err("timed out waiting for sync completion\n"); ++ ret = -ETIME; ++ /* todo: what happens if the message arrives after aborting */ ++ release_msg_context(msg_context); ++ return ret; ++ } ++ ++ *msg_out = msg_context->u.sync.msg; ++ *msg_handle_out = msg_context->u.sync.msg_handle; ++ release_msg_context(msg_context); ++ ++ return 0; ++} ++ ++static void dump_port_info(struct vchiq_mmal_port *port) ++{ ++ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled); ++ ++ pr_debug("buffer minimum num:%d size:%d align:%d\n", ++ port->minimum_buffer.num, ++ port->minimum_buffer.size, port->minimum_buffer.alignment); ++ ++ pr_debug("buffer recommended num:%d size:%d align:%d\n", ++ port->recommended_buffer.num, ++ port->recommended_buffer.size, ++ port->recommended_buffer.alignment); ++ ++ pr_debug("buffer current values num:%d size:%d align:%d\n", ++ port->current_buffer.num, ++ port->current_buffer.size, port->current_buffer.alignment); ++ ++ pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n", ++ port->format.type, ++ port->format.encoding, port->format.encoding_variant); ++ ++ pr_debug(" bitrate:%d flags:0x%x\n", ++ port->format.bitrate, port->format.flags); ++ ++ if (port->format.type == MMAL_ES_TYPE_VIDEO) { ++ pr_debug ++ ("es video format: width:%d height:%d colourspace:0x%x\n", ++ port->es.video.width, port->es.video.height, ++ port->es.video.color_space); ++ ++ pr_debug(" : crop xywh %d,%d,%d,%d\n", ++ port->es.video.crop.x, ++ port->es.video.crop.y, ++ port->es.video.crop.width, port->es.video.crop.height); ++ pr_debug(" : framerate %d/%d aspect %d/%d\n", ++ port->es.video.frame_rate.num, ++ port->es.video.frame_rate.den, ++ port->es.video.par.num, port->es.video.par.den); ++ } ++} ++ ++static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p) ++{ ++ /* todo do readonly fields need setting at all? */ ++ p->type = port->type; ++ p->index = port->index; ++ p->index_all = 0; ++ p->is_enabled = port->enabled; ++ p->buffer_num_min = port->minimum_buffer.num; ++ p->buffer_size_min = port->minimum_buffer.size; ++ p->buffer_alignment_min = port->minimum_buffer.alignment; ++ p->buffer_num_recommended = port->recommended_buffer.num; ++ p->buffer_size_recommended = port->recommended_buffer.size; ++ ++ /* only three writable fields in a port */ ++ p->buffer_num = port->current_buffer.num; ++ p->buffer_size = port->current_buffer.size; ++ p->userdata = (u32)(unsigned long)port; ++} ++ ++static int port_info_set(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ pr_debug("setting port info port %p\n", port); ++ if (!port) ++ return -1; ++ dump_port_info(port); ++ ++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET; ++ ++ m.u.port_info_set.component_handle = port->component->handle; ++ m.u.port_info_set.port_type = port->type; ++ m.u.port_info_set.port_index = port->index; ++ ++ port_to_mmal_msg(port, &m.u.port_info_set.port); ++ ++ /* elementary stream format setup */ ++ m.u.port_info_set.format.type = port->format.type; ++ m.u.port_info_set.format.encoding = port->format.encoding; ++ m.u.port_info_set.format.encoding_variant = ++ port->format.encoding_variant; ++ m.u.port_info_set.format.bitrate = port->format.bitrate; ++ m.u.port_info_set.format.flags = port->format.flags; ++ ++ memcpy(&m.u.port_info_set.es, &port->es, ++ sizeof(union mmal_es_specific_format)); ++ ++ m.u.port_info_set.format.extradata_size = port->format.extradata_size; ++ memcpy(&m.u.port_info_set.extradata, port->format.extradata, ++ port->format.extradata_size); ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.port_info_set), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ /* return operation status */ ++ ret = -rmsg->u.port_info_get_reply.status; ++ ++ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret, ++ port->component->handle, port->handle); ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* use port info get message to retrieve port information */ ++static int port_info_get(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ /* port info time */ ++ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET; ++ m.u.port_info_get.component_handle = port->component->handle; ++ m.u.port_info_get.port_type = port->type; ++ m.u.port_info_get.index = port->index; ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.port_info_get), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ /* return operation status */ ++ ret = -rmsg->u.port_info_get_reply.status; ++ if (ret != MMAL_MSG_STATUS_SUCCESS) ++ goto release_msg; ++ ++ if (rmsg->u.port_info_get_reply.port.is_enabled == 0) ++ port->enabled = 0; ++ else ++ port->enabled = 1; ++ ++ /* copy the values out of the message */ ++ port->handle = rmsg->u.port_info_get_reply.port_handle; ++ ++ /* port type and index cached to use on port info set because ++ * it does not use a port handle ++ */ ++ port->type = rmsg->u.port_info_get_reply.port_type; ++ port->index = rmsg->u.port_info_get_reply.port_index; ++ ++ port->minimum_buffer.num = ++ rmsg->u.port_info_get_reply.port.buffer_num_min; ++ port->minimum_buffer.size = ++ rmsg->u.port_info_get_reply.port.buffer_size_min; ++ port->minimum_buffer.alignment = ++ rmsg->u.port_info_get_reply.port.buffer_alignment_min; ++ ++ port->recommended_buffer.alignment = ++ rmsg->u.port_info_get_reply.port.buffer_alignment_min; ++ port->recommended_buffer.num = ++ rmsg->u.port_info_get_reply.port.buffer_num_recommended; ++ ++ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num; ++ port->current_buffer.size = ++ rmsg->u.port_info_get_reply.port.buffer_size; ++ ++ /* stream format */ ++ port->format.type = rmsg->u.port_info_get_reply.format.type; ++ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding; ++ port->format.encoding_variant = ++ rmsg->u.port_info_get_reply.format.encoding_variant; ++ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate; ++ port->format.flags = rmsg->u.port_info_get_reply.format.flags; ++ ++ /* elementary stream format */ ++ memcpy(&port->es, ++ &rmsg->u.port_info_get_reply.es, ++ sizeof(union mmal_es_specific_format)); ++ port->format.es = &port->es; ++ ++ port->format.extradata_size = ++ rmsg->u.port_info_get_reply.format.extradata_size; ++ memcpy(port->format.extradata, ++ rmsg->u.port_info_get_reply.extradata, ++ port->format.extradata_size); ++ ++ pr_debug("received port info\n"); ++ dump_port_info(port); ++ ++release_msg: ++ ++ pr_debug("%s:result:%d component:0x%x port:%d\n", ++ __func__, ret, port->component->handle, port->handle); ++ ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* create comonent on vc */ ++static int create_component(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component, ++ const char *name) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ /* build component create message */ ++ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE; ++ m.u.component_create.client_component = (u32)(unsigned long)component; ++ strncpy(m.u.component_create.name, name, ++ sizeof(m.u.component_create.name)); ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.component_create), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != m.h.type) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.component_create_reply.status; ++ if (ret != MMAL_MSG_STATUS_SUCCESS) ++ goto release_msg; ++ ++ /* a valid component response received */ ++ component->handle = rmsg->u.component_create_reply.component_handle; ++ component->inputs = rmsg->u.component_create_reply.input_num; ++ component->outputs = rmsg->u.component_create_reply.output_num; ++ component->clocks = rmsg->u.component_create_reply.clock_num; ++ ++ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n", ++ component->handle, ++ component->inputs, component->outputs, component->clocks); ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* destroys a component on vc */ ++static int destroy_component(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY; ++ m.u.component_destroy.component_handle = component->handle; ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.component_destroy), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != m.h.type) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.component_destroy_reply.status; ++ ++release_msg: ++ ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* enable a component on vc */ ++static int enable_component(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE; ++ m.u.component_enable.component_handle = component->handle; ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.component_enable), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != m.h.type) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.component_enable_reply.status; ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* disable a component on vc */ ++static int disable_component(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE; ++ m.u.component_disable.component_handle = component->handle; ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.component_disable), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != m.h.type) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.component_disable_reply.status; ++ ++release_msg: ++ ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* get version of mmal implementation */ ++static int get_version(struct vchiq_mmal_instance *instance, ++ u32 *major_out, u32 *minor_out) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_GET_VERSION; ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.version), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != m.h.type) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ *major_out = rmsg->u.version.major; ++ *minor_out = rmsg->u.version.minor; ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* do a port action with a port as a parameter */ ++static int port_action_port(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ enum mmal_msg_port_action_type action_type) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION; ++ m.u.port_action_port.component_handle = port->component->handle; ++ m.u.port_action_port.port_handle = port->handle; ++ m.u.port_action_port.action = action_type; ++ ++ port_to_mmal_msg(port, &m.u.port_action_port.port); ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.port_action_port), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.port_action_reply.status; ++ ++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n", ++ __func__, ++ ret, port->component->handle, port->handle, ++ port_action_type_names[action_type], action_type); ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* do a port action with handles as parameters */ ++static int port_action_handle(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ enum mmal_msg_port_action_type action_type, ++ u32 connect_component_handle, ++ u32 connect_port_handle) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_PORT_ACTION; ++ ++ m.u.port_action_handle.component_handle = port->component->handle; ++ m.u.port_action_handle.port_handle = port->handle; ++ m.u.port_action_handle.action = action_type; ++ ++ m.u.port_action_handle.connect_component_handle = ++ connect_component_handle; ++ m.u.port_action_handle.connect_port_handle = connect_port_handle; ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(m.u.port_action_handle), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.port_action_reply.status; ++ ++ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n", ++ __func__, ++ ret, port->component->handle, port->handle, ++ port_action_type_names[action_type], ++ action_type, connect_component_handle, connect_port_handle); ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++static int port_parameter_set(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ u32 parameter_id, void *value, u32 value_size) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET; ++ ++ m.u.port_parameter_set.component_handle = port->component->handle; ++ m.u.port_parameter_set.port_handle = port->handle; ++ m.u.port_parameter_set.id = parameter_id; ++ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size; ++ memcpy(&m.u.port_parameter_set.value, value, value_size); ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ (4 * sizeof(u32)) + value_size, ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) { ++ /* got an unexpected message type in reply */ ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.port_parameter_set_reply.status; ++ ++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", ++ __func__, ++ ret, port->component->handle, port->handle, parameter_id); ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++static int port_parameter_get(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ u32 parameter_id, void *value, u32 *value_size) ++{ ++ int ret; ++ struct mmal_msg m; ++ struct mmal_msg *rmsg; ++ struct vchi_held_msg rmsg_handle; ++ ++ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET; ++ ++ m.u.port_parameter_get.component_handle = port->component->handle; ++ m.u.port_parameter_get.port_handle = port->handle; ++ m.u.port_parameter_get.id = parameter_id; ++ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size; ++ ++ ret = send_synchronous_mmal_msg(instance, &m, ++ sizeof(struct ++ mmal_msg_port_parameter_get), ++ &rmsg, &rmsg_handle); ++ if (ret) ++ return ret; ++ ++ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) { ++ /* got an unexpected message type in reply */ ++ pr_err("Incorrect reply type %d\n", rmsg->h.type); ++ ret = -EINVAL; ++ goto release_msg; ++ } ++ ++ ret = -rmsg->u.port_parameter_get_reply.status; ++ /* port_parameter_get_reply.size includes the header, ++ * whilst *value_size doesn't. ++ */ ++ rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32)); ++ ++ if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) { ++ /* Copy only as much as we have space for ++ * but report true size of parameter ++ */ ++ memcpy(value, &rmsg->u.port_parameter_get_reply.value, ++ *value_size); ++ *value_size = rmsg->u.port_parameter_get_reply.size; ++ } else { ++ memcpy(value, &rmsg->u.port_parameter_get_reply.value, ++ rmsg->u.port_parameter_get_reply.size); ++ } ++ ++ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, ++ ret, port->component->handle, port->handle, parameter_id); ++ ++release_msg: ++ vchi_held_msg_release(&rmsg_handle); ++ ++ return ret; ++} ++ ++/* disables a port and drains buffers from it */ ++static int port_disable(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port) ++{ ++ int ret; ++ struct list_head *q, *buf_head; ++ unsigned long flags = 0; ++ ++ if (!port->enabled) ++ return 0; ++ ++ port->enabled = 0; ++ ++ ret = port_action_port(instance, port, ++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE); ++ if (ret == 0) { ++ /* ++ * Drain all queued buffers on port. This should only ++ * apply to buffers that have been queued before the port ++ * has been enabled. If the port has been enabled and buffers ++ * passed, then the buffers should have been removed from this ++ * list, and we should get the relevant callbacks via VCHIQ ++ * to release the buffers. ++ */ ++ spin_lock_irqsave(&port->slock, flags); ++ ++ list_for_each_safe(buf_head, q, &port->buffers) { ++ struct mmal_buffer *mmalbuf; ++ ++ mmalbuf = list_entry(buf_head, struct mmal_buffer, ++ list); ++ list_del(buf_head); ++ if (port->buffer_cb) ++ port->buffer_cb(instance, ++ port, 0, mmalbuf, 0, 0, ++ MMAL_TIME_UNKNOWN, ++ MMAL_TIME_UNKNOWN); ++ } ++ ++ spin_unlock_irqrestore(&port->slock, flags); ++ ++ ret = port_info_get(instance, port); ++ } ++ ++ return ret; ++} ++ ++/* enable a port */ ++static int port_enable(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port) ++{ ++ unsigned int hdr_count; ++ struct list_head *q, *buf_head; ++ int ret; ++ ++ if (port->enabled) ++ return 0; ++ ++ ret = port_action_port(instance, port, ++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE); ++ if (ret) ++ goto done; ++ ++ port->enabled = 1; ++ ++ if (port->buffer_cb) { ++ /* send buffer headers to videocore */ ++ hdr_count = 1; ++ list_for_each_safe(buf_head, q, &port->buffers) { ++ struct mmal_buffer *mmalbuf; ++ ++ mmalbuf = list_entry(buf_head, struct mmal_buffer, ++ list); ++ ret = buffer_from_host(instance, port, mmalbuf); ++ if (ret) ++ goto done; ++ ++ list_del(buf_head); ++ hdr_count++; ++ if (hdr_count > port->current_buffer.num) ++ break; ++ } ++ } ++ ++ ret = port_info_get(instance, port); ++ ++done: ++ return ret; ++} ++ ++/* ------------------------------------------------------------------ ++ * Exported API ++ *------------------------------------------------------------------ ++ */ ++ ++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ ret = port_info_set(instance, port); ++ if (ret) ++ goto release_unlock; ++ ++ /* read what has actually been set */ ++ ret = port_info_get(instance, port); ++ ++release_unlock: ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_port_set_format); ++ ++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ u32 parameter, void *value, u32 value_size) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ ret = port_parameter_set(instance, port, parameter, value, value_size); ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set); ++ ++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ u32 parameter, void *value, u32 *value_size) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ ret = port_parameter_get(instance, port, parameter, value, value_size); ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_get); ++ ++/* enable a port ++ * ++ * enables a port and queues buffers for satisfying callbacks if we ++ * provide a callback handler ++ */ ++int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ vchiq_mmal_buffer_cb buffer_cb) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ /* already enabled - noop */ ++ if (port->enabled) { ++ ret = 0; ++ goto unlock; ++ } ++ ++ port->buffer_cb = buffer_cb; ++ ++ ret = port_enable(instance, port); ++ ++unlock: ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_port_enable); ++ ++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ if (!port->enabled) { ++ mutex_unlock(&instance->vchiq_mutex); ++ return 0; ++ } ++ ++ ret = port_disable(instance, port); ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_port_disable); ++ ++/* ports will be connected in a tunneled manner so data buffers ++ * are not handled by client. ++ */ ++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *src, ++ struct vchiq_mmal_port *dst) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ /* disconnect ports if connected */ ++ if (src->connected) { ++ ret = port_disable(instance, src); ++ if (ret) { ++ pr_err("failed disabling src port(%d)\n", ret); ++ goto release_unlock; ++ } ++ ++ /* do not need to disable the destination port as they ++ * are connected and it is done automatically ++ */ ++ ++ ret = port_action_handle(instance, src, ++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, ++ src->connected->component->handle, ++ src->connected->handle); ++ if (ret < 0) { ++ pr_err("failed disconnecting src port\n"); ++ goto release_unlock; ++ } ++ src->connected->enabled = 0; ++ src->connected = NULL; ++ } ++ ++ if (!dst) { ++ /* do not make new connection */ ++ ret = 0; ++ pr_debug("not making new connection\n"); ++ goto release_unlock; ++ } ++ ++ /* copy src port format to dst */ ++ dst->format.encoding = src->format.encoding; ++ dst->es.video.width = src->es.video.width; ++ dst->es.video.height = src->es.video.height; ++ dst->es.video.crop.x = src->es.video.crop.x; ++ dst->es.video.crop.y = src->es.video.crop.y; ++ dst->es.video.crop.width = src->es.video.crop.width; ++ dst->es.video.crop.height = src->es.video.crop.height; ++ dst->es.video.frame_rate.num = src->es.video.frame_rate.num; ++ dst->es.video.frame_rate.den = src->es.video.frame_rate.den; ++ ++ /* set new format */ ++ ret = port_info_set(instance, dst); ++ if (ret) { ++ pr_debug("setting port info failed\n"); ++ goto release_unlock; ++ } ++ ++ /* read what has actually been set */ ++ ret = port_info_get(instance, dst); ++ if (ret) { ++ pr_debug("read back port info failed\n"); ++ goto release_unlock; ++ } ++ ++ /* connect two ports together */ ++ ret = port_action_handle(instance, src, ++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, ++ dst->component->handle, dst->handle); ++ if (ret < 0) { ++ pr_debug("connecting port %d:%d to %d:%d failed\n", ++ src->component->handle, src->handle, ++ dst->component->handle, dst->handle); ++ goto release_unlock; ++ } ++ src->connected = dst; ++ ++release_unlock: ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_port_connect_tunnel); ++ ++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ struct mmal_buffer *buffer) ++{ ++ unsigned long flags = 0; ++ int ret; ++ ++ ret = buffer_from_host(instance, port, buffer); ++ if (ret == -EINVAL) { ++ /* Port is disabled. Queue for when it is enabled. */ ++ spin_lock_irqsave(&port->slock, flags); ++ list_add_tail(&buffer->list, &port->buffers); ++ spin_unlock_irqrestore(&port->slock, flags); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_submit_buffer); ++ ++int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, ++ struct mmal_buffer *buf) ++{ ++ struct mmal_msg_context *msg_context = get_msg_context(instance); ++ ++ if (IS_ERR(msg_context)) ++ return (PTR_ERR(msg_context)); ++ ++ buf->msg_context = msg_context; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init); ++ ++int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) ++{ ++ struct mmal_msg_context *msg_context = buf->msg_context; ++ ++ if (msg_context) ++ release_msg_context(msg_context); ++ buf->msg_context = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); ++ ++/* Initialise a mmal component and its ports ++ * ++ */ ++int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, ++ const char *name, ++ struct vchiq_mmal_component **component_out) ++{ ++ int ret; ++ int idx; /* port index */ ++ struct vchiq_mmal_component *component; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) { ++ ret = -EINVAL; /* todo is this correct error? */ ++ goto unlock; ++ } ++ ++ component = &instance->component[instance->component_idx]; ++ ++ ret = create_component(instance, component, name); ++ if (ret < 0) { ++ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", ++ __func__, ret); ++ goto unlock; ++ } ++ ++ /* ports info needs gathering */ ++ component->control.type = MMAL_PORT_TYPE_CONTROL; ++ component->control.index = 0; ++ component->control.component = component; ++ spin_lock_init(&component->control.slock); ++ INIT_LIST_HEAD(&component->control.buffers); ++ ret = port_info_get(instance, &component->control); ++ if (ret < 0) ++ goto release_component; ++ ++ for (idx = 0; idx < component->inputs; idx++) { ++ component->input[idx].type = MMAL_PORT_TYPE_INPUT; ++ component->input[idx].index = idx; ++ component->input[idx].component = component; ++ spin_lock_init(&component->input[idx].slock); ++ INIT_LIST_HEAD(&component->input[idx].buffers); ++ ret = port_info_get(instance, &component->input[idx]); ++ if (ret < 0) ++ goto release_component; ++ } ++ ++ for (idx = 0; idx < component->outputs; idx++) { ++ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT; ++ component->output[idx].index = idx; ++ component->output[idx].component = component; ++ spin_lock_init(&component->output[idx].slock); ++ INIT_LIST_HEAD(&component->output[idx].buffers); ++ ret = port_info_get(instance, &component->output[idx]); ++ if (ret < 0) ++ goto release_component; ++ } ++ ++ for (idx = 0; idx < component->clocks; idx++) { ++ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK; ++ component->clock[idx].index = idx; ++ component->clock[idx].component = component; ++ spin_lock_init(&component->clock[idx].slock); ++ INIT_LIST_HEAD(&component->clock[idx].buffers); ++ ret = port_info_get(instance, &component->clock[idx]); ++ if (ret < 0) ++ goto release_component; ++ } ++ ++ instance->component_idx++; ++ ++ *component_out = component; ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return 0; ++ ++release_component: ++ destroy_component(instance, component); ++unlock: ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_component_init); ++ ++/* ++ * cause a mmal component to be destroyed ++ */ ++int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ if (component->enabled) ++ ret = disable_component(instance, component); ++ ++ ret = destroy_component(instance, component); ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_component_finalise); ++ ++/* ++ * cause a mmal component to be enabled ++ */ ++int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ if (component->enabled) { ++ mutex_unlock(&instance->vchiq_mutex); ++ return 0; ++ } ++ ++ ret = enable_component(instance, component); ++ if (ret == 0) ++ component->enabled = true; ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_component_enable); ++ ++/* ++ * cause a mmal component to be enabled ++ */ ++int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ if (!component->enabled) { ++ mutex_unlock(&instance->vchiq_mutex); ++ return 0; ++ } ++ ++ ret = disable_component(instance, component); ++ if (ret == 0) ++ component->enabled = 0; ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_component_disable); ++ ++int vchiq_mmal_version(struct vchiq_mmal_instance *instance, ++ u32 *major_out, u32 *minor_out) ++{ ++ int ret; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ ret = get_version(instance, major_out, minor_out); ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_version); ++ ++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance) ++{ ++ int status = 0; ++ ++ if (!instance) ++ return -EINVAL; ++ ++ if (mutex_lock_interruptible(&instance->vchiq_mutex)) ++ return -EINTR; ++ ++ vchi_service_use(instance->handle); ++ ++ status = vchi_service_close(instance->handle); ++ if (status != 0) ++ pr_err("mmal-vchiq: VCHIQ close failed\n"); ++ ++ mutex_unlock(&instance->vchiq_mutex); ++ ++ flush_workqueue(instance->bulk_wq); ++ destroy_workqueue(instance->bulk_wq); ++ ++ vfree(instance->bulk_scratch); ++ ++ idr_destroy(&instance->context_map); ++ ++ kfree(instance); ++ ++ return status; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_finalise); ++ ++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) ++{ ++ int status; ++ struct vchiq_mmal_instance *instance; ++ static VCHI_INSTANCE_T vchi_instance; ++ struct service_creation params = { ++ .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER), ++ .service_id = VC_MMAL_SERVER_NAME, ++ .callback = service_callback, ++ .callback_param = NULL, ++ }; ++ ++ /* compile time checks to ensure structure size as they are ++ * directly (de)serialised from memory. ++ */ ++ ++ /* ensure the header structure has packed to the correct size */ ++ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24); ++ ++ /* ensure message structure does not exceed maximum length */ ++ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE); ++ ++ /* mmal port struct is correct size */ ++ BUILD_BUG_ON(sizeof(struct mmal_port) != 64); ++ ++ /* create a vchi instance */ ++ status = vchi_initialise(&vchi_instance); ++ if (status) { ++ pr_err("Failed to initialise VCHI instance (status=%d)\n", ++ status); ++ return -EIO; ++ } ++ ++ status = vchi_connect(vchi_instance); ++ if (status) { ++ pr_err("Failed to connect VCHI instance (status=%d)\n", status); ++ return -EIO; ++ } ++ ++ instance = kzalloc(sizeof(*instance), GFP_KERNEL); ++ ++ if (!instance) ++ return -ENOMEM; ++ ++ mutex_init(&instance->vchiq_mutex); ++ ++ instance->bulk_scratch = vmalloc(PAGE_SIZE); ++ ++ mutex_init(&instance->context_map_lock); ++ idr_init_base(&instance->context_map, 1); ++ ++ params.callback_param = instance; ++ ++ instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq", ++ WQ_MEM_RECLAIM); ++ if (!instance->bulk_wq) ++ goto err_free; ++ ++ status = vchi_service_open(vchi_instance, ¶ms, &instance->handle); ++ if (status) { ++ pr_err("Failed to open VCHI service connection (status=%d)\n", ++ status); ++ goto err_close_services; ++ } ++ ++ vchi_service_release(instance->handle); ++ ++ *out_instance = instance; ++ ++ return 0; ++ ++err_close_services: ++ vchi_service_close(instance->handle); ++ destroy_workqueue(instance->bulk_wq); ++err_free: ++ vfree(instance->bulk_scratch); ++ kfree(instance); ++ return -ENODEV; ++} ++EXPORT_SYMBOL_GPL(vchiq_mmal_init); +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- * +- * MMAL structures +- * +- */ +-#ifndef MMAL_COMMON_H +-#define MMAL_COMMON_H +- +-#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24)) +-#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l') +- +-/** Special value signalling that time is not known */ +-#define MMAL_TIME_UNKNOWN BIT_ULL(63) +- +-struct mmal_msg_context; +- +-/* mapping between v4l and mmal video modes */ +-struct mmal_fmt { +- u32 fourcc; /* v4l2 format id */ +- int flags; /* v4l2 flags field */ +- u32 mmal; +- int depth; +- u32 mmal_component; /* MMAL component index to be used to encode */ +- u32 ybbp; /* depth of first Y plane for planar formats */ +- bool remove_padding; /* Does the GPU have to remove padding, +- * or can we do hide padding via bytesperline. +- */ +-}; +- +-/* buffer for one video frame */ +-struct mmal_buffer { +- /* v4l buffer data -- must be first */ +- struct vb2_v4l2_buffer vb; +- +- /* list of buffers available */ +- struct list_head list; +- +- void *buffer; /* buffer pointer */ +- unsigned long buffer_size; /* size of allocated buffer */ +- +- struct mmal_msg_context *msg_context; +-}; +- +-/* */ +-struct mmal_colourfx { +- s32 enable; +- u32 u; +- u32 v; +-}; +-#endif +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h ++++ /dev/null +@@ -1,124 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- */ +-#ifndef MMAL_ENCODINGS_H +-#define MMAL_ENCODINGS_H +- +-#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4') +-#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3') +-#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V') +-#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V') +-#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V') +-#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3') +-#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2') +-#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1') +-#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1') +-#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ') +-#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ') +-#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ') +-#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O') +-#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K') +-#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G') +- +-#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G') +-#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ') +-#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ') +-#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ') +-#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ') +-#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ') +- +-#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0') +-#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0') +-#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2') +-#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2') +-#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2') +-#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V') +-#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U') +-#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y') +-#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y') +-#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2') +-#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1') +-#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B') +-#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A') +-#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R') +-#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A') +-#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2') +-#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3') +-#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4') +-#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2') +-#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3') +-#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4') +- +-/** SAND Video (YUVUV128) format, native format understood by VideoCore. +- * This format is *not* opaque - if requested you will receive full frames +- * of YUV_UV video. +- */ +-#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D') +- +-/** VideoCore opaque image format, image handles are returned to +- * the host but not the actual image data. +- */ +-#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V') +- +-/** An EGL image handle +- */ +-#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I') +- +-/* }@ */ +- +-/** \name Pre-defined audio encodings */ +-/* @{ */ +-#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U') +-#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u') +-#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S') +-#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's') +-#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F') +-#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f') +- +-/* Pre-defined H264 encoding variants */ +- +-/** ISO 14496-10 Annex B byte stream format */ +-#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0 +-/** ISO 14496-15 AVC stream format */ +-#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1') +-/** Implicitly delineated NAL units without emulation prevention */ +-#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ') +- +-/** \defgroup MmalColorSpace List of pre-defined video color spaces +- * This defines a list of common color spaces. This list isn't exhaustive and +- * is only provided as a convenience to avoid clients having to use FourCC +- * codes directly. However components are allowed to define and use their own +- * FourCC codes. +- */ +-/* @{ */ +- +-/** Unknown color space */ +-#define MMAL_COLOR_SPACE_UNKNOWN 0 +-/** ITU-R BT.601-5 [SDTV] */ +-#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1') +-/** ITU-R BT.709-3 [HDTV] */ +-#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9') +-/** JPEG JFIF */ +-#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I') +-/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ +-#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C') +-/** Society of Motion Picture and Television Engineers 240M (1999) */ +-#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0') +-/** ITU-R BT.470-2 System M */ +-#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M') +-/** ITU-R BT.470-2 System BG */ +-#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G') +-/** JPEG JFIF, but with 16..255 luma */ +-#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6') +-/* @} MmalColorSpace List */ +- +-#endif /* MMAL_ENCODINGS_H */ +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- */ +- +-#ifndef MMAL_MSG_COMMON_H +-#define MMAL_MSG_COMMON_H +- +-enum mmal_msg_status { +- MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */ +- MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */ +- MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */ +- MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */ +- MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */ +- MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */ +- MMAL_MSG_STATUS_ENXIO, /**< No such device or address */ +- MMAL_MSG_STATUS_EIO, /**< I/O error */ +- MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */ +- MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */ +- MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */ +- MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */ +- MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */ +- MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */ +- MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */ +- MMAL_MSG_STATUS_EFAULT, /**< Bad address */ +-}; +- +-struct mmal_rect { +- s32 x; /**< x coordinate (from left) */ +- s32 y; /**< y coordinate (from top) */ +- s32 width; /**< width */ +- s32 height; /**< height */ +-}; +- +-struct mmal_rational { +- s32 num; /**< Numerator */ +- s32 den; /**< Denominator */ +-}; +- +-#endif /* MMAL_MSG_COMMON_H */ +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h ++++ /dev/null +@@ -1,106 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- */ +- +-#ifndef MMAL_MSG_FORMAT_H +-#define MMAL_MSG_FORMAT_H +- +-#include "mmal-msg-common.h" +- +-/* MMAL_ES_FORMAT_T */ +- +-struct mmal_audio_format { +- u32 channels; /* Number of audio channels */ +- u32 sample_rate; /* Sample rate */ +- +- u32 bits_per_sample; /* Bits per sample */ +- u32 block_align; /* Size of a block of data */ +-}; +- +-struct mmal_video_format { +- u32 width; /* Width of frame in pixels */ +- u32 height; /* Height of frame in rows of pixels */ +- struct mmal_rect crop; /* Visible region of the frame */ +- struct mmal_rational frame_rate; /* Frame rate */ +- struct mmal_rational par; /* Pixel aspect ratio */ +- +- /* +- * FourCC specifying the color space of the video stream. See the +- * MmalColorSpace "pre-defined color spaces" for some examples. +- */ +- u32 color_space; +-}; +- +-struct mmal_subpicture_format { +- u32 x_offset; +- u32 y_offset; +-}; +- +-union mmal_es_specific_format { +- struct mmal_audio_format audio; +- struct mmal_video_format video; +- struct mmal_subpicture_format subpicture; +-}; +- +-/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */ +-struct mmal_es_format_local { +- u32 type; /* enum mmal_es_type */ +- +- u32 encoding; /* FourCC specifying encoding of the elementary +- * stream. +- */ +- u32 encoding_variant; /* FourCC specifying the specific +- * encoding variant of the elementary +- * stream. +- */ +- +- union mmal_es_specific_format *es; /* Type specific +- * information for the +- * elementary stream +- */ +- +- u32 bitrate; /* Bitrate in bits per second */ +- u32 flags; /* Flags describing properties of the elementary +- * stream. +- */ +- +- u32 extradata_size; /* Size of the codec specific data */ +- u8 *extradata; /* Codec specific data */ +-}; +- +-/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */ +-struct mmal_es_format { +- u32 type; /* enum mmal_es_type */ +- +- u32 encoding; /* FourCC specifying encoding of the elementary +- * stream. +- */ +- u32 encoding_variant; /* FourCC specifying the specific +- * encoding variant of the elementary +- * stream. +- */ +- +- u32 es; /* Type specific +- * information for the +- * elementary stream +- */ +- +- u32 bitrate; /* Bitrate in bits per second */ +- u32 flags; /* Flags describing properties of the elementary +- * stream. +- */ +- +- u32 extradata_size; /* Size of the codec specific data */ +- u32 extradata; /* Codec specific data */ +-}; +- +-#endif /* MMAL_MSG_FORMAT_H */ +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h ++++ /dev/null +@@ -1,109 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- */ +- +-/* MMAL_PORT_TYPE_T */ +-enum mmal_port_type { +- MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */ +- MMAL_PORT_TYPE_CONTROL, /* Control port */ +- MMAL_PORT_TYPE_INPUT, /* Input port */ +- MMAL_PORT_TYPE_OUTPUT, /* Output port */ +- MMAL_PORT_TYPE_CLOCK, /* Clock port */ +-}; +- +-/* The port is pass-through and doesn't need buffer headers allocated */ +-#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01 +-/* +- *The port wants to allocate the buffer payloads. +- * This signals a preference that payload allocation should be done +- * on this port for efficiency reasons. +- */ +-#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02 +-/* +- * The port supports format change events. +- * This applies to input ports and is used to let the client know +- * whether the port supports being reconfigured via a format +- * change event (i.e. without having to disable the port). +- */ +-#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04 +- +-/* +- * mmal port structure (MMAL_PORT_T) +- * +- * most elements are informational only, the pointer values for +- * interogation messages are generally provided as additional +- * structures within the message. When used to set values only the +- * buffer_num, buffer_size and userdata parameters are writable. +- */ +-struct mmal_port { +- u32 priv; /* Private member used by the framework */ +- u32 name; /* Port name. Used for debugging purposes (RO) */ +- +- u32 type; /* Type of the port (RO) enum mmal_port_type */ +- u16 index; /* Index of the port in its type list (RO) */ +- u16 index_all; /* Index of the port in the list of all ports (RO) */ +- +- u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */ +- u32 format; /* Format of the elementary stream */ +- +- u32 buffer_num_min; /* Minimum number of buffers the port +- * requires (RO). This is set by the +- * component. +- */ +- +- u32 buffer_size_min; /* Minimum size of buffers the port +- * requires (RO). This is set by the +- * component. +- */ +- +- u32 buffer_alignment_min;/* Minimum alignment requirement for +- * the buffers (RO). A value of +- * zero means no special alignment +- * requirements. This is set by the +- * component. +- */ +- +- u32 buffer_num_recommended; /* Number of buffers the port +- * recommends for optimal +- * performance (RO). A value of +- * zero means no special +- * recommendation. This is set +- * by the component. +- */ +- +- u32 buffer_size_recommended; /* Size of buffers the port +- * recommends for optimal +- * performance (RO). A value of +- * zero means no special +- * recommendation. This is set +- * by the component. +- */ +- +- u32 buffer_num; /* Actual number of buffers the port will use. +- * This is set by the client. +- */ +- +- u32 buffer_size; /* Actual maximum size of the buffers that +- * will be sent to the port. This is set by +- * the client. +- */ +- +- u32 component; /* Component this port belongs to (Read Only) */ +- +- u32 userdata; /* Field reserved for use by the client */ +- +- u32 capabilities; /* Flags describing the capabilities of a +- * port (RO). Bitwise combination of \ref +- * portcapabilities "Port capabilities" +- * values. +- */ +-}; +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h ++++ /dev/null +@@ -1,406 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- */ +- +-/* +- * all the data structures which serialise the MMAL protocol. note +- * these are directly mapped onto the recived message data. +- * +- * BEWARE: They seem to *assume* pointers are u32 and that there is no +- * structure padding! +- * +- * NOTE: this implementation uses kernel types to ensure sizes. Rather +- * than assigning values to enums to force their size the +- * implementation uses fixed size types and not the enums (though the +- * comments have the actual enum type +- */ +-#ifndef MMAL_MSG_H +-#define MMAL_MSG_H +- +-#define VC_MMAL_VER 15 +-#define VC_MMAL_MIN_VER 10 +-#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal") +- +-/* max total message size is 512 bytes */ +-#define MMAL_MSG_MAX_SIZE 512 +-/* with six 32bit header elements max payload is therefore 488 bytes */ +-#define MMAL_MSG_MAX_PAYLOAD 488 +- +-#include "mmal-msg-common.h" +-#include "mmal-msg-format.h" +-#include "mmal-msg-port.h" +- +-enum mmal_msg_type { +- MMAL_MSG_TYPE_QUIT = 1, +- MMAL_MSG_TYPE_SERVICE_CLOSED, +- MMAL_MSG_TYPE_GET_VERSION, +- MMAL_MSG_TYPE_COMPONENT_CREATE, +- MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */ +- MMAL_MSG_TYPE_COMPONENT_ENABLE, +- MMAL_MSG_TYPE_COMPONENT_DISABLE, +- MMAL_MSG_TYPE_PORT_INFO_GET, +- MMAL_MSG_TYPE_PORT_INFO_SET, +- MMAL_MSG_TYPE_PORT_ACTION, /* 10 */ +- MMAL_MSG_TYPE_BUFFER_FROM_HOST, +- MMAL_MSG_TYPE_BUFFER_TO_HOST, +- MMAL_MSG_TYPE_GET_STATS, +- MMAL_MSG_TYPE_PORT_PARAMETER_SET, +- MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */ +- MMAL_MSG_TYPE_EVENT_TO_HOST, +- MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT, +- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR, +- MMAL_MSG_TYPE_CONSUME_MEM, +- MMAL_MSG_TYPE_LMK, /* 20 */ +- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC, +- MMAL_MSG_TYPE_DRM_GET_LHS32, +- MMAL_MSG_TYPE_DRM_GET_TIME, +- MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN, +- MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */ +- MMAL_MSG_TYPE_HOST_LOG, +- MMAL_MSG_TYPE_MSG_LAST +-}; +- +-/* port action request messages differ depending on the action type */ +-enum mmal_msg_port_action_type { +- MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */ +- MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */ +- MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */ +- MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */ +- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */ +- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */ +- MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/ +-}; +- +-struct mmal_msg_header { +- u32 magic; +- u32 type; /* enum mmal_msg_type */ +- +- /* Opaque handle to the control service */ +- u32 control_service; +- +- u32 context; /* a u32 per message context */ +- u32 status; /* The status of the vchiq operation */ +- u32 padding; +-}; +- +-/* Send from VC to host to report version */ +-struct mmal_msg_version { +- u32 flags; +- u32 major; +- u32 minor; +- u32 minimum; +-}; +- +-/* request to VC to create component */ +-struct mmal_msg_component_create { +- u32 client_component; /* component context */ +- char name[128]; +- u32 pid; /* For debug */ +-}; +- +-/* reply from VC to component creation request */ +-struct mmal_msg_component_create_reply { +- u32 status; /* enum mmal_msg_status - how does this differ to +- * the one in the header? +- */ +- u32 component_handle; /* VideoCore handle for component */ +- u32 input_num; /* Number of input ports */ +- u32 output_num; /* Number of output ports */ +- u32 clock_num; /* Number of clock ports */ +-}; +- +-/* request to VC to destroy a component */ +-struct mmal_msg_component_destroy { +- u32 component_handle; +-}; +- +-struct mmal_msg_component_destroy_reply { +- u32 status; /* The component destruction status */ +-}; +- +-/* request and reply to VC to enable a component */ +-struct mmal_msg_component_enable { +- u32 component_handle; +-}; +- +-struct mmal_msg_component_enable_reply { +- u32 status; /* The component enable status */ +-}; +- +-/* request and reply to VC to disable a component */ +-struct mmal_msg_component_disable { +- u32 component_handle; +-}; +- +-struct mmal_msg_component_disable_reply { +- u32 status; /* The component disable status */ +-}; +- +-/* request to VC to get port information */ +-struct mmal_msg_port_info_get { +- u32 component_handle; /* component handle port is associated with */ +- u32 port_type; /* enum mmal_msg_port_type */ +- u32 index; /* port index to query */ +-}; +- +-/* reply from VC to get port info request */ +-struct mmal_msg_port_info_get_reply { +- u32 status; /* enum mmal_msg_status */ +- u32 component_handle; /* component handle port is associated with */ +- u32 port_type; /* enum mmal_msg_port_type */ +- u32 port_index; /* port indexed in query */ +- s32 found; /* unused */ +- u32 port_handle; /* Handle to use for this port */ +- struct mmal_port port; +- struct mmal_es_format format; /* elementary stream format */ +- union mmal_es_specific_format es; /* es type specific data */ +- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */ +-}; +- +-/* request to VC to set port information */ +-struct mmal_msg_port_info_set { +- u32 component_handle; +- u32 port_type; /* enum mmal_msg_port_type */ +- u32 port_index; /* port indexed in query */ +- struct mmal_port port; +- struct mmal_es_format format; +- union mmal_es_specific_format es; +- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; +-}; +- +-/* reply from VC to port info set request */ +-struct mmal_msg_port_info_set_reply { +- u32 status; +- u32 component_handle; /* component handle port is associated with */ +- u32 port_type; /* enum mmal_msg_port_type */ +- u32 index; /* port indexed in query */ +- s32 found; /* unused */ +- u32 port_handle; /* Handle to use for this port */ +- struct mmal_port port; +- struct mmal_es_format format; +- union mmal_es_specific_format es; +- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; +-}; +- +-/* port action requests that take a mmal_port as a parameter */ +-struct mmal_msg_port_action_port { +- u32 component_handle; +- u32 port_handle; +- u32 action; /* enum mmal_msg_port_action_type */ +- struct mmal_port port; +-}; +- +-/* port action requests that take handles as a parameter */ +-struct mmal_msg_port_action_handle { +- u32 component_handle; +- u32 port_handle; +- u32 action; /* enum mmal_msg_port_action_type */ +- u32 connect_component_handle; +- u32 connect_port_handle; +-}; +- +-struct mmal_msg_port_action_reply { +- u32 status; /* The port action operation status */ +-}; +- +-/* MMAL buffer transfer */ +- +-/* Size of space reserved in a buffer message for short messages. */ +-#define MMAL_VC_SHORT_DATA 128 +- +-/* Signals that the current payload is the end of the stream of data */ +-#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0) +-/* Signals that the start of the current payload starts a frame */ +-#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1) +-/* Signals that the end of the current payload ends a frame */ +-#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2) +-/* Signals that the current payload contains only complete frames (>1) */ +-#define MMAL_BUFFER_HEADER_FLAG_FRAME \ +- (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \ +- MMAL_BUFFER_HEADER_FLAG_FRAME_END) +-/* Signals that the current payload is a keyframe (i.e. self decodable) */ +-#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3) +-/* +- * Signals a discontinuity in the stream of data (e.g. after a seek). +- * Can be used for instance by a decoder to reset its state +- */ +-#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4) +-/* +- * Signals a buffer containing some kind of config data for the component +- * (e.g. codec config data) +- */ +-#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5) +-/* Signals an encrypted payload */ +-#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6) +-/* Signals a buffer containing side information */ +-#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7) +-/* +- * Signals a buffer which is the snapshot/postview image from a stills +- * capture +- */ +-#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8) +-/* Signals a buffer which contains data known to be corrupted */ +-#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9) +-/* Signals that a buffer failed to be transmitted */ +-#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10) +- +-struct mmal_driver_buffer { +- u32 magic; +- u32 component_handle; +- u32 port_handle; +- u32 client_context; +-}; +- +-/* buffer header */ +-struct mmal_buffer_header { +- u32 next; /* next header */ +- u32 priv; /* framework private data */ +- u32 cmd; +- u32 data; +- u32 alloc_size; +- u32 length; +- u32 offset; +- u32 flags; +- s64 pts; +- s64 dts; +- u32 type; +- u32 user_data; +-}; +- +-struct mmal_buffer_header_type_specific { +- union { +- struct { +- u32 planes; +- u32 offset[4]; +- u32 pitch[4]; +- u32 flags; +- } video; +- } u; +-}; +- +-struct mmal_msg_buffer_from_host { +- /* +- *The front 32 bytes of the buffer header are copied +- * back to us in the reply to allow for context. This +- * area is used to store two mmal_driver_buffer structures to +- * allow for multiple concurrent service users. +- */ +- /* control data */ +- struct mmal_driver_buffer drvbuf; +- +- /* referenced control data for passthrough buffer management */ +- struct mmal_driver_buffer drvbuf_ref; +- struct mmal_buffer_header buffer_header; /* buffer header itself */ +- struct mmal_buffer_header_type_specific buffer_header_type_specific; +- s32 is_zero_copy; +- s32 has_reference; +- +- /* allows short data to be xfered in control message */ +- u32 payload_in_message; +- u8 short_data[MMAL_VC_SHORT_DATA]; +-}; +- +-/* port parameter setting */ +- +-#define MMAL_WORKER_PORT_PARAMETER_SPACE 96 +- +-struct mmal_msg_port_parameter_set { +- u32 component_handle; /* component */ +- u32 port_handle; /* port */ +- u32 id; /* Parameter ID */ +- u32 size; /* Parameter size */ +- u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; +-}; +- +-struct mmal_msg_port_parameter_set_reply { +- u32 status; /* enum mmal_msg_status todo: how does this +- * differ to the one in the header? +- */ +-}; +- +-/* port parameter getting */ +- +-struct mmal_msg_port_parameter_get { +- u32 component_handle; /* component */ +- u32 port_handle; /* port */ +- u32 id; /* Parameter ID */ +- u32 size; /* Parameter size */ +-}; +- +-struct mmal_msg_port_parameter_get_reply { +- u32 status; /* Status of mmal_port_parameter_get call */ +- u32 id; /* Parameter ID */ +- u32 size; /* Parameter size */ +- u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; +-}; +- +-/* event messages */ +-#define MMAL_WORKER_EVENT_SPACE 256 +- +-struct mmal_msg_event_to_host { +- u32 client_component; /* component context */ +- +- u32 port_type; +- u32 port_num; +- +- u32 cmd; +- u32 length; +- u8 data[MMAL_WORKER_EVENT_SPACE]; +- u32 delayed_buffer; +-}; +- +-/* all mmal messages are serialised through this structure */ +-struct mmal_msg { +- /* header */ +- struct mmal_msg_header h; +- /* payload */ +- union { +- struct mmal_msg_version version; +- +- struct mmal_msg_component_create component_create; +- struct mmal_msg_component_create_reply component_create_reply; +- +- struct mmal_msg_component_destroy component_destroy; +- struct mmal_msg_component_destroy_reply component_destroy_reply; +- +- struct mmal_msg_component_enable component_enable; +- struct mmal_msg_component_enable_reply component_enable_reply; +- +- struct mmal_msg_component_disable component_disable; +- struct mmal_msg_component_disable_reply component_disable_reply; +- +- struct mmal_msg_port_info_get port_info_get; +- struct mmal_msg_port_info_get_reply port_info_get_reply; +- +- struct mmal_msg_port_info_set port_info_set; +- struct mmal_msg_port_info_set_reply port_info_set_reply; +- +- struct mmal_msg_port_action_port port_action_port; +- struct mmal_msg_port_action_handle port_action_handle; +- struct mmal_msg_port_action_reply port_action_reply; +- +- struct mmal_msg_buffer_from_host buffer_from_host; +- +- struct mmal_msg_port_parameter_set port_parameter_set; +- struct mmal_msg_port_parameter_set_reply +- port_parameter_set_reply; +- struct mmal_msg_port_parameter_get +- port_parameter_get; +- struct mmal_msg_port_parameter_get_reply +- port_parameter_get_reply; +- +- struct mmal_msg_event_to_host event_to_host; +- +- u8 payload[MMAL_MSG_MAX_PAYLOAD]; +- } u; +-}; +-#endif +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h ++++ /dev/null +@@ -1,755 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- */ +- +-/* common parameters */ +- +-/** @name Parameter groups +- * Parameters are divided into groups, and then allocated sequentially within +- * a group using an enum. +- * @{ +- */ +- +-#ifndef MMAL_PARAMETERS_H +-#define MMAL_PARAMETERS_H +- +-/** Common parameter ID group, used with many types of component. */ +-#define MMAL_PARAMETER_GROUP_COMMON (0 << 16) +-/** Camera-specific parameter ID group. */ +-#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16) +-/** Video-specific parameter ID group. */ +-#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16) +-/** Audio-specific parameter ID group. */ +-#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16) +-/** Clock-specific parameter ID group. */ +-#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16) +-/** Miracast-specific parameter ID group. */ +-#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16) +- +-/* Common parameters */ +-enum mmal_parameter_common_type { +- /**< Never a valid parameter ID */ +- MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON, +- +- /**< MMAL_PARAMETER_ENCODING_T */ +- MMAL_PARAMETER_SUPPORTED_ENCODINGS, +- /**< MMAL_PARAMETER_URI_T */ +- MMAL_PARAMETER_URI, +- /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */ +- MMAL_PARAMETER_CHANGE_EVENT_REQUEST, +- /** MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_ZERO_COPY, +- /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */ +- MMAL_PARAMETER_BUFFER_REQUIREMENTS, +- /**< MMAL_PARAMETER_STATISTICS_T */ +- MMAL_PARAMETER_STATISTICS, +- /**< MMAL_PARAMETER_CORE_STATISTICS_T */ +- MMAL_PARAMETER_CORE_STATISTICS, +- /**< MMAL_PARAMETER_MEM_USAGE_T */ +- MMAL_PARAMETER_MEM_USAGE, +- /**< MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_BUFFER_FLAG_FILTER, +- /**< MMAL_PARAMETER_SEEK_T */ +- MMAL_PARAMETER_SEEK, +- /**< MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_POWERMON_ENABLE, +- /**< MMAL_PARAMETER_LOGGING_T */ +- MMAL_PARAMETER_LOGGING, +- /**< MMAL_PARAMETER_UINT64_T */ +- MMAL_PARAMETER_SYSTEM_TIME, +- /**< MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_NO_IMAGE_PADDING, +-}; +- +-/* camera parameters */ +- +-enum mmal_parameter_camera_type { +- /* 0 */ +- /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */ +- MMAL_PARAMETER_THUMBNAIL_CONFIGURATION = +- MMAL_PARAMETER_GROUP_CAMERA, +- /**< Unused? */ +- MMAL_PARAMETER_CAPTURE_QUALITY, +- /**< @ref MMAL_PARAMETER_INT32_T */ +- MMAL_PARAMETER_ROTATION, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_EXIF_DISABLE, +- /**< @ref MMAL_PARAMETER_EXIF_T */ +- MMAL_PARAMETER_EXIF, +- /**< @ref MMAL_PARAM_AWBMODE_T */ +- MMAL_PARAMETER_AWB_MODE, +- /**< @ref MMAL_PARAMETER_IMAGEFX_T */ +- MMAL_PARAMETER_IMAGE_EFFECT, +- /**< @ref MMAL_PARAMETER_COLOURFX_T */ +- MMAL_PARAMETER_COLOUR_EFFECT, +- /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */ +- MMAL_PARAMETER_FLICKER_AVOID, +- /**< @ref MMAL_PARAMETER_FLASH_T */ +- MMAL_PARAMETER_FLASH, +- /**< @ref MMAL_PARAMETER_REDEYE_T */ +- MMAL_PARAMETER_REDEYE, +- /**< @ref MMAL_PARAMETER_FOCUS_T */ +- MMAL_PARAMETER_FOCUS, +- /**< Unused? */ +- MMAL_PARAMETER_FOCAL_LENGTHS, +- /**< @ref MMAL_PARAMETER_INT32_T */ +- MMAL_PARAMETER_EXPOSURE_COMP, +- /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */ +- MMAL_PARAMETER_ZOOM, +- /**< @ref MMAL_PARAMETER_MIRROR_T */ +- MMAL_PARAMETER_MIRROR, +- +- /* 0x10 */ +- /**< @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_CAMERA_NUM, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_CAPTURE, +- /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */ +- MMAL_PARAMETER_EXPOSURE_MODE, +- /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */ +- MMAL_PARAMETER_EXP_METERING_MODE, +- /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */ +- MMAL_PARAMETER_FOCUS_STATUS, +- /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */ +- MMAL_PARAMETER_CAMERA_CONFIG, +- /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */ +- MMAL_PARAMETER_CAPTURE_STATUS, +- /**< @ref MMAL_PARAMETER_FACE_TRACK_T */ +- MMAL_PARAMETER_FACE_TRACK, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, +- /**< @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_JPEG_Q_FACTOR, +- /**< @ref MMAL_PARAMETER_FRAME_RATE_T */ +- MMAL_PARAMETER_FRAME_RATE, +- /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */ +- MMAL_PARAMETER_USE_STC, +- /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */ +- MMAL_PARAMETER_CAMERA_INFO, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_STABILISATION, +- /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */ +- MMAL_PARAMETER_FACE_TRACK_RESULTS, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_ENABLE_RAW_CAPTURE, +- +- /* 0x20 */ +- /**< @ref MMAL_PARAMETER_URI_T */ +- MMAL_PARAMETER_DPF_FILE, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_ENABLE_DPF_FILE, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_DPF_FAIL_IS_FATAL, +- /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */ +- MMAL_PARAMETER_CAPTURE_MODE, +- /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */ +- MMAL_PARAMETER_FOCUS_REGIONS, +- /**< @ref MMAL_PARAMETER_INPUT_CROP_T */ +- MMAL_PARAMETER_INPUT_CROP, +- /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */ +- MMAL_PARAMETER_SENSOR_INFORMATION, +- /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */ +- MMAL_PARAMETER_FLASH_SELECT, +- /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */ +- MMAL_PARAMETER_FIELD_OF_VIEW, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, +- /**< @ref MMAL_PARAMETER_DRC_T */ +- MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, +- /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */ +- MMAL_PARAMETER_ALGORITHM_CONTROL, +- /**< @ref MMAL_PARAMETER_RATIONAL_T */ +- MMAL_PARAMETER_SHARPNESS, +- /**< @ref MMAL_PARAMETER_RATIONAL_T */ +- MMAL_PARAMETER_CONTRAST, +- /**< @ref MMAL_PARAMETER_RATIONAL_T */ +- MMAL_PARAMETER_BRIGHTNESS, +- /**< @ref MMAL_PARAMETER_RATIONAL_T */ +- MMAL_PARAMETER_SATURATION, +- +- /* 0x30 */ +- /**< @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_ISO, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_ANTISHAKE, +- /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */ +- MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_CAMERA_BURST_CAPTURE, +- /** @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_CAMERA_MIN_ISO, +- /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */ +- MMAL_PARAMETER_CAMERA_USE_CASE, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_CAPTURE_STATS_PASS, +- /** @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_ENABLE_REGISTER_FILE, +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL, +- /** @ref MMAL_PARAMETER_CONFIGFILE_T */ +- MMAL_PARAMETER_CONFIGFILE_REGISTERS, +- /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */ +- MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_JPEG_ATTACH_LOG, +- /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */ +- MMAL_PARAMETER_ZERO_SHUTTER_LAG, +- /**< @ref MMAL_PARAMETER_FPS_RANGE_T */ +- MMAL_PARAMETER_FPS_RANGE, +- /**< @ref MMAL_PARAMETER_INT32_T */ +- MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, +- +- /* 0x40 */ +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_SW_SHARPEN_DISABLE, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_FLASH_REQUIRED, +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_SW_SATURATION_DISABLE, +- /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_SHUTTER_SPEED, +- /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */ +- MMAL_PARAMETER_CUSTOM_AWB_GAINS, +-}; +- +-struct mmal_parameter_rational { +- s32 num; /**< Numerator */ +- s32 den; /**< Denominator */ +-}; +- +-enum mmal_parameter_camera_config_timestamp_mode { +- MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */ +- MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value +- * for the frame timestamp +- */ +- MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp +- * but subtract the +- * timestamp of the first +- * frame sent to give a +- * zero based timestamp. +- */ +-}; +- +-struct mmal_parameter_fps_range { +- /**< Low end of the permitted framerate range */ +- struct mmal_parameter_rational fps_low; +- /**< High end of the permitted framerate range */ +- struct mmal_parameter_rational fps_high; +-}; +- +-/* camera configuration parameter */ +-struct mmal_parameter_camera_config { +- /* Parameters for setting up the image pools */ +- u32 max_stills_w; /* Max size of stills capture */ +- u32 max_stills_h; +- u32 stills_yuv422; /* Allow YUV422 stills capture */ +- u32 one_shot_stills; /* Continuous or one shot stills captures. */ +- +- u32 max_preview_video_w; /* Max size of the preview or video +- * capture frames +- */ +- u32 max_preview_video_h; +- u32 num_preview_video_frames; +- +- /** Sets the height of the circular buffer for stills capture. */ +- u32 stills_capture_circular_buffer_height; +- +- /** Allows preview/encode to resume as fast as possible after the stills +- * input frame has been received, and then processes the still frame in +- * the background whilst preview/encode has resumed. +- * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE. +- */ +- u32 fast_preview_resume; +- +- /** Selects algorithm for timestamping frames if +- * there is no clock component connected. +- * enum mmal_parameter_camera_config_timestamp_mode +- */ +- s32 use_stc_timestamp; +-}; +- +-enum mmal_parameter_exposuremode { +- MMAL_PARAM_EXPOSUREMODE_OFF, +- MMAL_PARAM_EXPOSUREMODE_AUTO, +- MMAL_PARAM_EXPOSUREMODE_NIGHT, +- MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, +- MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, +- MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, +- MMAL_PARAM_EXPOSUREMODE_SPORTS, +- MMAL_PARAM_EXPOSUREMODE_SNOW, +- MMAL_PARAM_EXPOSUREMODE_BEACH, +- MMAL_PARAM_EXPOSUREMODE_VERYLONG, +- MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, +- MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, +- MMAL_PARAM_EXPOSUREMODE_FIREWORKS, +-}; +- +-enum mmal_parameter_exposuremeteringmode { +- MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE, +- MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT, +- MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT, +- MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX, +-}; +- +-enum mmal_parameter_awbmode { +- MMAL_PARAM_AWBMODE_OFF, +- MMAL_PARAM_AWBMODE_AUTO, +- MMAL_PARAM_AWBMODE_SUNLIGHT, +- MMAL_PARAM_AWBMODE_CLOUDY, +- MMAL_PARAM_AWBMODE_SHADE, +- MMAL_PARAM_AWBMODE_TUNGSTEN, +- MMAL_PARAM_AWBMODE_FLUORESCENT, +- MMAL_PARAM_AWBMODE_INCANDESCENT, +- MMAL_PARAM_AWBMODE_FLASH, +- MMAL_PARAM_AWBMODE_HORIZON, +-}; +- +-enum mmal_parameter_imagefx { +- MMAL_PARAM_IMAGEFX_NONE, +- MMAL_PARAM_IMAGEFX_NEGATIVE, +- MMAL_PARAM_IMAGEFX_SOLARIZE, +- MMAL_PARAM_IMAGEFX_POSTERIZE, +- MMAL_PARAM_IMAGEFX_WHITEBOARD, +- MMAL_PARAM_IMAGEFX_BLACKBOARD, +- MMAL_PARAM_IMAGEFX_SKETCH, +- MMAL_PARAM_IMAGEFX_DENOISE, +- MMAL_PARAM_IMAGEFX_EMBOSS, +- MMAL_PARAM_IMAGEFX_OILPAINT, +- MMAL_PARAM_IMAGEFX_HATCH, +- MMAL_PARAM_IMAGEFX_GPEN, +- MMAL_PARAM_IMAGEFX_PASTEL, +- MMAL_PARAM_IMAGEFX_WATERCOLOUR, +- MMAL_PARAM_IMAGEFX_FILM, +- MMAL_PARAM_IMAGEFX_BLUR, +- MMAL_PARAM_IMAGEFX_SATURATION, +- MMAL_PARAM_IMAGEFX_COLOURSWAP, +- MMAL_PARAM_IMAGEFX_WASHEDOUT, +- MMAL_PARAM_IMAGEFX_POSTERISE, +- MMAL_PARAM_IMAGEFX_COLOURPOINT, +- MMAL_PARAM_IMAGEFX_COLOURBALANCE, +- MMAL_PARAM_IMAGEFX_CARTOON, +-}; +- +-enum MMAL_PARAM_FLICKERAVOID_T { +- MMAL_PARAM_FLICKERAVOID_OFF, +- MMAL_PARAM_FLICKERAVOID_AUTO, +- MMAL_PARAM_FLICKERAVOID_50HZ, +- MMAL_PARAM_FLICKERAVOID_60HZ, +- MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF +-}; +- +-struct mmal_parameter_awbgains { +- struct mmal_parameter_rational r_gain; /**< Red gain */ +- struct mmal_parameter_rational b_gain; /**< Blue gain */ +-}; +- +-/** Manner of video rate control */ +-enum mmal_parameter_rate_control_mode { +- MMAL_VIDEO_RATECONTROL_DEFAULT, +- MMAL_VIDEO_RATECONTROL_VARIABLE, +- MMAL_VIDEO_RATECONTROL_CONSTANT, +- MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES, +- MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES +-}; +- +-enum mmal_video_profile { +- MMAL_VIDEO_PROFILE_H263_BASELINE, +- MMAL_VIDEO_PROFILE_H263_H320CODING, +- MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE, +- MMAL_VIDEO_PROFILE_H263_ISWV2, +- MMAL_VIDEO_PROFILE_H263_ISWV3, +- MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION, +- MMAL_VIDEO_PROFILE_H263_INTERNET, +- MMAL_VIDEO_PROFILE_H263_INTERLACE, +- MMAL_VIDEO_PROFILE_H263_HIGHLATENCY, +- MMAL_VIDEO_PROFILE_MP4V_SIMPLE, +- MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE, +- MMAL_VIDEO_PROFILE_MP4V_CORE, +- MMAL_VIDEO_PROFILE_MP4V_MAIN, +- MMAL_VIDEO_PROFILE_MP4V_NBIT, +- MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE, +- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE, +- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA, +- MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED, +- MMAL_VIDEO_PROFILE_MP4V_HYBRID, +- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME, +- MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE, +- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING, +- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE, +- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE, +- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE, +- MMAL_VIDEO_PROFILE_H264_BASELINE, +- MMAL_VIDEO_PROFILE_H264_MAIN, +- MMAL_VIDEO_PROFILE_H264_EXTENDED, +- MMAL_VIDEO_PROFILE_H264_HIGH, +- MMAL_VIDEO_PROFILE_H264_HIGH10, +- MMAL_VIDEO_PROFILE_H264_HIGH422, +- MMAL_VIDEO_PROFILE_H264_HIGH444, +- MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, +- MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF +-}; +- +-enum mmal_video_level { +- MMAL_VIDEO_LEVEL_H263_10, +- MMAL_VIDEO_LEVEL_H263_20, +- MMAL_VIDEO_LEVEL_H263_30, +- MMAL_VIDEO_LEVEL_H263_40, +- MMAL_VIDEO_LEVEL_H263_45, +- MMAL_VIDEO_LEVEL_H263_50, +- MMAL_VIDEO_LEVEL_H263_60, +- MMAL_VIDEO_LEVEL_H263_70, +- MMAL_VIDEO_LEVEL_MP4V_0, +- MMAL_VIDEO_LEVEL_MP4V_0b, +- MMAL_VIDEO_LEVEL_MP4V_1, +- MMAL_VIDEO_LEVEL_MP4V_2, +- MMAL_VIDEO_LEVEL_MP4V_3, +- MMAL_VIDEO_LEVEL_MP4V_4, +- MMAL_VIDEO_LEVEL_MP4V_4a, +- MMAL_VIDEO_LEVEL_MP4V_5, +- MMAL_VIDEO_LEVEL_MP4V_6, +- MMAL_VIDEO_LEVEL_H264_1, +- MMAL_VIDEO_LEVEL_H264_1b, +- MMAL_VIDEO_LEVEL_H264_11, +- MMAL_VIDEO_LEVEL_H264_12, +- MMAL_VIDEO_LEVEL_H264_13, +- MMAL_VIDEO_LEVEL_H264_2, +- MMAL_VIDEO_LEVEL_H264_21, +- MMAL_VIDEO_LEVEL_H264_22, +- MMAL_VIDEO_LEVEL_H264_3, +- MMAL_VIDEO_LEVEL_H264_31, +- MMAL_VIDEO_LEVEL_H264_32, +- MMAL_VIDEO_LEVEL_H264_4, +- MMAL_VIDEO_LEVEL_H264_41, +- MMAL_VIDEO_LEVEL_H264_42, +- MMAL_VIDEO_LEVEL_H264_5, +- MMAL_VIDEO_LEVEL_H264_51, +- MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF +-}; +- +-struct mmal_parameter_video_profile { +- enum mmal_video_profile profile; +- enum mmal_video_level level; +-}; +- +-/* video parameters */ +- +-enum mmal_parameter_video_type { +- /** @ref MMAL_DISPLAYREGION_T */ +- MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO, +- +- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ +- MMAL_PARAMETER_SUPPORTED_PROFILES, +- +- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ +- MMAL_PARAMETER_PROFILE, +- +- /** @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_INTRAPERIOD, +- +- /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */ +- MMAL_PARAMETER_RATECONTROL, +- +- /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */ +- MMAL_PARAMETER_NALUNITFORMAT, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_MINIMISE_FRAGMENTATION, +- +- /** @ref MMAL_PARAMETER_UINT32_T. +- * Setting the value to zero resets to the default (one slice per +- * frame). +- */ +- MMAL_PARAMETER_MB_ROWS_PER_SLICE, +- +- /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */ +- MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION, +- +- /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */ +- MMAL_PARAMETER_VIDEO_EEDE_ENABLE, +- +- /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */ +- MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */ +- MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, +- /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */ +- MMAL_PARAMETER_VIDEO_INTRA_REFRESH, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ +- MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, +- +- /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */ +- MMAL_PARAMETER_VIDEO_BIT_RATE, +- +- /** @ref MMAL_PARAMETER_FRAME_RATE_T */ +- MMAL_PARAMETER_VIDEO_FRAME_RATE, +- +- /** @ref MMAL_PARAMETER_UINT32_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, +- +- /** @ref MMAL_PARAMETER_UINT32_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, +- +- /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL, +- +- MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */ +- /** @ref MMAL_PARAMETER_UINT32_T. +- * Changing this parameter from the default can reduce frame rate +- * because image buffers need to be re-pitched. +- */ +- MMAL_PARAMETER_VIDEO_ALIGN_HORIZ, +- +- /** @ref MMAL_PARAMETER_UINT32_T. +- * Changing this parameter from the default can reduce frame rate +- * because image buffers need to be re-pitched. +- */ +- MMAL_PARAMETER_VIDEO_ALIGN_VERT, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ +- MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES, +- +- /** @ref MMAL_PARAMETER_UINT32_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, +- +- /**< @ref MMAL_PARAMETER_UINT32_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_QP_P, +- +- /**< @ref MMAL_PARAMETER_UINT32_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT, +- +- /** @ref MMAL_PARAMETER_UINT32_T */ +- MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS, +- +- /** @ref MMAL_PARAMETER_UINT32_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE, +- +- /* H264 specific parameters */ +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS, +- +- /** @ref MMAL_PARAMETER_UINT32_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC, +- +- /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */ +- MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP, +- +- /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */ +- MMAL_PARAMETER_VIDEO_DRM_INIT_INFO, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO, +- +- /** @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT, +- +- /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */ +- MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER, +- +- /** @ref MMAL_PARAMETER_BYTES_T */ +- MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3, +- +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS, +- +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, +- +- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER +-}; +- +-/** Valid mirror modes */ +-enum mmal_parameter_mirror { +- MMAL_PARAM_MIRROR_NONE, +- MMAL_PARAM_MIRROR_VERTICAL, +- MMAL_PARAM_MIRROR_HORIZONTAL, +- MMAL_PARAM_MIRROR_BOTH, +-}; +- +-enum mmal_parameter_displaytransform { +- MMAL_DISPLAY_ROT0 = 0, +- MMAL_DISPLAY_MIRROR_ROT0 = 1, +- MMAL_DISPLAY_MIRROR_ROT180 = 2, +- MMAL_DISPLAY_ROT180 = 3, +- MMAL_DISPLAY_MIRROR_ROT90 = 4, +- MMAL_DISPLAY_ROT270 = 5, +- MMAL_DISPLAY_ROT90 = 6, +- MMAL_DISPLAY_MIRROR_ROT270 = 7, +-}; +- +-enum mmal_parameter_displaymode { +- MMAL_DISPLAY_MODE_FILL = 0, +- MMAL_DISPLAY_MODE_LETTERBOX = 1, +-}; +- +-enum mmal_parameter_displayset { +- MMAL_DISPLAY_SET_NONE = 0, +- MMAL_DISPLAY_SET_NUM = 1, +- MMAL_DISPLAY_SET_FULLSCREEN = 2, +- MMAL_DISPLAY_SET_TRANSFORM = 4, +- MMAL_DISPLAY_SET_DEST_RECT = 8, +- MMAL_DISPLAY_SET_SRC_RECT = 0x10, +- MMAL_DISPLAY_SET_MODE = 0x20, +- MMAL_DISPLAY_SET_PIXEL = 0x40, +- MMAL_DISPLAY_SET_NOASPECT = 0x80, +- MMAL_DISPLAY_SET_LAYER = 0x100, +- MMAL_DISPLAY_SET_COPYPROTECT = 0x200, +- MMAL_DISPLAY_SET_ALPHA = 0x400, +-}; +- +-/* rectangle, used lots so it gets its own struct */ +-struct vchiq_mmal_rect { +- s32 x; +- s32 y; +- s32 width; +- s32 height; +-}; +- +-struct mmal_parameter_displayregion { +- /** Bitfield that indicates which fields are set and should be +- * used. All other fields will maintain their current value. +- * \ref MMAL_DISPLAYSET_T defines the bits that can be +- * combined. +- */ +- u32 set; +- +- /** Describes the display output device, with 0 typically +- * being a directly connected LCD display. The actual values +- * will depend on the hardware. Code using hard-wired numbers +- * (e.g. 2) is certain to fail. +- */ +- +- u32 display_num; +- /** Indicates that we are using the full device screen area, +- * rather than a window of the display. If zero, then +- * dest_rect is used to specify a region of the display to +- * use. +- */ +- +- s32 fullscreen; +- /** Indicates any rotation or flipping used to map frames onto +- * the natural display orientation. +- */ +- u32 transform; /* enum mmal_parameter_displaytransform */ +- +- /** Where to display the frame within the screen, if +- * fullscreen is zero. +- */ +- struct vchiq_mmal_rect dest_rect; +- +- /** Indicates which area of the frame to display. If all +- * values are zero, the whole frame will be used. +- */ +- struct vchiq_mmal_rect src_rect; +- +- /** If set to non-zero, indicates that any display scaling +- * should disregard the aspect ratio of the frame region being +- * displayed. +- */ +- s32 noaspect; +- +- /** Indicates how the image should be scaled to fit the +- * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates +- * that the image should fill the screen by potentially +- * cropping the frames. Setting \code mode \endcode to \code +- * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the +- * source region should be displayed and black bars added if +- * necessary. +- */ +- u32 mode; /* enum mmal_parameter_displaymode */ +- +- /** If non-zero, defines the width of a source pixel relative +- * to \code pixel_y \endcode. If zero, then pixels default to +- * being square. +- */ +- u32 pixel_x; +- +- /** If non-zero, defines the height of a source pixel relative +- * to \code pixel_x \endcode. If zero, then pixels default to +- * being square. +- */ +- u32 pixel_y; +- +- /** Sets the relative depth of the images, with greater values +- * being in front of smaller values. +- */ +- u32 layer; +- +- /** Set to non-zero to ensure copy protection is used on +- * output. +- */ +- s32 copyprotect_required; +- +- /** Level of opacity of the layer, where zero is fully +- * transparent and 255 is fully opaque. +- */ +- u32 alpha; +-}; +- +-#define MMAL_MAX_IMAGEFX_PARAMETERS 5 +- +-struct mmal_parameter_imagefx_parameters { +- enum mmal_parameter_imagefx effect; +- u32 num_effect_params; +- u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS]; +-}; +- +-#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4 +-#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2 +-#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16 +- +-struct mmal_parameter_camera_info_camera_t { +- u32 port_id; +- u32 max_width; +- u32 max_height; +- u32 lens_present; +- u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN]; +-}; +- +-enum mmal_parameter_camera_info_flash_type_t { +- /* Make values explicit to ensure they match values in config ini */ +- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0, +- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1, +- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2, +- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF +-}; +- +-struct mmal_parameter_camera_info_flash_t { +- enum mmal_parameter_camera_info_flash_type_t flash_type; +-}; +- +-struct mmal_parameter_camera_info_t { +- u32 num_cameras; +- u32 num_flashes; +- struct mmal_parameter_camera_info_camera_t +- cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS]; +- struct mmal_parameter_camera_info_flash_t +- flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES]; +-}; +- +-#endif +--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h ++++ /dev/null +@@ -1,166 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Broadcom BM2835 V4L2 driver +- * +- * Copyright © 2013 Raspberry Pi (Trading) Ltd. +- * +- * Authors: Vincent Sanders @ Collabora +- * Dave Stevenson @ Broadcom +- * (now dave.stevenson@raspberrypi.org) +- * Simon Mellor @ Broadcom +- * Luke Diamand @ Broadcom +- * +- * MMAL interface to VCHIQ message passing +- */ +- +-#ifndef MMAL_VCHIQ_H +-#define MMAL_VCHIQ_H +- +-#include "mmal-msg-format.h" +- +-#define MAX_PORT_COUNT 4 +- +-/* Maximum size of the format extradata. */ +-#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128 +- +-struct vchiq_mmal_instance; +- +-enum vchiq_mmal_es_type { +- MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */ +- MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */ +- MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */ +- MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */ +- MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */ +-}; +- +-struct vchiq_mmal_port_buffer { +- unsigned int num; /* number of buffers */ +- u32 size; /* size of buffers */ +- u32 alignment; /* alignment of buffers */ +-}; +- +-struct vchiq_mmal_port; +- +-typedef void (*vchiq_mmal_buffer_cb)( +- struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- int status, struct mmal_buffer *buffer, +- unsigned long length, u32 mmal_flags, s64 dts, s64 pts); +- +-struct vchiq_mmal_port { +- u32 enabled:1; +- u32 handle; +- u32 type; /* port type, cached to use on port info set */ +- u32 index; /* port index, cached to use on port info set */ +- +- /* component port belongs to, allows simple deref */ +- struct vchiq_mmal_component *component; +- +- struct vchiq_mmal_port *connected; /* port connected to */ +- +- /* buffer info */ +- struct vchiq_mmal_port_buffer minimum_buffer; +- struct vchiq_mmal_port_buffer recommended_buffer; +- struct vchiq_mmal_port_buffer current_buffer; +- +- /* stream format */ +- struct mmal_es_format_local format; +- /* elementary stream format */ +- union mmal_es_specific_format es; +- +- /* data buffers to fill */ +- struct list_head buffers; +- /* lock to serialise adding and removing buffers from list */ +- spinlock_t slock; +- +- /* Count of buffers the VPU has yet to return */ +- atomic_t buffers_with_vpu; +- /* callback on buffer completion */ +- vchiq_mmal_buffer_cb buffer_cb; +- /* callback context */ +- void *cb_ctx; +-}; +- +-struct vchiq_mmal_component { +- u32 enabled:1; +- u32 handle; /* VideoCore handle for component */ +- u32 inputs; /* Number of input ports */ +- u32 outputs; /* Number of output ports */ +- u32 clocks; /* Number of clock ports */ +- struct vchiq_mmal_port control; /* control port */ +- struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */ +- struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */ +- struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */ +-}; +- +-int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance); +-int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance); +- +-/* Initialise a mmal component and its ports +- * +- */ +-int vchiq_mmal_component_init( +- struct vchiq_mmal_instance *instance, +- const char *name, +- struct vchiq_mmal_component **component_out); +- +-int vchiq_mmal_component_finalise( +- struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component); +- +-int vchiq_mmal_component_enable( +- struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component); +- +-int vchiq_mmal_component_disable( +- struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_component *component); +- +-/* enable a mmal port +- * +- * enables a port and if a buffer callback provided enque buffer +- * headers as appropriate for the port. +- */ +-int vchiq_mmal_port_enable( +- struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- vchiq_mmal_buffer_cb buffer_cb); +- +-/* disable a port +- * +- * disable a port will dequeue any pending buffers +- */ +-int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port); +- +-int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- u32 parameter, +- void *value, +- u32 value_size); +- +-int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- u32 parameter, +- void *value, +- u32 *value_size); +- +-int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port); +- +-int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *src, +- struct vchiq_mmal_port *dst); +- +-int vchiq_mmal_version(struct vchiq_mmal_instance *instance, +- u32 *major_out, +- u32 *minor_out); +- +-int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, +- struct vchiq_mmal_port *port, +- struct mmal_buffer *buf); +- +-int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, +- struct mmal_buffer *buf); +-int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf); +-#endif /* MMAL_VCHIQ_H */ +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ * ++ * MMAL structures ++ * ++ */ ++#ifndef MMAL_COMMON_H ++#define MMAL_COMMON_H ++ ++#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24)) ++#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l') ++ ++/** Special value signalling that time is not known */ ++#define MMAL_TIME_UNKNOWN BIT_ULL(63) ++ ++struct mmal_msg_context; ++ ++/* mapping between v4l and mmal video modes */ ++struct mmal_fmt { ++ u32 fourcc; /* v4l2 format id */ ++ int flags; /* v4l2 flags field */ ++ u32 mmal; ++ int depth; ++ u32 mmal_component; /* MMAL component index to be used to encode */ ++ u32 ybbp; /* depth of first Y plane for planar formats */ ++ bool remove_padding; /* Does the GPU have to remove padding, ++ * or can we do hide padding via bytesperline. ++ */ ++}; ++ ++/* buffer for one video frame */ ++struct mmal_buffer { ++ /* v4l buffer data -- must be first */ ++ struct vb2_v4l2_buffer vb; ++ ++ /* list of buffers available */ ++ struct list_head list; ++ ++ void *buffer; /* buffer pointer */ ++ unsigned long buffer_size; /* size of allocated buffer */ ++ ++ struct mmal_msg_context *msg_context; ++}; ++ ++/* */ ++struct mmal_colourfx { ++ s32 enable; ++ u32 u; ++ u32 v; ++}; ++#endif +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ */ ++#ifndef MMAL_ENCODINGS_H ++#define MMAL_ENCODINGS_H ++ ++#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4') ++#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3') ++#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V') ++#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V') ++#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V') ++#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3') ++#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2') ++#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1') ++#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1') ++#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ') ++#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ') ++#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ') ++#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O') ++#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K') ++#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G') ++ ++#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G') ++#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ') ++#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ') ++#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ') ++#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ') ++#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ') ++ ++#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0') ++#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0') ++#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2') ++#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2') ++#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2') ++#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V') ++#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U') ++#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y') ++#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y') ++#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2') ++#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1') ++#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B') ++#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A') ++#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R') ++#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A') ++#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2') ++#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3') ++#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4') ++#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2') ++#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3') ++#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4') ++ ++/** SAND Video (YUVUV128) format, native format understood by VideoCore. ++ * This format is *not* opaque - if requested you will receive full frames ++ * of YUV_UV video. ++ */ ++#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D') ++ ++/** VideoCore opaque image format, image handles are returned to ++ * the host but not the actual image data. ++ */ ++#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V') ++ ++/** An EGL image handle ++ */ ++#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I') ++ ++/* }@ */ ++ ++/** \name Pre-defined audio encodings */ ++/* @{ */ ++#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U') ++#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u') ++#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S') ++#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's') ++#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F') ++#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f') ++ ++/* Pre-defined H264 encoding variants */ ++ ++/** ISO 14496-10 Annex B byte stream format */ ++#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0 ++/** ISO 14496-15 AVC stream format */ ++#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1') ++/** Implicitly delineated NAL units without emulation prevention */ ++#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ') ++ ++/** \defgroup MmalColorSpace List of pre-defined video color spaces ++ * This defines a list of common color spaces. This list isn't exhaustive and ++ * is only provided as a convenience to avoid clients having to use FourCC ++ * codes directly. However components are allowed to define and use their own ++ * FourCC codes. ++ */ ++/* @{ */ ++ ++/** Unknown color space */ ++#define MMAL_COLOR_SPACE_UNKNOWN 0 ++/** ITU-R BT.601-5 [SDTV] */ ++#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1') ++/** ITU-R BT.709-3 [HDTV] */ ++#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9') ++/** JPEG JFIF */ ++#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I') ++/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ ++#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C') ++/** Society of Motion Picture and Television Engineers 240M (1999) */ ++#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0') ++/** ITU-R BT.470-2 System M */ ++#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M') ++/** ITU-R BT.470-2 System BG */ ++#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G') ++/** JPEG JFIF, but with 16..255 luma */ ++#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6') ++/* @} MmalColorSpace List */ ++ ++#endif /* MMAL_ENCODINGS_H */ +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-common.h +@@ -0,0 +1,48 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ */ ++ ++#ifndef MMAL_MSG_COMMON_H ++#define MMAL_MSG_COMMON_H ++ ++enum mmal_msg_status { ++ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */ ++ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */ ++ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */ ++ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */ ++ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */ ++ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */ ++ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */ ++ MMAL_MSG_STATUS_EIO, /**< I/O error */ ++ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */ ++ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */ ++ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */ ++ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */ ++ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */ ++ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */ ++ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */ ++ MMAL_MSG_STATUS_EFAULT, /**< Bad address */ ++}; ++ ++struct mmal_rect { ++ s32 x; /**< x coordinate (from left) */ ++ s32 y; /**< y coordinate (from top) */ ++ s32 width; /**< width */ ++ s32 height; /**< height */ ++}; ++ ++struct mmal_rational { ++ s32 num; /**< Numerator */ ++ s32 den; /**< Denominator */ ++}; ++ ++#endif /* MMAL_MSG_COMMON_H */ +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h +@@ -0,0 +1,106 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ */ ++ ++#ifndef MMAL_MSG_FORMAT_H ++#define MMAL_MSG_FORMAT_H ++ ++#include "mmal-msg-common.h" ++ ++/* MMAL_ES_FORMAT_T */ ++ ++struct mmal_audio_format { ++ u32 channels; /* Number of audio channels */ ++ u32 sample_rate; /* Sample rate */ ++ ++ u32 bits_per_sample; /* Bits per sample */ ++ u32 block_align; /* Size of a block of data */ ++}; ++ ++struct mmal_video_format { ++ u32 width; /* Width of frame in pixels */ ++ u32 height; /* Height of frame in rows of pixels */ ++ struct mmal_rect crop; /* Visible region of the frame */ ++ struct mmal_rational frame_rate; /* Frame rate */ ++ struct mmal_rational par; /* Pixel aspect ratio */ ++ ++ /* ++ * FourCC specifying the color space of the video stream. See the ++ * MmalColorSpace "pre-defined color spaces" for some examples. ++ */ ++ u32 color_space; ++}; ++ ++struct mmal_subpicture_format { ++ u32 x_offset; ++ u32 y_offset; ++}; ++ ++union mmal_es_specific_format { ++ struct mmal_audio_format audio; ++ struct mmal_video_format video; ++ struct mmal_subpicture_format subpicture; ++}; ++ ++/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */ ++struct mmal_es_format_local { ++ u32 type; /* enum mmal_es_type */ ++ ++ u32 encoding; /* FourCC specifying encoding of the elementary ++ * stream. ++ */ ++ u32 encoding_variant; /* FourCC specifying the specific ++ * encoding variant of the elementary ++ * stream. ++ */ ++ ++ union mmal_es_specific_format *es; /* Type specific ++ * information for the ++ * elementary stream ++ */ ++ ++ u32 bitrate; /* Bitrate in bits per second */ ++ u32 flags; /* Flags describing properties of the elementary ++ * stream. ++ */ ++ ++ u32 extradata_size; /* Size of the codec specific data */ ++ u8 *extradata; /* Codec specific data */ ++}; ++ ++/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */ ++struct mmal_es_format { ++ u32 type; /* enum mmal_es_type */ ++ ++ u32 encoding; /* FourCC specifying encoding of the elementary ++ * stream. ++ */ ++ u32 encoding_variant; /* FourCC specifying the specific ++ * encoding variant of the elementary ++ * stream. ++ */ ++ ++ u32 es; /* Type specific ++ * information for the ++ * elementary stream ++ */ ++ ++ u32 bitrate; /* Bitrate in bits per second */ ++ u32 flags; /* Flags describing properties of the elementary ++ * stream. ++ */ ++ ++ u32 extradata_size; /* Size of the codec specific data */ ++ u32 extradata; /* Codec specific data */ ++}; ++ ++#endif /* MMAL_MSG_FORMAT_H */ +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-port.h +@@ -0,0 +1,109 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ */ ++ ++/* MMAL_PORT_TYPE_T */ ++enum mmal_port_type { ++ MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */ ++ MMAL_PORT_TYPE_CONTROL, /* Control port */ ++ MMAL_PORT_TYPE_INPUT, /* Input port */ ++ MMAL_PORT_TYPE_OUTPUT, /* Output port */ ++ MMAL_PORT_TYPE_CLOCK, /* Clock port */ ++}; ++ ++/* The port is pass-through and doesn't need buffer headers allocated */ ++#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01 ++/* ++ *The port wants to allocate the buffer payloads. ++ * This signals a preference that payload allocation should be done ++ * on this port for efficiency reasons. ++ */ ++#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02 ++/* ++ * The port supports format change events. ++ * This applies to input ports and is used to let the client know ++ * whether the port supports being reconfigured via a format ++ * change event (i.e. without having to disable the port). ++ */ ++#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04 ++ ++/* ++ * mmal port structure (MMAL_PORT_T) ++ * ++ * most elements are informational only, the pointer values for ++ * interogation messages are generally provided as additional ++ * structures within the message. When used to set values only the ++ * buffer_num, buffer_size and userdata parameters are writable. ++ */ ++struct mmal_port { ++ u32 priv; /* Private member used by the framework */ ++ u32 name; /* Port name. Used for debugging purposes (RO) */ ++ ++ u32 type; /* Type of the port (RO) enum mmal_port_type */ ++ u16 index; /* Index of the port in its type list (RO) */ ++ u16 index_all; /* Index of the port in the list of all ports (RO) */ ++ ++ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */ ++ u32 format; /* Format of the elementary stream */ ++ ++ u32 buffer_num_min; /* Minimum number of buffers the port ++ * requires (RO). This is set by the ++ * component. ++ */ ++ ++ u32 buffer_size_min; /* Minimum size of buffers the port ++ * requires (RO). This is set by the ++ * component. ++ */ ++ ++ u32 buffer_alignment_min;/* Minimum alignment requirement for ++ * the buffers (RO). A value of ++ * zero means no special alignment ++ * requirements. This is set by the ++ * component. ++ */ ++ ++ u32 buffer_num_recommended; /* Number of buffers the port ++ * recommends for optimal ++ * performance (RO). A value of ++ * zero means no special ++ * recommendation. This is set ++ * by the component. ++ */ ++ ++ u32 buffer_size_recommended; /* Size of buffers the port ++ * recommends for optimal ++ * performance (RO). A value of ++ * zero means no special ++ * recommendation. This is set ++ * by the component. ++ */ ++ ++ u32 buffer_num; /* Actual number of buffers the port will use. ++ * This is set by the client. ++ */ ++ ++ u32 buffer_size; /* Actual maximum size of the buffers that ++ * will be sent to the port. This is set by ++ * the client. ++ */ ++ ++ u32 component; /* Component this port belongs to (Read Only) */ ++ ++ u32 userdata; /* Field reserved for use by the client */ ++ ++ u32 capabilities; /* Flags describing the capabilities of a ++ * port (RO). Bitwise combination of \ref ++ * portcapabilities "Port capabilities" ++ * values. ++ */ ++}; +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h +@@ -0,0 +1,406 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ */ ++ ++/* ++ * all the data structures which serialise the MMAL protocol. note ++ * these are directly mapped onto the recived message data. ++ * ++ * BEWARE: They seem to *assume* pointers are u32 and that there is no ++ * structure padding! ++ * ++ * NOTE: this implementation uses kernel types to ensure sizes. Rather ++ * than assigning values to enums to force their size the ++ * implementation uses fixed size types and not the enums (though the ++ * comments have the actual enum type ++ */ ++#ifndef MMAL_MSG_H ++#define MMAL_MSG_H ++ ++#define VC_MMAL_VER 15 ++#define VC_MMAL_MIN_VER 10 ++#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal") ++ ++/* max total message size is 512 bytes */ ++#define MMAL_MSG_MAX_SIZE 512 ++/* with six 32bit header elements max payload is therefore 488 bytes */ ++#define MMAL_MSG_MAX_PAYLOAD 488 ++ ++#include "mmal-msg-common.h" ++#include "mmal-msg-format.h" ++#include "mmal-msg-port.h" ++ ++enum mmal_msg_type { ++ MMAL_MSG_TYPE_QUIT = 1, ++ MMAL_MSG_TYPE_SERVICE_CLOSED, ++ MMAL_MSG_TYPE_GET_VERSION, ++ MMAL_MSG_TYPE_COMPONENT_CREATE, ++ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */ ++ MMAL_MSG_TYPE_COMPONENT_ENABLE, ++ MMAL_MSG_TYPE_COMPONENT_DISABLE, ++ MMAL_MSG_TYPE_PORT_INFO_GET, ++ MMAL_MSG_TYPE_PORT_INFO_SET, ++ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */ ++ MMAL_MSG_TYPE_BUFFER_FROM_HOST, ++ MMAL_MSG_TYPE_BUFFER_TO_HOST, ++ MMAL_MSG_TYPE_GET_STATS, ++ MMAL_MSG_TYPE_PORT_PARAMETER_SET, ++ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */ ++ MMAL_MSG_TYPE_EVENT_TO_HOST, ++ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT, ++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR, ++ MMAL_MSG_TYPE_CONSUME_MEM, ++ MMAL_MSG_TYPE_LMK, /* 20 */ ++ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC, ++ MMAL_MSG_TYPE_DRM_GET_LHS32, ++ MMAL_MSG_TYPE_DRM_GET_TIME, ++ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN, ++ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */ ++ MMAL_MSG_TYPE_HOST_LOG, ++ MMAL_MSG_TYPE_MSG_LAST ++}; ++ ++/* port action request messages differ depending on the action type */ ++enum mmal_msg_port_action_type { ++ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */ ++ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */ ++ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */ ++ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */ ++ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */ ++ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */ ++ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/ ++}; ++ ++struct mmal_msg_header { ++ u32 magic; ++ u32 type; /* enum mmal_msg_type */ ++ ++ /* Opaque handle to the control service */ ++ u32 control_service; ++ ++ u32 context; /* a u32 per message context */ ++ u32 status; /* The status of the vchiq operation */ ++ u32 padding; ++}; ++ ++/* Send from VC to host to report version */ ++struct mmal_msg_version { ++ u32 flags; ++ u32 major; ++ u32 minor; ++ u32 minimum; ++}; ++ ++/* request to VC to create component */ ++struct mmal_msg_component_create { ++ u32 client_component; /* component context */ ++ char name[128]; ++ u32 pid; /* For debug */ ++}; ++ ++/* reply from VC to component creation request */ ++struct mmal_msg_component_create_reply { ++ u32 status; /* enum mmal_msg_status - how does this differ to ++ * the one in the header? ++ */ ++ u32 component_handle; /* VideoCore handle for component */ ++ u32 input_num; /* Number of input ports */ ++ u32 output_num; /* Number of output ports */ ++ u32 clock_num; /* Number of clock ports */ ++}; ++ ++/* request to VC to destroy a component */ ++struct mmal_msg_component_destroy { ++ u32 component_handle; ++}; ++ ++struct mmal_msg_component_destroy_reply { ++ u32 status; /* The component destruction status */ ++}; ++ ++/* request and reply to VC to enable a component */ ++struct mmal_msg_component_enable { ++ u32 component_handle; ++}; ++ ++struct mmal_msg_component_enable_reply { ++ u32 status; /* The component enable status */ ++}; ++ ++/* request and reply to VC to disable a component */ ++struct mmal_msg_component_disable { ++ u32 component_handle; ++}; ++ ++struct mmal_msg_component_disable_reply { ++ u32 status; /* The component disable status */ ++}; ++ ++/* request to VC to get port information */ ++struct mmal_msg_port_info_get { ++ u32 component_handle; /* component handle port is associated with */ ++ u32 port_type; /* enum mmal_msg_port_type */ ++ u32 index; /* port index to query */ ++}; ++ ++/* reply from VC to get port info request */ ++struct mmal_msg_port_info_get_reply { ++ u32 status; /* enum mmal_msg_status */ ++ u32 component_handle; /* component handle port is associated with */ ++ u32 port_type; /* enum mmal_msg_port_type */ ++ u32 port_index; /* port indexed in query */ ++ s32 found; /* unused */ ++ u32 port_handle; /* Handle to use for this port */ ++ struct mmal_port port; ++ struct mmal_es_format format; /* elementary stream format */ ++ union mmal_es_specific_format es; /* es type specific data */ ++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */ ++}; ++ ++/* request to VC to set port information */ ++struct mmal_msg_port_info_set { ++ u32 component_handle; ++ u32 port_type; /* enum mmal_msg_port_type */ ++ u32 port_index; /* port indexed in query */ ++ struct mmal_port port; ++ struct mmal_es_format format; ++ union mmal_es_specific_format es; ++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; ++}; ++ ++/* reply from VC to port info set request */ ++struct mmal_msg_port_info_set_reply { ++ u32 status; ++ u32 component_handle; /* component handle port is associated with */ ++ u32 port_type; /* enum mmal_msg_port_type */ ++ u32 index; /* port indexed in query */ ++ s32 found; /* unused */ ++ u32 port_handle; /* Handle to use for this port */ ++ struct mmal_port port; ++ struct mmal_es_format format; ++ union mmal_es_specific_format es; ++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; ++}; ++ ++/* port action requests that take a mmal_port as a parameter */ ++struct mmal_msg_port_action_port { ++ u32 component_handle; ++ u32 port_handle; ++ u32 action; /* enum mmal_msg_port_action_type */ ++ struct mmal_port port; ++}; ++ ++/* port action requests that take handles as a parameter */ ++struct mmal_msg_port_action_handle { ++ u32 component_handle; ++ u32 port_handle; ++ u32 action; /* enum mmal_msg_port_action_type */ ++ u32 connect_component_handle; ++ u32 connect_port_handle; ++}; ++ ++struct mmal_msg_port_action_reply { ++ u32 status; /* The port action operation status */ ++}; ++ ++/* MMAL buffer transfer */ ++ ++/* Size of space reserved in a buffer message for short messages. */ ++#define MMAL_VC_SHORT_DATA 128 ++ ++/* Signals that the current payload is the end of the stream of data */ ++#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0) ++/* Signals that the start of the current payload starts a frame */ ++#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1) ++/* Signals that the end of the current payload ends a frame */ ++#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2) ++/* Signals that the current payload contains only complete frames (>1) */ ++#define MMAL_BUFFER_HEADER_FLAG_FRAME \ ++ (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \ ++ MMAL_BUFFER_HEADER_FLAG_FRAME_END) ++/* Signals that the current payload is a keyframe (i.e. self decodable) */ ++#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3) ++/* ++ * Signals a discontinuity in the stream of data (e.g. after a seek). ++ * Can be used for instance by a decoder to reset its state ++ */ ++#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4) ++/* ++ * Signals a buffer containing some kind of config data for the component ++ * (e.g. codec config data) ++ */ ++#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5) ++/* Signals an encrypted payload */ ++#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6) ++/* Signals a buffer containing side information */ ++#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7) ++/* ++ * Signals a buffer which is the snapshot/postview image from a stills ++ * capture ++ */ ++#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8) ++/* Signals a buffer which contains data known to be corrupted */ ++#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9) ++/* Signals that a buffer failed to be transmitted */ ++#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10) ++ ++struct mmal_driver_buffer { ++ u32 magic; ++ u32 component_handle; ++ u32 port_handle; ++ u32 client_context; ++}; ++ ++/* buffer header */ ++struct mmal_buffer_header { ++ u32 next; /* next header */ ++ u32 priv; /* framework private data */ ++ u32 cmd; ++ u32 data; ++ u32 alloc_size; ++ u32 length; ++ u32 offset; ++ u32 flags; ++ s64 pts; ++ s64 dts; ++ u32 type; ++ u32 user_data; ++}; ++ ++struct mmal_buffer_header_type_specific { ++ union { ++ struct { ++ u32 planes; ++ u32 offset[4]; ++ u32 pitch[4]; ++ u32 flags; ++ } video; ++ } u; ++}; ++ ++struct mmal_msg_buffer_from_host { ++ /* ++ *The front 32 bytes of the buffer header are copied ++ * back to us in the reply to allow for context. This ++ * area is used to store two mmal_driver_buffer structures to ++ * allow for multiple concurrent service users. ++ */ ++ /* control data */ ++ struct mmal_driver_buffer drvbuf; ++ ++ /* referenced control data for passthrough buffer management */ ++ struct mmal_driver_buffer drvbuf_ref; ++ struct mmal_buffer_header buffer_header; /* buffer header itself */ ++ struct mmal_buffer_header_type_specific buffer_header_type_specific; ++ s32 is_zero_copy; ++ s32 has_reference; ++ ++ /* allows short data to be xfered in control message */ ++ u32 payload_in_message; ++ u8 short_data[MMAL_VC_SHORT_DATA]; ++}; ++ ++/* port parameter setting */ ++ ++#define MMAL_WORKER_PORT_PARAMETER_SPACE 96 ++ ++struct mmal_msg_port_parameter_set { ++ u32 component_handle; /* component */ ++ u32 port_handle; /* port */ ++ u32 id; /* Parameter ID */ ++ u32 size; /* Parameter size */ ++ u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; ++}; ++ ++struct mmal_msg_port_parameter_set_reply { ++ u32 status; /* enum mmal_msg_status todo: how does this ++ * differ to the one in the header? ++ */ ++}; ++ ++/* port parameter getting */ ++ ++struct mmal_msg_port_parameter_get { ++ u32 component_handle; /* component */ ++ u32 port_handle; /* port */ ++ u32 id; /* Parameter ID */ ++ u32 size; /* Parameter size */ ++}; ++ ++struct mmal_msg_port_parameter_get_reply { ++ u32 status; /* Status of mmal_port_parameter_get call */ ++ u32 id; /* Parameter ID */ ++ u32 size; /* Parameter size */ ++ u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; ++}; ++ ++/* event messages */ ++#define MMAL_WORKER_EVENT_SPACE 256 ++ ++struct mmal_msg_event_to_host { ++ u32 client_component; /* component context */ ++ ++ u32 port_type; ++ u32 port_num; ++ ++ u32 cmd; ++ u32 length; ++ u8 data[MMAL_WORKER_EVENT_SPACE]; ++ u32 delayed_buffer; ++}; ++ ++/* all mmal messages are serialised through this structure */ ++struct mmal_msg { ++ /* header */ ++ struct mmal_msg_header h; ++ /* payload */ ++ union { ++ struct mmal_msg_version version; ++ ++ struct mmal_msg_component_create component_create; ++ struct mmal_msg_component_create_reply component_create_reply; ++ ++ struct mmal_msg_component_destroy component_destroy; ++ struct mmal_msg_component_destroy_reply component_destroy_reply; ++ ++ struct mmal_msg_component_enable component_enable; ++ struct mmal_msg_component_enable_reply component_enable_reply; ++ ++ struct mmal_msg_component_disable component_disable; ++ struct mmal_msg_component_disable_reply component_disable_reply; ++ ++ struct mmal_msg_port_info_get port_info_get; ++ struct mmal_msg_port_info_get_reply port_info_get_reply; ++ ++ struct mmal_msg_port_info_set port_info_set; ++ struct mmal_msg_port_info_set_reply port_info_set_reply; ++ ++ struct mmal_msg_port_action_port port_action_port; ++ struct mmal_msg_port_action_handle port_action_handle; ++ struct mmal_msg_port_action_reply port_action_reply; ++ ++ struct mmal_msg_buffer_from_host buffer_from_host; ++ ++ struct mmal_msg_port_parameter_set port_parameter_set; ++ struct mmal_msg_port_parameter_set_reply ++ port_parameter_set_reply; ++ struct mmal_msg_port_parameter_get ++ port_parameter_get; ++ struct mmal_msg_port_parameter_get_reply ++ port_parameter_get_reply; ++ ++ struct mmal_msg_event_to_host event_to_host; ++ ++ u8 payload[MMAL_MSG_MAX_PAYLOAD]; ++ } u; ++}; ++#endif +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h +@@ -0,0 +1,755 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ */ ++ ++/* common parameters */ ++ ++/** @name Parameter groups ++ * Parameters are divided into groups, and then allocated sequentially within ++ * a group using an enum. ++ * @{ ++ */ ++ ++#ifndef MMAL_PARAMETERS_H ++#define MMAL_PARAMETERS_H ++ ++/** Common parameter ID group, used with many types of component. */ ++#define MMAL_PARAMETER_GROUP_COMMON (0 << 16) ++/** Camera-specific parameter ID group. */ ++#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16) ++/** Video-specific parameter ID group. */ ++#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16) ++/** Audio-specific parameter ID group. */ ++#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16) ++/** Clock-specific parameter ID group. */ ++#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16) ++/** Miracast-specific parameter ID group. */ ++#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16) ++ ++/* Common parameters */ ++enum mmal_parameter_common_type { ++ /**< Never a valid parameter ID */ ++ MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON, ++ ++ /**< MMAL_PARAMETER_ENCODING_T */ ++ MMAL_PARAMETER_SUPPORTED_ENCODINGS, ++ /**< MMAL_PARAMETER_URI_T */ ++ MMAL_PARAMETER_URI, ++ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */ ++ MMAL_PARAMETER_CHANGE_EVENT_REQUEST, ++ /** MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_ZERO_COPY, ++ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */ ++ MMAL_PARAMETER_BUFFER_REQUIREMENTS, ++ /**< MMAL_PARAMETER_STATISTICS_T */ ++ MMAL_PARAMETER_STATISTICS, ++ /**< MMAL_PARAMETER_CORE_STATISTICS_T */ ++ MMAL_PARAMETER_CORE_STATISTICS, ++ /**< MMAL_PARAMETER_MEM_USAGE_T */ ++ MMAL_PARAMETER_MEM_USAGE, ++ /**< MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_BUFFER_FLAG_FILTER, ++ /**< MMAL_PARAMETER_SEEK_T */ ++ MMAL_PARAMETER_SEEK, ++ /**< MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_POWERMON_ENABLE, ++ /**< MMAL_PARAMETER_LOGGING_T */ ++ MMAL_PARAMETER_LOGGING, ++ /**< MMAL_PARAMETER_UINT64_T */ ++ MMAL_PARAMETER_SYSTEM_TIME, ++ /**< MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_NO_IMAGE_PADDING, ++}; ++ ++/* camera parameters */ ++ ++enum mmal_parameter_camera_type { ++ /* 0 */ ++ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */ ++ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION = ++ MMAL_PARAMETER_GROUP_CAMERA, ++ /**< Unused? */ ++ MMAL_PARAMETER_CAPTURE_QUALITY, ++ /**< @ref MMAL_PARAMETER_INT32_T */ ++ MMAL_PARAMETER_ROTATION, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_EXIF_DISABLE, ++ /**< @ref MMAL_PARAMETER_EXIF_T */ ++ MMAL_PARAMETER_EXIF, ++ /**< @ref MMAL_PARAM_AWBMODE_T */ ++ MMAL_PARAMETER_AWB_MODE, ++ /**< @ref MMAL_PARAMETER_IMAGEFX_T */ ++ MMAL_PARAMETER_IMAGE_EFFECT, ++ /**< @ref MMAL_PARAMETER_COLOURFX_T */ ++ MMAL_PARAMETER_COLOUR_EFFECT, ++ /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */ ++ MMAL_PARAMETER_FLICKER_AVOID, ++ /**< @ref MMAL_PARAMETER_FLASH_T */ ++ MMAL_PARAMETER_FLASH, ++ /**< @ref MMAL_PARAMETER_REDEYE_T */ ++ MMAL_PARAMETER_REDEYE, ++ /**< @ref MMAL_PARAMETER_FOCUS_T */ ++ MMAL_PARAMETER_FOCUS, ++ /**< Unused? */ ++ MMAL_PARAMETER_FOCAL_LENGTHS, ++ /**< @ref MMAL_PARAMETER_INT32_T */ ++ MMAL_PARAMETER_EXPOSURE_COMP, ++ /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */ ++ MMAL_PARAMETER_ZOOM, ++ /**< @ref MMAL_PARAMETER_MIRROR_T */ ++ MMAL_PARAMETER_MIRROR, ++ ++ /* 0x10 */ ++ /**< @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_CAMERA_NUM, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_CAPTURE, ++ /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */ ++ MMAL_PARAMETER_EXPOSURE_MODE, ++ /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */ ++ MMAL_PARAMETER_EXP_METERING_MODE, ++ /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */ ++ MMAL_PARAMETER_FOCUS_STATUS, ++ /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */ ++ MMAL_PARAMETER_CAMERA_CONFIG, ++ /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */ ++ MMAL_PARAMETER_CAPTURE_STATUS, ++ /**< @ref MMAL_PARAMETER_FACE_TRACK_T */ ++ MMAL_PARAMETER_FACE_TRACK, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, ++ /**< @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_JPEG_Q_FACTOR, ++ /**< @ref MMAL_PARAMETER_FRAME_RATE_T */ ++ MMAL_PARAMETER_FRAME_RATE, ++ /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */ ++ MMAL_PARAMETER_USE_STC, ++ /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */ ++ MMAL_PARAMETER_CAMERA_INFO, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_STABILISATION, ++ /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */ ++ MMAL_PARAMETER_FACE_TRACK_RESULTS, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_ENABLE_RAW_CAPTURE, ++ ++ /* 0x20 */ ++ /**< @ref MMAL_PARAMETER_URI_T */ ++ MMAL_PARAMETER_DPF_FILE, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_ENABLE_DPF_FILE, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_DPF_FAIL_IS_FATAL, ++ /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */ ++ MMAL_PARAMETER_CAPTURE_MODE, ++ /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */ ++ MMAL_PARAMETER_FOCUS_REGIONS, ++ /**< @ref MMAL_PARAMETER_INPUT_CROP_T */ ++ MMAL_PARAMETER_INPUT_CROP, ++ /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */ ++ MMAL_PARAMETER_SENSOR_INFORMATION, ++ /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */ ++ MMAL_PARAMETER_FLASH_SELECT, ++ /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */ ++ MMAL_PARAMETER_FIELD_OF_VIEW, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, ++ /**< @ref MMAL_PARAMETER_DRC_T */ ++ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, ++ /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */ ++ MMAL_PARAMETER_ALGORITHM_CONTROL, ++ /**< @ref MMAL_PARAMETER_RATIONAL_T */ ++ MMAL_PARAMETER_SHARPNESS, ++ /**< @ref MMAL_PARAMETER_RATIONAL_T */ ++ MMAL_PARAMETER_CONTRAST, ++ /**< @ref MMAL_PARAMETER_RATIONAL_T */ ++ MMAL_PARAMETER_BRIGHTNESS, ++ /**< @ref MMAL_PARAMETER_RATIONAL_T */ ++ MMAL_PARAMETER_SATURATION, ++ ++ /* 0x30 */ ++ /**< @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_ISO, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_ANTISHAKE, ++ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */ ++ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_CAMERA_BURST_CAPTURE, ++ /** @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_CAMERA_MIN_ISO, ++ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */ ++ MMAL_PARAMETER_CAMERA_USE_CASE, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_CAPTURE_STATS_PASS, ++ /** @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_ENABLE_REGISTER_FILE, ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL, ++ /** @ref MMAL_PARAMETER_CONFIGFILE_T */ ++ MMAL_PARAMETER_CONFIGFILE_REGISTERS, ++ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */ ++ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_JPEG_ATTACH_LOG, ++ /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */ ++ MMAL_PARAMETER_ZERO_SHUTTER_LAG, ++ /**< @ref MMAL_PARAMETER_FPS_RANGE_T */ ++ MMAL_PARAMETER_FPS_RANGE, ++ /**< @ref MMAL_PARAMETER_INT32_T */ ++ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, ++ ++ /* 0x40 */ ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_SW_SHARPEN_DISABLE, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_FLASH_REQUIRED, ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_SW_SATURATION_DISABLE, ++ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_SHUTTER_SPEED, ++ /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */ ++ MMAL_PARAMETER_CUSTOM_AWB_GAINS, ++}; ++ ++struct mmal_parameter_rational { ++ s32 num; /**< Numerator */ ++ s32 den; /**< Denominator */ ++}; ++ ++enum mmal_parameter_camera_config_timestamp_mode { ++ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */ ++ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value ++ * for the frame timestamp ++ */ ++ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp ++ * but subtract the ++ * timestamp of the first ++ * frame sent to give a ++ * zero based timestamp. ++ */ ++}; ++ ++struct mmal_parameter_fps_range { ++ /**< Low end of the permitted framerate range */ ++ struct mmal_parameter_rational fps_low; ++ /**< High end of the permitted framerate range */ ++ struct mmal_parameter_rational fps_high; ++}; ++ ++/* camera configuration parameter */ ++struct mmal_parameter_camera_config { ++ /* Parameters for setting up the image pools */ ++ u32 max_stills_w; /* Max size of stills capture */ ++ u32 max_stills_h; ++ u32 stills_yuv422; /* Allow YUV422 stills capture */ ++ u32 one_shot_stills; /* Continuous or one shot stills captures. */ ++ ++ u32 max_preview_video_w; /* Max size of the preview or video ++ * capture frames ++ */ ++ u32 max_preview_video_h; ++ u32 num_preview_video_frames; ++ ++ /** Sets the height of the circular buffer for stills capture. */ ++ u32 stills_capture_circular_buffer_height; ++ ++ /** Allows preview/encode to resume as fast as possible after the stills ++ * input frame has been received, and then processes the still frame in ++ * the background whilst preview/encode has resumed. ++ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE. ++ */ ++ u32 fast_preview_resume; ++ ++ /** Selects algorithm for timestamping frames if ++ * there is no clock component connected. ++ * enum mmal_parameter_camera_config_timestamp_mode ++ */ ++ s32 use_stc_timestamp; ++}; ++ ++enum mmal_parameter_exposuremode { ++ MMAL_PARAM_EXPOSUREMODE_OFF, ++ MMAL_PARAM_EXPOSUREMODE_AUTO, ++ MMAL_PARAM_EXPOSUREMODE_NIGHT, ++ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, ++ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, ++ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, ++ MMAL_PARAM_EXPOSUREMODE_SPORTS, ++ MMAL_PARAM_EXPOSUREMODE_SNOW, ++ MMAL_PARAM_EXPOSUREMODE_BEACH, ++ MMAL_PARAM_EXPOSUREMODE_VERYLONG, ++ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, ++ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, ++ MMAL_PARAM_EXPOSUREMODE_FIREWORKS, ++}; ++ ++enum mmal_parameter_exposuremeteringmode { ++ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE, ++ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT, ++ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT, ++ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX, ++}; ++ ++enum mmal_parameter_awbmode { ++ MMAL_PARAM_AWBMODE_OFF, ++ MMAL_PARAM_AWBMODE_AUTO, ++ MMAL_PARAM_AWBMODE_SUNLIGHT, ++ MMAL_PARAM_AWBMODE_CLOUDY, ++ MMAL_PARAM_AWBMODE_SHADE, ++ MMAL_PARAM_AWBMODE_TUNGSTEN, ++ MMAL_PARAM_AWBMODE_FLUORESCENT, ++ MMAL_PARAM_AWBMODE_INCANDESCENT, ++ MMAL_PARAM_AWBMODE_FLASH, ++ MMAL_PARAM_AWBMODE_HORIZON, ++}; ++ ++enum mmal_parameter_imagefx { ++ MMAL_PARAM_IMAGEFX_NONE, ++ MMAL_PARAM_IMAGEFX_NEGATIVE, ++ MMAL_PARAM_IMAGEFX_SOLARIZE, ++ MMAL_PARAM_IMAGEFX_POSTERIZE, ++ MMAL_PARAM_IMAGEFX_WHITEBOARD, ++ MMAL_PARAM_IMAGEFX_BLACKBOARD, ++ MMAL_PARAM_IMAGEFX_SKETCH, ++ MMAL_PARAM_IMAGEFX_DENOISE, ++ MMAL_PARAM_IMAGEFX_EMBOSS, ++ MMAL_PARAM_IMAGEFX_OILPAINT, ++ MMAL_PARAM_IMAGEFX_HATCH, ++ MMAL_PARAM_IMAGEFX_GPEN, ++ MMAL_PARAM_IMAGEFX_PASTEL, ++ MMAL_PARAM_IMAGEFX_WATERCOLOUR, ++ MMAL_PARAM_IMAGEFX_FILM, ++ MMAL_PARAM_IMAGEFX_BLUR, ++ MMAL_PARAM_IMAGEFX_SATURATION, ++ MMAL_PARAM_IMAGEFX_COLOURSWAP, ++ MMAL_PARAM_IMAGEFX_WASHEDOUT, ++ MMAL_PARAM_IMAGEFX_POSTERISE, ++ MMAL_PARAM_IMAGEFX_COLOURPOINT, ++ MMAL_PARAM_IMAGEFX_COLOURBALANCE, ++ MMAL_PARAM_IMAGEFX_CARTOON, ++}; ++ ++enum MMAL_PARAM_FLICKERAVOID_T { ++ MMAL_PARAM_FLICKERAVOID_OFF, ++ MMAL_PARAM_FLICKERAVOID_AUTO, ++ MMAL_PARAM_FLICKERAVOID_50HZ, ++ MMAL_PARAM_FLICKERAVOID_60HZ, ++ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF ++}; ++ ++struct mmal_parameter_awbgains { ++ struct mmal_parameter_rational r_gain; /**< Red gain */ ++ struct mmal_parameter_rational b_gain; /**< Blue gain */ ++}; ++ ++/** Manner of video rate control */ ++enum mmal_parameter_rate_control_mode { ++ MMAL_VIDEO_RATECONTROL_DEFAULT, ++ MMAL_VIDEO_RATECONTROL_VARIABLE, ++ MMAL_VIDEO_RATECONTROL_CONSTANT, ++ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES, ++ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES ++}; ++ ++enum mmal_video_profile { ++ MMAL_VIDEO_PROFILE_H263_BASELINE, ++ MMAL_VIDEO_PROFILE_H263_H320CODING, ++ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE, ++ MMAL_VIDEO_PROFILE_H263_ISWV2, ++ MMAL_VIDEO_PROFILE_H263_ISWV3, ++ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION, ++ MMAL_VIDEO_PROFILE_H263_INTERNET, ++ MMAL_VIDEO_PROFILE_H263_INTERLACE, ++ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLE, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE, ++ MMAL_VIDEO_PROFILE_MP4V_CORE, ++ MMAL_VIDEO_PROFILE_MP4V_MAIN, ++ MMAL_VIDEO_PROFILE_MP4V_NBIT, ++ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE, ++ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA, ++ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED, ++ MMAL_VIDEO_PROFILE_MP4V_HYBRID, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME, ++ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE, ++ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE, ++ MMAL_VIDEO_PROFILE_H264_BASELINE, ++ MMAL_VIDEO_PROFILE_H264_MAIN, ++ MMAL_VIDEO_PROFILE_H264_EXTENDED, ++ MMAL_VIDEO_PROFILE_H264_HIGH, ++ MMAL_VIDEO_PROFILE_H264_HIGH10, ++ MMAL_VIDEO_PROFILE_H264_HIGH422, ++ MMAL_VIDEO_PROFILE_H264_HIGH444, ++ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, ++ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF ++}; ++ ++enum mmal_video_level { ++ MMAL_VIDEO_LEVEL_H263_10, ++ MMAL_VIDEO_LEVEL_H263_20, ++ MMAL_VIDEO_LEVEL_H263_30, ++ MMAL_VIDEO_LEVEL_H263_40, ++ MMAL_VIDEO_LEVEL_H263_45, ++ MMAL_VIDEO_LEVEL_H263_50, ++ MMAL_VIDEO_LEVEL_H263_60, ++ MMAL_VIDEO_LEVEL_H263_70, ++ MMAL_VIDEO_LEVEL_MP4V_0, ++ MMAL_VIDEO_LEVEL_MP4V_0b, ++ MMAL_VIDEO_LEVEL_MP4V_1, ++ MMAL_VIDEO_LEVEL_MP4V_2, ++ MMAL_VIDEO_LEVEL_MP4V_3, ++ MMAL_VIDEO_LEVEL_MP4V_4, ++ MMAL_VIDEO_LEVEL_MP4V_4a, ++ MMAL_VIDEO_LEVEL_MP4V_5, ++ MMAL_VIDEO_LEVEL_MP4V_6, ++ MMAL_VIDEO_LEVEL_H264_1, ++ MMAL_VIDEO_LEVEL_H264_1b, ++ MMAL_VIDEO_LEVEL_H264_11, ++ MMAL_VIDEO_LEVEL_H264_12, ++ MMAL_VIDEO_LEVEL_H264_13, ++ MMAL_VIDEO_LEVEL_H264_2, ++ MMAL_VIDEO_LEVEL_H264_21, ++ MMAL_VIDEO_LEVEL_H264_22, ++ MMAL_VIDEO_LEVEL_H264_3, ++ MMAL_VIDEO_LEVEL_H264_31, ++ MMAL_VIDEO_LEVEL_H264_32, ++ MMAL_VIDEO_LEVEL_H264_4, ++ MMAL_VIDEO_LEVEL_H264_41, ++ MMAL_VIDEO_LEVEL_H264_42, ++ MMAL_VIDEO_LEVEL_H264_5, ++ MMAL_VIDEO_LEVEL_H264_51, ++ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF ++}; ++ ++struct mmal_parameter_video_profile { ++ enum mmal_video_profile profile; ++ enum mmal_video_level level; ++}; ++ ++/* video parameters */ ++ ++enum mmal_parameter_video_type { ++ /** @ref MMAL_DISPLAYREGION_T */ ++ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ ++ MMAL_PARAMETER_SUPPORTED_PROFILES, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ ++ MMAL_PARAMETER_PROFILE, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_INTRAPERIOD, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */ ++ MMAL_PARAMETER_RATECONTROL, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */ ++ MMAL_PARAMETER_NALUNITFORMAT, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_MINIMISE_FRAGMENTATION, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. ++ * Setting the value to zero resets to the default (one slice per ++ * frame). ++ */ ++ MMAL_PARAMETER_MB_ROWS_PER_SLICE, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */ ++ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */ ++ MMAL_PARAMETER_VIDEO_EEDE_ENABLE, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */ ++ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */ ++ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, ++ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */ ++ MMAL_PARAMETER_VIDEO_INTRA_REFRESH, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ ++ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */ ++ MMAL_PARAMETER_VIDEO_BIT_RATE, ++ ++ /** @ref MMAL_PARAMETER_FRAME_RATE_T */ ++ MMAL_PARAMETER_VIDEO_FRAME_RATE, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL, ++ ++ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */ ++ /** @ref MMAL_PARAMETER_UINT32_T. ++ * Changing this parameter from the default can reduce frame rate ++ * because image buffers need to be re-pitched. ++ */ ++ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. ++ * Changing this parameter from the default can reduce frame rate ++ * because image buffers need to be re-pitched. ++ */ ++ MMAL_PARAMETER_VIDEO_ALIGN_VERT, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ ++ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, ++ ++ /**< @ref MMAL_PARAMETER_UINT32_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_QP_P, ++ ++ /**< @ref MMAL_PARAMETER_UINT32_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE, ++ ++ /* H264 specific parameters */ ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS, ++ ++ /** @ref MMAL_PARAMETER_UINT32_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */ ++ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO, ++ ++ /** @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT, ++ ++ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */ ++ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER, ++ ++ /** @ref MMAL_PARAMETER_BYTES_T */ ++ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3, ++ ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS, ++ ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, ++ ++ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER ++}; ++ ++/** Valid mirror modes */ ++enum mmal_parameter_mirror { ++ MMAL_PARAM_MIRROR_NONE, ++ MMAL_PARAM_MIRROR_VERTICAL, ++ MMAL_PARAM_MIRROR_HORIZONTAL, ++ MMAL_PARAM_MIRROR_BOTH, ++}; ++ ++enum mmal_parameter_displaytransform { ++ MMAL_DISPLAY_ROT0 = 0, ++ MMAL_DISPLAY_MIRROR_ROT0 = 1, ++ MMAL_DISPLAY_MIRROR_ROT180 = 2, ++ MMAL_DISPLAY_ROT180 = 3, ++ MMAL_DISPLAY_MIRROR_ROT90 = 4, ++ MMAL_DISPLAY_ROT270 = 5, ++ MMAL_DISPLAY_ROT90 = 6, ++ MMAL_DISPLAY_MIRROR_ROT270 = 7, ++}; ++ ++enum mmal_parameter_displaymode { ++ MMAL_DISPLAY_MODE_FILL = 0, ++ MMAL_DISPLAY_MODE_LETTERBOX = 1, ++}; ++ ++enum mmal_parameter_displayset { ++ MMAL_DISPLAY_SET_NONE = 0, ++ MMAL_DISPLAY_SET_NUM = 1, ++ MMAL_DISPLAY_SET_FULLSCREEN = 2, ++ MMAL_DISPLAY_SET_TRANSFORM = 4, ++ MMAL_DISPLAY_SET_DEST_RECT = 8, ++ MMAL_DISPLAY_SET_SRC_RECT = 0x10, ++ MMAL_DISPLAY_SET_MODE = 0x20, ++ MMAL_DISPLAY_SET_PIXEL = 0x40, ++ MMAL_DISPLAY_SET_NOASPECT = 0x80, ++ MMAL_DISPLAY_SET_LAYER = 0x100, ++ MMAL_DISPLAY_SET_COPYPROTECT = 0x200, ++ MMAL_DISPLAY_SET_ALPHA = 0x400, ++}; ++ ++/* rectangle, used lots so it gets its own struct */ ++struct vchiq_mmal_rect { ++ s32 x; ++ s32 y; ++ s32 width; ++ s32 height; ++}; ++ ++struct mmal_parameter_displayregion { ++ /** Bitfield that indicates which fields are set and should be ++ * used. All other fields will maintain their current value. ++ * \ref MMAL_DISPLAYSET_T defines the bits that can be ++ * combined. ++ */ ++ u32 set; ++ ++ /** Describes the display output device, with 0 typically ++ * being a directly connected LCD display. The actual values ++ * will depend on the hardware. Code using hard-wired numbers ++ * (e.g. 2) is certain to fail. ++ */ ++ ++ u32 display_num; ++ /** Indicates that we are using the full device screen area, ++ * rather than a window of the display. If zero, then ++ * dest_rect is used to specify a region of the display to ++ * use. ++ */ ++ ++ s32 fullscreen; ++ /** Indicates any rotation or flipping used to map frames onto ++ * the natural display orientation. ++ */ ++ u32 transform; /* enum mmal_parameter_displaytransform */ ++ ++ /** Where to display the frame within the screen, if ++ * fullscreen is zero. ++ */ ++ struct vchiq_mmal_rect dest_rect; ++ ++ /** Indicates which area of the frame to display. If all ++ * values are zero, the whole frame will be used. ++ */ ++ struct vchiq_mmal_rect src_rect; ++ ++ /** If set to non-zero, indicates that any display scaling ++ * should disregard the aspect ratio of the frame region being ++ * displayed. ++ */ ++ s32 noaspect; ++ ++ /** Indicates how the image should be scaled to fit the ++ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates ++ * that the image should fill the screen by potentially ++ * cropping the frames. Setting \code mode \endcode to \code ++ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the ++ * source region should be displayed and black bars added if ++ * necessary. ++ */ ++ u32 mode; /* enum mmal_parameter_displaymode */ ++ ++ /** If non-zero, defines the width of a source pixel relative ++ * to \code pixel_y \endcode. If zero, then pixels default to ++ * being square. ++ */ ++ u32 pixel_x; ++ ++ /** If non-zero, defines the height of a source pixel relative ++ * to \code pixel_x \endcode. If zero, then pixels default to ++ * being square. ++ */ ++ u32 pixel_y; ++ ++ /** Sets the relative depth of the images, with greater values ++ * being in front of smaller values. ++ */ ++ u32 layer; ++ ++ /** Set to non-zero to ensure copy protection is used on ++ * output. ++ */ ++ s32 copyprotect_required; ++ ++ /** Level of opacity of the layer, where zero is fully ++ * transparent and 255 is fully opaque. ++ */ ++ u32 alpha; ++}; ++ ++#define MMAL_MAX_IMAGEFX_PARAMETERS 5 ++ ++struct mmal_parameter_imagefx_parameters { ++ enum mmal_parameter_imagefx effect; ++ u32 num_effect_params; ++ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS]; ++}; ++ ++#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4 ++#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2 ++#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16 ++ ++struct mmal_parameter_camera_info_camera_t { ++ u32 port_id; ++ u32 max_width; ++ u32 max_height; ++ u32 lens_present; ++ u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN]; ++}; ++ ++enum mmal_parameter_camera_info_flash_type_t { ++ /* Make values explicit to ensure they match values in config ini */ ++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0, ++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1, ++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2, ++ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF ++}; ++ ++struct mmal_parameter_camera_info_flash_t { ++ enum mmal_parameter_camera_info_flash_type_t flash_type; ++}; ++ ++struct mmal_parameter_camera_info_t { ++ u32 num_cameras; ++ u32 num_flashes; ++ struct mmal_parameter_camera_info_camera_t ++ cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS]; ++ struct mmal_parameter_camera_info_flash_t ++ flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES]; ++}; ++ ++#endif +--- /dev/null ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -0,0 +1,166 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Broadcom BM2835 V4L2 driver ++ * ++ * Copyright © 2013 Raspberry Pi (Trading) Ltd. ++ * ++ * Authors: Vincent Sanders @ Collabora ++ * Dave Stevenson @ Broadcom ++ * (now dave.stevenson@raspberrypi.org) ++ * Simon Mellor @ Broadcom ++ * Luke Diamand @ Broadcom ++ * ++ * MMAL interface to VCHIQ message passing ++ */ ++ ++#ifndef MMAL_VCHIQ_H ++#define MMAL_VCHIQ_H ++ ++#include "mmal-msg-format.h" ++ ++#define MAX_PORT_COUNT 4 ++ ++/* Maximum size of the format extradata. */ ++#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128 ++ ++struct vchiq_mmal_instance; ++ ++enum vchiq_mmal_es_type { ++ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */ ++ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */ ++ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */ ++ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */ ++ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */ ++}; ++ ++struct vchiq_mmal_port_buffer { ++ unsigned int num; /* number of buffers */ ++ u32 size; /* size of buffers */ ++ u32 alignment; /* alignment of buffers */ ++}; ++ ++struct vchiq_mmal_port; ++ ++typedef void (*vchiq_mmal_buffer_cb)( ++ struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ int status, struct mmal_buffer *buffer, ++ unsigned long length, u32 mmal_flags, s64 dts, s64 pts); ++ ++struct vchiq_mmal_port { ++ u32 enabled:1; ++ u32 handle; ++ u32 type; /* port type, cached to use on port info set */ ++ u32 index; /* port index, cached to use on port info set */ ++ ++ /* component port belongs to, allows simple deref */ ++ struct vchiq_mmal_component *component; ++ ++ struct vchiq_mmal_port *connected; /* port connected to */ ++ ++ /* buffer info */ ++ struct vchiq_mmal_port_buffer minimum_buffer; ++ struct vchiq_mmal_port_buffer recommended_buffer; ++ struct vchiq_mmal_port_buffer current_buffer; ++ ++ /* stream format */ ++ struct mmal_es_format_local format; ++ /* elementary stream format */ ++ union mmal_es_specific_format es; ++ ++ /* data buffers to fill */ ++ struct list_head buffers; ++ /* lock to serialise adding and removing buffers from list */ ++ spinlock_t slock; ++ ++ /* Count of buffers the VPU has yet to return */ ++ atomic_t buffers_with_vpu; ++ /* callback on buffer completion */ ++ vchiq_mmal_buffer_cb buffer_cb; ++ /* callback context */ ++ void *cb_ctx; ++}; ++ ++struct vchiq_mmal_component { ++ u32 enabled:1; ++ u32 handle; /* VideoCore handle for component */ ++ u32 inputs; /* Number of input ports */ ++ u32 outputs; /* Number of output ports */ ++ u32 clocks; /* Number of clock ports */ ++ struct vchiq_mmal_port control; /* control port */ ++ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */ ++ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */ ++ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */ ++}; ++ ++int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance); ++int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance); ++ ++/* Initialise a mmal component and its ports ++ * ++ */ ++int vchiq_mmal_component_init( ++ struct vchiq_mmal_instance *instance, ++ const char *name, ++ struct vchiq_mmal_component **component_out); ++ ++int vchiq_mmal_component_finalise( ++ struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component); ++ ++int vchiq_mmal_component_enable( ++ struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component); ++ ++int vchiq_mmal_component_disable( ++ struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_component *component); ++ ++/* enable a mmal port ++ * ++ * enables a port and if a buffer callback provided enque buffer ++ * headers as appropriate for the port. ++ */ ++int vchiq_mmal_port_enable( ++ struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ vchiq_mmal_buffer_cb buffer_cb); ++ ++/* disable a port ++ * ++ * disable a port will dequeue any pending buffers ++ */ ++int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port); ++ ++int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ u32 parameter, ++ void *value, ++ u32 value_size); ++ ++int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ u32 parameter, ++ void *value, ++ u32 *value_size); ++ ++int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port); ++ ++int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *src, ++ struct vchiq_mmal_port *dst); ++ ++int vchiq_mmal_version(struct vchiq_mmal_instance *instance, ++ u32 *major_out, ++ u32 *minor_out); ++ ++int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, ++ struct mmal_buffer *buf); ++ ++int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, ++ struct mmal_buffer *buf); ++int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf); ++#endif /* MMAL_VCHIQ_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0165-staging-bcm2835-camera-Ensure-timestamps-never-go-ba.patch b/target/linux/bcm27xx/patches-5.4/950-0165-staging-bcm2835-camera-Ensure-timestamps-never-go-ba.patch deleted file mode 100644 index c9e18874ab..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0165-staging-bcm2835-camera-Ensure-timestamps-never-go-ba.patch +++ /dev/null @@ -1,38 +0,0 @@ -From fd3a6710bbcf875c85e6a2f3513c6eb4c46adeaa Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 24 Jul 2018 12:08:29 +0100 -Subject: [PATCH] staging: bcm2835-camera: Ensure timestamps never go - backwards. - -There is an awkward situation with H264 header bytes. Currently -they are returned with a PTS of 0 because they aren't associated -with a timestamped frame to encode. These are handled by either -returning the timestamp of the last buffer to have been received, -or in the case of the first buffer the timestamp taken at -start_streaming. -This results in a race where the current frame may have started -before we take the start time, which results in the first encoded -frame having an earlier timestamp than the header bytes. - -Ensure that we never return a negative delta to the user by checking -against the previous timestamp. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-camera/bcm2835-camera.c | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -@@ -380,6 +380,11 @@ static void buffer_cb(struct vchiq_mmal_ - ktime_to_ns(dev->capture.kernel_start_ts), - dev->capture.vc_start_timestamp, pts, - ktime_to_ns(timestamp)); -+ if (timestamp < dev->capture.last_timestamp) { -+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -+ "Negative delta - using last time\n"); -+ timestamp = dev->capture.last_timestamp; -+ } - buf->vb.vb2_buf.timestamp = ktime_to_ns(timestamp); - } else { - if (dev->capture.last_timestamp) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0165-staging-mmal-vchiq-Allocate-and-free-components-as-r.patch b/target/linux/bcm27xx/patches-5.4/950-0165-staging-mmal-vchiq-Allocate-and-free-components-as-r.patch new file mode 100644 index 0000000000..53a6c07e9d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0165-staging-mmal-vchiq-Allocate-and-free-components-as-r.patch @@ -0,0 +1,107 @@ +From 238065901c1b476a5b093f1710773322b3344847 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 24 Sep 2018 16:51:13 +0100 +Subject: [PATCH] staging: mmal-vchiq: Allocate and free components as + required + +The existing code assumed that there would only ever be 4 components, +and never freed the entries once used. +Allow arbitrary creation and destruction of components. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++++++++------- + .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + + 2 files changed, 20 insertions(+), 10 deletions(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -37,8 +37,11 @@ MODULE_AUTHOR("Dave Stevenson, vchiq_mutex)) + return -EINTR; + +- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) { ++ for (idx = 0; idx < VCHIQ_MMAL_MAX_COMPONENTS; idx++) { ++ if (!instance->component[idx].in_use) { ++ component = &instance->component[idx]; ++ component->in_use = 1; ++ break; ++ } ++ } ++ ++ if (!component) { + ret = -EINVAL; /* todo is this correct error? */ + goto unlock; + } + +- component = &instance->component[instance->component_idx]; +- + ret = create_component(instance, component, name); + if (ret < 0) { + pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", +@@ -1693,8 +1700,6 @@ int vchiq_mmal_component_init(struct vch + goto release_component; + } + +- instance->component_idx++; +- + *component_out = component; + + mutex_unlock(&instance->vchiq_mutex); +@@ -1704,6 +1709,8 @@ int vchiq_mmal_component_init(struct vch + release_component: + destroy_component(instance, component); + unlock: ++ if (component) ++ component->in_use = 0; + mutex_unlock(&instance->vchiq_mutex); + + return ret; +@@ -1726,6 +1733,8 @@ int vchiq_mmal_component_finalise(struct + + ret = destroy_component(instance, component); + ++ component->in_use = 0; ++ + mutex_unlock(&instance->vchiq_mutex); + + return ret; +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -82,6 +82,7 @@ struct vchiq_mmal_port { + }; + + struct vchiq_mmal_component { ++ u32 in_use:1; + u32 enabled:1; + u32 handle; /* VideoCore handle for component */ + u32 inputs; /* Number of input ports */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0166-staging-mmal-vchiq-Avoid-use-of-bool-in-structures.patch b/target/linux/bcm27xx/patches-5.4/950-0166-staging-mmal-vchiq-Avoid-use-of-bool-in-structures.patch new file mode 100644 index 0000000000..31f7c8a525 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0166-staging-mmal-vchiq-Avoid-use-of-bool-in-structures.patch @@ -0,0 +1,24 @@ +From 98ba3ab478e0628304379673a6fa0a02e8db2166 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 29 Oct 2018 16:20:46 +0000 +Subject: [PATCH] staging: mmal-vchiq: Avoid use of bool in structures + +Fixes up a checkpatch error "Avoid using bool structure members +because of possible alignment issues". + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -1759,7 +1759,7 @@ int vchiq_mmal_component_enable(struct v + + ret = enable_component(instance, component); + if (ret == 0) +- component->enabled = true; ++ component->enabled = 1; + + mutex_unlock(&instance->vchiq_mutex); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0166-staging-vc04_services-Split-vchiq-mmal-into-a-module.patch b/target/linux/bcm27xx/patches-5.4/950-0166-staging-vc04_services-Split-vchiq-mmal-into-a-module.patch deleted file mode 100644 index 278d57b1bd..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0166-staging-vc04_services-Split-vchiq-mmal-into-a-module.patch +++ /dev/null @@ -1,7518 +0,0 @@ -From 85961f2d8f646488acb86f996c78a1f9ad57cb0a Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 24 Sep 2018 16:30:37 +0100 -Subject: [PATCH] staging: vc04_services: Split vchiq-mmal into a - module - -In preparation for adding a video codec V4L2 module which also -wants to use vchiq-mmal functions, split it out into an -independent module. -The minimum number of changes have been made to achieve this -(eg straight moves where possible) so existing checkpatch -errors will still be present. - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/Kconfig | 1 + - drivers/staging/vc04_services/Makefile | 1 + - .../vc04_services/bcm2835-camera/Kconfig | 2 +- - .../vc04_services/bcm2835-camera/Makefile | 5 +++-- - .../staging/vc04_services/vchiq-mmal/Kconfig | 7 ++++++ - .../staging/vc04_services/vchiq-mmal/Makefile | 8 +++++++ - .../mmal-common.h | 0 - .../mmal-encodings.h | 0 - .../mmal-msg-common.h | 0 - .../mmal-msg-format.h | 0 - .../mmal-msg-port.h | 0 - .../{bcm2835-camera => vchiq-mmal}/mmal-msg.h | 0 - .../mmal-parameters.h | 0 - .../mmal-vchiq.c | 22 +++++++++++++++++++ - .../mmal-vchiq.h | 0 - 15 files changed, 43 insertions(+), 3 deletions(-) - create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Kconfig - create mode 100644 drivers/staging/vc04_services/vchiq-mmal/Makefile - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-common.h (100%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-encodings.h (100%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-common.h (100%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-format.h (100%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg-port.h (100%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-msg.h (100%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-parameters.h (100%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.c (98%) - rename drivers/staging/vc04_services/{bcm2835-camera => vchiq-mmal}/mmal-vchiq.h (100%) - ---- a/drivers/staging/vc04_services/Kconfig -+++ b/drivers/staging/vc04_services/Kconfig -@@ -22,6 +22,7 @@ config BCM2835_VCHIQ - source "drivers/staging/vc04_services/bcm2835-audio/Kconfig" - - source "drivers/staging/vc04_services/bcm2835-camera/Kconfig" -+source "drivers/staging/vc04_services/vchiq-mmal/Kconfig" - - endif - ---- a/drivers/staging/vc04_services/Makefile -+++ b/drivers/staging/vc04_services/Makefile -@@ -12,6 +12,7 @@ vchiq-objs := \ - - obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ - obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ -+obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ - - ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000 - ---- a/drivers/staging/vc04_services/bcm2835-camera/Kconfig -+++ b/drivers/staging/vc04_services/bcm2835-camera/Kconfig -@@ -3,7 +3,7 @@ config VIDEO_BCM2835 - tristate "BCM2835 Camera" - depends on MEDIA_SUPPORT - depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) -- select BCM2835_VCHIQ -+ select BCM2835_VCHIQ_MMAL - select VIDEOBUF2_VMALLOC - select BTREE - help ---- a/drivers/staging/vc04_services/bcm2835-camera/Makefile -+++ b/drivers/staging/vc04_services/bcm2835-camera/Makefile -@@ -1,11 +1,12 @@ - # SPDX-License-Identifier: GPL-2.0 - bcm2835-v4l2-$(CONFIG_VIDEO_BCM2835) := \ - bcm2835-camera.o \ -- controls.o \ -- mmal-vchiq.o -+ controls.o - - obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v4l2.o - - ccflags-y += \ - -I $(srctree)/$(src)/.. \ -+ -Idrivers/staging/vc04_services \ -+ -Idrivers/staging/vc04_services/vchiq-mmal \ - -D__VCCOREVER__=0x04000000 ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig -@@ -0,0 +1,7 @@ -+config BCM2835_VCHIQ_MMAL -+ tristate "BCM2835 MMAL VCHIQ service" -+ depends on (ARCH_BCM2835 || COMPILE_TEST) -+ select BCM2835_VCHIQ -+ help -+ Enables the MMAL API over VCHIQ as used for the -+ majority of the multimedia services on VideoCore. ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0 -+bcm2835-mmal-vchiq-objs := mmal-vchiq.o -+ -+obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += bcm2835-mmal-vchiq.o -+ -+ccflags-y += \ -+ -Idrivers/staging/vc04_services \ -+ -D__VCCOREVER__=0x04000000 ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c -+++ /dev/null -@@ -1,1891 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- * -- * V4L2 driver MMAL vchiq interface code -- */ -- --#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -- --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "mmal-common.h" --#include "mmal-vchiq.h" --#include "mmal-msg.h" -- --#define USE_VCHIQ_ARM --#include "interface/vchi/vchi.h" -- --/* maximum number of components supported */ --#define VCHIQ_MMAL_MAX_COMPONENTS 4 -- --/*#define FULL_MSG_DUMP 1*/ -- --#ifdef DEBUG --static const char *const msg_type_names[] = { -- "UNKNOWN", -- "QUIT", -- "SERVICE_CLOSED", -- "GET_VERSION", -- "COMPONENT_CREATE", -- "COMPONENT_DESTROY", -- "COMPONENT_ENABLE", -- "COMPONENT_DISABLE", -- "PORT_INFO_GET", -- "PORT_INFO_SET", -- "PORT_ACTION", -- "BUFFER_FROM_HOST", -- "BUFFER_TO_HOST", -- "GET_STATS", -- "PORT_PARAMETER_SET", -- "PORT_PARAMETER_GET", -- "EVENT_TO_HOST", -- "GET_CORE_STATS_FOR_PORT", -- "OPAQUE_ALLOCATOR", -- "CONSUME_MEM", -- "LMK", -- "OPAQUE_ALLOCATOR_DESC", -- "DRM_GET_LHS32", -- "DRM_GET_TIME", -- "BUFFER_FROM_HOST_ZEROLEN", -- "PORT_FLUSH", -- "HOST_LOG", --}; --#endif -- --static const char *const port_action_type_names[] = { -- "UNKNOWN", -- "ENABLE", -- "DISABLE", -- "FLUSH", -- "CONNECT", -- "DISCONNECT", -- "SET_REQUIREMENTS", --}; -- --#if defined(DEBUG) --#if defined(FULL_MSG_DUMP) --#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \ -- do { \ -- pr_debug(TITLE" type:%s(%d) length:%d\n", \ -- msg_type_names[(MSG)->h.type], \ -- (MSG)->h.type, (MSG_LEN)); \ -- print_hex_dump(KERN_DEBUG, "<h.type], \ -- (MSG)->h.type, (MSG_LEN)); \ -- } --#endif --#else --#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) --#endif -- --struct vchiq_mmal_instance; -- --/* normal message context */ --struct mmal_msg_context { -- struct vchiq_mmal_instance *instance; -- -- /* Index in the context_map idr so that we can find the -- * mmal_msg_context again when servicing the VCHI reply. -- */ -- int handle; -- -- union { -- struct { -- /* work struct for buffer_cb callback */ -- struct work_struct work; -- /* work struct for deferred callback */ -- struct work_struct buffer_to_host_work; -- /* mmal instance */ -- struct vchiq_mmal_instance *instance; -- /* mmal port */ -- struct vchiq_mmal_port *port; -- /* actual buffer used to store bulk reply */ -- struct mmal_buffer *buffer; -- /* amount of buffer used */ -- unsigned long buffer_used; -- /* MMAL buffer flags */ -- u32 mmal_flags; -- /* Presentation and Decode timestamps */ -- s64 pts; -- s64 dts; -- -- int status; /* context status */ -- -- } bulk; /* bulk data */ -- -- struct { -- /* message handle to release */ -- struct vchi_held_msg msg_handle; -- /* pointer to received message */ -- struct mmal_msg *msg; -- /* received message length */ -- u32 msg_len; -- /* completion upon reply */ -- struct completion cmplt; -- } sync; /* synchronous response */ -- } u; -- --}; -- --struct vchiq_mmal_instance { -- VCHI_SERVICE_HANDLE_T handle; -- -- /* ensure serialised access to service */ -- struct mutex vchiq_mutex; -- -- /* vmalloc page to receive scratch bulk xfers into */ -- void *bulk_scratch; -- -- struct idr context_map; -- /* protect accesses to context_map */ -- struct mutex context_map_lock; -- -- /* component to use next */ -- int component_idx; -- struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS]; -- -- /* ordered workqueue to process all bulk operations */ -- struct workqueue_struct *bulk_wq; --}; -- --static struct mmal_msg_context * --get_msg_context(struct vchiq_mmal_instance *instance) --{ -- struct mmal_msg_context *msg_context; -- int handle; -- -- /* todo: should this be allocated from a pool to avoid kzalloc */ -- msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL); -- -- if (!msg_context) -- return ERR_PTR(-ENOMEM); -- -- /* Create an ID that will be passed along with our message so -- * that when we service the VCHI reply, we can look up what -- * message is being replied to. -- */ -- mutex_lock(&instance->context_map_lock); -- handle = idr_alloc(&instance->context_map, msg_context, -- 0, 0, GFP_KERNEL); -- mutex_unlock(&instance->context_map_lock); -- -- if (handle < 0) { -- kfree(msg_context); -- return ERR_PTR(handle); -- } -- -- msg_context->instance = instance; -- msg_context->handle = handle; -- -- return msg_context; --} -- --static struct mmal_msg_context * --lookup_msg_context(struct vchiq_mmal_instance *instance, int handle) --{ -- return idr_find(&instance->context_map, handle); --} -- --static void --release_msg_context(struct mmal_msg_context *msg_context) --{ -- struct vchiq_mmal_instance *instance = msg_context->instance; -- -- mutex_lock(&instance->context_map_lock); -- idr_remove(&instance->context_map, msg_context->handle); -- mutex_unlock(&instance->context_map_lock); -- kfree(msg_context); --} -- --/* deals with receipt of event to host message */ --static void event_to_host_cb(struct vchiq_mmal_instance *instance, -- struct mmal_msg *msg, u32 msg_len) --{ -- pr_debug("unhandled event\n"); -- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n", -- msg->u.event_to_host.client_component, -- msg->u.event_to_host.port_type, -- msg->u.event_to_host.port_num, -- msg->u.event_to_host.cmd, msg->u.event_to_host.length); --} -- --/* workqueue scheduled callback -- * -- * we do this because it is important we do not call any other vchiq -- * sync calls from witin the message delivery thread -- */ --static void buffer_work_cb(struct work_struct *work) --{ -- struct mmal_msg_context *msg_context = -- container_of(work, struct mmal_msg_context, u.bulk.work); -- -- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); -- -- msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, -- msg_context->u.bulk.port, -- msg_context->u.bulk.status, -- msg_context->u.bulk.buffer, -- msg_context->u.bulk.buffer_used, -- msg_context->u.bulk.mmal_flags, -- msg_context->u.bulk.dts, -- msg_context->u.bulk.pts); --} -- --/* workqueue scheduled callback to handle receiving buffers -- * -- * VCHI will allow up to 4 bulk receives to be scheduled before blocking. -- * If we block in the service_callback context then we can't process the -- * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked -- * vchi_bulk_queue_receive() call to complete. -- */ --static void buffer_to_host_work_cb(struct work_struct *work) --{ -- struct mmal_msg_context *msg_context = -- container_of(work, struct mmal_msg_context, -- u.bulk.buffer_to_host_work); -- struct vchiq_mmal_instance *instance = msg_context->instance; -- unsigned long len = msg_context->u.bulk.buffer_used; -- int ret; -- -- if (!len) -- /* Dummy receive to ensure the buffers remain in order */ -- len = 8; -- /* queue the bulk submission */ -- vchi_service_use(instance->handle); -- ret = vchi_bulk_queue_receive(instance->handle, -- msg_context->u.bulk.buffer->buffer, -- /* Actual receive needs to be a multiple -- * of 4 bytes -- */ -- (len + 3) & ~3, -- VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | -- VCHI_FLAGS_BLOCK_UNTIL_QUEUED, -- msg_context); -- -- vchi_service_release(instance->handle); -- -- if (ret != 0) -- pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n", -- __func__, msg_context, ret); --} -- --/* enqueue a bulk receive for a given message context */ --static int bulk_receive(struct vchiq_mmal_instance *instance, -- struct mmal_msg *msg, -- struct mmal_msg_context *msg_context) --{ -- unsigned long rd_len; -- -- rd_len = msg->u.buffer_from_host.buffer_header.length; -- -- if (!msg_context->u.bulk.buffer) { -- pr_err("bulk.buffer not configured - error in buffer_from_host\n"); -- -- /* todo: this is a serious error, we should never have -- * committed a buffer_to_host operation to the mmal -- * port without the buffer to back it up (underflow -- * handling) and there is no obvious way to deal with -- * this - how is the mmal servie going to react when -- * we fail to do the xfer and reschedule a buffer when -- * it arrives? perhaps a starved flag to indicate a -- * waiting bulk receive? -- */ -- -- return -EINVAL; -- } -- -- /* ensure we do not overrun the available buffer */ -- if (rd_len > msg_context->u.bulk.buffer->buffer_size) { -- rd_len = msg_context->u.bulk.buffer->buffer_size; -- pr_warn("short read as not enough receive buffer space\n"); -- /* todo: is this the correct response, what happens to -- * the rest of the message data? -- */ -- } -- -- /* store length */ -- msg_context->u.bulk.buffer_used = rd_len; -- msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts; -- msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts; -- -- queue_work(msg_context->instance->bulk_wq, -- &msg_context->u.bulk.buffer_to_host_work); -- -- return 0; --} -- --/* data in message, memcpy from packet into output buffer */ --static int inline_receive(struct vchiq_mmal_instance *instance, -- struct mmal_msg *msg, -- struct mmal_msg_context *msg_context) --{ -- memcpy(msg_context->u.bulk.buffer->buffer, -- msg->u.buffer_from_host.short_data, -- msg->u.buffer_from_host.payload_in_message); -- -- msg_context->u.bulk.buffer_used = -- msg->u.buffer_from_host.payload_in_message; -- -- return 0; --} -- --/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */ --static int --buffer_from_host(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, struct mmal_buffer *buf) --{ -- struct mmal_msg_context *msg_context; -- struct mmal_msg m; -- int ret; -- -- if (!port->enabled) -- return -EINVAL; -- -- pr_debug("instance:%p buffer:%p\n", instance->handle, buf); -- -- /* get context */ -- if (!buf->msg_context) { -- pr_err("%s: msg_context not allocated, buf %p\n", __func__, -- buf); -- return -EINVAL; -- } -- msg_context = buf->msg_context; -- -- /* store bulk message context for when data arrives */ -- msg_context->u.bulk.instance = instance; -- msg_context->u.bulk.port = port; -- msg_context->u.bulk.buffer = buf; -- msg_context->u.bulk.buffer_used = 0; -- -- /* initialise work structure ready to schedule callback */ -- INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb); -- INIT_WORK(&msg_context->u.bulk.buffer_to_host_work, -- buffer_to_host_work_cb); -- -- atomic_inc(&port->buffers_with_vpu); -- -- /* prep the buffer from host message */ -- memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */ -- -- m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST; -- m.h.magic = MMAL_MAGIC; -- m.h.context = msg_context->handle; -- m.h.status = 0; -- -- /* drvbuf is our private data passed back */ -- m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC; -- m.u.buffer_from_host.drvbuf.component_handle = port->component->handle; -- m.u.buffer_from_host.drvbuf.port_handle = port->handle; -- m.u.buffer_from_host.drvbuf.client_context = msg_context->handle; -- -- /* buffer header */ -- m.u.buffer_from_host.buffer_header.cmd = 0; -- m.u.buffer_from_host.buffer_header.data = -- (u32)(unsigned long)buf->buffer; -- m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; -- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */ -- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */ -- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */ -- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; -- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; -- -- /* clear buffer type sepecific data */ -- memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, -- sizeof(m.u.buffer_from_host.buffer_header_type_specific)); -- -- /* no payload in message */ -- m.u.buffer_from_host.payload_in_message = 0; -- -- vchi_service_use(instance->handle); -- -- ret = vchi_queue_kernel_message(instance->handle, -- &m, -- sizeof(struct mmal_msg_header) + -- sizeof(m.u.buffer_from_host)); -- -- vchi_service_release(instance->handle); -- -- return ret; --} -- --/* deals with receipt of buffer to host message */ --static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, -- struct mmal_msg *msg, u32 msg_len) --{ -- struct mmal_msg_context *msg_context; -- u32 handle; -- -- pr_debug("%s: instance:%p msg:%p msg_len:%d\n", -- __func__, instance, msg, msg_len); -- -- if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) { -- handle = msg->u.buffer_from_host.drvbuf.client_context; -- msg_context = lookup_msg_context(instance, handle); -- -- if (!msg_context) { -- pr_err("drvbuf.client_context(%u) is invalid\n", -- handle); -- return; -- } -- } else { -- pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n"); -- return; -- } -- -- msg_context->u.bulk.mmal_flags = -- msg->u.buffer_from_host.buffer_header.flags; -- -- if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) { -- /* message reception had an error */ -- pr_warn("error %d in reply\n", msg->h.status); -- -- msg_context->u.bulk.status = msg->h.status; -- -- } else if (msg->u.buffer_from_host.buffer_header.length == 0) { -- /* empty buffer */ -- if (msg->u.buffer_from_host.buffer_header.flags & -- MMAL_BUFFER_HEADER_FLAG_EOS) { -- msg_context->u.bulk.status = -- bulk_receive(instance, msg, msg_context); -- if (msg_context->u.bulk.status == 0) -- return; /* successful bulk submission, bulk -- * completion will trigger callback -- */ -- } else { -- /* do callback with empty buffer - not EOS though */ -- msg_context->u.bulk.status = 0; -- msg_context->u.bulk.buffer_used = 0; -- } -- } else if (msg->u.buffer_from_host.payload_in_message == 0) { -- /* data is not in message, queue a bulk receive */ -- msg_context->u.bulk.status = -- bulk_receive(instance, msg, msg_context); -- if (msg_context->u.bulk.status == 0) -- return; /* successful bulk submission, bulk -- * completion will trigger callback -- */ -- -- /* failed to submit buffer, this will end badly */ -- pr_err("error %d on bulk submission\n", -- msg_context->u.bulk.status); -- -- } else if (msg->u.buffer_from_host.payload_in_message <= -- MMAL_VC_SHORT_DATA) { -- /* data payload within message */ -- msg_context->u.bulk.status = inline_receive(instance, msg, -- msg_context); -- } else { -- pr_err("message with invalid short payload\n"); -- -- /* signal error */ -- msg_context->u.bulk.status = -EINVAL; -- msg_context->u.bulk.buffer_used = -- msg->u.buffer_from_host.payload_in_message; -- } -- -- /* schedule the port callback */ -- schedule_work(&msg_context->u.bulk.work); --} -- --static void bulk_receive_cb(struct vchiq_mmal_instance *instance, -- struct mmal_msg_context *msg_context) --{ -- msg_context->u.bulk.status = 0; -- -- /* schedule the port callback */ -- schedule_work(&msg_context->u.bulk.work); --} -- --static void bulk_abort_cb(struct vchiq_mmal_instance *instance, -- struct mmal_msg_context *msg_context) --{ -- pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context); -- -- msg_context->u.bulk.status = -EINTR; -- -- schedule_work(&msg_context->u.bulk.work); --} -- --/* incoming event service callback */ --static void service_callback(void *param, -- const VCHI_CALLBACK_REASON_T reason, -- void *bulk_ctx) --{ -- struct vchiq_mmal_instance *instance = param; -- int status; -- u32 msg_len; -- struct mmal_msg *msg; -- struct vchi_held_msg msg_handle; -- struct mmal_msg_context *msg_context; -- -- if (!instance) { -- pr_err("Message callback passed NULL instance\n"); -- return; -- } -- -- switch (reason) { -- case VCHI_CALLBACK_MSG_AVAILABLE: -- status = vchi_msg_hold(instance->handle, (void **)&msg, -- &msg_len, VCHI_FLAGS_NONE, &msg_handle); -- if (status) { -- pr_err("Unable to dequeue a message (%d)\n", status); -- break; -- } -- -- DBG_DUMP_MSG(msg, msg_len, "<<< reply message"); -- -- /* handling is different for buffer messages */ -- switch (msg->h.type) { -- case MMAL_MSG_TYPE_BUFFER_FROM_HOST: -- vchi_held_msg_release(&msg_handle); -- break; -- -- case MMAL_MSG_TYPE_EVENT_TO_HOST: -- event_to_host_cb(instance, msg, msg_len); -- vchi_held_msg_release(&msg_handle); -- -- break; -- -- case MMAL_MSG_TYPE_BUFFER_TO_HOST: -- buffer_to_host_cb(instance, msg, msg_len); -- vchi_held_msg_release(&msg_handle); -- break; -- -- default: -- /* messages dependent on header context to complete */ -- if (!msg->h.context) { -- pr_err("received message context was null!\n"); -- vchi_held_msg_release(&msg_handle); -- break; -- } -- -- msg_context = lookup_msg_context(instance, -- msg->h.context); -- if (!msg_context) { -- pr_err("received invalid message context %u!\n", -- msg->h.context); -- vchi_held_msg_release(&msg_handle); -- break; -- } -- -- /* fill in context values */ -- msg_context->u.sync.msg_handle = msg_handle; -- msg_context->u.sync.msg = msg; -- msg_context->u.sync.msg_len = msg_len; -- -- /* todo: should this check (completion_done() -- * == 1) for no one waiting? or do we need a -- * flag to tell us the completion has been -- * interrupted so we can free the message and -- * its context. This probably also solves the -- * message arriving after interruption todo -- * below -- */ -- -- /* complete message so caller knows it happened */ -- complete(&msg_context->u.sync.cmplt); -- break; -- } -- -- break; -- -- case VCHI_CALLBACK_BULK_RECEIVED: -- bulk_receive_cb(instance, bulk_ctx); -- break; -- -- case VCHI_CALLBACK_BULK_RECEIVE_ABORTED: -- bulk_abort_cb(instance, bulk_ctx); -- break; -- -- case VCHI_CALLBACK_SERVICE_CLOSED: -- /* TODO: consider if this requires action if received when -- * driver is not explicitly closing the service -- */ -- break; -- -- default: -- pr_err("Received unhandled message reason %d\n", reason); -- break; -- } --} -- --static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, -- struct mmal_msg *msg, -- unsigned int payload_len, -- struct mmal_msg **msg_out, -- struct vchi_held_msg *msg_handle_out) --{ -- struct mmal_msg_context *msg_context; -- int ret; -- unsigned long timeout; -- -- /* payload size must not cause message to exceed max size */ -- if (payload_len > -- (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) { -- pr_err("payload length %d exceeds max:%d\n", payload_len, -- (int)(MMAL_MSG_MAX_SIZE - -- sizeof(struct mmal_msg_header))); -- return -EINVAL; -- } -- -- msg_context = get_msg_context(instance); -- if (IS_ERR(msg_context)) -- return PTR_ERR(msg_context); -- -- init_completion(&msg_context->u.sync.cmplt); -- -- msg->h.magic = MMAL_MAGIC; -- msg->h.context = msg_context->handle; -- msg->h.status = 0; -- -- DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len), -- ">>> sync message"); -- -- vchi_service_use(instance->handle); -- -- ret = vchi_queue_kernel_message(instance->handle, -- msg, -- sizeof(struct mmal_msg_header) + -- payload_len); -- -- vchi_service_release(instance->handle); -- -- if (ret) { -- pr_err("error %d queuing message\n", ret); -- release_msg_context(msg_context); -- return ret; -- } -- -- timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt, -- 3 * HZ); -- if (timeout == 0) { -- pr_err("timed out waiting for sync completion\n"); -- ret = -ETIME; -- /* todo: what happens if the message arrives after aborting */ -- release_msg_context(msg_context); -- return ret; -- } -- -- *msg_out = msg_context->u.sync.msg; -- *msg_handle_out = msg_context->u.sync.msg_handle; -- release_msg_context(msg_context); -- -- return 0; --} -- --static void dump_port_info(struct vchiq_mmal_port *port) --{ -- pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled); -- -- pr_debug("buffer minimum num:%d size:%d align:%d\n", -- port->minimum_buffer.num, -- port->minimum_buffer.size, port->minimum_buffer.alignment); -- -- pr_debug("buffer recommended num:%d size:%d align:%d\n", -- port->recommended_buffer.num, -- port->recommended_buffer.size, -- port->recommended_buffer.alignment); -- -- pr_debug("buffer current values num:%d size:%d align:%d\n", -- port->current_buffer.num, -- port->current_buffer.size, port->current_buffer.alignment); -- -- pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n", -- port->format.type, -- port->format.encoding, port->format.encoding_variant); -- -- pr_debug(" bitrate:%d flags:0x%x\n", -- port->format.bitrate, port->format.flags); -- -- if (port->format.type == MMAL_ES_TYPE_VIDEO) { -- pr_debug -- ("es video format: width:%d height:%d colourspace:0x%x\n", -- port->es.video.width, port->es.video.height, -- port->es.video.color_space); -- -- pr_debug(" : crop xywh %d,%d,%d,%d\n", -- port->es.video.crop.x, -- port->es.video.crop.y, -- port->es.video.crop.width, port->es.video.crop.height); -- pr_debug(" : framerate %d/%d aspect %d/%d\n", -- port->es.video.frame_rate.num, -- port->es.video.frame_rate.den, -- port->es.video.par.num, port->es.video.par.den); -- } --} -- --static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p) --{ -- /* todo do readonly fields need setting at all? */ -- p->type = port->type; -- p->index = port->index; -- p->index_all = 0; -- p->is_enabled = port->enabled; -- p->buffer_num_min = port->minimum_buffer.num; -- p->buffer_size_min = port->minimum_buffer.size; -- p->buffer_alignment_min = port->minimum_buffer.alignment; -- p->buffer_num_recommended = port->recommended_buffer.num; -- p->buffer_size_recommended = port->recommended_buffer.size; -- -- /* only three writable fields in a port */ -- p->buffer_num = port->current_buffer.num; -- p->buffer_size = port->current_buffer.size; -- p->userdata = (u32)(unsigned long)port; --} -- --static int port_info_set(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- pr_debug("setting port info port %p\n", port); -- if (!port) -- return -1; -- dump_port_info(port); -- -- m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET; -- -- m.u.port_info_set.component_handle = port->component->handle; -- m.u.port_info_set.port_type = port->type; -- m.u.port_info_set.port_index = port->index; -- -- port_to_mmal_msg(port, &m.u.port_info_set.port); -- -- /* elementary stream format setup */ -- m.u.port_info_set.format.type = port->format.type; -- m.u.port_info_set.format.encoding = port->format.encoding; -- m.u.port_info_set.format.encoding_variant = -- port->format.encoding_variant; -- m.u.port_info_set.format.bitrate = port->format.bitrate; -- m.u.port_info_set.format.flags = port->format.flags; -- -- memcpy(&m.u.port_info_set.es, &port->es, -- sizeof(union mmal_es_specific_format)); -- -- m.u.port_info_set.format.extradata_size = port->format.extradata_size; -- memcpy(&m.u.port_info_set.extradata, port->format.extradata, -- port->format.extradata_size); -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.port_info_set), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- /* return operation status */ -- ret = -rmsg->u.port_info_get_reply.status; -- -- pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret, -- port->component->handle, port->handle); -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* use port info get message to retrieve port information */ --static int port_info_get(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- /* port info time */ -- m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET; -- m.u.port_info_get.component_handle = port->component->handle; -- m.u.port_info_get.port_type = port->type; -- m.u.port_info_get.index = port->index; -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.port_info_get), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- /* return operation status */ -- ret = -rmsg->u.port_info_get_reply.status; -- if (ret != MMAL_MSG_STATUS_SUCCESS) -- goto release_msg; -- -- if (rmsg->u.port_info_get_reply.port.is_enabled == 0) -- port->enabled = 0; -- else -- port->enabled = 1; -- -- /* copy the values out of the message */ -- port->handle = rmsg->u.port_info_get_reply.port_handle; -- -- /* port type and index cached to use on port info set because -- * it does not use a port handle -- */ -- port->type = rmsg->u.port_info_get_reply.port_type; -- port->index = rmsg->u.port_info_get_reply.port_index; -- -- port->minimum_buffer.num = -- rmsg->u.port_info_get_reply.port.buffer_num_min; -- port->minimum_buffer.size = -- rmsg->u.port_info_get_reply.port.buffer_size_min; -- port->minimum_buffer.alignment = -- rmsg->u.port_info_get_reply.port.buffer_alignment_min; -- -- port->recommended_buffer.alignment = -- rmsg->u.port_info_get_reply.port.buffer_alignment_min; -- port->recommended_buffer.num = -- rmsg->u.port_info_get_reply.port.buffer_num_recommended; -- -- port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num; -- port->current_buffer.size = -- rmsg->u.port_info_get_reply.port.buffer_size; -- -- /* stream format */ -- port->format.type = rmsg->u.port_info_get_reply.format.type; -- port->format.encoding = rmsg->u.port_info_get_reply.format.encoding; -- port->format.encoding_variant = -- rmsg->u.port_info_get_reply.format.encoding_variant; -- port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate; -- port->format.flags = rmsg->u.port_info_get_reply.format.flags; -- -- /* elementary stream format */ -- memcpy(&port->es, -- &rmsg->u.port_info_get_reply.es, -- sizeof(union mmal_es_specific_format)); -- port->format.es = &port->es; -- -- port->format.extradata_size = -- rmsg->u.port_info_get_reply.format.extradata_size; -- memcpy(port->format.extradata, -- rmsg->u.port_info_get_reply.extradata, -- port->format.extradata_size); -- -- pr_debug("received port info\n"); -- dump_port_info(port); -- --release_msg: -- -- pr_debug("%s:result:%d component:0x%x port:%d\n", -- __func__, ret, port->component->handle, port->handle); -- -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* create comonent on vc */ --static int create_component(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component, -- const char *name) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- /* build component create message */ -- m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE; -- m.u.component_create.client_component = (u32)(unsigned long)component; -- strncpy(m.u.component_create.name, name, -- sizeof(m.u.component_create.name)); -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.component_create), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != m.h.type) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.component_create_reply.status; -- if (ret != MMAL_MSG_STATUS_SUCCESS) -- goto release_msg; -- -- /* a valid component response received */ -- component->handle = rmsg->u.component_create_reply.component_handle; -- component->inputs = rmsg->u.component_create_reply.input_num; -- component->outputs = rmsg->u.component_create_reply.output_num; -- component->clocks = rmsg->u.component_create_reply.clock_num; -- -- pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n", -- component->handle, -- component->inputs, component->outputs, component->clocks); -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* destroys a component on vc */ --static int destroy_component(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY; -- m.u.component_destroy.component_handle = component->handle; -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.component_destroy), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != m.h.type) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.component_destroy_reply.status; -- --release_msg: -- -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* enable a component on vc */ --static int enable_component(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE; -- m.u.component_enable.component_handle = component->handle; -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.component_enable), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != m.h.type) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.component_enable_reply.status; -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* disable a component on vc */ --static int disable_component(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE; -- m.u.component_disable.component_handle = component->handle; -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.component_disable), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != m.h.type) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.component_disable_reply.status; -- --release_msg: -- -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* get version of mmal implementation */ --static int get_version(struct vchiq_mmal_instance *instance, -- u32 *major_out, u32 *minor_out) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_GET_VERSION; -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.version), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != m.h.type) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- *major_out = rmsg->u.version.major; -- *minor_out = rmsg->u.version.minor; -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* do a port action with a port as a parameter */ --static int port_action_port(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- enum mmal_msg_port_action_type action_type) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_PORT_ACTION; -- m.u.port_action_port.component_handle = port->component->handle; -- m.u.port_action_port.port_handle = port->handle; -- m.u.port_action_port.action = action_type; -- -- port_to_mmal_msg(port, &m.u.port_action_port.port); -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.port_action_port), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.port_action_reply.status; -- -- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n", -- __func__, -- ret, port->component->handle, port->handle, -- port_action_type_names[action_type], action_type); -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* do a port action with handles as parameters */ --static int port_action_handle(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- enum mmal_msg_port_action_type action_type, -- u32 connect_component_handle, -- u32 connect_port_handle) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_PORT_ACTION; -- -- m.u.port_action_handle.component_handle = port->component->handle; -- m.u.port_action_handle.port_handle = port->handle; -- m.u.port_action_handle.action = action_type; -- -- m.u.port_action_handle.connect_component_handle = -- connect_component_handle; -- m.u.port_action_handle.connect_port_handle = connect_port_handle; -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(m.u.port_action_handle), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.port_action_reply.status; -- -- pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n", -- __func__, -- ret, port->component->handle, port->handle, -- port_action_type_names[action_type], -- action_type, connect_component_handle, connect_port_handle); -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --static int port_parameter_set(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- u32 parameter_id, void *value, u32 value_size) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET; -- -- m.u.port_parameter_set.component_handle = port->component->handle; -- m.u.port_parameter_set.port_handle = port->handle; -- m.u.port_parameter_set.id = parameter_id; -- m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size; -- memcpy(&m.u.port_parameter_set.value, value, value_size); -- -- ret = send_synchronous_mmal_msg(instance, &m, -- (4 * sizeof(u32)) + value_size, -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) { -- /* got an unexpected message type in reply */ -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.port_parameter_set_reply.status; -- -- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", -- __func__, -- ret, port->component->handle, port->handle, parameter_id); -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --static int port_parameter_get(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- u32 parameter_id, void *value, u32 *value_size) --{ -- int ret; -- struct mmal_msg m; -- struct mmal_msg *rmsg; -- struct vchi_held_msg rmsg_handle; -- -- m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET; -- -- m.u.port_parameter_get.component_handle = port->component->handle; -- m.u.port_parameter_get.port_handle = port->handle; -- m.u.port_parameter_get.id = parameter_id; -- m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size; -- -- ret = send_synchronous_mmal_msg(instance, &m, -- sizeof(struct -- mmal_msg_port_parameter_get), -- &rmsg, &rmsg_handle); -- if (ret) -- return ret; -- -- if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) { -- /* got an unexpected message type in reply */ -- pr_err("Incorrect reply type %d\n", rmsg->h.type); -- ret = -EINVAL; -- goto release_msg; -- } -- -- ret = -rmsg->u.port_parameter_get_reply.status; -- /* port_parameter_get_reply.size includes the header, -- * whilst *value_size doesn't. -- */ -- rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32)); -- -- if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) { -- /* Copy only as much as we have space for -- * but report true size of parameter -- */ -- memcpy(value, &rmsg->u.port_parameter_get_reply.value, -- *value_size); -- *value_size = rmsg->u.port_parameter_get_reply.size; -- } else { -- memcpy(value, &rmsg->u.port_parameter_get_reply.value, -- rmsg->u.port_parameter_get_reply.size); -- } -- -- pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, -- ret, port->component->handle, port->handle, parameter_id); -- --release_msg: -- vchi_held_msg_release(&rmsg_handle); -- -- return ret; --} -- --/* disables a port and drains buffers from it */ --static int port_disable(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port) --{ -- int ret; -- struct list_head *q, *buf_head; -- unsigned long flags = 0; -- -- if (!port->enabled) -- return 0; -- -- port->enabled = 0; -- -- ret = port_action_port(instance, port, -- MMAL_MSG_PORT_ACTION_TYPE_DISABLE); -- if (ret == 0) { -- /* -- * Drain all queued buffers on port. This should only -- * apply to buffers that have been queued before the port -- * has been enabled. If the port has been enabled and buffers -- * passed, then the buffers should have been removed from this -- * list, and we should get the relevant callbacks via VCHIQ -- * to release the buffers. -- */ -- spin_lock_irqsave(&port->slock, flags); -- -- list_for_each_safe(buf_head, q, &port->buffers) { -- struct mmal_buffer *mmalbuf; -- -- mmalbuf = list_entry(buf_head, struct mmal_buffer, -- list); -- list_del(buf_head); -- if (port->buffer_cb) -- port->buffer_cb(instance, -- port, 0, mmalbuf, 0, 0, -- MMAL_TIME_UNKNOWN, -- MMAL_TIME_UNKNOWN); -- } -- -- spin_unlock_irqrestore(&port->slock, flags); -- -- ret = port_info_get(instance, port); -- } -- -- return ret; --} -- --/* enable a port */ --static int port_enable(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port) --{ -- unsigned int hdr_count; -- struct list_head *q, *buf_head; -- int ret; -- -- if (port->enabled) -- return 0; -- -- ret = port_action_port(instance, port, -- MMAL_MSG_PORT_ACTION_TYPE_ENABLE); -- if (ret) -- goto done; -- -- port->enabled = 1; -- -- if (port->buffer_cb) { -- /* send buffer headers to videocore */ -- hdr_count = 1; -- list_for_each_safe(buf_head, q, &port->buffers) { -- struct mmal_buffer *mmalbuf; -- -- mmalbuf = list_entry(buf_head, struct mmal_buffer, -- list); -- ret = buffer_from_host(instance, port, mmalbuf); -- if (ret) -- goto done; -- -- list_del(buf_head); -- hdr_count++; -- if (hdr_count > port->current_buffer.num) -- break; -- } -- } -- -- ret = port_info_get(instance, port); -- --done: -- return ret; --} -- --/* ------------------------------------------------------------------ -- * Exported API -- *------------------------------------------------------------------ -- */ -- --int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- ret = port_info_set(instance, port); -- if (ret) -- goto release_unlock; -- -- /* read what has actually been set */ -- ret = port_info_get(instance, port); -- --release_unlock: -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- u32 parameter, void *value, u32 value_size) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- ret = port_parameter_set(instance, port, parameter, value, value_size); -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- u32 parameter, void *value, u32 *value_size) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- ret = port_parameter_get(instance, port, parameter, value, value_size); -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --/* enable a port -- * -- * enables a port and queues buffers for satisfying callbacks if we -- * provide a callback handler -- */ --int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- vchiq_mmal_buffer_cb buffer_cb) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- /* already enabled - noop */ -- if (port->enabled) { -- ret = 0; -- goto unlock; -- } -- -- port->buffer_cb = buffer_cb; -- -- ret = port_enable(instance, port); -- --unlock: -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- if (!port->enabled) { -- mutex_unlock(&instance->vchiq_mutex); -- return 0; -- } -- -- ret = port_disable(instance, port); -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --/* ports will be connected in a tunneled manner so data buffers -- * are not handled by client. -- */ --int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *src, -- struct vchiq_mmal_port *dst) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- /* disconnect ports if connected */ -- if (src->connected) { -- ret = port_disable(instance, src); -- if (ret) { -- pr_err("failed disabling src port(%d)\n", ret); -- goto release_unlock; -- } -- -- /* do not need to disable the destination port as they -- * are connected and it is done automatically -- */ -- -- ret = port_action_handle(instance, src, -- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, -- src->connected->component->handle, -- src->connected->handle); -- if (ret < 0) { -- pr_err("failed disconnecting src port\n"); -- goto release_unlock; -- } -- src->connected->enabled = 0; -- src->connected = NULL; -- } -- -- if (!dst) { -- /* do not make new connection */ -- ret = 0; -- pr_debug("not making new connection\n"); -- goto release_unlock; -- } -- -- /* copy src port format to dst */ -- dst->format.encoding = src->format.encoding; -- dst->es.video.width = src->es.video.width; -- dst->es.video.height = src->es.video.height; -- dst->es.video.crop.x = src->es.video.crop.x; -- dst->es.video.crop.y = src->es.video.crop.y; -- dst->es.video.crop.width = src->es.video.crop.width; -- dst->es.video.crop.height = src->es.video.crop.height; -- dst->es.video.frame_rate.num = src->es.video.frame_rate.num; -- dst->es.video.frame_rate.den = src->es.video.frame_rate.den; -- -- /* set new format */ -- ret = port_info_set(instance, dst); -- if (ret) { -- pr_debug("setting port info failed\n"); -- goto release_unlock; -- } -- -- /* read what has actually been set */ -- ret = port_info_get(instance, dst); -- if (ret) { -- pr_debug("read back port info failed\n"); -- goto release_unlock; -- } -- -- /* connect two ports together */ -- ret = port_action_handle(instance, src, -- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, -- dst->component->handle, dst->handle); -- if (ret < 0) { -- pr_debug("connecting port %d:%d to %d:%d failed\n", -- src->component->handle, src->handle, -- dst->component->handle, dst->handle); -- goto release_unlock; -- } -- src->connected = dst; -- --release_unlock: -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- struct mmal_buffer *buffer) --{ -- unsigned long flags = 0; -- int ret; -- -- ret = buffer_from_host(instance, port, buffer); -- if (ret == -EINVAL) { -- /* Port is disabled. Queue for when it is enabled. */ -- spin_lock_irqsave(&port->slock, flags); -- list_add_tail(&buffer->list, &port->buffers); -- spin_unlock_irqrestore(&port->slock, flags); -- } -- -- return 0; --} -- --int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, -- struct mmal_buffer *buf) --{ -- struct mmal_msg_context *msg_context = get_msg_context(instance); -- -- if (IS_ERR(msg_context)) -- return (PTR_ERR(msg_context)); -- -- buf->msg_context = msg_context; -- return 0; --} -- --int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) --{ -- struct mmal_msg_context *msg_context = buf->msg_context; -- -- if (msg_context) -- release_msg_context(msg_context); -- buf->msg_context = NULL; -- -- return 0; --} -- --/* Initialise a mmal component and its ports -- * -- */ --int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, -- const char *name, -- struct vchiq_mmal_component **component_out) --{ -- int ret; -- int idx; /* port index */ -- struct vchiq_mmal_component *component; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) { -- ret = -EINVAL; /* todo is this correct error? */ -- goto unlock; -- } -- -- component = &instance->component[instance->component_idx]; -- -- ret = create_component(instance, component, name); -- if (ret < 0) { -- pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", -- __func__, ret); -- goto unlock; -- } -- -- /* ports info needs gathering */ -- component->control.type = MMAL_PORT_TYPE_CONTROL; -- component->control.index = 0; -- component->control.component = component; -- spin_lock_init(&component->control.slock); -- INIT_LIST_HEAD(&component->control.buffers); -- ret = port_info_get(instance, &component->control); -- if (ret < 0) -- goto release_component; -- -- for (idx = 0; idx < component->inputs; idx++) { -- component->input[idx].type = MMAL_PORT_TYPE_INPUT; -- component->input[idx].index = idx; -- component->input[idx].component = component; -- spin_lock_init(&component->input[idx].slock); -- INIT_LIST_HEAD(&component->input[idx].buffers); -- ret = port_info_get(instance, &component->input[idx]); -- if (ret < 0) -- goto release_component; -- } -- -- for (idx = 0; idx < component->outputs; idx++) { -- component->output[idx].type = MMAL_PORT_TYPE_OUTPUT; -- component->output[idx].index = idx; -- component->output[idx].component = component; -- spin_lock_init(&component->output[idx].slock); -- INIT_LIST_HEAD(&component->output[idx].buffers); -- ret = port_info_get(instance, &component->output[idx]); -- if (ret < 0) -- goto release_component; -- } -- -- for (idx = 0; idx < component->clocks; idx++) { -- component->clock[idx].type = MMAL_PORT_TYPE_CLOCK; -- component->clock[idx].index = idx; -- component->clock[idx].component = component; -- spin_lock_init(&component->clock[idx].slock); -- INIT_LIST_HEAD(&component->clock[idx].buffers); -- ret = port_info_get(instance, &component->clock[idx]); -- if (ret < 0) -- goto release_component; -- } -- -- instance->component_idx++; -- -- *component_out = component; -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return 0; -- --release_component: -- destroy_component(instance, component); --unlock: -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --/* -- * cause a mmal component to be destroyed -- */ --int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- if (component->enabled) -- ret = disable_component(instance, component); -- -- ret = destroy_component(instance, component); -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --/* -- * cause a mmal component to be enabled -- */ --int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- if (component->enabled) { -- mutex_unlock(&instance->vchiq_mutex); -- return 0; -- } -- -- ret = enable_component(instance, component); -- if (ret == 0) -- component->enabled = true; -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --/* -- * cause a mmal component to be enabled -- */ --int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- if (!component->enabled) { -- mutex_unlock(&instance->vchiq_mutex); -- return 0; -- } -- -- ret = disable_component(instance, component); -- if (ret == 0) -- component->enabled = 0; -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --int vchiq_mmal_version(struct vchiq_mmal_instance *instance, -- u32 *major_out, u32 *minor_out) --{ -- int ret; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- ret = get_version(instance, major_out, minor_out); -- -- mutex_unlock(&instance->vchiq_mutex); -- -- return ret; --} -- --int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance) --{ -- int status = 0; -- -- if (!instance) -- return -EINVAL; -- -- if (mutex_lock_interruptible(&instance->vchiq_mutex)) -- return -EINTR; -- -- vchi_service_use(instance->handle); -- -- status = vchi_service_close(instance->handle); -- if (status != 0) -- pr_err("mmal-vchiq: VCHIQ close failed\n"); -- -- mutex_unlock(&instance->vchiq_mutex); -- -- flush_workqueue(instance->bulk_wq); -- destroy_workqueue(instance->bulk_wq); -- -- vfree(instance->bulk_scratch); -- -- idr_destroy(&instance->context_map); -- -- kfree(instance); -- -- return status; --} -- --int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) --{ -- int status; -- struct vchiq_mmal_instance *instance; -- static VCHI_INSTANCE_T vchi_instance; -- struct service_creation params = { -- .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER), -- .service_id = VC_MMAL_SERVER_NAME, -- .callback = service_callback, -- .callback_param = NULL, -- }; -- -- /* compile time checks to ensure structure size as they are -- * directly (de)serialised from memory. -- */ -- -- /* ensure the header structure has packed to the correct size */ -- BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24); -- -- /* ensure message structure does not exceed maximum length */ -- BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE); -- -- /* mmal port struct is correct size */ -- BUILD_BUG_ON(sizeof(struct mmal_port) != 64); -- -- /* create a vchi instance */ -- status = vchi_initialise(&vchi_instance); -- if (status) { -- pr_err("Failed to initialise VCHI instance (status=%d)\n", -- status); -- return -EIO; -- } -- -- status = vchi_connect(vchi_instance); -- if (status) { -- pr_err("Failed to connect VCHI instance (status=%d)\n", status); -- return -EIO; -- } -- -- instance = kzalloc(sizeof(*instance), GFP_KERNEL); -- -- if (!instance) -- return -ENOMEM; -- -- mutex_init(&instance->vchiq_mutex); -- -- instance->bulk_scratch = vmalloc(PAGE_SIZE); -- -- mutex_init(&instance->context_map_lock); -- idr_init_base(&instance->context_map, 1); -- -- params.callback_param = instance; -- -- instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq", -- WQ_MEM_RECLAIM); -- if (!instance->bulk_wq) -- goto err_free; -- -- status = vchi_service_open(vchi_instance, ¶ms, &instance->handle); -- if (status) { -- pr_err("Failed to open VCHI service connection (status=%d)\n", -- status); -- goto err_close_services; -- } -- -- vchi_service_release(instance->handle); -- -- *out_instance = instance; -- -- return 0; -- --err_close_services: -- vchi_service_close(instance->handle); -- destroy_workqueue(instance->bulk_wq); --err_free: -- vfree(instance->bulk_scratch); -- kfree(instance); -- return -ENODEV; --} ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -0,0 +1,1913 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ * -+ * V4L2 driver MMAL vchiq interface code -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mmal-common.h" -+#include "mmal-vchiq.h" -+#include "mmal-msg.h" -+ -+#define USE_VCHIQ_ARM -+#include "interface/vchi/vchi.h" -+ -+MODULE_DESCRIPTION("BCM2835 MMAL VCHIQ interface"); -+MODULE_AUTHOR("Dave Stevenson, "); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION("0.0.1"); -+ -+/* maximum number of components supported */ -+#define VCHIQ_MMAL_MAX_COMPONENTS 4 -+ -+/*#define FULL_MSG_DUMP 1*/ -+ -+#ifdef DEBUG -+static const char *const msg_type_names[] = { -+ "UNKNOWN", -+ "QUIT", -+ "SERVICE_CLOSED", -+ "GET_VERSION", -+ "COMPONENT_CREATE", -+ "COMPONENT_DESTROY", -+ "COMPONENT_ENABLE", -+ "COMPONENT_DISABLE", -+ "PORT_INFO_GET", -+ "PORT_INFO_SET", -+ "PORT_ACTION", -+ "BUFFER_FROM_HOST", -+ "BUFFER_TO_HOST", -+ "GET_STATS", -+ "PORT_PARAMETER_SET", -+ "PORT_PARAMETER_GET", -+ "EVENT_TO_HOST", -+ "GET_CORE_STATS_FOR_PORT", -+ "OPAQUE_ALLOCATOR", -+ "CONSUME_MEM", -+ "LMK", -+ "OPAQUE_ALLOCATOR_DESC", -+ "DRM_GET_LHS32", -+ "DRM_GET_TIME", -+ "BUFFER_FROM_HOST_ZEROLEN", -+ "PORT_FLUSH", -+ "HOST_LOG", -+}; -+#endif -+ -+static const char *const port_action_type_names[] = { -+ "UNKNOWN", -+ "ENABLE", -+ "DISABLE", -+ "FLUSH", -+ "CONNECT", -+ "DISCONNECT", -+ "SET_REQUIREMENTS", -+}; -+ -+#if defined(DEBUG) -+#if defined(FULL_MSG_DUMP) -+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \ -+ do { \ -+ pr_debug(TITLE" type:%s(%d) length:%d\n", \ -+ msg_type_names[(MSG)->h.type], \ -+ (MSG)->h.type, (MSG_LEN)); \ -+ print_hex_dump(KERN_DEBUG, "<h.type], \ -+ (MSG)->h.type, (MSG_LEN)); \ -+ } -+#endif -+#else -+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) -+#endif -+ -+struct vchiq_mmal_instance; -+ -+/* normal message context */ -+struct mmal_msg_context { -+ struct vchiq_mmal_instance *instance; -+ -+ /* Index in the context_map idr so that we can find the -+ * mmal_msg_context again when servicing the VCHI reply. -+ */ -+ int handle; -+ -+ union { -+ struct { -+ /* work struct for buffer_cb callback */ -+ struct work_struct work; -+ /* work struct for deferred callback */ -+ struct work_struct buffer_to_host_work; -+ /* mmal instance */ -+ struct vchiq_mmal_instance *instance; -+ /* mmal port */ -+ struct vchiq_mmal_port *port; -+ /* actual buffer used to store bulk reply */ -+ struct mmal_buffer *buffer; -+ /* amount of buffer used */ -+ unsigned long buffer_used; -+ /* MMAL buffer flags */ -+ u32 mmal_flags; -+ /* Presentation and Decode timestamps */ -+ s64 pts; -+ s64 dts; -+ -+ int status; /* context status */ -+ -+ } bulk; /* bulk data */ -+ -+ struct { -+ /* message handle to release */ -+ struct vchi_held_msg msg_handle; -+ /* pointer to received message */ -+ struct mmal_msg *msg; -+ /* received message length */ -+ u32 msg_len; -+ /* completion upon reply */ -+ struct completion cmplt; -+ } sync; /* synchronous response */ -+ } u; -+ -+}; -+ -+struct vchiq_mmal_instance { -+ VCHI_SERVICE_HANDLE_T handle; -+ -+ /* ensure serialised access to service */ -+ struct mutex vchiq_mutex; -+ -+ /* vmalloc page to receive scratch bulk xfers into */ -+ void *bulk_scratch; -+ -+ struct idr context_map; -+ /* protect accesses to context_map */ -+ struct mutex context_map_lock; -+ -+ /* component to use next */ -+ int component_idx; -+ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS]; -+ -+ /* ordered workqueue to process all bulk operations */ -+ struct workqueue_struct *bulk_wq; -+}; -+ -+static struct mmal_msg_context * -+get_msg_context(struct vchiq_mmal_instance *instance) -+{ -+ struct mmal_msg_context *msg_context; -+ int handle; -+ -+ /* todo: should this be allocated from a pool to avoid kzalloc */ -+ msg_context = kzalloc(sizeof(*msg_context), GFP_KERNEL); -+ -+ if (!msg_context) -+ return ERR_PTR(-ENOMEM); -+ -+ /* Create an ID that will be passed along with our message so -+ * that when we service the VCHI reply, we can look up what -+ * message is being replied to. -+ */ -+ mutex_lock(&instance->context_map_lock); -+ handle = idr_alloc(&instance->context_map, msg_context, -+ 0, 0, GFP_KERNEL); -+ mutex_unlock(&instance->context_map_lock); -+ -+ if (handle < 0) { -+ kfree(msg_context); -+ return ERR_PTR(handle); -+ } -+ -+ msg_context->instance = instance; -+ msg_context->handle = handle; -+ -+ return msg_context; -+} -+ -+static struct mmal_msg_context * -+lookup_msg_context(struct vchiq_mmal_instance *instance, int handle) -+{ -+ return idr_find(&instance->context_map, handle); -+} -+ -+static void -+release_msg_context(struct mmal_msg_context *msg_context) -+{ -+ struct vchiq_mmal_instance *instance = msg_context->instance; -+ -+ mutex_lock(&instance->context_map_lock); -+ idr_remove(&instance->context_map, msg_context->handle); -+ mutex_unlock(&instance->context_map_lock); -+ kfree(msg_context); -+} -+ -+/* deals with receipt of event to host message */ -+static void event_to_host_cb(struct vchiq_mmal_instance *instance, -+ struct mmal_msg *msg, u32 msg_len) -+{ -+ pr_debug("unhandled event\n"); -+ pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n", -+ msg->u.event_to_host.client_component, -+ msg->u.event_to_host.port_type, -+ msg->u.event_to_host.port_num, -+ msg->u.event_to_host.cmd, msg->u.event_to_host.length); -+} -+ -+/* workqueue scheduled callback -+ * -+ * we do this because it is important we do not call any other vchiq -+ * sync calls from witin the message delivery thread -+ */ -+static void buffer_work_cb(struct work_struct *work) -+{ -+ struct mmal_msg_context *msg_context = -+ container_of(work, struct mmal_msg_context, u.bulk.work); -+ -+ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); -+ -+ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, -+ msg_context->u.bulk.port, -+ msg_context->u.bulk.status, -+ msg_context->u.bulk.buffer, -+ msg_context->u.bulk.buffer_used, -+ msg_context->u.bulk.mmal_flags, -+ msg_context->u.bulk.dts, -+ msg_context->u.bulk.pts); -+} -+ -+/* workqueue scheduled callback to handle receiving buffers -+ * -+ * VCHI will allow up to 4 bulk receives to be scheduled before blocking. -+ * If we block in the service_callback context then we can't process the -+ * VCHI_CALLBACK_BULK_RECEIVED message that would otherwise allow the blocked -+ * vchi_bulk_queue_receive() call to complete. -+ */ -+static void buffer_to_host_work_cb(struct work_struct *work) -+{ -+ struct mmal_msg_context *msg_context = -+ container_of(work, struct mmal_msg_context, -+ u.bulk.buffer_to_host_work); -+ struct vchiq_mmal_instance *instance = msg_context->instance; -+ unsigned long len = msg_context->u.bulk.buffer_used; -+ int ret; -+ -+ if (!len) -+ /* Dummy receive to ensure the buffers remain in order */ -+ len = 8; -+ /* queue the bulk submission */ -+ vchi_service_use(instance->handle); -+ ret = vchi_bulk_queue_receive(instance->handle, -+ msg_context->u.bulk.buffer->buffer, -+ /* Actual receive needs to be a multiple -+ * of 4 bytes -+ */ -+ (len + 3) & ~3, -+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | -+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, -+ msg_context); -+ -+ vchi_service_release(instance->handle); -+ -+ if (ret != 0) -+ pr_err("%s: ctx: %p, vchi_bulk_queue_receive failed %d\n", -+ __func__, msg_context, ret); -+} -+ -+/* enqueue a bulk receive for a given message context */ -+static int bulk_receive(struct vchiq_mmal_instance *instance, -+ struct mmal_msg *msg, -+ struct mmal_msg_context *msg_context) -+{ -+ unsigned long rd_len; -+ -+ rd_len = msg->u.buffer_from_host.buffer_header.length; -+ -+ if (!msg_context->u.bulk.buffer) { -+ pr_err("bulk.buffer not configured - error in buffer_from_host\n"); -+ -+ /* todo: this is a serious error, we should never have -+ * committed a buffer_to_host operation to the mmal -+ * port without the buffer to back it up (underflow -+ * handling) and there is no obvious way to deal with -+ * this - how is the mmal servie going to react when -+ * we fail to do the xfer and reschedule a buffer when -+ * it arrives? perhaps a starved flag to indicate a -+ * waiting bulk receive? -+ */ -+ -+ return -EINVAL; -+ } -+ -+ /* ensure we do not overrun the available buffer */ -+ if (rd_len > msg_context->u.bulk.buffer->buffer_size) { -+ rd_len = msg_context->u.bulk.buffer->buffer_size; -+ pr_warn("short read as not enough receive buffer space\n"); -+ /* todo: is this the correct response, what happens to -+ * the rest of the message data? -+ */ -+ } -+ -+ /* store length */ -+ msg_context->u.bulk.buffer_used = rd_len; -+ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts; -+ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts; -+ -+ queue_work(msg_context->instance->bulk_wq, -+ &msg_context->u.bulk.buffer_to_host_work); -+ -+ return 0; -+} -+ -+/* data in message, memcpy from packet into output buffer */ -+static int inline_receive(struct vchiq_mmal_instance *instance, -+ struct mmal_msg *msg, -+ struct mmal_msg_context *msg_context) -+{ -+ memcpy(msg_context->u.bulk.buffer->buffer, -+ msg->u.buffer_from_host.short_data, -+ msg->u.buffer_from_host.payload_in_message); -+ -+ msg_context->u.bulk.buffer_used = -+ msg->u.buffer_from_host.payload_in_message; -+ -+ return 0; -+} -+ -+/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */ -+static int -+buffer_from_host(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, struct mmal_buffer *buf) -+{ -+ struct mmal_msg_context *msg_context; -+ struct mmal_msg m; -+ int ret; -+ -+ if (!port->enabled) -+ return -EINVAL; -+ -+ pr_debug("instance:%p buffer:%p\n", instance->handle, buf); -+ -+ /* get context */ -+ if (!buf->msg_context) { -+ pr_err("%s: msg_context not allocated, buf %p\n", __func__, -+ buf); -+ return -EINVAL; -+ } -+ msg_context = buf->msg_context; -+ -+ /* store bulk message context for when data arrives */ -+ msg_context->u.bulk.instance = instance; -+ msg_context->u.bulk.port = port; -+ msg_context->u.bulk.buffer = buf; -+ msg_context->u.bulk.buffer_used = 0; -+ -+ /* initialise work structure ready to schedule callback */ -+ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb); -+ INIT_WORK(&msg_context->u.bulk.buffer_to_host_work, -+ buffer_to_host_work_cb); -+ -+ atomic_inc(&port->buffers_with_vpu); -+ -+ /* prep the buffer from host message */ -+ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */ -+ -+ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST; -+ m.h.magic = MMAL_MAGIC; -+ m.h.context = msg_context->handle; -+ m.h.status = 0; -+ -+ /* drvbuf is our private data passed back */ -+ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC; -+ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle; -+ m.u.buffer_from_host.drvbuf.port_handle = port->handle; -+ m.u.buffer_from_host.drvbuf.client_context = msg_context->handle; -+ -+ /* buffer header */ -+ m.u.buffer_from_host.buffer_header.cmd = 0; -+ m.u.buffer_from_host.buffer_header.data = -+ (u32)(unsigned long)buf->buffer; -+ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; -+ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */ -+ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */ -+ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */ -+ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; -+ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; -+ -+ /* clear buffer type sepecific data */ -+ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, -+ sizeof(m.u.buffer_from_host.buffer_header_type_specific)); -+ -+ /* no payload in message */ -+ m.u.buffer_from_host.payload_in_message = 0; -+ -+ vchi_service_use(instance->handle); -+ -+ ret = vchi_queue_kernel_message(instance->handle, -+ &m, -+ sizeof(struct mmal_msg_header) + -+ sizeof(m.u.buffer_from_host)); -+ -+ vchi_service_release(instance->handle); -+ -+ return ret; -+} -+ -+/* deals with receipt of buffer to host message */ -+static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, -+ struct mmal_msg *msg, u32 msg_len) -+{ -+ struct mmal_msg_context *msg_context; -+ u32 handle; -+ -+ pr_debug("%s: instance:%p msg:%p msg_len:%d\n", -+ __func__, instance, msg, msg_len); -+ -+ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) { -+ handle = msg->u.buffer_from_host.drvbuf.client_context; -+ msg_context = lookup_msg_context(instance, handle); -+ -+ if (!msg_context) { -+ pr_err("drvbuf.client_context(%u) is invalid\n", -+ handle); -+ return; -+ } -+ } else { -+ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n"); -+ return; -+ } -+ -+ msg_context->u.bulk.mmal_flags = -+ msg->u.buffer_from_host.buffer_header.flags; -+ -+ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) { -+ /* message reception had an error */ -+ pr_warn("error %d in reply\n", msg->h.status); -+ -+ msg_context->u.bulk.status = msg->h.status; -+ -+ } else if (msg->u.buffer_from_host.buffer_header.length == 0) { -+ /* empty buffer */ -+ if (msg->u.buffer_from_host.buffer_header.flags & -+ MMAL_BUFFER_HEADER_FLAG_EOS) { -+ msg_context->u.bulk.status = -+ bulk_receive(instance, msg, msg_context); -+ if (msg_context->u.bulk.status == 0) -+ return; /* successful bulk submission, bulk -+ * completion will trigger callback -+ */ -+ } else { -+ /* do callback with empty buffer - not EOS though */ -+ msg_context->u.bulk.status = 0; -+ msg_context->u.bulk.buffer_used = 0; -+ } -+ } else if (msg->u.buffer_from_host.payload_in_message == 0) { -+ /* data is not in message, queue a bulk receive */ -+ msg_context->u.bulk.status = -+ bulk_receive(instance, msg, msg_context); -+ if (msg_context->u.bulk.status == 0) -+ return; /* successful bulk submission, bulk -+ * completion will trigger callback -+ */ -+ -+ /* failed to submit buffer, this will end badly */ -+ pr_err("error %d on bulk submission\n", -+ msg_context->u.bulk.status); -+ -+ } else if (msg->u.buffer_from_host.payload_in_message <= -+ MMAL_VC_SHORT_DATA) { -+ /* data payload within message */ -+ msg_context->u.bulk.status = inline_receive(instance, msg, -+ msg_context); -+ } else { -+ pr_err("message with invalid short payload\n"); -+ -+ /* signal error */ -+ msg_context->u.bulk.status = -EINVAL; -+ msg_context->u.bulk.buffer_used = -+ msg->u.buffer_from_host.payload_in_message; -+ } -+ -+ /* schedule the port callback */ -+ schedule_work(&msg_context->u.bulk.work); -+} -+ -+static void bulk_receive_cb(struct vchiq_mmal_instance *instance, -+ struct mmal_msg_context *msg_context) -+{ -+ msg_context->u.bulk.status = 0; -+ -+ /* schedule the port callback */ -+ schedule_work(&msg_context->u.bulk.work); -+} -+ -+static void bulk_abort_cb(struct vchiq_mmal_instance *instance, -+ struct mmal_msg_context *msg_context) -+{ -+ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context); -+ -+ msg_context->u.bulk.status = -EINTR; -+ -+ schedule_work(&msg_context->u.bulk.work); -+} -+ -+/* incoming event service callback */ -+static void service_callback(void *param, -+ const VCHI_CALLBACK_REASON_T reason, -+ void *bulk_ctx) -+{ -+ struct vchiq_mmal_instance *instance = param; -+ int status; -+ u32 msg_len; -+ struct mmal_msg *msg; -+ struct vchi_held_msg msg_handle; -+ struct mmal_msg_context *msg_context; -+ -+ if (!instance) { -+ pr_err("Message callback passed NULL instance\n"); -+ return; -+ } -+ -+ switch (reason) { -+ case VCHI_CALLBACK_MSG_AVAILABLE: -+ status = vchi_msg_hold(instance->handle, (void **)&msg, -+ &msg_len, VCHI_FLAGS_NONE, &msg_handle); -+ if (status) { -+ pr_err("Unable to dequeue a message (%d)\n", status); -+ break; -+ } -+ -+ DBG_DUMP_MSG(msg, msg_len, "<<< reply message"); -+ -+ /* handling is different for buffer messages */ -+ switch (msg->h.type) { -+ case MMAL_MSG_TYPE_BUFFER_FROM_HOST: -+ vchi_held_msg_release(&msg_handle); -+ break; -+ -+ case MMAL_MSG_TYPE_EVENT_TO_HOST: -+ event_to_host_cb(instance, msg, msg_len); -+ vchi_held_msg_release(&msg_handle); -+ -+ break; -+ -+ case MMAL_MSG_TYPE_BUFFER_TO_HOST: -+ buffer_to_host_cb(instance, msg, msg_len); -+ vchi_held_msg_release(&msg_handle); -+ break; -+ -+ default: -+ /* messages dependent on header context to complete */ -+ if (!msg->h.context) { -+ pr_err("received message context was null!\n"); -+ vchi_held_msg_release(&msg_handle); -+ break; -+ } -+ -+ msg_context = lookup_msg_context(instance, -+ msg->h.context); -+ if (!msg_context) { -+ pr_err("received invalid message context %u!\n", -+ msg->h.context); -+ vchi_held_msg_release(&msg_handle); -+ break; -+ } -+ -+ /* fill in context values */ -+ msg_context->u.sync.msg_handle = msg_handle; -+ msg_context->u.sync.msg = msg; -+ msg_context->u.sync.msg_len = msg_len; -+ -+ /* todo: should this check (completion_done() -+ * == 1) for no one waiting? or do we need a -+ * flag to tell us the completion has been -+ * interrupted so we can free the message and -+ * its context. This probably also solves the -+ * message arriving after interruption todo -+ * below -+ */ -+ -+ /* complete message so caller knows it happened */ -+ complete(&msg_context->u.sync.cmplt); -+ break; -+ } -+ -+ break; -+ -+ case VCHI_CALLBACK_BULK_RECEIVED: -+ bulk_receive_cb(instance, bulk_ctx); -+ break; -+ -+ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED: -+ bulk_abort_cb(instance, bulk_ctx); -+ break; -+ -+ case VCHI_CALLBACK_SERVICE_CLOSED: -+ /* TODO: consider if this requires action if received when -+ * driver is not explicitly closing the service -+ */ -+ break; -+ -+ default: -+ pr_err("Received unhandled message reason %d\n", reason); -+ break; -+ } -+} -+ -+static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, -+ struct mmal_msg *msg, -+ unsigned int payload_len, -+ struct mmal_msg **msg_out, -+ struct vchi_held_msg *msg_handle_out) -+{ -+ struct mmal_msg_context *msg_context; -+ int ret; -+ unsigned long timeout; -+ -+ /* payload size must not cause message to exceed max size */ -+ if (payload_len > -+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) { -+ pr_err("payload length %d exceeds max:%d\n", payload_len, -+ (int)(MMAL_MSG_MAX_SIZE - -+ sizeof(struct mmal_msg_header))); -+ return -EINVAL; -+ } -+ -+ msg_context = get_msg_context(instance); -+ if (IS_ERR(msg_context)) -+ return PTR_ERR(msg_context); -+ -+ init_completion(&msg_context->u.sync.cmplt); -+ -+ msg->h.magic = MMAL_MAGIC; -+ msg->h.context = msg_context->handle; -+ msg->h.status = 0; -+ -+ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len), -+ ">>> sync message"); -+ -+ vchi_service_use(instance->handle); -+ -+ ret = vchi_queue_kernel_message(instance->handle, -+ msg, -+ sizeof(struct mmal_msg_header) + -+ payload_len); -+ -+ vchi_service_release(instance->handle); -+ -+ if (ret) { -+ pr_err("error %d queuing message\n", ret); -+ release_msg_context(msg_context); -+ return ret; -+ } -+ -+ timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt, -+ 3 * HZ); -+ if (timeout == 0) { -+ pr_err("timed out waiting for sync completion\n"); -+ ret = -ETIME; -+ /* todo: what happens if the message arrives after aborting */ -+ release_msg_context(msg_context); -+ return ret; -+ } -+ -+ *msg_out = msg_context->u.sync.msg; -+ *msg_handle_out = msg_context->u.sync.msg_handle; -+ release_msg_context(msg_context); -+ -+ return 0; -+} -+ -+static void dump_port_info(struct vchiq_mmal_port *port) -+{ -+ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled); -+ -+ pr_debug("buffer minimum num:%d size:%d align:%d\n", -+ port->minimum_buffer.num, -+ port->minimum_buffer.size, port->minimum_buffer.alignment); -+ -+ pr_debug("buffer recommended num:%d size:%d align:%d\n", -+ port->recommended_buffer.num, -+ port->recommended_buffer.size, -+ port->recommended_buffer.alignment); -+ -+ pr_debug("buffer current values num:%d size:%d align:%d\n", -+ port->current_buffer.num, -+ port->current_buffer.size, port->current_buffer.alignment); -+ -+ pr_debug("elementary stream: type:%d encoding:0x%x variant:0x%x\n", -+ port->format.type, -+ port->format.encoding, port->format.encoding_variant); -+ -+ pr_debug(" bitrate:%d flags:0x%x\n", -+ port->format.bitrate, port->format.flags); -+ -+ if (port->format.type == MMAL_ES_TYPE_VIDEO) { -+ pr_debug -+ ("es video format: width:%d height:%d colourspace:0x%x\n", -+ port->es.video.width, port->es.video.height, -+ port->es.video.color_space); -+ -+ pr_debug(" : crop xywh %d,%d,%d,%d\n", -+ port->es.video.crop.x, -+ port->es.video.crop.y, -+ port->es.video.crop.width, port->es.video.crop.height); -+ pr_debug(" : framerate %d/%d aspect %d/%d\n", -+ port->es.video.frame_rate.num, -+ port->es.video.frame_rate.den, -+ port->es.video.par.num, port->es.video.par.den); -+ } -+} -+ -+static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p) -+{ -+ /* todo do readonly fields need setting at all? */ -+ p->type = port->type; -+ p->index = port->index; -+ p->index_all = 0; -+ p->is_enabled = port->enabled; -+ p->buffer_num_min = port->minimum_buffer.num; -+ p->buffer_size_min = port->minimum_buffer.size; -+ p->buffer_alignment_min = port->minimum_buffer.alignment; -+ p->buffer_num_recommended = port->recommended_buffer.num; -+ p->buffer_size_recommended = port->recommended_buffer.size; -+ -+ /* only three writable fields in a port */ -+ p->buffer_num = port->current_buffer.num; -+ p->buffer_size = port->current_buffer.size; -+ p->userdata = (u32)(unsigned long)port; -+} -+ -+static int port_info_set(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ pr_debug("setting port info port %p\n", port); -+ if (!port) -+ return -1; -+ dump_port_info(port); -+ -+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET; -+ -+ m.u.port_info_set.component_handle = port->component->handle; -+ m.u.port_info_set.port_type = port->type; -+ m.u.port_info_set.port_index = port->index; -+ -+ port_to_mmal_msg(port, &m.u.port_info_set.port); -+ -+ /* elementary stream format setup */ -+ m.u.port_info_set.format.type = port->format.type; -+ m.u.port_info_set.format.encoding = port->format.encoding; -+ m.u.port_info_set.format.encoding_variant = -+ port->format.encoding_variant; -+ m.u.port_info_set.format.bitrate = port->format.bitrate; -+ m.u.port_info_set.format.flags = port->format.flags; -+ -+ memcpy(&m.u.port_info_set.es, &port->es, -+ sizeof(union mmal_es_specific_format)); -+ -+ m.u.port_info_set.format.extradata_size = port->format.extradata_size; -+ memcpy(&m.u.port_info_set.extradata, port->format.extradata, -+ port->format.extradata_size); -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.port_info_set), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ /* return operation status */ -+ ret = -rmsg->u.port_info_get_reply.status; -+ -+ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret, -+ port->component->handle, port->handle); -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* use port info get message to retrieve port information */ -+static int port_info_get(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ /* port info time */ -+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET; -+ m.u.port_info_get.component_handle = port->component->handle; -+ m.u.port_info_get.port_type = port->type; -+ m.u.port_info_get.index = port->index; -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.port_info_get), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ /* return operation status */ -+ ret = -rmsg->u.port_info_get_reply.status; -+ if (ret != MMAL_MSG_STATUS_SUCCESS) -+ goto release_msg; -+ -+ if (rmsg->u.port_info_get_reply.port.is_enabled == 0) -+ port->enabled = 0; -+ else -+ port->enabled = 1; -+ -+ /* copy the values out of the message */ -+ port->handle = rmsg->u.port_info_get_reply.port_handle; -+ -+ /* port type and index cached to use on port info set because -+ * it does not use a port handle -+ */ -+ port->type = rmsg->u.port_info_get_reply.port_type; -+ port->index = rmsg->u.port_info_get_reply.port_index; -+ -+ port->minimum_buffer.num = -+ rmsg->u.port_info_get_reply.port.buffer_num_min; -+ port->minimum_buffer.size = -+ rmsg->u.port_info_get_reply.port.buffer_size_min; -+ port->minimum_buffer.alignment = -+ rmsg->u.port_info_get_reply.port.buffer_alignment_min; -+ -+ port->recommended_buffer.alignment = -+ rmsg->u.port_info_get_reply.port.buffer_alignment_min; -+ port->recommended_buffer.num = -+ rmsg->u.port_info_get_reply.port.buffer_num_recommended; -+ -+ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num; -+ port->current_buffer.size = -+ rmsg->u.port_info_get_reply.port.buffer_size; -+ -+ /* stream format */ -+ port->format.type = rmsg->u.port_info_get_reply.format.type; -+ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding; -+ port->format.encoding_variant = -+ rmsg->u.port_info_get_reply.format.encoding_variant; -+ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate; -+ port->format.flags = rmsg->u.port_info_get_reply.format.flags; -+ -+ /* elementary stream format */ -+ memcpy(&port->es, -+ &rmsg->u.port_info_get_reply.es, -+ sizeof(union mmal_es_specific_format)); -+ port->format.es = &port->es; -+ -+ port->format.extradata_size = -+ rmsg->u.port_info_get_reply.format.extradata_size; -+ memcpy(port->format.extradata, -+ rmsg->u.port_info_get_reply.extradata, -+ port->format.extradata_size); -+ -+ pr_debug("received port info\n"); -+ dump_port_info(port); -+ -+release_msg: -+ -+ pr_debug("%s:result:%d component:0x%x port:%d\n", -+ __func__, ret, port->component->handle, port->handle); -+ -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* create comonent on vc */ -+static int create_component(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component, -+ const char *name) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ /* build component create message */ -+ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE; -+ m.u.component_create.client_component = (u32)(unsigned long)component; -+ strncpy(m.u.component_create.name, name, -+ sizeof(m.u.component_create.name)); -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.component_create), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != m.h.type) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.component_create_reply.status; -+ if (ret != MMAL_MSG_STATUS_SUCCESS) -+ goto release_msg; -+ -+ /* a valid component response received */ -+ component->handle = rmsg->u.component_create_reply.component_handle; -+ component->inputs = rmsg->u.component_create_reply.input_num; -+ component->outputs = rmsg->u.component_create_reply.output_num; -+ component->clocks = rmsg->u.component_create_reply.clock_num; -+ -+ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n", -+ component->handle, -+ component->inputs, component->outputs, component->clocks); -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* destroys a component on vc */ -+static int destroy_component(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY; -+ m.u.component_destroy.component_handle = component->handle; -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.component_destroy), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != m.h.type) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.component_destroy_reply.status; -+ -+release_msg: -+ -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* enable a component on vc */ -+static int enable_component(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE; -+ m.u.component_enable.component_handle = component->handle; -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.component_enable), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != m.h.type) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.component_enable_reply.status; -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* disable a component on vc */ -+static int disable_component(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE; -+ m.u.component_disable.component_handle = component->handle; -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.component_disable), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != m.h.type) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.component_disable_reply.status; -+ -+release_msg: -+ -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* get version of mmal implementation */ -+static int get_version(struct vchiq_mmal_instance *instance, -+ u32 *major_out, u32 *minor_out) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_GET_VERSION; -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.version), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != m.h.type) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ *major_out = rmsg->u.version.major; -+ *minor_out = rmsg->u.version.minor; -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* do a port action with a port as a parameter */ -+static int port_action_port(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ enum mmal_msg_port_action_type action_type) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION; -+ m.u.port_action_port.component_handle = port->component->handle; -+ m.u.port_action_port.port_handle = port->handle; -+ m.u.port_action_port.action = action_type; -+ -+ port_to_mmal_msg(port, &m.u.port_action_port.port); -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.port_action_port), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.port_action_reply.status; -+ -+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n", -+ __func__, -+ ret, port->component->handle, port->handle, -+ port_action_type_names[action_type], action_type); -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* do a port action with handles as parameters */ -+static int port_action_handle(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ enum mmal_msg_port_action_type action_type, -+ u32 connect_component_handle, -+ u32 connect_port_handle) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION; -+ -+ m.u.port_action_handle.component_handle = port->component->handle; -+ m.u.port_action_handle.port_handle = port->handle; -+ m.u.port_action_handle.action = action_type; -+ -+ m.u.port_action_handle.connect_component_handle = -+ connect_component_handle; -+ m.u.port_action_handle.connect_port_handle = connect_port_handle; -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(m.u.port_action_handle), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.port_action_reply.status; -+ -+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d) connect component:0x%x connect port:%d\n", -+ __func__, -+ ret, port->component->handle, port->handle, -+ port_action_type_names[action_type], -+ action_type, connect_component_handle, connect_port_handle); -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+static int port_parameter_set(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ u32 parameter_id, void *value, u32 value_size) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET; -+ -+ m.u.port_parameter_set.component_handle = port->component->handle; -+ m.u.port_parameter_set.port_handle = port->handle; -+ m.u.port_parameter_set.id = parameter_id; -+ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size; -+ memcpy(&m.u.port_parameter_set.value, value, value_size); -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ (4 * sizeof(u32)) + value_size, -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) { -+ /* got an unexpected message type in reply */ -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.port_parameter_set_reply.status; -+ -+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", -+ __func__, -+ ret, port->component->handle, port->handle, parameter_id); -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+static int port_parameter_get(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ u32 parameter_id, void *value, u32 *value_size) -+{ -+ int ret; -+ struct mmal_msg m; -+ struct mmal_msg *rmsg; -+ struct vchi_held_msg rmsg_handle; -+ -+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET; -+ -+ m.u.port_parameter_get.component_handle = port->component->handle; -+ m.u.port_parameter_get.port_handle = port->handle; -+ m.u.port_parameter_get.id = parameter_id; -+ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size; -+ -+ ret = send_synchronous_mmal_msg(instance, &m, -+ sizeof(struct -+ mmal_msg_port_parameter_get), -+ &rmsg, &rmsg_handle); -+ if (ret) -+ return ret; -+ -+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) { -+ /* got an unexpected message type in reply */ -+ pr_err("Incorrect reply type %d\n", rmsg->h.type); -+ ret = -EINVAL; -+ goto release_msg; -+ } -+ -+ ret = -rmsg->u.port_parameter_get_reply.status; -+ /* port_parameter_get_reply.size includes the header, -+ * whilst *value_size doesn't. -+ */ -+ rmsg->u.port_parameter_get_reply.size -= (2 * sizeof(u32)); -+ -+ if (ret || rmsg->u.port_parameter_get_reply.size > *value_size) { -+ /* Copy only as much as we have space for -+ * but report true size of parameter -+ */ -+ memcpy(value, &rmsg->u.port_parameter_get_reply.value, -+ *value_size); -+ *value_size = rmsg->u.port_parameter_get_reply.size; -+ } else { -+ memcpy(value, &rmsg->u.port_parameter_get_reply.value, -+ rmsg->u.port_parameter_get_reply.size); -+ } -+ -+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, -+ ret, port->component->handle, port->handle, parameter_id); -+ -+release_msg: -+ vchi_held_msg_release(&rmsg_handle); -+ -+ return ret; -+} -+ -+/* disables a port and drains buffers from it */ -+static int port_disable(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port) -+{ -+ int ret; -+ struct list_head *q, *buf_head; -+ unsigned long flags = 0; -+ -+ if (!port->enabled) -+ return 0; -+ -+ port->enabled = 0; -+ -+ ret = port_action_port(instance, port, -+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE); -+ if (ret == 0) { -+ /* -+ * Drain all queued buffers on port. This should only -+ * apply to buffers that have been queued before the port -+ * has been enabled. If the port has been enabled and buffers -+ * passed, then the buffers should have been removed from this -+ * list, and we should get the relevant callbacks via VCHIQ -+ * to release the buffers. -+ */ -+ spin_lock_irqsave(&port->slock, flags); -+ -+ list_for_each_safe(buf_head, q, &port->buffers) { -+ struct mmal_buffer *mmalbuf; -+ -+ mmalbuf = list_entry(buf_head, struct mmal_buffer, -+ list); -+ list_del(buf_head); -+ if (port->buffer_cb) -+ port->buffer_cb(instance, -+ port, 0, mmalbuf, 0, 0, -+ MMAL_TIME_UNKNOWN, -+ MMAL_TIME_UNKNOWN); -+ } -+ -+ spin_unlock_irqrestore(&port->slock, flags); -+ -+ ret = port_info_get(instance, port); -+ } -+ -+ return ret; -+} -+ -+/* enable a port */ -+static int port_enable(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port) -+{ -+ unsigned int hdr_count; -+ struct list_head *q, *buf_head; -+ int ret; -+ -+ if (port->enabled) -+ return 0; -+ -+ ret = port_action_port(instance, port, -+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE); -+ if (ret) -+ goto done; -+ -+ port->enabled = 1; -+ -+ if (port->buffer_cb) { -+ /* send buffer headers to videocore */ -+ hdr_count = 1; -+ list_for_each_safe(buf_head, q, &port->buffers) { -+ struct mmal_buffer *mmalbuf; -+ -+ mmalbuf = list_entry(buf_head, struct mmal_buffer, -+ list); -+ ret = buffer_from_host(instance, port, mmalbuf); -+ if (ret) -+ goto done; -+ -+ list_del(buf_head); -+ hdr_count++; -+ if (hdr_count > port->current_buffer.num) -+ break; -+ } -+ } -+ -+ ret = port_info_get(instance, port); -+ -+done: -+ return ret; -+} -+ -+/* ------------------------------------------------------------------ -+ * Exported API -+ *------------------------------------------------------------------ -+ */ -+ -+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ ret = port_info_set(instance, port); -+ if (ret) -+ goto release_unlock; -+ -+ /* read what has actually been set */ -+ ret = port_info_get(instance, port); -+ -+release_unlock: -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_port_set_format); -+ -+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ u32 parameter, void *value, u32 value_size) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ ret = port_parameter_set(instance, port, parameter, value, value_size); -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set); -+ -+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ u32 parameter, void *value, u32 *value_size) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ ret = port_parameter_get(instance, port, parameter, value, value_size); -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_get); -+ -+/* enable a port -+ * -+ * enables a port and queues buffers for satisfying callbacks if we -+ * provide a callback handler -+ */ -+int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ vchiq_mmal_buffer_cb buffer_cb) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ /* already enabled - noop */ -+ if (port->enabled) { -+ ret = 0; -+ goto unlock; -+ } -+ -+ port->buffer_cb = buffer_cb; -+ -+ ret = port_enable(instance, port); -+ -+unlock: -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_port_enable); -+ -+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ if (!port->enabled) { -+ mutex_unlock(&instance->vchiq_mutex); -+ return 0; -+ } -+ -+ ret = port_disable(instance, port); -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_port_disable); -+ -+/* ports will be connected in a tunneled manner so data buffers -+ * are not handled by client. -+ */ -+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *src, -+ struct vchiq_mmal_port *dst) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ /* disconnect ports if connected */ -+ if (src->connected) { -+ ret = port_disable(instance, src); -+ if (ret) { -+ pr_err("failed disabling src port(%d)\n", ret); -+ goto release_unlock; -+ } -+ -+ /* do not need to disable the destination port as they -+ * are connected and it is done automatically -+ */ -+ -+ ret = port_action_handle(instance, src, -+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, -+ src->connected->component->handle, -+ src->connected->handle); -+ if (ret < 0) { -+ pr_err("failed disconnecting src port\n"); -+ goto release_unlock; -+ } -+ src->connected->enabled = 0; -+ src->connected = NULL; -+ } -+ -+ if (!dst) { -+ /* do not make new connection */ -+ ret = 0; -+ pr_debug("not making new connection\n"); -+ goto release_unlock; -+ } -+ -+ /* copy src port format to dst */ -+ dst->format.encoding = src->format.encoding; -+ dst->es.video.width = src->es.video.width; -+ dst->es.video.height = src->es.video.height; -+ dst->es.video.crop.x = src->es.video.crop.x; -+ dst->es.video.crop.y = src->es.video.crop.y; -+ dst->es.video.crop.width = src->es.video.crop.width; -+ dst->es.video.crop.height = src->es.video.crop.height; -+ dst->es.video.frame_rate.num = src->es.video.frame_rate.num; -+ dst->es.video.frame_rate.den = src->es.video.frame_rate.den; -+ -+ /* set new format */ -+ ret = port_info_set(instance, dst); -+ if (ret) { -+ pr_debug("setting port info failed\n"); -+ goto release_unlock; -+ } -+ -+ /* read what has actually been set */ -+ ret = port_info_get(instance, dst); -+ if (ret) { -+ pr_debug("read back port info failed\n"); -+ goto release_unlock; -+ } -+ -+ /* connect two ports together */ -+ ret = port_action_handle(instance, src, -+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, -+ dst->component->handle, dst->handle); -+ if (ret < 0) { -+ pr_debug("connecting port %d:%d to %d:%d failed\n", -+ src->component->handle, src->handle, -+ dst->component->handle, dst->handle); -+ goto release_unlock; -+ } -+ src->connected = dst; -+ -+release_unlock: -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_port_connect_tunnel); -+ -+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ struct mmal_buffer *buffer) -+{ -+ unsigned long flags = 0; -+ int ret; -+ -+ ret = buffer_from_host(instance, port, buffer); -+ if (ret == -EINVAL) { -+ /* Port is disabled. Queue for when it is enabled. */ -+ spin_lock_irqsave(&port->slock, flags); -+ list_add_tail(&buffer->list, &port->buffers); -+ spin_unlock_irqrestore(&port->slock, flags); -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_submit_buffer); -+ -+int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, -+ struct mmal_buffer *buf) -+{ -+ struct mmal_msg_context *msg_context = get_msg_context(instance); -+ -+ if (IS_ERR(msg_context)) -+ return (PTR_ERR(msg_context)); -+ -+ buf->msg_context = msg_context; -+ return 0; -+} -+EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init); -+ -+int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) -+{ -+ struct mmal_msg_context *msg_context = buf->msg_context; -+ -+ if (msg_context) -+ release_msg_context(msg_context); -+ buf->msg_context = NULL; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); -+ -+/* Initialise a mmal component and its ports -+ * -+ */ -+int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance, -+ const char *name, -+ struct vchiq_mmal_component **component_out) -+{ -+ int ret; -+ int idx; /* port index */ -+ struct vchiq_mmal_component *component; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) { -+ ret = -EINVAL; /* todo is this correct error? */ -+ goto unlock; -+ } -+ -+ component = &instance->component[instance->component_idx]; -+ -+ ret = create_component(instance, component, name); -+ if (ret < 0) { -+ pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", -+ __func__, ret); -+ goto unlock; -+ } -+ -+ /* ports info needs gathering */ -+ component->control.type = MMAL_PORT_TYPE_CONTROL; -+ component->control.index = 0; -+ component->control.component = component; -+ spin_lock_init(&component->control.slock); -+ INIT_LIST_HEAD(&component->control.buffers); -+ ret = port_info_get(instance, &component->control); -+ if (ret < 0) -+ goto release_component; -+ -+ for (idx = 0; idx < component->inputs; idx++) { -+ component->input[idx].type = MMAL_PORT_TYPE_INPUT; -+ component->input[idx].index = idx; -+ component->input[idx].component = component; -+ spin_lock_init(&component->input[idx].slock); -+ INIT_LIST_HEAD(&component->input[idx].buffers); -+ ret = port_info_get(instance, &component->input[idx]); -+ if (ret < 0) -+ goto release_component; -+ } -+ -+ for (idx = 0; idx < component->outputs; idx++) { -+ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT; -+ component->output[idx].index = idx; -+ component->output[idx].component = component; -+ spin_lock_init(&component->output[idx].slock); -+ INIT_LIST_HEAD(&component->output[idx].buffers); -+ ret = port_info_get(instance, &component->output[idx]); -+ if (ret < 0) -+ goto release_component; -+ } -+ -+ for (idx = 0; idx < component->clocks; idx++) { -+ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK; -+ component->clock[idx].index = idx; -+ component->clock[idx].component = component; -+ spin_lock_init(&component->clock[idx].slock); -+ INIT_LIST_HEAD(&component->clock[idx].buffers); -+ ret = port_info_get(instance, &component->clock[idx]); -+ if (ret < 0) -+ goto release_component; -+ } -+ -+ instance->component_idx++; -+ -+ *component_out = component; -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return 0; -+ -+release_component: -+ destroy_component(instance, component); -+unlock: -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_component_init); -+ -+/* -+ * cause a mmal component to be destroyed -+ */ -+int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ if (component->enabled) -+ ret = disable_component(instance, component); -+ -+ ret = destroy_component(instance, component); -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_component_finalise); -+ -+/* -+ * cause a mmal component to be enabled -+ */ -+int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ if (component->enabled) { -+ mutex_unlock(&instance->vchiq_mutex); -+ return 0; -+ } -+ -+ ret = enable_component(instance, component); -+ if (ret == 0) -+ component->enabled = true; -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_component_enable); -+ -+/* -+ * cause a mmal component to be enabled -+ */ -+int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ if (!component->enabled) { -+ mutex_unlock(&instance->vchiq_mutex); -+ return 0; -+ } -+ -+ ret = disable_component(instance, component); -+ if (ret == 0) -+ component->enabled = 0; -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_component_disable); -+ -+int vchiq_mmal_version(struct vchiq_mmal_instance *instance, -+ u32 *major_out, u32 *minor_out) -+{ -+ int ret; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ ret = get_version(instance, major_out, minor_out); -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_version); -+ -+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance) -+{ -+ int status = 0; -+ -+ if (!instance) -+ return -EINVAL; -+ -+ if (mutex_lock_interruptible(&instance->vchiq_mutex)) -+ return -EINTR; -+ -+ vchi_service_use(instance->handle); -+ -+ status = vchi_service_close(instance->handle); -+ if (status != 0) -+ pr_err("mmal-vchiq: VCHIQ close failed\n"); -+ -+ mutex_unlock(&instance->vchiq_mutex); -+ -+ flush_workqueue(instance->bulk_wq); -+ destroy_workqueue(instance->bulk_wq); -+ -+ vfree(instance->bulk_scratch); -+ -+ idr_destroy(&instance->context_map); -+ -+ kfree(instance); -+ -+ return status; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_finalise); -+ -+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) -+{ -+ int status; -+ struct vchiq_mmal_instance *instance; -+ static VCHI_INSTANCE_T vchi_instance; -+ struct service_creation params = { -+ .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER), -+ .service_id = VC_MMAL_SERVER_NAME, -+ .callback = service_callback, -+ .callback_param = NULL, -+ }; -+ -+ /* compile time checks to ensure structure size as they are -+ * directly (de)serialised from memory. -+ */ -+ -+ /* ensure the header structure has packed to the correct size */ -+ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24); -+ -+ /* ensure message structure does not exceed maximum length */ -+ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE); -+ -+ /* mmal port struct is correct size */ -+ BUILD_BUG_ON(sizeof(struct mmal_port) != 64); -+ -+ /* create a vchi instance */ -+ status = vchi_initialise(&vchi_instance); -+ if (status) { -+ pr_err("Failed to initialise VCHI instance (status=%d)\n", -+ status); -+ return -EIO; -+ } -+ -+ status = vchi_connect(vchi_instance); -+ if (status) { -+ pr_err("Failed to connect VCHI instance (status=%d)\n", status); -+ return -EIO; -+ } -+ -+ instance = kzalloc(sizeof(*instance), GFP_KERNEL); -+ -+ if (!instance) -+ return -ENOMEM; -+ -+ mutex_init(&instance->vchiq_mutex); -+ -+ instance->bulk_scratch = vmalloc(PAGE_SIZE); -+ -+ mutex_init(&instance->context_map_lock); -+ idr_init_base(&instance->context_map, 1); -+ -+ params.callback_param = instance; -+ -+ instance->bulk_wq = alloc_ordered_workqueue("mmal-vchiq", -+ WQ_MEM_RECLAIM); -+ if (!instance->bulk_wq) -+ goto err_free; -+ -+ status = vchi_service_open(vchi_instance, ¶ms, &instance->handle); -+ if (status) { -+ pr_err("Failed to open VCHI service connection (status=%d)\n", -+ status); -+ goto err_close_services; -+ } -+ -+ vchi_service_release(instance->handle); -+ -+ *out_instance = instance; -+ -+ return 0; -+ -+err_close_services: -+ vchi_service_close(instance->handle); -+ destroy_workqueue(instance->bulk_wq); -+err_free: -+ vfree(instance->bulk_scratch); -+ kfree(instance); -+ return -ENODEV; -+} -+EXPORT_SYMBOL_GPL(vchiq_mmal_init); ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h -+++ /dev/null -@@ -1,60 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- * -- * MMAL structures -- * -- */ --#ifndef MMAL_COMMON_H --#define MMAL_COMMON_H -- --#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24)) --#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l') -- --/** Special value signalling that time is not known */ --#define MMAL_TIME_UNKNOWN BIT_ULL(63) -- --struct mmal_msg_context; -- --/* mapping between v4l and mmal video modes */ --struct mmal_fmt { -- u32 fourcc; /* v4l2 format id */ -- int flags; /* v4l2 flags field */ -- u32 mmal; -- int depth; -- u32 mmal_component; /* MMAL component index to be used to encode */ -- u32 ybbp; /* depth of first Y plane for planar formats */ -- bool remove_padding; /* Does the GPU have to remove padding, -- * or can we do hide padding via bytesperline. -- */ --}; -- --/* buffer for one video frame */ --struct mmal_buffer { -- /* v4l buffer data -- must be first */ -- struct vb2_v4l2_buffer vb; -- -- /* list of buffers available */ -- struct list_head list; -- -- void *buffer; /* buffer pointer */ -- unsigned long buffer_size; /* size of allocated buffer */ -- -- struct mmal_msg_context *msg_context; --}; -- --/* */ --struct mmal_colourfx { -- s32 enable; -- u32 u; -- u32 v; --}; --#endif ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-encodings.h -+++ /dev/null -@@ -1,124 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- */ --#ifndef MMAL_ENCODINGS_H --#define MMAL_ENCODINGS_H -- --#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4') --#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3') --#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V') --#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V') --#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V') --#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3') --#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2') --#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1') --#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1') --#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ') --#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ') --#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ') --#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O') --#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K') --#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G') -- --#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G') --#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ') --#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ') --#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ') --#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ') --#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ') -- --#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0') --#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0') --#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2') --#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2') --#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2') --#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V') --#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U') --#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y') --#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y') --#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2') --#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1') --#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B') --#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A') --#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R') --#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A') --#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2') --#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3') --#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4') --#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2') --#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3') --#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4') -- --/** SAND Video (YUVUV128) format, native format understood by VideoCore. -- * This format is *not* opaque - if requested you will receive full frames -- * of YUV_UV video. -- */ --#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D') -- --/** VideoCore opaque image format, image handles are returned to -- * the host but not the actual image data. -- */ --#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V') -- --/** An EGL image handle -- */ --#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I') -- --/* }@ */ -- --/** \name Pre-defined audio encodings */ --/* @{ */ --#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U') --#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u') --#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S') --#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's') --#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F') --#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f') -- --/* Pre-defined H264 encoding variants */ -- --/** ISO 14496-10 Annex B byte stream format */ --#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0 --/** ISO 14496-15 AVC stream format */ --#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1') --/** Implicitly delineated NAL units without emulation prevention */ --#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ') -- --/** \defgroup MmalColorSpace List of pre-defined video color spaces -- * This defines a list of common color spaces. This list isn't exhaustive and -- * is only provided as a convenience to avoid clients having to use FourCC -- * codes directly. However components are allowed to define and use their own -- * FourCC codes. -- */ --/* @{ */ -- --/** Unknown color space */ --#define MMAL_COLOR_SPACE_UNKNOWN 0 --/** ITU-R BT.601-5 [SDTV] */ --#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1') --/** ITU-R BT.709-3 [HDTV] */ --#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9') --/** JPEG JFIF */ --#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I') --/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ --#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C') --/** Society of Motion Picture and Television Engineers 240M (1999) */ --#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0') --/** ITU-R BT.470-2 System M */ --#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M') --/** ITU-R BT.470-2 System BG */ --#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G') --/** JPEG JFIF, but with 16..255 luma */ --#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6') --/* @} MmalColorSpace List */ -- --#endif /* MMAL_ENCODINGS_H */ ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-common.h -+++ /dev/null -@@ -1,48 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- */ -- --#ifndef MMAL_MSG_COMMON_H --#define MMAL_MSG_COMMON_H -- --enum mmal_msg_status { -- MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */ -- MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */ -- MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */ -- MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */ -- MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */ -- MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */ -- MMAL_MSG_STATUS_ENXIO, /**< No such device or address */ -- MMAL_MSG_STATUS_EIO, /**< I/O error */ -- MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */ -- MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */ -- MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */ -- MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */ -- MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */ -- MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */ -- MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */ -- MMAL_MSG_STATUS_EFAULT, /**< Bad address */ --}; -- --struct mmal_rect { -- s32 x; /**< x coordinate (from left) */ -- s32 y; /**< y coordinate (from top) */ -- s32 width; /**< width */ -- s32 height; /**< height */ --}; -- --struct mmal_rational { -- s32 num; /**< Numerator */ -- s32 den; /**< Denominator */ --}; -- --#endif /* MMAL_MSG_COMMON_H */ ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-format.h -+++ /dev/null -@@ -1,106 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- */ -- --#ifndef MMAL_MSG_FORMAT_H --#define MMAL_MSG_FORMAT_H -- --#include "mmal-msg-common.h" -- --/* MMAL_ES_FORMAT_T */ -- --struct mmal_audio_format { -- u32 channels; /* Number of audio channels */ -- u32 sample_rate; /* Sample rate */ -- -- u32 bits_per_sample; /* Bits per sample */ -- u32 block_align; /* Size of a block of data */ --}; -- --struct mmal_video_format { -- u32 width; /* Width of frame in pixels */ -- u32 height; /* Height of frame in rows of pixels */ -- struct mmal_rect crop; /* Visible region of the frame */ -- struct mmal_rational frame_rate; /* Frame rate */ -- struct mmal_rational par; /* Pixel aspect ratio */ -- -- /* -- * FourCC specifying the color space of the video stream. See the -- * MmalColorSpace "pre-defined color spaces" for some examples. -- */ -- u32 color_space; --}; -- --struct mmal_subpicture_format { -- u32 x_offset; -- u32 y_offset; --}; -- --union mmal_es_specific_format { -- struct mmal_audio_format audio; -- struct mmal_video_format video; -- struct mmal_subpicture_format subpicture; --}; -- --/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */ --struct mmal_es_format_local { -- u32 type; /* enum mmal_es_type */ -- -- u32 encoding; /* FourCC specifying encoding of the elementary -- * stream. -- */ -- u32 encoding_variant; /* FourCC specifying the specific -- * encoding variant of the elementary -- * stream. -- */ -- -- union mmal_es_specific_format *es; /* Type specific -- * information for the -- * elementary stream -- */ -- -- u32 bitrate; /* Bitrate in bits per second */ -- u32 flags; /* Flags describing properties of the elementary -- * stream. -- */ -- -- u32 extradata_size; /* Size of the codec specific data */ -- u8 *extradata; /* Codec specific data */ --}; -- --/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */ --struct mmal_es_format { -- u32 type; /* enum mmal_es_type */ -- -- u32 encoding; /* FourCC specifying encoding of the elementary -- * stream. -- */ -- u32 encoding_variant; /* FourCC specifying the specific -- * encoding variant of the elementary -- * stream. -- */ -- -- u32 es; /* Type specific -- * information for the -- * elementary stream -- */ -- -- u32 bitrate; /* Bitrate in bits per second */ -- u32 flags; /* Flags describing properties of the elementary -- * stream. -- */ -- -- u32 extradata_size; /* Size of the codec specific data */ -- u32 extradata; /* Codec specific data */ --}; -- --#endif /* MMAL_MSG_FORMAT_H */ ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg-port.h -+++ /dev/null -@@ -1,109 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- */ -- --/* MMAL_PORT_TYPE_T */ --enum mmal_port_type { -- MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */ -- MMAL_PORT_TYPE_CONTROL, /* Control port */ -- MMAL_PORT_TYPE_INPUT, /* Input port */ -- MMAL_PORT_TYPE_OUTPUT, /* Output port */ -- MMAL_PORT_TYPE_CLOCK, /* Clock port */ --}; -- --/* The port is pass-through and doesn't need buffer headers allocated */ --#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01 --/* -- *The port wants to allocate the buffer payloads. -- * This signals a preference that payload allocation should be done -- * on this port for efficiency reasons. -- */ --#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02 --/* -- * The port supports format change events. -- * This applies to input ports and is used to let the client know -- * whether the port supports being reconfigured via a format -- * change event (i.e. without having to disable the port). -- */ --#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04 -- --/* -- * mmal port structure (MMAL_PORT_T) -- * -- * most elements are informational only, the pointer values for -- * interogation messages are generally provided as additional -- * structures within the message. When used to set values only the -- * buffer_num, buffer_size and userdata parameters are writable. -- */ --struct mmal_port { -- u32 priv; /* Private member used by the framework */ -- u32 name; /* Port name. Used for debugging purposes (RO) */ -- -- u32 type; /* Type of the port (RO) enum mmal_port_type */ -- u16 index; /* Index of the port in its type list (RO) */ -- u16 index_all; /* Index of the port in the list of all ports (RO) */ -- -- u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */ -- u32 format; /* Format of the elementary stream */ -- -- u32 buffer_num_min; /* Minimum number of buffers the port -- * requires (RO). This is set by the -- * component. -- */ -- -- u32 buffer_size_min; /* Minimum size of buffers the port -- * requires (RO). This is set by the -- * component. -- */ -- -- u32 buffer_alignment_min;/* Minimum alignment requirement for -- * the buffers (RO). A value of -- * zero means no special alignment -- * requirements. This is set by the -- * component. -- */ -- -- u32 buffer_num_recommended; /* Number of buffers the port -- * recommends for optimal -- * performance (RO). A value of -- * zero means no special -- * recommendation. This is set -- * by the component. -- */ -- -- u32 buffer_size_recommended; /* Size of buffers the port -- * recommends for optimal -- * performance (RO). A value of -- * zero means no special -- * recommendation. This is set -- * by the component. -- */ -- -- u32 buffer_num; /* Actual number of buffers the port will use. -- * This is set by the client. -- */ -- -- u32 buffer_size; /* Actual maximum size of the buffers that -- * will be sent to the port. This is set by -- * the client. -- */ -- -- u32 component; /* Component this port belongs to (Read Only) */ -- -- u32 userdata; /* Field reserved for use by the client */ -- -- u32 capabilities; /* Flags describing the capabilities of a -- * port (RO). Bitwise combination of \ref -- * portcapabilities "Port capabilities" -- * values. -- */ --}; ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-msg.h -+++ /dev/null -@@ -1,406 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- */ -- --/* -- * all the data structures which serialise the MMAL protocol. note -- * these are directly mapped onto the recived message data. -- * -- * BEWARE: They seem to *assume* pointers are u32 and that there is no -- * structure padding! -- * -- * NOTE: this implementation uses kernel types to ensure sizes. Rather -- * than assigning values to enums to force their size the -- * implementation uses fixed size types and not the enums (though the -- * comments have the actual enum type -- */ --#ifndef MMAL_MSG_H --#define MMAL_MSG_H -- --#define VC_MMAL_VER 15 --#define VC_MMAL_MIN_VER 10 --#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal") -- --/* max total message size is 512 bytes */ --#define MMAL_MSG_MAX_SIZE 512 --/* with six 32bit header elements max payload is therefore 488 bytes */ --#define MMAL_MSG_MAX_PAYLOAD 488 -- --#include "mmal-msg-common.h" --#include "mmal-msg-format.h" --#include "mmal-msg-port.h" -- --enum mmal_msg_type { -- MMAL_MSG_TYPE_QUIT = 1, -- MMAL_MSG_TYPE_SERVICE_CLOSED, -- MMAL_MSG_TYPE_GET_VERSION, -- MMAL_MSG_TYPE_COMPONENT_CREATE, -- MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */ -- MMAL_MSG_TYPE_COMPONENT_ENABLE, -- MMAL_MSG_TYPE_COMPONENT_DISABLE, -- MMAL_MSG_TYPE_PORT_INFO_GET, -- MMAL_MSG_TYPE_PORT_INFO_SET, -- MMAL_MSG_TYPE_PORT_ACTION, /* 10 */ -- MMAL_MSG_TYPE_BUFFER_FROM_HOST, -- MMAL_MSG_TYPE_BUFFER_TO_HOST, -- MMAL_MSG_TYPE_GET_STATS, -- MMAL_MSG_TYPE_PORT_PARAMETER_SET, -- MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */ -- MMAL_MSG_TYPE_EVENT_TO_HOST, -- MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT, -- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR, -- MMAL_MSG_TYPE_CONSUME_MEM, -- MMAL_MSG_TYPE_LMK, /* 20 */ -- MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC, -- MMAL_MSG_TYPE_DRM_GET_LHS32, -- MMAL_MSG_TYPE_DRM_GET_TIME, -- MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN, -- MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */ -- MMAL_MSG_TYPE_HOST_LOG, -- MMAL_MSG_TYPE_MSG_LAST --}; -- --/* port action request messages differ depending on the action type */ --enum mmal_msg_port_action_type { -- MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */ -- MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */ -- MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */ -- MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */ -- MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */ -- MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */ -- MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/ --}; -- --struct mmal_msg_header { -- u32 magic; -- u32 type; /* enum mmal_msg_type */ -- -- /* Opaque handle to the control service */ -- u32 control_service; -- -- u32 context; /* a u32 per message context */ -- u32 status; /* The status of the vchiq operation */ -- u32 padding; --}; -- --/* Send from VC to host to report version */ --struct mmal_msg_version { -- u32 flags; -- u32 major; -- u32 minor; -- u32 minimum; --}; -- --/* request to VC to create component */ --struct mmal_msg_component_create { -- u32 client_component; /* component context */ -- char name[128]; -- u32 pid; /* For debug */ --}; -- --/* reply from VC to component creation request */ --struct mmal_msg_component_create_reply { -- u32 status; /* enum mmal_msg_status - how does this differ to -- * the one in the header? -- */ -- u32 component_handle; /* VideoCore handle for component */ -- u32 input_num; /* Number of input ports */ -- u32 output_num; /* Number of output ports */ -- u32 clock_num; /* Number of clock ports */ --}; -- --/* request to VC to destroy a component */ --struct mmal_msg_component_destroy { -- u32 component_handle; --}; -- --struct mmal_msg_component_destroy_reply { -- u32 status; /* The component destruction status */ --}; -- --/* request and reply to VC to enable a component */ --struct mmal_msg_component_enable { -- u32 component_handle; --}; -- --struct mmal_msg_component_enable_reply { -- u32 status; /* The component enable status */ --}; -- --/* request and reply to VC to disable a component */ --struct mmal_msg_component_disable { -- u32 component_handle; --}; -- --struct mmal_msg_component_disable_reply { -- u32 status; /* The component disable status */ --}; -- --/* request to VC to get port information */ --struct mmal_msg_port_info_get { -- u32 component_handle; /* component handle port is associated with */ -- u32 port_type; /* enum mmal_msg_port_type */ -- u32 index; /* port index to query */ --}; -- --/* reply from VC to get port info request */ --struct mmal_msg_port_info_get_reply { -- u32 status; /* enum mmal_msg_status */ -- u32 component_handle; /* component handle port is associated with */ -- u32 port_type; /* enum mmal_msg_port_type */ -- u32 port_index; /* port indexed in query */ -- s32 found; /* unused */ -- u32 port_handle; /* Handle to use for this port */ -- struct mmal_port port; -- struct mmal_es_format format; /* elementary stream format */ -- union mmal_es_specific_format es; /* es type specific data */ -- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */ --}; -- --/* request to VC to set port information */ --struct mmal_msg_port_info_set { -- u32 component_handle; -- u32 port_type; /* enum mmal_msg_port_type */ -- u32 port_index; /* port indexed in query */ -- struct mmal_port port; -- struct mmal_es_format format; -- union mmal_es_specific_format es; -- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; --}; -- --/* reply from VC to port info set request */ --struct mmal_msg_port_info_set_reply { -- u32 status; -- u32 component_handle; /* component handle port is associated with */ -- u32 port_type; /* enum mmal_msg_port_type */ -- u32 index; /* port indexed in query */ -- s32 found; /* unused */ -- u32 port_handle; /* Handle to use for this port */ -- struct mmal_port port; -- struct mmal_es_format format; -- union mmal_es_specific_format es; -- u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; --}; -- --/* port action requests that take a mmal_port as a parameter */ --struct mmal_msg_port_action_port { -- u32 component_handle; -- u32 port_handle; -- u32 action; /* enum mmal_msg_port_action_type */ -- struct mmal_port port; --}; -- --/* port action requests that take handles as a parameter */ --struct mmal_msg_port_action_handle { -- u32 component_handle; -- u32 port_handle; -- u32 action; /* enum mmal_msg_port_action_type */ -- u32 connect_component_handle; -- u32 connect_port_handle; --}; -- --struct mmal_msg_port_action_reply { -- u32 status; /* The port action operation status */ --}; -- --/* MMAL buffer transfer */ -- --/* Size of space reserved in a buffer message for short messages. */ --#define MMAL_VC_SHORT_DATA 128 -- --/* Signals that the current payload is the end of the stream of data */ --#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0) --/* Signals that the start of the current payload starts a frame */ --#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1) --/* Signals that the end of the current payload ends a frame */ --#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2) --/* Signals that the current payload contains only complete frames (>1) */ --#define MMAL_BUFFER_HEADER_FLAG_FRAME \ -- (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \ -- MMAL_BUFFER_HEADER_FLAG_FRAME_END) --/* Signals that the current payload is a keyframe (i.e. self decodable) */ --#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3) --/* -- * Signals a discontinuity in the stream of data (e.g. after a seek). -- * Can be used for instance by a decoder to reset its state -- */ --#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4) --/* -- * Signals a buffer containing some kind of config data for the component -- * (e.g. codec config data) -- */ --#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5) --/* Signals an encrypted payload */ --#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6) --/* Signals a buffer containing side information */ --#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7) --/* -- * Signals a buffer which is the snapshot/postview image from a stills -- * capture -- */ --#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8) --/* Signals a buffer which contains data known to be corrupted */ --#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9) --/* Signals that a buffer failed to be transmitted */ --#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10) -- --struct mmal_driver_buffer { -- u32 magic; -- u32 component_handle; -- u32 port_handle; -- u32 client_context; --}; -- --/* buffer header */ --struct mmal_buffer_header { -- u32 next; /* next header */ -- u32 priv; /* framework private data */ -- u32 cmd; -- u32 data; -- u32 alloc_size; -- u32 length; -- u32 offset; -- u32 flags; -- s64 pts; -- s64 dts; -- u32 type; -- u32 user_data; --}; -- --struct mmal_buffer_header_type_specific { -- union { -- struct { -- u32 planes; -- u32 offset[4]; -- u32 pitch[4]; -- u32 flags; -- } video; -- } u; --}; -- --struct mmal_msg_buffer_from_host { -- /* -- *The front 32 bytes of the buffer header are copied -- * back to us in the reply to allow for context. This -- * area is used to store two mmal_driver_buffer structures to -- * allow for multiple concurrent service users. -- */ -- /* control data */ -- struct mmal_driver_buffer drvbuf; -- -- /* referenced control data for passthrough buffer management */ -- struct mmal_driver_buffer drvbuf_ref; -- struct mmal_buffer_header buffer_header; /* buffer header itself */ -- struct mmal_buffer_header_type_specific buffer_header_type_specific; -- s32 is_zero_copy; -- s32 has_reference; -- -- /* allows short data to be xfered in control message */ -- u32 payload_in_message; -- u8 short_data[MMAL_VC_SHORT_DATA]; --}; -- --/* port parameter setting */ -- --#define MMAL_WORKER_PORT_PARAMETER_SPACE 96 -- --struct mmal_msg_port_parameter_set { -- u32 component_handle; /* component */ -- u32 port_handle; /* port */ -- u32 id; /* Parameter ID */ -- u32 size; /* Parameter size */ -- u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; --}; -- --struct mmal_msg_port_parameter_set_reply { -- u32 status; /* enum mmal_msg_status todo: how does this -- * differ to the one in the header? -- */ --}; -- --/* port parameter getting */ -- --struct mmal_msg_port_parameter_get { -- u32 component_handle; /* component */ -- u32 port_handle; /* port */ -- u32 id; /* Parameter ID */ -- u32 size; /* Parameter size */ --}; -- --struct mmal_msg_port_parameter_get_reply { -- u32 status; /* Status of mmal_port_parameter_get call */ -- u32 id; /* Parameter ID */ -- u32 size; /* Parameter size */ -- u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; --}; -- --/* event messages */ --#define MMAL_WORKER_EVENT_SPACE 256 -- --struct mmal_msg_event_to_host { -- u32 client_component; /* component context */ -- -- u32 port_type; -- u32 port_num; -- -- u32 cmd; -- u32 length; -- u8 data[MMAL_WORKER_EVENT_SPACE]; -- u32 delayed_buffer; --}; -- --/* all mmal messages are serialised through this structure */ --struct mmal_msg { -- /* header */ -- struct mmal_msg_header h; -- /* payload */ -- union { -- struct mmal_msg_version version; -- -- struct mmal_msg_component_create component_create; -- struct mmal_msg_component_create_reply component_create_reply; -- -- struct mmal_msg_component_destroy component_destroy; -- struct mmal_msg_component_destroy_reply component_destroy_reply; -- -- struct mmal_msg_component_enable component_enable; -- struct mmal_msg_component_enable_reply component_enable_reply; -- -- struct mmal_msg_component_disable component_disable; -- struct mmal_msg_component_disable_reply component_disable_reply; -- -- struct mmal_msg_port_info_get port_info_get; -- struct mmal_msg_port_info_get_reply port_info_get_reply; -- -- struct mmal_msg_port_info_set port_info_set; -- struct mmal_msg_port_info_set_reply port_info_set_reply; -- -- struct mmal_msg_port_action_port port_action_port; -- struct mmal_msg_port_action_handle port_action_handle; -- struct mmal_msg_port_action_reply port_action_reply; -- -- struct mmal_msg_buffer_from_host buffer_from_host; -- -- struct mmal_msg_port_parameter_set port_parameter_set; -- struct mmal_msg_port_parameter_set_reply -- port_parameter_set_reply; -- struct mmal_msg_port_parameter_get -- port_parameter_get; -- struct mmal_msg_port_parameter_get_reply -- port_parameter_get_reply; -- -- struct mmal_msg_event_to_host event_to_host; -- -- u8 payload[MMAL_MSG_MAX_PAYLOAD]; -- } u; --}; --#endif ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-parameters.h -+++ /dev/null -@@ -1,755 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- */ -- --/* common parameters */ -- --/** @name Parameter groups -- * Parameters are divided into groups, and then allocated sequentially within -- * a group using an enum. -- * @{ -- */ -- --#ifndef MMAL_PARAMETERS_H --#define MMAL_PARAMETERS_H -- --/** Common parameter ID group, used with many types of component. */ --#define MMAL_PARAMETER_GROUP_COMMON (0 << 16) --/** Camera-specific parameter ID group. */ --#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16) --/** Video-specific parameter ID group. */ --#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16) --/** Audio-specific parameter ID group. */ --#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16) --/** Clock-specific parameter ID group. */ --#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16) --/** Miracast-specific parameter ID group. */ --#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16) -- --/* Common parameters */ --enum mmal_parameter_common_type { -- /**< Never a valid parameter ID */ -- MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON, -- -- /**< MMAL_PARAMETER_ENCODING_T */ -- MMAL_PARAMETER_SUPPORTED_ENCODINGS, -- /**< MMAL_PARAMETER_URI_T */ -- MMAL_PARAMETER_URI, -- /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */ -- MMAL_PARAMETER_CHANGE_EVENT_REQUEST, -- /** MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_ZERO_COPY, -- /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */ -- MMAL_PARAMETER_BUFFER_REQUIREMENTS, -- /**< MMAL_PARAMETER_STATISTICS_T */ -- MMAL_PARAMETER_STATISTICS, -- /**< MMAL_PARAMETER_CORE_STATISTICS_T */ -- MMAL_PARAMETER_CORE_STATISTICS, -- /**< MMAL_PARAMETER_MEM_USAGE_T */ -- MMAL_PARAMETER_MEM_USAGE, -- /**< MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_BUFFER_FLAG_FILTER, -- /**< MMAL_PARAMETER_SEEK_T */ -- MMAL_PARAMETER_SEEK, -- /**< MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_POWERMON_ENABLE, -- /**< MMAL_PARAMETER_LOGGING_T */ -- MMAL_PARAMETER_LOGGING, -- /**< MMAL_PARAMETER_UINT64_T */ -- MMAL_PARAMETER_SYSTEM_TIME, -- /**< MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_NO_IMAGE_PADDING, --}; -- --/* camera parameters */ -- --enum mmal_parameter_camera_type { -- /* 0 */ -- /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */ -- MMAL_PARAMETER_THUMBNAIL_CONFIGURATION = -- MMAL_PARAMETER_GROUP_CAMERA, -- /**< Unused? */ -- MMAL_PARAMETER_CAPTURE_QUALITY, -- /**< @ref MMAL_PARAMETER_INT32_T */ -- MMAL_PARAMETER_ROTATION, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_EXIF_DISABLE, -- /**< @ref MMAL_PARAMETER_EXIF_T */ -- MMAL_PARAMETER_EXIF, -- /**< @ref MMAL_PARAM_AWBMODE_T */ -- MMAL_PARAMETER_AWB_MODE, -- /**< @ref MMAL_PARAMETER_IMAGEFX_T */ -- MMAL_PARAMETER_IMAGE_EFFECT, -- /**< @ref MMAL_PARAMETER_COLOURFX_T */ -- MMAL_PARAMETER_COLOUR_EFFECT, -- /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */ -- MMAL_PARAMETER_FLICKER_AVOID, -- /**< @ref MMAL_PARAMETER_FLASH_T */ -- MMAL_PARAMETER_FLASH, -- /**< @ref MMAL_PARAMETER_REDEYE_T */ -- MMAL_PARAMETER_REDEYE, -- /**< @ref MMAL_PARAMETER_FOCUS_T */ -- MMAL_PARAMETER_FOCUS, -- /**< Unused? */ -- MMAL_PARAMETER_FOCAL_LENGTHS, -- /**< @ref MMAL_PARAMETER_INT32_T */ -- MMAL_PARAMETER_EXPOSURE_COMP, -- /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */ -- MMAL_PARAMETER_ZOOM, -- /**< @ref MMAL_PARAMETER_MIRROR_T */ -- MMAL_PARAMETER_MIRROR, -- -- /* 0x10 */ -- /**< @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_CAMERA_NUM, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_CAPTURE, -- /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */ -- MMAL_PARAMETER_EXPOSURE_MODE, -- /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */ -- MMAL_PARAMETER_EXP_METERING_MODE, -- /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */ -- MMAL_PARAMETER_FOCUS_STATUS, -- /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */ -- MMAL_PARAMETER_CAMERA_CONFIG, -- /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */ -- MMAL_PARAMETER_CAPTURE_STATUS, -- /**< @ref MMAL_PARAMETER_FACE_TRACK_T */ -- MMAL_PARAMETER_FACE_TRACK, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, -- /**< @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_JPEG_Q_FACTOR, -- /**< @ref MMAL_PARAMETER_FRAME_RATE_T */ -- MMAL_PARAMETER_FRAME_RATE, -- /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */ -- MMAL_PARAMETER_USE_STC, -- /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */ -- MMAL_PARAMETER_CAMERA_INFO, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_STABILISATION, -- /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */ -- MMAL_PARAMETER_FACE_TRACK_RESULTS, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_ENABLE_RAW_CAPTURE, -- -- /* 0x20 */ -- /**< @ref MMAL_PARAMETER_URI_T */ -- MMAL_PARAMETER_DPF_FILE, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_ENABLE_DPF_FILE, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_DPF_FAIL_IS_FATAL, -- /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */ -- MMAL_PARAMETER_CAPTURE_MODE, -- /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */ -- MMAL_PARAMETER_FOCUS_REGIONS, -- /**< @ref MMAL_PARAMETER_INPUT_CROP_T */ -- MMAL_PARAMETER_INPUT_CROP, -- /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */ -- MMAL_PARAMETER_SENSOR_INFORMATION, -- /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */ -- MMAL_PARAMETER_FLASH_SELECT, -- /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */ -- MMAL_PARAMETER_FIELD_OF_VIEW, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, -- /**< @ref MMAL_PARAMETER_DRC_T */ -- MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, -- /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */ -- MMAL_PARAMETER_ALGORITHM_CONTROL, -- /**< @ref MMAL_PARAMETER_RATIONAL_T */ -- MMAL_PARAMETER_SHARPNESS, -- /**< @ref MMAL_PARAMETER_RATIONAL_T */ -- MMAL_PARAMETER_CONTRAST, -- /**< @ref MMAL_PARAMETER_RATIONAL_T */ -- MMAL_PARAMETER_BRIGHTNESS, -- /**< @ref MMAL_PARAMETER_RATIONAL_T */ -- MMAL_PARAMETER_SATURATION, -- -- /* 0x30 */ -- /**< @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_ISO, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_ANTISHAKE, -- /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */ -- MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_CAMERA_BURST_CAPTURE, -- /** @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_CAMERA_MIN_ISO, -- /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */ -- MMAL_PARAMETER_CAMERA_USE_CASE, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_CAPTURE_STATS_PASS, -- /** @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_ENABLE_REGISTER_FILE, -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL, -- /** @ref MMAL_PARAMETER_CONFIGFILE_T */ -- MMAL_PARAMETER_CONFIGFILE_REGISTERS, -- /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */ -- MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_JPEG_ATTACH_LOG, -- /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */ -- MMAL_PARAMETER_ZERO_SHUTTER_LAG, -- /**< @ref MMAL_PARAMETER_FPS_RANGE_T */ -- MMAL_PARAMETER_FPS_RANGE, -- /**< @ref MMAL_PARAMETER_INT32_T */ -- MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, -- -- /* 0x40 */ -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_SW_SHARPEN_DISABLE, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_FLASH_REQUIRED, -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_SW_SATURATION_DISABLE, -- /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_SHUTTER_SPEED, -- /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */ -- MMAL_PARAMETER_CUSTOM_AWB_GAINS, --}; -- --struct mmal_parameter_rational { -- s32 num; /**< Numerator */ -- s32 den; /**< Denominator */ --}; -- --enum mmal_parameter_camera_config_timestamp_mode { -- MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */ -- MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value -- * for the frame timestamp -- */ -- MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp -- * but subtract the -- * timestamp of the first -- * frame sent to give a -- * zero based timestamp. -- */ --}; -- --struct mmal_parameter_fps_range { -- /**< Low end of the permitted framerate range */ -- struct mmal_parameter_rational fps_low; -- /**< High end of the permitted framerate range */ -- struct mmal_parameter_rational fps_high; --}; -- --/* camera configuration parameter */ --struct mmal_parameter_camera_config { -- /* Parameters for setting up the image pools */ -- u32 max_stills_w; /* Max size of stills capture */ -- u32 max_stills_h; -- u32 stills_yuv422; /* Allow YUV422 stills capture */ -- u32 one_shot_stills; /* Continuous or one shot stills captures. */ -- -- u32 max_preview_video_w; /* Max size of the preview or video -- * capture frames -- */ -- u32 max_preview_video_h; -- u32 num_preview_video_frames; -- -- /** Sets the height of the circular buffer for stills capture. */ -- u32 stills_capture_circular_buffer_height; -- -- /** Allows preview/encode to resume as fast as possible after the stills -- * input frame has been received, and then processes the still frame in -- * the background whilst preview/encode has resumed. -- * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE. -- */ -- u32 fast_preview_resume; -- -- /** Selects algorithm for timestamping frames if -- * there is no clock component connected. -- * enum mmal_parameter_camera_config_timestamp_mode -- */ -- s32 use_stc_timestamp; --}; -- --enum mmal_parameter_exposuremode { -- MMAL_PARAM_EXPOSUREMODE_OFF, -- MMAL_PARAM_EXPOSUREMODE_AUTO, -- MMAL_PARAM_EXPOSUREMODE_NIGHT, -- MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, -- MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, -- MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, -- MMAL_PARAM_EXPOSUREMODE_SPORTS, -- MMAL_PARAM_EXPOSUREMODE_SNOW, -- MMAL_PARAM_EXPOSUREMODE_BEACH, -- MMAL_PARAM_EXPOSUREMODE_VERYLONG, -- MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, -- MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, -- MMAL_PARAM_EXPOSUREMODE_FIREWORKS, --}; -- --enum mmal_parameter_exposuremeteringmode { -- MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE, -- MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT, -- MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT, -- MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX, --}; -- --enum mmal_parameter_awbmode { -- MMAL_PARAM_AWBMODE_OFF, -- MMAL_PARAM_AWBMODE_AUTO, -- MMAL_PARAM_AWBMODE_SUNLIGHT, -- MMAL_PARAM_AWBMODE_CLOUDY, -- MMAL_PARAM_AWBMODE_SHADE, -- MMAL_PARAM_AWBMODE_TUNGSTEN, -- MMAL_PARAM_AWBMODE_FLUORESCENT, -- MMAL_PARAM_AWBMODE_INCANDESCENT, -- MMAL_PARAM_AWBMODE_FLASH, -- MMAL_PARAM_AWBMODE_HORIZON, --}; -- --enum mmal_parameter_imagefx { -- MMAL_PARAM_IMAGEFX_NONE, -- MMAL_PARAM_IMAGEFX_NEGATIVE, -- MMAL_PARAM_IMAGEFX_SOLARIZE, -- MMAL_PARAM_IMAGEFX_POSTERIZE, -- MMAL_PARAM_IMAGEFX_WHITEBOARD, -- MMAL_PARAM_IMAGEFX_BLACKBOARD, -- MMAL_PARAM_IMAGEFX_SKETCH, -- MMAL_PARAM_IMAGEFX_DENOISE, -- MMAL_PARAM_IMAGEFX_EMBOSS, -- MMAL_PARAM_IMAGEFX_OILPAINT, -- MMAL_PARAM_IMAGEFX_HATCH, -- MMAL_PARAM_IMAGEFX_GPEN, -- MMAL_PARAM_IMAGEFX_PASTEL, -- MMAL_PARAM_IMAGEFX_WATERCOLOUR, -- MMAL_PARAM_IMAGEFX_FILM, -- MMAL_PARAM_IMAGEFX_BLUR, -- MMAL_PARAM_IMAGEFX_SATURATION, -- MMAL_PARAM_IMAGEFX_COLOURSWAP, -- MMAL_PARAM_IMAGEFX_WASHEDOUT, -- MMAL_PARAM_IMAGEFX_POSTERISE, -- MMAL_PARAM_IMAGEFX_COLOURPOINT, -- MMAL_PARAM_IMAGEFX_COLOURBALANCE, -- MMAL_PARAM_IMAGEFX_CARTOON, --}; -- --enum MMAL_PARAM_FLICKERAVOID_T { -- MMAL_PARAM_FLICKERAVOID_OFF, -- MMAL_PARAM_FLICKERAVOID_AUTO, -- MMAL_PARAM_FLICKERAVOID_50HZ, -- MMAL_PARAM_FLICKERAVOID_60HZ, -- MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF --}; -- --struct mmal_parameter_awbgains { -- struct mmal_parameter_rational r_gain; /**< Red gain */ -- struct mmal_parameter_rational b_gain; /**< Blue gain */ --}; -- --/** Manner of video rate control */ --enum mmal_parameter_rate_control_mode { -- MMAL_VIDEO_RATECONTROL_DEFAULT, -- MMAL_VIDEO_RATECONTROL_VARIABLE, -- MMAL_VIDEO_RATECONTROL_CONSTANT, -- MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES, -- MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES --}; -- --enum mmal_video_profile { -- MMAL_VIDEO_PROFILE_H263_BASELINE, -- MMAL_VIDEO_PROFILE_H263_H320CODING, -- MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE, -- MMAL_VIDEO_PROFILE_H263_ISWV2, -- MMAL_VIDEO_PROFILE_H263_ISWV3, -- MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION, -- MMAL_VIDEO_PROFILE_H263_INTERNET, -- MMAL_VIDEO_PROFILE_H263_INTERLACE, -- MMAL_VIDEO_PROFILE_H263_HIGHLATENCY, -- MMAL_VIDEO_PROFILE_MP4V_SIMPLE, -- MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE, -- MMAL_VIDEO_PROFILE_MP4V_CORE, -- MMAL_VIDEO_PROFILE_MP4V_MAIN, -- MMAL_VIDEO_PROFILE_MP4V_NBIT, -- MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE, -- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE, -- MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA, -- MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED, -- MMAL_VIDEO_PROFILE_MP4V_HYBRID, -- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME, -- MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE, -- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING, -- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE, -- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE, -- MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE, -- MMAL_VIDEO_PROFILE_H264_BASELINE, -- MMAL_VIDEO_PROFILE_H264_MAIN, -- MMAL_VIDEO_PROFILE_H264_EXTENDED, -- MMAL_VIDEO_PROFILE_H264_HIGH, -- MMAL_VIDEO_PROFILE_H264_HIGH10, -- MMAL_VIDEO_PROFILE_H264_HIGH422, -- MMAL_VIDEO_PROFILE_H264_HIGH444, -- MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, -- MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF --}; -- --enum mmal_video_level { -- MMAL_VIDEO_LEVEL_H263_10, -- MMAL_VIDEO_LEVEL_H263_20, -- MMAL_VIDEO_LEVEL_H263_30, -- MMAL_VIDEO_LEVEL_H263_40, -- MMAL_VIDEO_LEVEL_H263_45, -- MMAL_VIDEO_LEVEL_H263_50, -- MMAL_VIDEO_LEVEL_H263_60, -- MMAL_VIDEO_LEVEL_H263_70, -- MMAL_VIDEO_LEVEL_MP4V_0, -- MMAL_VIDEO_LEVEL_MP4V_0b, -- MMAL_VIDEO_LEVEL_MP4V_1, -- MMAL_VIDEO_LEVEL_MP4V_2, -- MMAL_VIDEO_LEVEL_MP4V_3, -- MMAL_VIDEO_LEVEL_MP4V_4, -- MMAL_VIDEO_LEVEL_MP4V_4a, -- MMAL_VIDEO_LEVEL_MP4V_5, -- MMAL_VIDEO_LEVEL_MP4V_6, -- MMAL_VIDEO_LEVEL_H264_1, -- MMAL_VIDEO_LEVEL_H264_1b, -- MMAL_VIDEO_LEVEL_H264_11, -- MMAL_VIDEO_LEVEL_H264_12, -- MMAL_VIDEO_LEVEL_H264_13, -- MMAL_VIDEO_LEVEL_H264_2, -- MMAL_VIDEO_LEVEL_H264_21, -- MMAL_VIDEO_LEVEL_H264_22, -- MMAL_VIDEO_LEVEL_H264_3, -- MMAL_VIDEO_LEVEL_H264_31, -- MMAL_VIDEO_LEVEL_H264_32, -- MMAL_VIDEO_LEVEL_H264_4, -- MMAL_VIDEO_LEVEL_H264_41, -- MMAL_VIDEO_LEVEL_H264_42, -- MMAL_VIDEO_LEVEL_H264_5, -- MMAL_VIDEO_LEVEL_H264_51, -- MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF --}; -- --struct mmal_parameter_video_profile { -- enum mmal_video_profile profile; -- enum mmal_video_level level; --}; -- --/* video parameters */ -- --enum mmal_parameter_video_type { -- /** @ref MMAL_DISPLAYREGION_T */ -- MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO, -- -- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ -- MMAL_PARAMETER_SUPPORTED_PROFILES, -- -- /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ -- MMAL_PARAMETER_PROFILE, -- -- /** @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_INTRAPERIOD, -- -- /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */ -- MMAL_PARAMETER_RATECONTROL, -- -- /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */ -- MMAL_PARAMETER_NALUNITFORMAT, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_MINIMISE_FRAGMENTATION, -- -- /** @ref MMAL_PARAMETER_UINT32_T. -- * Setting the value to zero resets to the default (one slice per -- * frame). -- */ -- MMAL_PARAMETER_MB_ROWS_PER_SLICE, -- -- /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */ -- MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION, -- -- /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */ -- MMAL_PARAMETER_VIDEO_EEDE_ENABLE, -- -- /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */ -- MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */ -- MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, -- /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */ -- MMAL_PARAMETER_VIDEO_INTRA_REFRESH, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -- MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, -- -- /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */ -- MMAL_PARAMETER_VIDEO_BIT_RATE, -- -- /** @ref MMAL_PARAMETER_FRAME_RATE_T */ -- MMAL_PARAMETER_VIDEO_FRAME_RATE, -- -- /** @ref MMAL_PARAMETER_UINT32_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, -- -- /** @ref MMAL_PARAMETER_UINT32_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, -- -- /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL, -- -- MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */ -- /** @ref MMAL_PARAMETER_UINT32_T. -- * Changing this parameter from the default can reduce frame rate -- * because image buffers need to be re-pitched. -- */ -- MMAL_PARAMETER_VIDEO_ALIGN_HORIZ, -- -- /** @ref MMAL_PARAMETER_UINT32_T. -- * Changing this parameter from the default can reduce frame rate -- * because image buffers need to be re-pitched. -- */ -- MMAL_PARAMETER_VIDEO_ALIGN_VERT, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -- MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES, -- -- /** @ref MMAL_PARAMETER_UINT32_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, -- -- /**< @ref MMAL_PARAMETER_UINT32_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_QP_P, -- -- /**< @ref MMAL_PARAMETER_UINT32_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT, -- -- /** @ref MMAL_PARAMETER_UINT32_T */ -- MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS, -- -- /** @ref MMAL_PARAMETER_UINT32_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE, -- -- /* H264 specific parameters */ -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS, -- -- /** @ref MMAL_PARAMETER_UINT32_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC, -- -- /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */ -- MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP, -- -- /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */ -- MMAL_PARAMETER_VIDEO_DRM_INIT_INFO, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO, -- -- /** @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT, -- -- /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */ -- MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER, -- -- /** @ref MMAL_PARAMETER_BYTES_T */ -- MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3, -- -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS, -- -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, -- -- /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER --}; -- --/** Valid mirror modes */ --enum mmal_parameter_mirror { -- MMAL_PARAM_MIRROR_NONE, -- MMAL_PARAM_MIRROR_VERTICAL, -- MMAL_PARAM_MIRROR_HORIZONTAL, -- MMAL_PARAM_MIRROR_BOTH, --}; -- --enum mmal_parameter_displaytransform { -- MMAL_DISPLAY_ROT0 = 0, -- MMAL_DISPLAY_MIRROR_ROT0 = 1, -- MMAL_DISPLAY_MIRROR_ROT180 = 2, -- MMAL_DISPLAY_ROT180 = 3, -- MMAL_DISPLAY_MIRROR_ROT90 = 4, -- MMAL_DISPLAY_ROT270 = 5, -- MMAL_DISPLAY_ROT90 = 6, -- MMAL_DISPLAY_MIRROR_ROT270 = 7, --}; -- --enum mmal_parameter_displaymode { -- MMAL_DISPLAY_MODE_FILL = 0, -- MMAL_DISPLAY_MODE_LETTERBOX = 1, --}; -- --enum mmal_parameter_displayset { -- MMAL_DISPLAY_SET_NONE = 0, -- MMAL_DISPLAY_SET_NUM = 1, -- MMAL_DISPLAY_SET_FULLSCREEN = 2, -- MMAL_DISPLAY_SET_TRANSFORM = 4, -- MMAL_DISPLAY_SET_DEST_RECT = 8, -- MMAL_DISPLAY_SET_SRC_RECT = 0x10, -- MMAL_DISPLAY_SET_MODE = 0x20, -- MMAL_DISPLAY_SET_PIXEL = 0x40, -- MMAL_DISPLAY_SET_NOASPECT = 0x80, -- MMAL_DISPLAY_SET_LAYER = 0x100, -- MMAL_DISPLAY_SET_COPYPROTECT = 0x200, -- MMAL_DISPLAY_SET_ALPHA = 0x400, --}; -- --/* rectangle, used lots so it gets its own struct */ --struct vchiq_mmal_rect { -- s32 x; -- s32 y; -- s32 width; -- s32 height; --}; -- --struct mmal_parameter_displayregion { -- /** Bitfield that indicates which fields are set and should be -- * used. All other fields will maintain their current value. -- * \ref MMAL_DISPLAYSET_T defines the bits that can be -- * combined. -- */ -- u32 set; -- -- /** Describes the display output device, with 0 typically -- * being a directly connected LCD display. The actual values -- * will depend on the hardware. Code using hard-wired numbers -- * (e.g. 2) is certain to fail. -- */ -- -- u32 display_num; -- /** Indicates that we are using the full device screen area, -- * rather than a window of the display. If zero, then -- * dest_rect is used to specify a region of the display to -- * use. -- */ -- -- s32 fullscreen; -- /** Indicates any rotation or flipping used to map frames onto -- * the natural display orientation. -- */ -- u32 transform; /* enum mmal_parameter_displaytransform */ -- -- /** Where to display the frame within the screen, if -- * fullscreen is zero. -- */ -- struct vchiq_mmal_rect dest_rect; -- -- /** Indicates which area of the frame to display. If all -- * values are zero, the whole frame will be used. -- */ -- struct vchiq_mmal_rect src_rect; -- -- /** If set to non-zero, indicates that any display scaling -- * should disregard the aspect ratio of the frame region being -- * displayed. -- */ -- s32 noaspect; -- -- /** Indicates how the image should be scaled to fit the -- * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates -- * that the image should fill the screen by potentially -- * cropping the frames. Setting \code mode \endcode to \code -- * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the -- * source region should be displayed and black bars added if -- * necessary. -- */ -- u32 mode; /* enum mmal_parameter_displaymode */ -- -- /** If non-zero, defines the width of a source pixel relative -- * to \code pixel_y \endcode. If zero, then pixels default to -- * being square. -- */ -- u32 pixel_x; -- -- /** If non-zero, defines the height of a source pixel relative -- * to \code pixel_x \endcode. If zero, then pixels default to -- * being square. -- */ -- u32 pixel_y; -- -- /** Sets the relative depth of the images, with greater values -- * being in front of smaller values. -- */ -- u32 layer; -- -- /** Set to non-zero to ensure copy protection is used on -- * output. -- */ -- s32 copyprotect_required; -- -- /** Level of opacity of the layer, where zero is fully -- * transparent and 255 is fully opaque. -- */ -- u32 alpha; --}; -- --#define MMAL_MAX_IMAGEFX_PARAMETERS 5 -- --struct mmal_parameter_imagefx_parameters { -- enum mmal_parameter_imagefx effect; -- u32 num_effect_params; -- u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS]; --}; -- --#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4 --#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2 --#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16 -- --struct mmal_parameter_camera_info_camera_t { -- u32 port_id; -- u32 max_width; -- u32 max_height; -- u32 lens_present; -- u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN]; --}; -- --enum mmal_parameter_camera_info_flash_type_t { -- /* Make values explicit to ensure they match values in config ini */ -- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0, -- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1, -- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2, -- MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF --}; -- --struct mmal_parameter_camera_info_flash_t { -- enum mmal_parameter_camera_info_flash_type_t flash_type; --}; -- --struct mmal_parameter_camera_info_t { -- u32 num_cameras; -- u32 num_flashes; -- struct mmal_parameter_camera_info_camera_t -- cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS]; -- struct mmal_parameter_camera_info_flash_t -- flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES]; --}; -- --#endif ---- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h -+++ /dev/null -@@ -1,166 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --/* -- * Broadcom BM2835 V4L2 driver -- * -- * Copyright © 2013 Raspberry Pi (Trading) Ltd. -- * -- * Authors: Vincent Sanders @ Collabora -- * Dave Stevenson @ Broadcom -- * (now dave.stevenson@raspberrypi.org) -- * Simon Mellor @ Broadcom -- * Luke Diamand @ Broadcom -- * -- * MMAL interface to VCHIQ message passing -- */ -- --#ifndef MMAL_VCHIQ_H --#define MMAL_VCHIQ_H -- --#include "mmal-msg-format.h" -- --#define MAX_PORT_COUNT 4 -- --/* Maximum size of the format extradata. */ --#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128 -- --struct vchiq_mmal_instance; -- --enum vchiq_mmal_es_type { -- MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */ -- MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */ -- MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */ -- MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */ -- MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */ --}; -- --struct vchiq_mmal_port_buffer { -- unsigned int num; /* number of buffers */ -- u32 size; /* size of buffers */ -- u32 alignment; /* alignment of buffers */ --}; -- --struct vchiq_mmal_port; -- --typedef void (*vchiq_mmal_buffer_cb)( -- struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- int status, struct mmal_buffer *buffer, -- unsigned long length, u32 mmal_flags, s64 dts, s64 pts); -- --struct vchiq_mmal_port { -- u32 enabled:1; -- u32 handle; -- u32 type; /* port type, cached to use on port info set */ -- u32 index; /* port index, cached to use on port info set */ -- -- /* component port belongs to, allows simple deref */ -- struct vchiq_mmal_component *component; -- -- struct vchiq_mmal_port *connected; /* port connected to */ -- -- /* buffer info */ -- struct vchiq_mmal_port_buffer minimum_buffer; -- struct vchiq_mmal_port_buffer recommended_buffer; -- struct vchiq_mmal_port_buffer current_buffer; -- -- /* stream format */ -- struct mmal_es_format_local format; -- /* elementary stream format */ -- union mmal_es_specific_format es; -- -- /* data buffers to fill */ -- struct list_head buffers; -- /* lock to serialise adding and removing buffers from list */ -- spinlock_t slock; -- -- /* Count of buffers the VPU has yet to return */ -- atomic_t buffers_with_vpu; -- /* callback on buffer completion */ -- vchiq_mmal_buffer_cb buffer_cb; -- /* callback context */ -- void *cb_ctx; --}; -- --struct vchiq_mmal_component { -- u32 enabled:1; -- u32 handle; /* VideoCore handle for component */ -- u32 inputs; /* Number of input ports */ -- u32 outputs; /* Number of output ports */ -- u32 clocks; /* Number of clock ports */ -- struct vchiq_mmal_port control; /* control port */ -- struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */ -- struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */ -- struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */ --}; -- --int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance); --int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance); -- --/* Initialise a mmal component and its ports -- * -- */ --int vchiq_mmal_component_init( -- struct vchiq_mmal_instance *instance, -- const char *name, -- struct vchiq_mmal_component **component_out); -- --int vchiq_mmal_component_finalise( -- struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component); -- --int vchiq_mmal_component_enable( -- struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component); -- --int vchiq_mmal_component_disable( -- struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_component *component); -- --/* enable a mmal port -- * -- * enables a port and if a buffer callback provided enque buffer -- * headers as appropriate for the port. -- */ --int vchiq_mmal_port_enable( -- struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- vchiq_mmal_buffer_cb buffer_cb); -- --/* disable a port -- * -- * disable a port will dequeue any pending buffers -- */ --int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port); -- --int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- u32 parameter, -- void *value, -- u32 value_size); -- --int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- u32 parameter, -- void *value, -- u32 *value_size); -- --int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port); -- --int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *src, -- struct vchiq_mmal_port *dst); -- --int vchiq_mmal_version(struct vchiq_mmal_instance *instance, -- u32 *major_out, -- u32 *minor_out); -- --int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, -- struct vchiq_mmal_port *port, -- struct mmal_buffer *buf); -- --int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, -- struct mmal_buffer *buf); --int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf); --#endif /* MMAL_VCHIQ_H */ ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ * -+ * MMAL structures -+ * -+ */ -+#ifndef MMAL_COMMON_H -+#define MMAL_COMMON_H -+ -+#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24)) -+#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l') -+ -+/** Special value signalling that time is not known */ -+#define MMAL_TIME_UNKNOWN BIT_ULL(63) -+ -+struct mmal_msg_context; -+ -+/* mapping between v4l and mmal video modes */ -+struct mmal_fmt { -+ u32 fourcc; /* v4l2 format id */ -+ int flags; /* v4l2 flags field */ -+ u32 mmal; -+ int depth; -+ u32 mmal_component; /* MMAL component index to be used to encode */ -+ u32 ybbp; /* depth of first Y plane for planar formats */ -+ bool remove_padding; /* Does the GPU have to remove padding, -+ * or can we do hide padding via bytesperline. -+ */ -+}; -+ -+/* buffer for one video frame */ -+struct mmal_buffer { -+ /* v4l buffer data -- must be first */ -+ struct vb2_v4l2_buffer vb; -+ -+ /* list of buffers available */ -+ struct list_head list; -+ -+ void *buffer; /* buffer pointer */ -+ unsigned long buffer_size; /* size of allocated buffer */ -+ -+ struct mmal_msg_context *msg_context; -+}; -+ -+/* */ -+struct mmal_colourfx { -+ s32 enable; -+ u32 u; -+ u32 v; -+}; -+#endif ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h -@@ -0,0 +1,124 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ */ -+#ifndef MMAL_ENCODINGS_H -+#define MMAL_ENCODINGS_H -+ -+#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4') -+#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3') -+#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V') -+#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V') -+#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V') -+#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3') -+#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2') -+#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1') -+#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1') -+#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ') -+#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ') -+#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ') -+#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O') -+#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K') -+#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G') -+ -+#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G') -+#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ') -+#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ') -+#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ') -+#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ') -+#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ') -+ -+#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0') -+#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0') -+#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2') -+#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2') -+#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2') -+#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V') -+#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U') -+#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y') -+#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y') -+#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2') -+#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1') -+#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B') -+#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A') -+#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R') -+#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A') -+#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2') -+#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3') -+#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4') -+#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2') -+#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3') -+#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4') -+ -+/** SAND Video (YUVUV128) format, native format understood by VideoCore. -+ * This format is *not* opaque - if requested you will receive full frames -+ * of YUV_UV video. -+ */ -+#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D') -+ -+/** VideoCore opaque image format, image handles are returned to -+ * the host but not the actual image data. -+ */ -+#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V') -+ -+/** An EGL image handle -+ */ -+#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I') -+ -+/* }@ */ -+ -+/** \name Pre-defined audio encodings */ -+/* @{ */ -+#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U') -+#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u') -+#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S') -+#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's') -+#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F') -+#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f') -+ -+/* Pre-defined H264 encoding variants */ -+ -+/** ISO 14496-10 Annex B byte stream format */ -+#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0 -+/** ISO 14496-15 AVC stream format */ -+#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1') -+/** Implicitly delineated NAL units without emulation prevention */ -+#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ') -+ -+/** \defgroup MmalColorSpace List of pre-defined video color spaces -+ * This defines a list of common color spaces. This list isn't exhaustive and -+ * is only provided as a convenience to avoid clients having to use FourCC -+ * codes directly. However components are allowed to define and use their own -+ * FourCC codes. -+ */ -+/* @{ */ -+ -+/** Unknown color space */ -+#define MMAL_COLOR_SPACE_UNKNOWN 0 -+/** ITU-R BT.601-5 [SDTV] */ -+#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1') -+/** ITU-R BT.709-3 [HDTV] */ -+#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9') -+/** JPEG JFIF */ -+#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I') -+/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ -+#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C') -+/** Society of Motion Picture and Television Engineers 240M (1999) */ -+#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0') -+/** ITU-R BT.470-2 System M */ -+#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M') -+/** ITU-R BT.470-2 System BG */ -+#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G') -+/** JPEG JFIF, but with 16..255 luma */ -+#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6') -+/* @} MmalColorSpace List */ -+ -+#endif /* MMAL_ENCODINGS_H */ ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-common.h -@@ -0,0 +1,48 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ */ -+ -+#ifndef MMAL_MSG_COMMON_H -+#define MMAL_MSG_COMMON_H -+ -+enum mmal_msg_status { -+ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */ -+ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */ -+ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */ -+ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */ -+ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */ -+ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */ -+ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */ -+ MMAL_MSG_STATUS_EIO, /**< I/O error */ -+ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */ -+ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */ -+ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */ -+ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */ -+ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */ -+ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */ -+ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */ -+ MMAL_MSG_STATUS_EFAULT, /**< Bad address */ -+}; -+ -+struct mmal_rect { -+ s32 x; /**< x coordinate (from left) */ -+ s32 y; /**< y coordinate (from top) */ -+ s32 width; /**< width */ -+ s32 height; /**< height */ -+}; -+ -+struct mmal_rational { -+ s32 num; /**< Numerator */ -+ s32 den; /**< Denominator */ -+}; -+ -+#endif /* MMAL_MSG_COMMON_H */ ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-format.h -@@ -0,0 +1,106 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ */ -+ -+#ifndef MMAL_MSG_FORMAT_H -+#define MMAL_MSG_FORMAT_H -+ -+#include "mmal-msg-common.h" -+ -+/* MMAL_ES_FORMAT_T */ -+ -+struct mmal_audio_format { -+ u32 channels; /* Number of audio channels */ -+ u32 sample_rate; /* Sample rate */ -+ -+ u32 bits_per_sample; /* Bits per sample */ -+ u32 block_align; /* Size of a block of data */ -+}; -+ -+struct mmal_video_format { -+ u32 width; /* Width of frame in pixels */ -+ u32 height; /* Height of frame in rows of pixels */ -+ struct mmal_rect crop; /* Visible region of the frame */ -+ struct mmal_rational frame_rate; /* Frame rate */ -+ struct mmal_rational par; /* Pixel aspect ratio */ -+ -+ /* -+ * FourCC specifying the color space of the video stream. See the -+ * MmalColorSpace "pre-defined color spaces" for some examples. -+ */ -+ u32 color_space; -+}; -+ -+struct mmal_subpicture_format { -+ u32 x_offset; -+ u32 y_offset; -+}; -+ -+union mmal_es_specific_format { -+ struct mmal_audio_format audio; -+ struct mmal_video_format video; -+ struct mmal_subpicture_format subpicture; -+}; -+ -+/* Definition of an elementary stream format (MMAL_ES_FORMAT_T) */ -+struct mmal_es_format_local { -+ u32 type; /* enum mmal_es_type */ -+ -+ u32 encoding; /* FourCC specifying encoding of the elementary -+ * stream. -+ */ -+ u32 encoding_variant; /* FourCC specifying the specific -+ * encoding variant of the elementary -+ * stream. -+ */ -+ -+ union mmal_es_specific_format *es; /* Type specific -+ * information for the -+ * elementary stream -+ */ -+ -+ u32 bitrate; /* Bitrate in bits per second */ -+ u32 flags; /* Flags describing properties of the elementary -+ * stream. -+ */ -+ -+ u32 extradata_size; /* Size of the codec specific data */ -+ u8 *extradata; /* Codec specific data */ -+}; -+ -+/* Remote definition of an elementary stream format (MMAL_ES_FORMAT_T) */ -+struct mmal_es_format { -+ u32 type; /* enum mmal_es_type */ -+ -+ u32 encoding; /* FourCC specifying encoding of the elementary -+ * stream. -+ */ -+ u32 encoding_variant; /* FourCC specifying the specific -+ * encoding variant of the elementary -+ * stream. -+ */ -+ -+ u32 es; /* Type specific -+ * information for the -+ * elementary stream -+ */ -+ -+ u32 bitrate; /* Bitrate in bits per second */ -+ u32 flags; /* Flags describing properties of the elementary -+ * stream. -+ */ -+ -+ u32 extradata_size; /* Size of the codec specific data */ -+ u32 extradata; /* Codec specific data */ -+}; -+ -+#endif /* MMAL_MSG_FORMAT_H */ ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg-port.h -@@ -0,0 +1,109 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ */ -+ -+/* MMAL_PORT_TYPE_T */ -+enum mmal_port_type { -+ MMAL_PORT_TYPE_UNKNOWN = 0, /* Unknown port type */ -+ MMAL_PORT_TYPE_CONTROL, /* Control port */ -+ MMAL_PORT_TYPE_INPUT, /* Input port */ -+ MMAL_PORT_TYPE_OUTPUT, /* Output port */ -+ MMAL_PORT_TYPE_CLOCK, /* Clock port */ -+}; -+ -+/* The port is pass-through and doesn't need buffer headers allocated */ -+#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01 -+/* -+ *The port wants to allocate the buffer payloads. -+ * This signals a preference that payload allocation should be done -+ * on this port for efficiency reasons. -+ */ -+#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02 -+/* -+ * The port supports format change events. -+ * This applies to input ports and is used to let the client know -+ * whether the port supports being reconfigured via a format -+ * change event (i.e. without having to disable the port). -+ */ -+#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04 -+ -+/* -+ * mmal port structure (MMAL_PORT_T) -+ * -+ * most elements are informational only, the pointer values for -+ * interogation messages are generally provided as additional -+ * structures within the message. When used to set values only the -+ * buffer_num, buffer_size and userdata parameters are writable. -+ */ -+struct mmal_port { -+ u32 priv; /* Private member used by the framework */ -+ u32 name; /* Port name. Used for debugging purposes (RO) */ -+ -+ u32 type; /* Type of the port (RO) enum mmal_port_type */ -+ u16 index; /* Index of the port in its type list (RO) */ -+ u16 index_all; /* Index of the port in the list of all ports (RO) */ -+ -+ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */ -+ u32 format; /* Format of the elementary stream */ -+ -+ u32 buffer_num_min; /* Minimum number of buffers the port -+ * requires (RO). This is set by the -+ * component. -+ */ -+ -+ u32 buffer_size_min; /* Minimum size of buffers the port -+ * requires (RO). This is set by the -+ * component. -+ */ -+ -+ u32 buffer_alignment_min;/* Minimum alignment requirement for -+ * the buffers (RO). A value of -+ * zero means no special alignment -+ * requirements. This is set by the -+ * component. -+ */ -+ -+ u32 buffer_num_recommended; /* Number of buffers the port -+ * recommends for optimal -+ * performance (RO). A value of -+ * zero means no special -+ * recommendation. This is set -+ * by the component. -+ */ -+ -+ u32 buffer_size_recommended; /* Size of buffers the port -+ * recommends for optimal -+ * performance (RO). A value of -+ * zero means no special -+ * recommendation. This is set -+ * by the component. -+ */ -+ -+ u32 buffer_num; /* Actual number of buffers the port will use. -+ * This is set by the client. -+ */ -+ -+ u32 buffer_size; /* Actual maximum size of the buffers that -+ * will be sent to the port. This is set by -+ * the client. -+ */ -+ -+ u32 component; /* Component this port belongs to (Read Only) */ -+ -+ u32 userdata; /* Field reserved for use by the client */ -+ -+ u32 capabilities; /* Flags describing the capabilities of a -+ * port (RO). Bitwise combination of \ref -+ * portcapabilities "Port capabilities" -+ * values. -+ */ -+}; ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h -@@ -0,0 +1,406 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ */ -+ -+/* -+ * all the data structures which serialise the MMAL protocol. note -+ * these are directly mapped onto the recived message data. -+ * -+ * BEWARE: They seem to *assume* pointers are u32 and that there is no -+ * structure padding! -+ * -+ * NOTE: this implementation uses kernel types to ensure sizes. Rather -+ * than assigning values to enums to force their size the -+ * implementation uses fixed size types and not the enums (though the -+ * comments have the actual enum type -+ */ -+#ifndef MMAL_MSG_H -+#define MMAL_MSG_H -+ -+#define VC_MMAL_VER 15 -+#define VC_MMAL_MIN_VER 10 -+#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal") -+ -+/* max total message size is 512 bytes */ -+#define MMAL_MSG_MAX_SIZE 512 -+/* with six 32bit header elements max payload is therefore 488 bytes */ -+#define MMAL_MSG_MAX_PAYLOAD 488 -+ -+#include "mmal-msg-common.h" -+#include "mmal-msg-format.h" -+#include "mmal-msg-port.h" -+ -+enum mmal_msg_type { -+ MMAL_MSG_TYPE_QUIT = 1, -+ MMAL_MSG_TYPE_SERVICE_CLOSED, -+ MMAL_MSG_TYPE_GET_VERSION, -+ MMAL_MSG_TYPE_COMPONENT_CREATE, -+ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */ -+ MMAL_MSG_TYPE_COMPONENT_ENABLE, -+ MMAL_MSG_TYPE_COMPONENT_DISABLE, -+ MMAL_MSG_TYPE_PORT_INFO_GET, -+ MMAL_MSG_TYPE_PORT_INFO_SET, -+ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */ -+ MMAL_MSG_TYPE_BUFFER_FROM_HOST, -+ MMAL_MSG_TYPE_BUFFER_TO_HOST, -+ MMAL_MSG_TYPE_GET_STATS, -+ MMAL_MSG_TYPE_PORT_PARAMETER_SET, -+ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */ -+ MMAL_MSG_TYPE_EVENT_TO_HOST, -+ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT, -+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR, -+ MMAL_MSG_TYPE_CONSUME_MEM, -+ MMAL_MSG_TYPE_LMK, /* 20 */ -+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC, -+ MMAL_MSG_TYPE_DRM_GET_LHS32, -+ MMAL_MSG_TYPE_DRM_GET_TIME, -+ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN, -+ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */ -+ MMAL_MSG_TYPE_HOST_LOG, -+ MMAL_MSG_TYPE_MSG_LAST -+}; -+ -+/* port action request messages differ depending on the action type */ -+enum mmal_msg_port_action_type { -+ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unknown action */ -+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */ -+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */ -+ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */ -+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */ -+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */ -+ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/ -+}; -+ -+struct mmal_msg_header { -+ u32 magic; -+ u32 type; /* enum mmal_msg_type */ -+ -+ /* Opaque handle to the control service */ -+ u32 control_service; -+ -+ u32 context; /* a u32 per message context */ -+ u32 status; /* The status of the vchiq operation */ -+ u32 padding; -+}; -+ -+/* Send from VC to host to report version */ -+struct mmal_msg_version { -+ u32 flags; -+ u32 major; -+ u32 minor; -+ u32 minimum; -+}; -+ -+/* request to VC to create component */ -+struct mmal_msg_component_create { -+ u32 client_component; /* component context */ -+ char name[128]; -+ u32 pid; /* For debug */ -+}; -+ -+/* reply from VC to component creation request */ -+struct mmal_msg_component_create_reply { -+ u32 status; /* enum mmal_msg_status - how does this differ to -+ * the one in the header? -+ */ -+ u32 component_handle; /* VideoCore handle for component */ -+ u32 input_num; /* Number of input ports */ -+ u32 output_num; /* Number of output ports */ -+ u32 clock_num; /* Number of clock ports */ -+}; -+ -+/* request to VC to destroy a component */ -+struct mmal_msg_component_destroy { -+ u32 component_handle; -+}; -+ -+struct mmal_msg_component_destroy_reply { -+ u32 status; /* The component destruction status */ -+}; -+ -+/* request and reply to VC to enable a component */ -+struct mmal_msg_component_enable { -+ u32 component_handle; -+}; -+ -+struct mmal_msg_component_enable_reply { -+ u32 status; /* The component enable status */ -+}; -+ -+/* request and reply to VC to disable a component */ -+struct mmal_msg_component_disable { -+ u32 component_handle; -+}; -+ -+struct mmal_msg_component_disable_reply { -+ u32 status; /* The component disable status */ -+}; -+ -+/* request to VC to get port information */ -+struct mmal_msg_port_info_get { -+ u32 component_handle; /* component handle port is associated with */ -+ u32 port_type; /* enum mmal_msg_port_type */ -+ u32 index; /* port index to query */ -+}; -+ -+/* reply from VC to get port info request */ -+struct mmal_msg_port_info_get_reply { -+ u32 status; /* enum mmal_msg_status */ -+ u32 component_handle; /* component handle port is associated with */ -+ u32 port_type; /* enum mmal_msg_port_type */ -+ u32 port_index; /* port indexed in query */ -+ s32 found; /* unused */ -+ u32 port_handle; /* Handle to use for this port */ -+ struct mmal_port port; -+ struct mmal_es_format format; /* elementary stream format */ -+ union mmal_es_specific_format es; /* es type specific data */ -+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */ -+}; -+ -+/* request to VC to set port information */ -+struct mmal_msg_port_info_set { -+ u32 component_handle; -+ u32 port_type; /* enum mmal_msg_port_type */ -+ u32 port_index; /* port indexed in query */ -+ struct mmal_port port; -+ struct mmal_es_format format; -+ union mmal_es_specific_format es; -+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; -+}; -+ -+/* reply from VC to port info set request */ -+struct mmal_msg_port_info_set_reply { -+ u32 status; -+ u32 component_handle; /* component handle port is associated with */ -+ u32 port_type; /* enum mmal_msg_port_type */ -+ u32 index; /* port indexed in query */ -+ s32 found; /* unused */ -+ u32 port_handle; /* Handle to use for this port */ -+ struct mmal_port port; -+ struct mmal_es_format format; -+ union mmal_es_specific_format es; -+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; -+}; -+ -+/* port action requests that take a mmal_port as a parameter */ -+struct mmal_msg_port_action_port { -+ u32 component_handle; -+ u32 port_handle; -+ u32 action; /* enum mmal_msg_port_action_type */ -+ struct mmal_port port; -+}; -+ -+/* port action requests that take handles as a parameter */ -+struct mmal_msg_port_action_handle { -+ u32 component_handle; -+ u32 port_handle; -+ u32 action; /* enum mmal_msg_port_action_type */ -+ u32 connect_component_handle; -+ u32 connect_port_handle; -+}; -+ -+struct mmal_msg_port_action_reply { -+ u32 status; /* The port action operation status */ -+}; -+ -+/* MMAL buffer transfer */ -+ -+/* Size of space reserved in a buffer message for short messages. */ -+#define MMAL_VC_SHORT_DATA 128 -+ -+/* Signals that the current payload is the end of the stream of data */ -+#define MMAL_BUFFER_HEADER_FLAG_EOS BIT(0) -+/* Signals that the start of the current payload starts a frame */ -+#define MMAL_BUFFER_HEADER_FLAG_FRAME_START BIT(1) -+/* Signals that the end of the current payload ends a frame */ -+#define MMAL_BUFFER_HEADER_FLAG_FRAME_END BIT(2) -+/* Signals that the current payload contains only complete frames (>1) */ -+#define MMAL_BUFFER_HEADER_FLAG_FRAME \ -+ (MMAL_BUFFER_HEADER_FLAG_FRAME_START | \ -+ MMAL_BUFFER_HEADER_FLAG_FRAME_END) -+/* Signals that the current payload is a keyframe (i.e. self decodable) */ -+#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME BIT(3) -+/* -+ * Signals a discontinuity in the stream of data (e.g. after a seek). -+ * Can be used for instance by a decoder to reset its state -+ */ -+#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY BIT(4) -+/* -+ * Signals a buffer containing some kind of config data for the component -+ * (e.g. codec config data) -+ */ -+#define MMAL_BUFFER_HEADER_FLAG_CONFIG BIT(5) -+/* Signals an encrypted payload */ -+#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED BIT(6) -+/* Signals a buffer containing side information */ -+#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO BIT(7) -+/* -+ * Signals a buffer which is the snapshot/postview image from a stills -+ * capture -+ */ -+#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT BIT(8) -+/* Signals a buffer which contains data known to be corrupted */ -+#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED BIT(9) -+/* Signals that a buffer failed to be transmitted */ -+#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED BIT(10) -+ -+struct mmal_driver_buffer { -+ u32 magic; -+ u32 component_handle; -+ u32 port_handle; -+ u32 client_context; -+}; -+ -+/* buffer header */ -+struct mmal_buffer_header { -+ u32 next; /* next header */ -+ u32 priv; /* framework private data */ -+ u32 cmd; -+ u32 data; -+ u32 alloc_size; -+ u32 length; -+ u32 offset; -+ u32 flags; -+ s64 pts; -+ s64 dts; -+ u32 type; -+ u32 user_data; -+}; -+ -+struct mmal_buffer_header_type_specific { -+ union { -+ struct { -+ u32 planes; -+ u32 offset[4]; -+ u32 pitch[4]; -+ u32 flags; -+ } video; -+ } u; -+}; -+ -+struct mmal_msg_buffer_from_host { -+ /* -+ *The front 32 bytes of the buffer header are copied -+ * back to us in the reply to allow for context. This -+ * area is used to store two mmal_driver_buffer structures to -+ * allow for multiple concurrent service users. -+ */ -+ /* control data */ -+ struct mmal_driver_buffer drvbuf; -+ -+ /* referenced control data for passthrough buffer management */ -+ struct mmal_driver_buffer drvbuf_ref; -+ struct mmal_buffer_header buffer_header; /* buffer header itself */ -+ struct mmal_buffer_header_type_specific buffer_header_type_specific; -+ s32 is_zero_copy; -+ s32 has_reference; -+ -+ /* allows short data to be xfered in control message */ -+ u32 payload_in_message; -+ u8 short_data[MMAL_VC_SHORT_DATA]; -+}; -+ -+/* port parameter setting */ -+ -+#define MMAL_WORKER_PORT_PARAMETER_SPACE 96 -+ -+struct mmal_msg_port_parameter_set { -+ u32 component_handle; /* component */ -+ u32 port_handle; /* port */ -+ u32 id; /* Parameter ID */ -+ u32 size; /* Parameter size */ -+ u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; -+}; -+ -+struct mmal_msg_port_parameter_set_reply { -+ u32 status; /* enum mmal_msg_status todo: how does this -+ * differ to the one in the header? -+ */ -+}; -+ -+/* port parameter getting */ -+ -+struct mmal_msg_port_parameter_get { -+ u32 component_handle; /* component */ -+ u32 port_handle; /* port */ -+ u32 id; /* Parameter ID */ -+ u32 size; /* Parameter size */ -+}; -+ -+struct mmal_msg_port_parameter_get_reply { -+ u32 status; /* Status of mmal_port_parameter_get call */ -+ u32 id; /* Parameter ID */ -+ u32 size; /* Parameter size */ -+ u32 value[MMAL_WORKER_PORT_PARAMETER_SPACE]; -+}; -+ -+/* event messages */ -+#define MMAL_WORKER_EVENT_SPACE 256 -+ -+struct mmal_msg_event_to_host { -+ u32 client_component; /* component context */ -+ -+ u32 port_type; -+ u32 port_num; -+ -+ u32 cmd; -+ u32 length; -+ u8 data[MMAL_WORKER_EVENT_SPACE]; -+ u32 delayed_buffer; -+}; -+ -+/* all mmal messages are serialised through this structure */ -+struct mmal_msg { -+ /* header */ -+ struct mmal_msg_header h; -+ /* payload */ -+ union { -+ struct mmal_msg_version version; -+ -+ struct mmal_msg_component_create component_create; -+ struct mmal_msg_component_create_reply component_create_reply; -+ -+ struct mmal_msg_component_destroy component_destroy; -+ struct mmal_msg_component_destroy_reply component_destroy_reply; -+ -+ struct mmal_msg_component_enable component_enable; -+ struct mmal_msg_component_enable_reply component_enable_reply; -+ -+ struct mmal_msg_component_disable component_disable; -+ struct mmal_msg_component_disable_reply component_disable_reply; -+ -+ struct mmal_msg_port_info_get port_info_get; -+ struct mmal_msg_port_info_get_reply port_info_get_reply; -+ -+ struct mmal_msg_port_info_set port_info_set; -+ struct mmal_msg_port_info_set_reply port_info_set_reply; -+ -+ struct mmal_msg_port_action_port port_action_port; -+ struct mmal_msg_port_action_handle port_action_handle; -+ struct mmal_msg_port_action_reply port_action_reply; -+ -+ struct mmal_msg_buffer_from_host buffer_from_host; -+ -+ struct mmal_msg_port_parameter_set port_parameter_set; -+ struct mmal_msg_port_parameter_set_reply -+ port_parameter_set_reply; -+ struct mmal_msg_port_parameter_get -+ port_parameter_get; -+ struct mmal_msg_port_parameter_get_reply -+ port_parameter_get_reply; -+ -+ struct mmal_msg_event_to_host event_to_host; -+ -+ u8 payload[MMAL_MSG_MAX_PAYLOAD]; -+ } u; -+}; -+#endif ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h -@@ -0,0 +1,755 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ */ -+ -+/* common parameters */ -+ -+/** @name Parameter groups -+ * Parameters are divided into groups, and then allocated sequentially within -+ * a group using an enum. -+ * @{ -+ */ -+ -+#ifndef MMAL_PARAMETERS_H -+#define MMAL_PARAMETERS_H -+ -+/** Common parameter ID group, used with many types of component. */ -+#define MMAL_PARAMETER_GROUP_COMMON (0 << 16) -+/** Camera-specific parameter ID group. */ -+#define MMAL_PARAMETER_GROUP_CAMERA (1 << 16) -+/** Video-specific parameter ID group. */ -+#define MMAL_PARAMETER_GROUP_VIDEO (2 << 16) -+/** Audio-specific parameter ID group. */ -+#define MMAL_PARAMETER_GROUP_AUDIO (3 << 16) -+/** Clock-specific parameter ID group. */ -+#define MMAL_PARAMETER_GROUP_CLOCK (4 << 16) -+/** Miracast-specific parameter ID group. */ -+#define MMAL_PARAMETER_GROUP_MIRACAST (5 << 16) -+ -+/* Common parameters */ -+enum mmal_parameter_common_type { -+ /**< Never a valid parameter ID */ -+ MMAL_PARAMETER_UNUSED = MMAL_PARAMETER_GROUP_COMMON, -+ -+ /**< MMAL_PARAMETER_ENCODING_T */ -+ MMAL_PARAMETER_SUPPORTED_ENCODINGS, -+ /**< MMAL_PARAMETER_URI_T */ -+ MMAL_PARAMETER_URI, -+ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */ -+ MMAL_PARAMETER_CHANGE_EVENT_REQUEST, -+ /** MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_ZERO_COPY, -+ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */ -+ MMAL_PARAMETER_BUFFER_REQUIREMENTS, -+ /**< MMAL_PARAMETER_STATISTICS_T */ -+ MMAL_PARAMETER_STATISTICS, -+ /**< MMAL_PARAMETER_CORE_STATISTICS_T */ -+ MMAL_PARAMETER_CORE_STATISTICS, -+ /**< MMAL_PARAMETER_MEM_USAGE_T */ -+ MMAL_PARAMETER_MEM_USAGE, -+ /**< MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_BUFFER_FLAG_FILTER, -+ /**< MMAL_PARAMETER_SEEK_T */ -+ MMAL_PARAMETER_SEEK, -+ /**< MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_POWERMON_ENABLE, -+ /**< MMAL_PARAMETER_LOGGING_T */ -+ MMAL_PARAMETER_LOGGING, -+ /**< MMAL_PARAMETER_UINT64_T */ -+ MMAL_PARAMETER_SYSTEM_TIME, -+ /**< MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_NO_IMAGE_PADDING, -+}; -+ -+/* camera parameters */ -+ -+enum mmal_parameter_camera_type { -+ /* 0 */ -+ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */ -+ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION = -+ MMAL_PARAMETER_GROUP_CAMERA, -+ /**< Unused? */ -+ MMAL_PARAMETER_CAPTURE_QUALITY, -+ /**< @ref MMAL_PARAMETER_INT32_T */ -+ MMAL_PARAMETER_ROTATION, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_EXIF_DISABLE, -+ /**< @ref MMAL_PARAMETER_EXIF_T */ -+ MMAL_PARAMETER_EXIF, -+ /**< @ref MMAL_PARAM_AWBMODE_T */ -+ MMAL_PARAMETER_AWB_MODE, -+ /**< @ref MMAL_PARAMETER_IMAGEFX_T */ -+ MMAL_PARAMETER_IMAGE_EFFECT, -+ /**< @ref MMAL_PARAMETER_COLOURFX_T */ -+ MMAL_PARAMETER_COLOUR_EFFECT, -+ /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */ -+ MMAL_PARAMETER_FLICKER_AVOID, -+ /**< @ref MMAL_PARAMETER_FLASH_T */ -+ MMAL_PARAMETER_FLASH, -+ /**< @ref MMAL_PARAMETER_REDEYE_T */ -+ MMAL_PARAMETER_REDEYE, -+ /**< @ref MMAL_PARAMETER_FOCUS_T */ -+ MMAL_PARAMETER_FOCUS, -+ /**< Unused? */ -+ MMAL_PARAMETER_FOCAL_LENGTHS, -+ /**< @ref MMAL_PARAMETER_INT32_T */ -+ MMAL_PARAMETER_EXPOSURE_COMP, -+ /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */ -+ MMAL_PARAMETER_ZOOM, -+ /**< @ref MMAL_PARAMETER_MIRROR_T */ -+ MMAL_PARAMETER_MIRROR, -+ -+ /* 0x10 */ -+ /**< @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_CAMERA_NUM, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_CAPTURE, -+ /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */ -+ MMAL_PARAMETER_EXPOSURE_MODE, -+ /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */ -+ MMAL_PARAMETER_EXP_METERING_MODE, -+ /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */ -+ MMAL_PARAMETER_FOCUS_STATUS, -+ /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */ -+ MMAL_PARAMETER_CAMERA_CONFIG, -+ /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */ -+ MMAL_PARAMETER_CAPTURE_STATUS, -+ /**< @ref MMAL_PARAMETER_FACE_TRACK_T */ -+ MMAL_PARAMETER_FACE_TRACK, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, -+ /**< @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_JPEG_Q_FACTOR, -+ /**< @ref MMAL_PARAMETER_FRAME_RATE_T */ -+ MMAL_PARAMETER_FRAME_RATE, -+ /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */ -+ MMAL_PARAMETER_USE_STC, -+ /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */ -+ MMAL_PARAMETER_CAMERA_INFO, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_STABILISATION, -+ /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */ -+ MMAL_PARAMETER_FACE_TRACK_RESULTS, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_ENABLE_RAW_CAPTURE, -+ -+ /* 0x20 */ -+ /**< @ref MMAL_PARAMETER_URI_T */ -+ MMAL_PARAMETER_DPF_FILE, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_ENABLE_DPF_FILE, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_DPF_FAIL_IS_FATAL, -+ /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */ -+ MMAL_PARAMETER_CAPTURE_MODE, -+ /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */ -+ MMAL_PARAMETER_FOCUS_REGIONS, -+ /**< @ref MMAL_PARAMETER_INPUT_CROP_T */ -+ MMAL_PARAMETER_INPUT_CROP, -+ /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */ -+ MMAL_PARAMETER_SENSOR_INFORMATION, -+ /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */ -+ MMAL_PARAMETER_FLASH_SELECT, -+ /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */ -+ MMAL_PARAMETER_FIELD_OF_VIEW, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, -+ /**< @ref MMAL_PARAMETER_DRC_T */ -+ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, -+ /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */ -+ MMAL_PARAMETER_ALGORITHM_CONTROL, -+ /**< @ref MMAL_PARAMETER_RATIONAL_T */ -+ MMAL_PARAMETER_SHARPNESS, -+ /**< @ref MMAL_PARAMETER_RATIONAL_T */ -+ MMAL_PARAMETER_CONTRAST, -+ /**< @ref MMAL_PARAMETER_RATIONAL_T */ -+ MMAL_PARAMETER_BRIGHTNESS, -+ /**< @ref MMAL_PARAMETER_RATIONAL_T */ -+ MMAL_PARAMETER_SATURATION, -+ -+ /* 0x30 */ -+ /**< @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_ISO, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_ANTISHAKE, -+ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */ -+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_CAMERA_BURST_CAPTURE, -+ /** @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_CAMERA_MIN_ISO, -+ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */ -+ MMAL_PARAMETER_CAMERA_USE_CASE, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_CAPTURE_STATS_PASS, -+ /** @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_ENABLE_REGISTER_FILE, -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL, -+ /** @ref MMAL_PARAMETER_CONFIGFILE_T */ -+ MMAL_PARAMETER_CONFIGFILE_REGISTERS, -+ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */ -+ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_JPEG_ATTACH_LOG, -+ /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */ -+ MMAL_PARAMETER_ZERO_SHUTTER_LAG, -+ /**< @ref MMAL_PARAMETER_FPS_RANGE_T */ -+ MMAL_PARAMETER_FPS_RANGE, -+ /**< @ref MMAL_PARAMETER_INT32_T */ -+ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, -+ -+ /* 0x40 */ -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_SW_SHARPEN_DISABLE, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_FLASH_REQUIRED, -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_SW_SATURATION_DISABLE, -+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_SHUTTER_SPEED, -+ /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */ -+ MMAL_PARAMETER_CUSTOM_AWB_GAINS, -+}; -+ -+struct mmal_parameter_rational { -+ s32 num; /**< Numerator */ -+ s32 den; /**< Denominator */ -+}; -+ -+enum mmal_parameter_camera_config_timestamp_mode { -+ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */ -+ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value -+ * for the frame timestamp -+ */ -+ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp -+ * but subtract the -+ * timestamp of the first -+ * frame sent to give a -+ * zero based timestamp. -+ */ -+}; -+ -+struct mmal_parameter_fps_range { -+ /**< Low end of the permitted framerate range */ -+ struct mmal_parameter_rational fps_low; -+ /**< High end of the permitted framerate range */ -+ struct mmal_parameter_rational fps_high; -+}; -+ -+/* camera configuration parameter */ -+struct mmal_parameter_camera_config { -+ /* Parameters for setting up the image pools */ -+ u32 max_stills_w; /* Max size of stills capture */ -+ u32 max_stills_h; -+ u32 stills_yuv422; /* Allow YUV422 stills capture */ -+ u32 one_shot_stills; /* Continuous or one shot stills captures. */ -+ -+ u32 max_preview_video_w; /* Max size of the preview or video -+ * capture frames -+ */ -+ u32 max_preview_video_h; -+ u32 num_preview_video_frames; -+ -+ /** Sets the height of the circular buffer for stills capture. */ -+ u32 stills_capture_circular_buffer_height; -+ -+ /** Allows preview/encode to resume as fast as possible after the stills -+ * input frame has been received, and then processes the still frame in -+ * the background whilst preview/encode has resumed. -+ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE. -+ */ -+ u32 fast_preview_resume; -+ -+ /** Selects algorithm for timestamping frames if -+ * there is no clock component connected. -+ * enum mmal_parameter_camera_config_timestamp_mode -+ */ -+ s32 use_stc_timestamp; -+}; -+ -+enum mmal_parameter_exposuremode { -+ MMAL_PARAM_EXPOSUREMODE_OFF, -+ MMAL_PARAM_EXPOSUREMODE_AUTO, -+ MMAL_PARAM_EXPOSUREMODE_NIGHT, -+ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, -+ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, -+ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, -+ MMAL_PARAM_EXPOSUREMODE_SPORTS, -+ MMAL_PARAM_EXPOSUREMODE_SNOW, -+ MMAL_PARAM_EXPOSUREMODE_BEACH, -+ MMAL_PARAM_EXPOSUREMODE_VERYLONG, -+ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, -+ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, -+ MMAL_PARAM_EXPOSUREMODE_FIREWORKS, -+}; -+ -+enum mmal_parameter_exposuremeteringmode { -+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE, -+ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT, -+ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT, -+ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX, -+}; -+ -+enum mmal_parameter_awbmode { -+ MMAL_PARAM_AWBMODE_OFF, -+ MMAL_PARAM_AWBMODE_AUTO, -+ MMAL_PARAM_AWBMODE_SUNLIGHT, -+ MMAL_PARAM_AWBMODE_CLOUDY, -+ MMAL_PARAM_AWBMODE_SHADE, -+ MMAL_PARAM_AWBMODE_TUNGSTEN, -+ MMAL_PARAM_AWBMODE_FLUORESCENT, -+ MMAL_PARAM_AWBMODE_INCANDESCENT, -+ MMAL_PARAM_AWBMODE_FLASH, -+ MMAL_PARAM_AWBMODE_HORIZON, -+}; -+ -+enum mmal_parameter_imagefx { -+ MMAL_PARAM_IMAGEFX_NONE, -+ MMAL_PARAM_IMAGEFX_NEGATIVE, -+ MMAL_PARAM_IMAGEFX_SOLARIZE, -+ MMAL_PARAM_IMAGEFX_POSTERIZE, -+ MMAL_PARAM_IMAGEFX_WHITEBOARD, -+ MMAL_PARAM_IMAGEFX_BLACKBOARD, -+ MMAL_PARAM_IMAGEFX_SKETCH, -+ MMAL_PARAM_IMAGEFX_DENOISE, -+ MMAL_PARAM_IMAGEFX_EMBOSS, -+ MMAL_PARAM_IMAGEFX_OILPAINT, -+ MMAL_PARAM_IMAGEFX_HATCH, -+ MMAL_PARAM_IMAGEFX_GPEN, -+ MMAL_PARAM_IMAGEFX_PASTEL, -+ MMAL_PARAM_IMAGEFX_WATERCOLOUR, -+ MMAL_PARAM_IMAGEFX_FILM, -+ MMAL_PARAM_IMAGEFX_BLUR, -+ MMAL_PARAM_IMAGEFX_SATURATION, -+ MMAL_PARAM_IMAGEFX_COLOURSWAP, -+ MMAL_PARAM_IMAGEFX_WASHEDOUT, -+ MMAL_PARAM_IMAGEFX_POSTERISE, -+ MMAL_PARAM_IMAGEFX_COLOURPOINT, -+ MMAL_PARAM_IMAGEFX_COLOURBALANCE, -+ MMAL_PARAM_IMAGEFX_CARTOON, -+}; -+ -+enum MMAL_PARAM_FLICKERAVOID_T { -+ MMAL_PARAM_FLICKERAVOID_OFF, -+ MMAL_PARAM_FLICKERAVOID_AUTO, -+ MMAL_PARAM_FLICKERAVOID_50HZ, -+ MMAL_PARAM_FLICKERAVOID_60HZ, -+ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF -+}; -+ -+struct mmal_parameter_awbgains { -+ struct mmal_parameter_rational r_gain; /**< Red gain */ -+ struct mmal_parameter_rational b_gain; /**< Blue gain */ -+}; -+ -+/** Manner of video rate control */ -+enum mmal_parameter_rate_control_mode { -+ MMAL_VIDEO_RATECONTROL_DEFAULT, -+ MMAL_VIDEO_RATECONTROL_VARIABLE, -+ MMAL_VIDEO_RATECONTROL_CONSTANT, -+ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES, -+ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES -+}; -+ -+enum mmal_video_profile { -+ MMAL_VIDEO_PROFILE_H263_BASELINE, -+ MMAL_VIDEO_PROFILE_H263_H320CODING, -+ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE, -+ MMAL_VIDEO_PROFILE_H263_ISWV2, -+ MMAL_VIDEO_PROFILE_H263_ISWV3, -+ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION, -+ MMAL_VIDEO_PROFILE_H263_INTERNET, -+ MMAL_VIDEO_PROFILE_H263_INTERLACE, -+ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLE, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE, -+ MMAL_VIDEO_PROFILE_MP4V_CORE, -+ MMAL_VIDEO_PROFILE_MP4V_MAIN, -+ MMAL_VIDEO_PROFILE_MP4V_NBIT, -+ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE, -+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA, -+ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED, -+ MMAL_VIDEO_PROFILE_MP4V_HYBRID, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME, -+ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE, -+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE, -+ MMAL_VIDEO_PROFILE_H264_BASELINE, -+ MMAL_VIDEO_PROFILE_H264_MAIN, -+ MMAL_VIDEO_PROFILE_H264_EXTENDED, -+ MMAL_VIDEO_PROFILE_H264_HIGH, -+ MMAL_VIDEO_PROFILE_H264_HIGH10, -+ MMAL_VIDEO_PROFILE_H264_HIGH422, -+ MMAL_VIDEO_PROFILE_H264_HIGH444, -+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, -+ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF -+}; -+ -+enum mmal_video_level { -+ MMAL_VIDEO_LEVEL_H263_10, -+ MMAL_VIDEO_LEVEL_H263_20, -+ MMAL_VIDEO_LEVEL_H263_30, -+ MMAL_VIDEO_LEVEL_H263_40, -+ MMAL_VIDEO_LEVEL_H263_45, -+ MMAL_VIDEO_LEVEL_H263_50, -+ MMAL_VIDEO_LEVEL_H263_60, -+ MMAL_VIDEO_LEVEL_H263_70, -+ MMAL_VIDEO_LEVEL_MP4V_0, -+ MMAL_VIDEO_LEVEL_MP4V_0b, -+ MMAL_VIDEO_LEVEL_MP4V_1, -+ MMAL_VIDEO_LEVEL_MP4V_2, -+ MMAL_VIDEO_LEVEL_MP4V_3, -+ MMAL_VIDEO_LEVEL_MP4V_4, -+ MMAL_VIDEO_LEVEL_MP4V_4a, -+ MMAL_VIDEO_LEVEL_MP4V_5, -+ MMAL_VIDEO_LEVEL_MP4V_6, -+ MMAL_VIDEO_LEVEL_H264_1, -+ MMAL_VIDEO_LEVEL_H264_1b, -+ MMAL_VIDEO_LEVEL_H264_11, -+ MMAL_VIDEO_LEVEL_H264_12, -+ MMAL_VIDEO_LEVEL_H264_13, -+ MMAL_VIDEO_LEVEL_H264_2, -+ MMAL_VIDEO_LEVEL_H264_21, -+ MMAL_VIDEO_LEVEL_H264_22, -+ MMAL_VIDEO_LEVEL_H264_3, -+ MMAL_VIDEO_LEVEL_H264_31, -+ MMAL_VIDEO_LEVEL_H264_32, -+ MMAL_VIDEO_LEVEL_H264_4, -+ MMAL_VIDEO_LEVEL_H264_41, -+ MMAL_VIDEO_LEVEL_H264_42, -+ MMAL_VIDEO_LEVEL_H264_5, -+ MMAL_VIDEO_LEVEL_H264_51, -+ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF -+}; -+ -+struct mmal_parameter_video_profile { -+ enum mmal_video_profile profile; -+ enum mmal_video_level level; -+}; -+ -+/* video parameters */ -+ -+enum mmal_parameter_video_type { -+ /** @ref MMAL_DISPLAYREGION_T */ -+ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ -+ MMAL_PARAMETER_SUPPORTED_PROFILES, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */ -+ MMAL_PARAMETER_PROFILE, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_INTRAPERIOD, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */ -+ MMAL_PARAMETER_RATECONTROL, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */ -+ MMAL_PARAMETER_NALUNITFORMAT, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. -+ * Setting the value to zero resets to the default (one slice per -+ * frame). -+ */ -+ MMAL_PARAMETER_MB_ROWS_PER_SLICE, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */ -+ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */ -+ MMAL_PARAMETER_VIDEO_EEDE_ENABLE, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */ -+ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */ -+ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, -+ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */ -+ MMAL_PARAMETER_VIDEO_INTRA_REFRESH, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -+ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */ -+ MMAL_PARAMETER_VIDEO_BIT_RATE, -+ -+ /** @ref MMAL_PARAMETER_FRAME_RATE_T */ -+ MMAL_PARAMETER_VIDEO_FRAME_RATE, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL, -+ -+ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */ -+ /** @ref MMAL_PARAMETER_UINT32_T. -+ * Changing this parameter from the default can reduce frame rate -+ * because image buffers need to be re-pitched. -+ */ -+ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. -+ * Changing this parameter from the default can reduce frame rate -+ * because image buffers need to be re-pitched. -+ */ -+ MMAL_PARAMETER_VIDEO_ALIGN_VERT, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -+ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, -+ -+ /**< @ref MMAL_PARAMETER_UINT32_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_QP_P, -+ -+ /**< @ref MMAL_PARAMETER_UINT32_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE, -+ -+ /* H264 specific parameters */ -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS, -+ -+ /** @ref MMAL_PARAMETER_UINT32_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */ -+ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO, -+ -+ /** @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT, -+ -+ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */ -+ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER, -+ -+ /** @ref MMAL_PARAMETER_BYTES_T */ -+ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3, -+ -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS, -+ -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, -+ -+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER -+}; -+ -+/** Valid mirror modes */ -+enum mmal_parameter_mirror { -+ MMAL_PARAM_MIRROR_NONE, -+ MMAL_PARAM_MIRROR_VERTICAL, -+ MMAL_PARAM_MIRROR_HORIZONTAL, -+ MMAL_PARAM_MIRROR_BOTH, -+}; -+ -+enum mmal_parameter_displaytransform { -+ MMAL_DISPLAY_ROT0 = 0, -+ MMAL_DISPLAY_MIRROR_ROT0 = 1, -+ MMAL_DISPLAY_MIRROR_ROT180 = 2, -+ MMAL_DISPLAY_ROT180 = 3, -+ MMAL_DISPLAY_MIRROR_ROT90 = 4, -+ MMAL_DISPLAY_ROT270 = 5, -+ MMAL_DISPLAY_ROT90 = 6, -+ MMAL_DISPLAY_MIRROR_ROT270 = 7, -+}; -+ -+enum mmal_parameter_displaymode { -+ MMAL_DISPLAY_MODE_FILL = 0, -+ MMAL_DISPLAY_MODE_LETTERBOX = 1, -+}; -+ -+enum mmal_parameter_displayset { -+ MMAL_DISPLAY_SET_NONE = 0, -+ MMAL_DISPLAY_SET_NUM = 1, -+ MMAL_DISPLAY_SET_FULLSCREEN = 2, -+ MMAL_DISPLAY_SET_TRANSFORM = 4, -+ MMAL_DISPLAY_SET_DEST_RECT = 8, -+ MMAL_DISPLAY_SET_SRC_RECT = 0x10, -+ MMAL_DISPLAY_SET_MODE = 0x20, -+ MMAL_DISPLAY_SET_PIXEL = 0x40, -+ MMAL_DISPLAY_SET_NOASPECT = 0x80, -+ MMAL_DISPLAY_SET_LAYER = 0x100, -+ MMAL_DISPLAY_SET_COPYPROTECT = 0x200, -+ MMAL_DISPLAY_SET_ALPHA = 0x400, -+}; -+ -+/* rectangle, used lots so it gets its own struct */ -+struct vchiq_mmal_rect { -+ s32 x; -+ s32 y; -+ s32 width; -+ s32 height; -+}; -+ -+struct mmal_parameter_displayregion { -+ /** Bitfield that indicates which fields are set and should be -+ * used. All other fields will maintain their current value. -+ * \ref MMAL_DISPLAYSET_T defines the bits that can be -+ * combined. -+ */ -+ u32 set; -+ -+ /** Describes the display output device, with 0 typically -+ * being a directly connected LCD display. The actual values -+ * will depend on the hardware. Code using hard-wired numbers -+ * (e.g. 2) is certain to fail. -+ */ -+ -+ u32 display_num; -+ /** Indicates that we are using the full device screen area, -+ * rather than a window of the display. If zero, then -+ * dest_rect is used to specify a region of the display to -+ * use. -+ */ -+ -+ s32 fullscreen; -+ /** Indicates any rotation or flipping used to map frames onto -+ * the natural display orientation. -+ */ -+ u32 transform; /* enum mmal_parameter_displaytransform */ -+ -+ /** Where to display the frame within the screen, if -+ * fullscreen is zero. -+ */ -+ struct vchiq_mmal_rect dest_rect; -+ -+ /** Indicates which area of the frame to display. If all -+ * values are zero, the whole frame will be used. -+ */ -+ struct vchiq_mmal_rect src_rect; -+ -+ /** If set to non-zero, indicates that any display scaling -+ * should disregard the aspect ratio of the frame region being -+ * displayed. -+ */ -+ s32 noaspect; -+ -+ /** Indicates how the image should be scaled to fit the -+ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates -+ * that the image should fill the screen by potentially -+ * cropping the frames. Setting \code mode \endcode to \code -+ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the -+ * source region should be displayed and black bars added if -+ * necessary. -+ */ -+ u32 mode; /* enum mmal_parameter_displaymode */ -+ -+ /** If non-zero, defines the width of a source pixel relative -+ * to \code pixel_y \endcode. If zero, then pixels default to -+ * being square. -+ */ -+ u32 pixel_x; -+ -+ /** If non-zero, defines the height of a source pixel relative -+ * to \code pixel_x \endcode. If zero, then pixels default to -+ * being square. -+ */ -+ u32 pixel_y; -+ -+ /** Sets the relative depth of the images, with greater values -+ * being in front of smaller values. -+ */ -+ u32 layer; -+ -+ /** Set to non-zero to ensure copy protection is used on -+ * output. -+ */ -+ s32 copyprotect_required; -+ -+ /** Level of opacity of the layer, where zero is fully -+ * transparent and 255 is fully opaque. -+ */ -+ u32 alpha; -+}; -+ -+#define MMAL_MAX_IMAGEFX_PARAMETERS 5 -+ -+struct mmal_parameter_imagefx_parameters { -+ enum mmal_parameter_imagefx effect; -+ u32 num_effect_params; -+ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS]; -+}; -+ -+#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4 -+#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2 -+#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16 -+ -+struct mmal_parameter_camera_info_camera_t { -+ u32 port_id; -+ u32 max_width; -+ u32 max_height; -+ u32 lens_present; -+ u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN]; -+}; -+ -+enum mmal_parameter_camera_info_flash_type_t { -+ /* Make values explicit to ensure they match values in config ini */ -+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0, -+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1, -+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2, -+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF -+}; -+ -+struct mmal_parameter_camera_info_flash_t { -+ enum mmal_parameter_camera_info_flash_type_t flash_type; -+}; -+ -+struct mmal_parameter_camera_info_t { -+ u32 num_cameras; -+ u32 num_flashes; -+ struct mmal_parameter_camera_info_camera_t -+ cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS]; -+ struct mmal_parameter_camera_info_flash_t -+ flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES]; -+}; -+ -+#endif ---- /dev/null -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -0,0 +1,166 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Broadcom BM2835 V4L2 driver -+ * -+ * Copyright © 2013 Raspberry Pi (Trading) Ltd. -+ * -+ * Authors: Vincent Sanders @ Collabora -+ * Dave Stevenson @ Broadcom -+ * (now dave.stevenson@raspberrypi.org) -+ * Simon Mellor @ Broadcom -+ * Luke Diamand @ Broadcom -+ * -+ * MMAL interface to VCHIQ message passing -+ */ -+ -+#ifndef MMAL_VCHIQ_H -+#define MMAL_VCHIQ_H -+ -+#include "mmal-msg-format.h" -+ -+#define MAX_PORT_COUNT 4 -+ -+/* Maximum size of the format extradata. */ -+#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128 -+ -+struct vchiq_mmal_instance; -+ -+enum vchiq_mmal_es_type { -+ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */ -+ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */ -+ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */ -+ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */ -+ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */ -+}; -+ -+struct vchiq_mmal_port_buffer { -+ unsigned int num; /* number of buffers */ -+ u32 size; /* size of buffers */ -+ u32 alignment; /* alignment of buffers */ -+}; -+ -+struct vchiq_mmal_port; -+ -+typedef void (*vchiq_mmal_buffer_cb)( -+ struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ int status, struct mmal_buffer *buffer, -+ unsigned long length, u32 mmal_flags, s64 dts, s64 pts); -+ -+struct vchiq_mmal_port { -+ u32 enabled:1; -+ u32 handle; -+ u32 type; /* port type, cached to use on port info set */ -+ u32 index; /* port index, cached to use on port info set */ -+ -+ /* component port belongs to, allows simple deref */ -+ struct vchiq_mmal_component *component; -+ -+ struct vchiq_mmal_port *connected; /* port connected to */ -+ -+ /* buffer info */ -+ struct vchiq_mmal_port_buffer minimum_buffer; -+ struct vchiq_mmal_port_buffer recommended_buffer; -+ struct vchiq_mmal_port_buffer current_buffer; -+ -+ /* stream format */ -+ struct mmal_es_format_local format; -+ /* elementary stream format */ -+ union mmal_es_specific_format es; -+ -+ /* data buffers to fill */ -+ struct list_head buffers; -+ /* lock to serialise adding and removing buffers from list */ -+ spinlock_t slock; -+ -+ /* Count of buffers the VPU has yet to return */ -+ atomic_t buffers_with_vpu; -+ /* callback on buffer completion */ -+ vchiq_mmal_buffer_cb buffer_cb; -+ /* callback context */ -+ void *cb_ctx; -+}; -+ -+struct vchiq_mmal_component { -+ u32 enabled:1; -+ u32 handle; /* VideoCore handle for component */ -+ u32 inputs; /* Number of input ports */ -+ u32 outputs; /* Number of output ports */ -+ u32 clocks; /* Number of clock ports */ -+ struct vchiq_mmal_port control; /* control port */ -+ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */ -+ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */ -+ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */ -+}; -+ -+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance); -+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance); -+ -+/* Initialise a mmal component and its ports -+ * -+ */ -+int vchiq_mmal_component_init( -+ struct vchiq_mmal_instance *instance, -+ const char *name, -+ struct vchiq_mmal_component **component_out); -+ -+int vchiq_mmal_component_finalise( -+ struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component); -+ -+int vchiq_mmal_component_enable( -+ struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component); -+ -+int vchiq_mmal_component_disable( -+ struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_component *component); -+ -+/* enable a mmal port -+ * -+ * enables a port and if a buffer callback provided enque buffer -+ * headers as appropriate for the port. -+ */ -+int vchiq_mmal_port_enable( -+ struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ vchiq_mmal_buffer_cb buffer_cb); -+ -+/* disable a port -+ * -+ * disable a port will dequeue any pending buffers -+ */ -+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port); -+ -+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ u32 parameter, -+ void *value, -+ u32 value_size); -+ -+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ u32 parameter, -+ void *value, -+ u32 *value_size); -+ -+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port); -+ -+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *src, -+ struct vchiq_mmal_port *dst); -+ -+int vchiq_mmal_version(struct vchiq_mmal_instance *instance, -+ u32 *major_out, -+ u32 *minor_out); -+ -+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, -+ struct mmal_buffer *buf); -+ -+int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, -+ struct mmal_buffer *buf); -+int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf); -+#endif /* MMAL_VCHIQ_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0167-staging-mmal-vchiq-Allocate-and-free-components-as-r.patch b/target/linux/bcm27xx/patches-5.4/950-0167-staging-mmal-vchiq-Allocate-and-free-components-as-r.patch deleted file mode 100644 index 53a6c07e9d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0167-staging-mmal-vchiq-Allocate-and-free-components-as-r.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 238065901c1b476a5b093f1710773322b3344847 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 24 Sep 2018 16:51:13 +0100 -Subject: [PATCH] staging: mmal-vchiq: Allocate and free components as - required - -The existing code assumed that there would only ever be 4 components, -and never freed the entries once used. -Allow arbitrary creation and destruction of components. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++++++++------- - .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + - 2 files changed, 20 insertions(+), 10 deletions(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -37,8 +37,11 @@ MODULE_AUTHOR("Dave Stevenson, vchiq_mutex)) - return -EINTR; - -- if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) { -+ for (idx = 0; idx < VCHIQ_MMAL_MAX_COMPONENTS; idx++) { -+ if (!instance->component[idx].in_use) { -+ component = &instance->component[idx]; -+ component->in_use = 1; -+ break; -+ } -+ } -+ -+ if (!component) { - ret = -EINVAL; /* todo is this correct error? */ - goto unlock; - } - -- component = &instance->component[instance->component_idx]; -- - ret = create_component(instance, component, name); - if (ret < 0) { - pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", -@@ -1693,8 +1700,6 @@ int vchiq_mmal_component_init(struct vch - goto release_component; - } - -- instance->component_idx++; -- - *component_out = component; - - mutex_unlock(&instance->vchiq_mutex); -@@ -1704,6 +1709,8 @@ int vchiq_mmal_component_init(struct vch - release_component: - destroy_component(instance, component); - unlock: -+ if (component) -+ component->in_use = 0; - mutex_unlock(&instance->vchiq_mutex); - - return ret; -@@ -1726,6 +1733,8 @@ int vchiq_mmal_component_finalise(struct - - ret = destroy_component(instance, component); - -+ component->in_use = 0; -+ - mutex_unlock(&instance->vchiq_mutex); - - return ret; ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -82,6 +82,7 @@ struct vchiq_mmal_port { - }; - - struct vchiq_mmal_component { -+ u32 in_use:1; - u32 enabled:1; - u32 handle; /* VideoCore handle for component */ - u32 inputs; /* Number of input ports */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0167-staging-mmal-vchiq-Make-timeout-a-defined-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0167-staging-mmal-vchiq-Make-timeout-a-defined-parameter.patch new file mode 100644 index 0000000000..fa37fff35f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0167-staging-mmal-vchiq-Make-timeout-a-defined-parameter.patch @@ -0,0 +1,38 @@ +From e080da14485a0aba8dc364b02b7ff2c92e5a4fe8 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 24 Sep 2018 16:57:09 +0100 +Subject: [PATCH] staging: mmal-vchiq: Make timeout a defined parameter + +The timeout period for VPU communications is a useful thing +to extend when debugging. +Set it via a define, rather than a magic number buried in the code. + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -43,6 +43,12 @@ MODULE_VERSION("0.0.1"); + */ + #define VCHIQ_MMAL_MAX_COMPONENTS 64 + ++/* ++ * Timeout for synchronous msg responses in seconds. ++ * Helpful to increase this if stopping in the VPU debugger. ++ */ ++#define SYNC_MSG_TIMEOUT 3 ++ + /*#define FULL_MSG_DUMP 1*/ + + #ifdef DEBUG +@@ -691,7 +697,7 @@ static int send_synchronous_mmal_msg(str + } + + timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt, +- 3 * HZ); ++ SYNC_MSG_TIMEOUT * HZ); + if (timeout == 0) { + pr_err("timed out waiting for sync completion\n"); + ret = -ETIME; diff --git a/target/linux/bcm27xx/patches-5.4/950-0168-staging-mmal-vchiq-Avoid-use-of-bool-in-structures.patch b/target/linux/bcm27xx/patches-5.4/950-0168-staging-mmal-vchiq-Avoid-use-of-bool-in-structures.patch deleted file mode 100644 index 31f7c8a525..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0168-staging-mmal-vchiq-Avoid-use-of-bool-in-structures.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 98ba3ab478e0628304379673a6fa0a02e8db2166 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 29 Oct 2018 16:20:46 +0000 -Subject: [PATCH] staging: mmal-vchiq: Avoid use of bool in structures - -Fixes up a checkpatch error "Avoid using bool structure members -because of possible alignment issues". - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -1759,7 +1759,7 @@ int vchiq_mmal_component_enable(struct v - - ret = enable_component(instance, component); - if (ret == 0) -- component->enabled = true; -+ component->enabled = 1; - - mutex_unlock(&instance->vchiq_mutex); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0168-staging-mmal-vchiq-Make-a-mmal_buf-struct-for-passin.patch b/target/linux/bcm27xx/patches-5.4/950-0168-staging-mmal-vchiq-Make-a-mmal_buf-struct-for-passin.patch new file mode 100644 index 0000000000..95f5885c4a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0168-staging-mmal-vchiq-Make-a-mmal_buf-struct-for-passin.patch @@ -0,0 +1,278 @@ +From b4c0c420e616e1cdf7abd309000e779b350fb2da Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 24 Sep 2018 17:33:37 +0100 +Subject: [PATCH] staging: mmal-vchiq: Make a mmal_buf struct for + passing parameters + +The callback from vchi_mmal to the client was growing lots of extra +parameters. Consolidate them into a single struct instead of +growing the list further. +The struct is associated with the client buffer, therefore there +are various changes to setup various containers for the struct, +and pass the appropriate members. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-camera/bcm2835-camera.c | 60 ++++++++++++------- + .../vc04_services/vchiq-mmal/mmal-common.h | 5 ++ + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++--- + .../vc04_services/vchiq-mmal/mmal-vchiq.h | 3 +- + 4 files changed, 63 insertions(+), 34 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c ++++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +@@ -72,6 +72,12 @@ static const struct v4l2_fract + tpf_max = {.numerator = 1, .denominator = FPS_MIN}, + tpf_default = {.numerator = 1000, .denominator = 30000}; + ++/* Container for MMAL and VB2 buffers*/ ++struct vb2_mmal_buffer { ++ struct vb2_v4l2_buffer vb; ++ struct mmal_buffer mmal; ++}; ++ + /* video formats */ + static struct mmal_fmt formats[] = { + { +@@ -258,14 +264,15 @@ static int buffer_init(struct vb2_buffer + { + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); +- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); ++ struct vb2_mmal_buffer *buf = ++ container_of(vb2, struct vb2_mmal_buffer, vb); + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n", + __func__, dev, vb); +- buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); +- buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0); ++ buf->mmal.buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); ++ buf->mmal.buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0); + +- return mmal_vchi_buffer_init(dev->instance, buf); ++ return mmal_vchi_buffer_init(dev->instance, &buf->mmal); + } + + static int buffer_prepare(struct vb2_buffer *vb) +@@ -294,11 +301,13 @@ static void buffer_cleanup(struct vb2_bu + { + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); +- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); ++ struct vb2_mmal_buffer *buf = ++ container_of(vb2, struct vb2_mmal_buffer, vb); + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n", + __func__, dev, vb); +- mmal_vchi_buffer_cleanup(buf); ++ ++ mmal_vchi_buffer_cleanup(&buf->mmal); + } + + static inline bool is_capturing(struct bm2835_mmal_dev *dev) +@@ -310,14 +319,16 @@ static inline bool is_capturing(struct b + static void buffer_cb(struct vchiq_mmal_instance *instance, + struct vchiq_mmal_port *port, + int status, +- struct mmal_buffer *buf, +- unsigned long length, u32 mmal_flags, s64 dts, s64 pts) ++ struct mmal_buffer *mmal_buf) + { + struct bm2835_mmal_dev *dev = port->cb_ctx; ++ struct vb2_mmal_buffer *buf = ++ container_of(mmal_buf, struct vb2_mmal_buffer, mmal); + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n", +- __func__, status, buf, length, mmal_flags, pts); ++ __func__, status, buf, mmal_buf->length, mmal_buf->mmal_flags, ++ mmal_buf->pts); + + if (status) { + /* error in transfer */ +@@ -328,7 +339,7 @@ static void buffer_cb(struct vchiq_mmal_ + return; + } + +- if (length == 0) { ++ if (mmal_buf->length == 0) { + /* stream ended */ + if (dev->capture.frame_count) { + /* empty buffer whilst capturing - expected to be an +@@ -344,7 +355,8 @@ static void buffer_cb(struct vchiq_mmal_ + &dev->capture.frame_count, + sizeof(dev->capture.frame_count)); + } +- if (vchiq_mmal_submit_buffer(instance, port, buf)) ++ if (vchiq_mmal_submit_buffer(instance, port, ++ &buf->mmal)) + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "Failed to return EOS buffer"); + } else { +@@ -371,14 +383,14 @@ static void buffer_cb(struct vchiq_mmal_ + buf->vb.vb2_buf.timestamp); + } else if (mmal_buf->pts != 0) { + ktime_t timestamp; +- s64 runtime_us = pts - ++ s64 runtime_us = mmal_buf->pts - + dev->capture.vc_start_timestamp; + timestamp = ktime_add_us(dev->capture.kernel_start_ts, + runtime_us); + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "Convert start time %llu and %llu with offset %llu to %llu\n", + ktime_to_ns(dev->capture.kernel_start_ts), +- dev->capture.vc_start_timestamp, pts, ++ dev->capture.vc_start_timestamp, mmal_buf->pts, + ktime_to_ns(timestamp)); + if (timestamp < dev->capture.last_timestamp) { + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, +@@ -407,8 +419,8 @@ static void buffer_cb(struct vchiq_mmal_ + buf->vb.sequence = dev->capture.sequence++; + buf->vb.field = V4L2_FIELD_NONE; + +- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length); +- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) ++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, mmal_buf->length); ++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) + buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME; + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, +@@ -416,7 +428,7 @@ static void buffer_cb(struct vchiq_mmal_ + dev->capture.last_timestamp); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + +- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS && ++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS && + is_capturing(dev)) { + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "Grab another frame as buffer has EOS"); +@@ -500,14 +512,16 @@ static void buffer_queue(struct vb2_buff + { + struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); +- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); ++ struct vb2_mmal_buffer *buf = ++ container_of(vb2, struct vb2_mmal_buffer, vb); + int ret; + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "%s: dev:%p buf:%p, idx %u\n", + __func__, dev, buf, vb2->vb2_buf.index); + +- ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf); ++ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, ++ &buf->mmal); + if (ret < 0) + v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n", + __func__); +@@ -621,7 +635,7 @@ static void stop_streaming(struct vb2_qu + dev->capture.frame_count = 0; + + /* ensure a format has actually been set */ +- if (!dev->capture.port) { ++ if (!port) { + v4l2_err(&dev->v4l2_dev, + "no capture port - stream not started?\n"); + return; +@@ -641,11 +655,11 @@ static void stop_streaming(struct vb2_qu + + /* disable the connection from camera to encoder */ + ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port); +- if (!ret && dev->capture.camera_port != dev->capture.port) { ++ if (!ret && dev->capture.camera_port != port) { + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "disabling port\n"); +- ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port); +- } else if (dev->capture.camera_port != dev->capture.port) { ++ ret = vchiq_mmal_port_disable(dev->instance, port); ++ } else if (dev->capture.camera_port != port) { + v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n", + ret); + } +@@ -1947,7 +1961,7 @@ static int bcm2835_mmal_probe(struct pla + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + q->drv_priv = dev; +- q->buf_struct_size = sizeof(struct mmal_buffer); ++ q->buf_struct_size = sizeof(struct vb2_mmal_buffer); + q->ops = &bm2835_mmal_video_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h +@@ -49,6 +49,11 @@ struct mmal_buffer { + unsigned long buffer_size; /* size of allocated buffer */ + + struct mmal_msg_context *msg_context; ++ ++ unsigned long length; ++ u32 mmal_flags; ++ s64 dts; ++ s64 pts; + }; + + /* */ +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -258,17 +258,25 @@ static void buffer_work_cb(struct work_s + { + struct mmal_msg_context *msg_context = + container_of(work, struct mmal_msg_context, u.bulk.work); ++ struct mmal_buffer *buffer = msg_context->u.bulk.buffer; ++ ++ if (!buffer) { ++ pr_err("%s: ctx: %p, No mmal buffer to pass details\n", ++ __func__, msg_context); ++ return; ++ } ++ ++ buffer->length = msg_context->u.bulk.buffer_used; ++ buffer->mmal_flags = msg_context->u.bulk.mmal_flags; ++ buffer->dts = msg_context->u.bulk.dts; ++ buffer->pts = msg_context->u.bulk.pts; + + atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); + + msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, + msg_context->u.bulk.port, + msg_context->u.bulk.status, +- msg_context->u.bulk.buffer, +- msg_context->u.bulk.buffer_used, +- msg_context->u.bulk.mmal_flags, +- msg_context->u.bulk.dts, +- msg_context->u.bulk.pts); ++ msg_context->u.bulk.buffer); + } + + /* workqueue scheduled callback to handle receiving buffers +@@ -1326,11 +1334,14 @@ static int port_disable(struct vchiq_mma + mmalbuf = list_entry(buf_head, struct mmal_buffer, + list); + list_del(buf_head); +- if (port->buffer_cb) ++ if (port->buffer_cb) { ++ mmalbuf->length = 0; ++ mmalbuf->mmal_flags = 0; ++ mmalbuf->dts = MMAL_TIME_UNKNOWN; ++ mmalbuf->pts = MMAL_TIME_UNKNOWN; + port->buffer_cb(instance, +- port, 0, mmalbuf, 0, 0, +- MMAL_TIME_UNKNOWN, +- MMAL_TIME_UNKNOWN); ++ port, 0, mmalbuf); ++ } + } + + spin_unlock_irqrestore(&port->slock, flags); +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -44,8 +44,7 @@ struct vchiq_mmal_port; + typedef void (*vchiq_mmal_buffer_cb)( + struct vchiq_mmal_instance *instance, + struct vchiq_mmal_port *port, +- int status, struct mmal_buffer *buffer, +- unsigned long length, u32 mmal_flags, s64 dts, s64 pts); ++ int status, struct mmal_buffer *buffer); + + struct vchiq_mmal_port { + u32 enabled:1; diff --git a/target/linux/bcm27xx/patches-5.4/950-0169-staging-mmal-vchiq-Add-support-for-event-callbacks.patch b/target/linux/bcm27xx/patches-5.4/950-0169-staging-mmal-vchiq-Add-support-for-event-callbacks.patch new file mode 100644 index 0000000000..125f9d552e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0169-staging-mmal-vchiq-Add-support-for-event-callbacks.patch @@ -0,0 +1,356 @@ +From 10f4396064d55253a9af8ec3856519bbe606ddf4 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 24 Sep 2018 18:15:38 +0100 +Subject: [PATCH] staging: mmal-vchiq: Add support for event callbacks. + +(Preparation for the codec driver). +The codec uses the event mechanism to report things such as +resolution changes. It is signalled by the cmd field of the buffer +being non-zero. + +Add support for passing this information out to the client. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/vchiq-mmal/mmal-common.h | 1 + + .../vc04_services/vchiq-mmal/mmal-msg.h | 35 ++++ + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 170 ++++++++++++++++-- + .../vc04_services/vchiq-mmal/mmal-vchiq.h | 4 + + 4 files changed, 196 insertions(+), 14 deletions(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h +@@ -50,6 +50,7 @@ struct mmal_buffer { + + struct mmal_msg_context *msg_context; + ++ u32 cmd; /* MMAL command. 0=data. */ + unsigned long length; + u32 mmal_flags; + s64 dts; +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h +@@ -346,6 +346,41 @@ struct mmal_msg_port_parameter_get_reply + /* event messages */ + #define MMAL_WORKER_EVENT_SPACE 256 + ++/* Four CC's for events */ ++#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24)) ++ ++#define MMAL_EVENT_ERROR MMAL_FOURCC('E', 'R', 'R', 'O') ++#define MMAL_EVENT_EOS MMAL_FOURCC('E', 'E', 'O', 'S') ++#define MMAL_EVENT_FORMAT_CHANGED MMAL_FOURCC('E', 'F', 'C', 'H') ++#define MMAL_EVENT_PARAMETER_CHANGED MMAL_FOURCC('E', 'P', 'C', 'H') ++ ++/* Structs for each of the event message payloads */ ++struct mmal_msg_event_eos { ++ u32 port_type; /**< Type of port that received the end of stream */ ++ u32 port_index; /**< Index of port that received the end of stream */ ++}; ++ ++/** Format changed event data. */ ++struct mmal_msg_event_format_changed { ++ /* Minimum size of buffers the port requires */ ++ u32 buffer_size_min; ++ /* Minimum number of buffers the port requires */ ++ u32 buffer_num_min; ++ /* Size of buffers the port recommends for optimal performance. ++ * A value of zero means no special recommendation. ++ */ ++ u32 buffer_size_recommended; ++ /* Number of buffers the port recommends for optimal ++ * performance. A value of zero means no special recommendation. ++ */ ++ u32 buffer_num_recommended; ++ ++ u32 es_ptr; ++ struct mmal_es_format format; ++ union mmal_es_specific_format es; ++ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; ++}; ++ + struct mmal_msg_event_to_host { + u32 client_component; /* component context */ + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -150,6 +150,8 @@ struct mmal_msg_context { + /* Presentation and Decode timestamps */ + s64 pts; + s64 dts; ++ /* MMAL buffer command flag */ ++ u32 cmd; + + int status; /* context status */ + +@@ -237,18 +239,6 @@ release_msg_context(struct mmal_msg_cont + kfree(msg_context); + } + +-/* deals with receipt of event to host message */ +-static void event_to_host_cb(struct vchiq_mmal_instance *instance, +- struct mmal_msg *msg, u32 msg_len) +-{ +- pr_debug("unhandled event\n"); +- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n", +- msg->u.event_to_host.client_component, +- msg->u.event_to_host.port_type, +- msg->u.event_to_host.port_num, +- msg->u.event_to_host.cmd, msg->u.event_to_host.length); +-} +- + /* workqueue scheduled callback + * + * we do this because it is important we do not call any other vchiq +@@ -270,13 +260,18 @@ static void buffer_work_cb(struct work_s + buffer->mmal_flags = msg_context->u.bulk.mmal_flags; + buffer->dts = msg_context->u.bulk.dts; + buffer->pts = msg_context->u.bulk.pts; ++ buffer->cmd = msg_context->u.bulk.cmd; + +- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); ++ if (!buffer->cmd) ++ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); + + msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, + msg_context->u.bulk.port, + msg_context->u.bulk.status, + msg_context->u.bulk.buffer); ++ ++ if (buffer->cmd) ++ mutex_unlock(&msg_context->u.bulk.port->event_context_mutex); + } + + /* workqueue scheduled callback to handle receiving buffers +@@ -355,6 +350,7 @@ static int bulk_receive(struct vchiq_mma + msg_context->u.bulk.buffer_used = rd_len; + msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts; + msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts; ++ msg_context->u.bulk.cmd = msg->u.buffer_from_host.buffer_header.cmd; + + queue_work(msg_context->instance->bulk_wq, + &msg_context->u.bulk.buffer_to_host_work); +@@ -456,6 +452,103 @@ buffer_from_host(struct vchiq_mmal_insta + return ret; + } + ++/* deals with receipt of event to host message */ ++static void event_to_host_cb(struct vchiq_mmal_instance *instance, ++ struct mmal_msg *msg, u32 msg_len) ++{ ++ /* FIXME: Not going to work on 64 bit */ ++ struct vchiq_mmal_component *component = ++ (struct vchiq_mmal_component *)msg->u.event_to_host.client_component; ++ struct vchiq_mmal_port *port = NULL; ++ struct mmal_msg_context *msg_context; ++ u32 port_num = msg->u.event_to_host.port_num; ++ ++ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) { ++ pr_err("%s: MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n", ++ __func__); ++ return; ++ } ++ ++ switch (msg->u.event_to_host.port_type) { ++ case MMAL_PORT_TYPE_CONTROL: ++ if (port_num) { ++ pr_err("%s: port_num of %u >= number of ports 1", ++ __func__, port_num); ++ return; ++ } ++ port = &component->control; ++ break; ++ case MMAL_PORT_TYPE_INPUT: ++ if (port_num >= component->inputs) { ++ pr_err("%s: port_num of %u >= number of ports %u", ++ __func__, port_num, ++ port_num >= component->inputs); ++ return; ++ } ++ port = &component->input[port_num]; ++ break; ++ case MMAL_PORT_TYPE_OUTPUT: ++ if (port_num >= component->outputs) { ++ pr_err("%s: port_num of %u >= number of ports %u", ++ __func__, port_num, ++ port_num >= component->outputs); ++ return; ++ } ++ port = &component->output[port_num]; ++ break; ++ case MMAL_PORT_TYPE_CLOCK: ++ if (port_num >= component->clocks) { ++ pr_err("%s: port_num of %u >= number of ports %u", ++ __func__, port_num, ++ port_num >= component->clocks); ++ return; ++ } ++ port = &component->clock[port_num]; ++ break; ++ default: ++ break; ++ } ++ ++ if (!mutex_trylock(&port->event_context_mutex)) { ++ pr_err("dropping event 0x%x\n", msg->u.event_to_host.cmd); ++ return; ++ } ++ msg_context = port->event_context; ++ ++ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) { ++ /* message reception had an error */ ++ //pr_warn ++ pr_err("%s: error %d in reply\n", __func__, msg->h.status); ++ ++ msg_context->u.bulk.status = msg->h.status; ++ } else if (msg->u.event_to_host.length > MMAL_WORKER_EVENT_SPACE) { ++ /* data is not in message, queue a bulk receive */ ++ pr_err("%s: payload not in message - bulk receive??! NOT SUPPORTED\n", ++ __func__); ++ msg_context->u.bulk.status = -1; ++ } else { ++ memcpy(msg_context->u.bulk.buffer->buffer, ++ msg->u.event_to_host.data, ++ msg->u.event_to_host.length); ++ ++ msg_context->u.bulk.buffer_used = ++ msg->u.event_to_host.length; ++ ++ msg_context->u.bulk.mmal_flags = 0; ++ msg_context->u.bulk.dts = MMAL_TIME_UNKNOWN; ++ msg_context->u.bulk.pts = MMAL_TIME_UNKNOWN; ++ msg_context->u.bulk.cmd = msg->u.event_to_host.cmd; ++ ++ pr_debug("event component:%u port type:%d num:%d cmd:0x%x length:%d\n", ++ msg->u.event_to_host.client_component, ++ msg->u.event_to_host.port_type, ++ msg->u.event_to_host.port_num, ++ msg->u.event_to_host.cmd, msg->u.event_to_host.length); ++ } ++ ++ schedule_work(&msg_context->u.bulk.work); ++} ++ + /* deals with receipt of buffer to host message */ + static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, + struct mmal_msg *msg, u32 msg_len) +@@ -1339,6 +1432,7 @@ static int port_disable(struct vchiq_mma + mmalbuf->mmal_flags = 0; + mmalbuf->dts = MMAL_TIME_UNKNOWN; + mmalbuf->pts = MMAL_TIME_UNKNOWN; ++ mmalbuf->cmd = 0; + port->buffer_cb(instance, + port, 0, mmalbuf); + } +@@ -1640,6 +1734,43 @@ int mmal_vchi_buffer_cleanup(struct mmal + } + EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); + ++static void init_event_context(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port) ++{ ++ struct mmal_msg_context *ctx = get_msg_context(instance); ++ ++ mutex_init(&port->event_context_mutex); ++ ++ port->event_context = ctx; ++ ctx->u.bulk.instance = instance; ++ ctx->u.bulk.port = port; ++ ctx->u.bulk.buffer = ++ kzalloc(sizeof(*ctx->u.bulk.buffer), GFP_KERNEL); ++ if (!ctx->u.bulk.buffer) ++ goto release_msg_context; ++ ctx->u.bulk.buffer->buffer = kzalloc(MMAL_WORKER_EVENT_SPACE, ++ GFP_KERNEL); ++ if (!ctx->u.bulk.buffer->buffer) ++ goto release_buffer; ++ ++ INIT_WORK(&ctx->u.bulk.work, buffer_work_cb); ++ return; ++ ++release_buffer: ++ kfree(ctx->u.bulk.buffer); ++release_msg_context: ++ release_msg_context(ctx); ++} ++ ++static void free_event_context(struct vchiq_mmal_port *port) ++{ ++ struct mmal_msg_context *ctx = port->event_context; ++ ++ kfree(ctx->u.bulk.buffer->buffer); ++ kfree(ctx->u.bulk.buffer); ++ release_msg_context(ctx); ++} ++ + /* Initialise a mmal component and its ports + * + */ +@@ -1683,6 +1814,7 @@ int vchiq_mmal_component_init(struct vch + ret = port_info_get(instance, &component->control); + if (ret < 0) + goto release_component; ++ init_event_context(instance, &component->control); + + for (idx = 0; idx < component->inputs; idx++) { + component->input[idx].type = MMAL_PORT_TYPE_INPUT; +@@ -1693,6 +1825,7 @@ int vchiq_mmal_component_init(struct vch + ret = port_info_get(instance, &component->input[idx]); + if (ret < 0) + goto release_component; ++ init_event_context(instance, &component->input[idx]); + } + + for (idx = 0; idx < component->outputs; idx++) { +@@ -1704,6 +1837,7 @@ int vchiq_mmal_component_init(struct vch + ret = port_info_get(instance, &component->output[idx]); + if (ret < 0) + goto release_component; ++ init_event_context(instance, &component->output[idx]); + } + + for (idx = 0; idx < component->clocks; idx++) { +@@ -1715,6 +1849,7 @@ int vchiq_mmal_component_init(struct vch + ret = port_info_get(instance, &component->clock[idx]); + if (ret < 0) + goto release_component; ++ init_event_context(instance, &component->clock[idx]); + } + + *component_out = component; +@@ -1740,7 +1875,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i + int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, + struct vchiq_mmal_component *component) + { +- int ret; ++ int ret, idx; + + if (mutex_lock_interruptible(&instance->vchiq_mutex)) + return -EINTR; +@@ -1752,6 +1887,13 @@ int vchiq_mmal_component_finalise(struct + + component->in_use = 0; + ++ for (idx = 0; idx < component->inputs; idx++) ++ free_event_context(&component->input[idx]); ++ for (idx = 0; idx < component->outputs; idx++) ++ free_event_context(&component->output[idx]); ++ for (idx = 0; idx < component->clocks; idx++) ++ free_event_context(&component->clock[idx]); ++ + mutex_unlock(&instance->vchiq_mutex); + + return ret; +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -78,6 +78,10 @@ struct vchiq_mmal_port { + vchiq_mmal_buffer_cb buffer_cb; + /* callback context */ + void *cb_ctx; ++ ++ /* ensure serialised use of the one event context structure */ ++ struct mutex event_context_mutex; ++ struct mmal_msg_context *event_context; + }; + + struct vchiq_mmal_component { diff --git a/target/linux/bcm27xx/patches-5.4/950-0169-staging-mmal-vchiq-Make-timeout-a-defined-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0169-staging-mmal-vchiq-Make-timeout-a-defined-parameter.patch deleted file mode 100644 index fa37fff35f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0169-staging-mmal-vchiq-Make-timeout-a-defined-parameter.patch +++ /dev/null @@ -1,38 +0,0 @@ -From e080da14485a0aba8dc364b02b7ff2c92e5a4fe8 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 24 Sep 2018 16:57:09 +0100 -Subject: [PATCH] staging: mmal-vchiq: Make timeout a defined parameter - -The timeout period for VPU communications is a useful thing -to extend when debugging. -Set it via a define, rather than a magic number buried in the code. - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -43,6 +43,12 @@ MODULE_VERSION("0.0.1"); - */ - #define VCHIQ_MMAL_MAX_COMPONENTS 64 - -+/* -+ * Timeout for synchronous msg responses in seconds. -+ * Helpful to increase this if stopping in the VPU debugger. -+ */ -+#define SYNC_MSG_TIMEOUT 3 -+ - /*#define FULL_MSG_DUMP 1*/ - - #ifdef DEBUG -@@ -691,7 +697,7 @@ static int send_synchronous_mmal_msg(str - } - - timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt, -- 3 * HZ); -+ SYNC_MSG_TIMEOUT * HZ); - if (timeout == 0) { - pr_err("timed out waiting for sync completion\n"); - ret = -ETIME; diff --git a/target/linux/bcm27xx/patches-5.4/950-0170-staging-mmal-vchiq-Make-a-mmal_buf-struct-for-passin.patch b/target/linux/bcm27xx/patches-5.4/950-0170-staging-mmal-vchiq-Make-a-mmal_buf-struct-for-passin.patch deleted file mode 100644 index 95f5885c4a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0170-staging-mmal-vchiq-Make-a-mmal_buf-struct-for-passin.patch +++ /dev/null @@ -1,278 +0,0 @@ -From b4c0c420e616e1cdf7abd309000e779b350fb2da Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 24 Sep 2018 17:33:37 +0100 -Subject: [PATCH] staging: mmal-vchiq: Make a mmal_buf struct for - passing parameters - -The callback from vchi_mmal to the client was growing lots of extra -parameters. Consolidate them into a single struct instead of -growing the list further. -The struct is associated with the client buffer, therefore there -are various changes to setup various containers for the struct, -and pass the appropriate members. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-camera/bcm2835-camera.c | 60 ++++++++++++------- - .../vc04_services/vchiq-mmal/mmal-common.h | 5 ++ - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 ++++++--- - .../vc04_services/vchiq-mmal/mmal-vchiq.h | 3 +- - 4 files changed, 63 insertions(+), 34 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c -@@ -72,6 +72,12 @@ static const struct v4l2_fract - tpf_max = {.numerator = 1, .denominator = FPS_MIN}, - tpf_default = {.numerator = 1000, .denominator = 30000}; - -+/* Container for MMAL and VB2 buffers*/ -+struct vb2_mmal_buffer { -+ struct vb2_v4l2_buffer vb; -+ struct mmal_buffer mmal; -+}; -+ - /* video formats */ - static struct mmal_fmt formats[] = { - { -@@ -258,14 +264,15 @@ static int buffer_init(struct vb2_buffer - { - struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); -- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); -+ struct vb2_mmal_buffer *buf = -+ container_of(vb2, struct vb2_mmal_buffer, vb); - - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n", - __func__, dev, vb); -- buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); -- buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0); -+ buf->mmal.buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); -+ buf->mmal.buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0); - -- return mmal_vchi_buffer_init(dev->instance, buf); -+ return mmal_vchi_buffer_init(dev->instance, &buf->mmal); - } - - static int buffer_prepare(struct vb2_buffer *vb) -@@ -294,11 +301,13 @@ static void buffer_cleanup(struct vb2_bu - { - struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); -- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); -+ struct vb2_mmal_buffer *buf = -+ container_of(vb2, struct vb2_mmal_buffer, vb); - - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p, vb %p\n", - __func__, dev, vb); -- mmal_vchi_buffer_cleanup(buf); -+ -+ mmal_vchi_buffer_cleanup(&buf->mmal); - } - - static inline bool is_capturing(struct bm2835_mmal_dev *dev) -@@ -310,14 +319,16 @@ static inline bool is_capturing(struct b - static void buffer_cb(struct vchiq_mmal_instance *instance, - struct vchiq_mmal_port *port, - int status, -- struct mmal_buffer *buf, -- unsigned long length, u32 mmal_flags, s64 dts, s64 pts) -+ struct mmal_buffer *mmal_buf) - { - struct bm2835_mmal_dev *dev = port->cb_ctx; -+ struct vb2_mmal_buffer *buf = -+ container_of(mmal_buf, struct vb2_mmal_buffer, mmal); - - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, - "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n", -- __func__, status, buf, length, mmal_flags, pts); -+ __func__, status, buf, mmal_buf->length, mmal_buf->mmal_flags, -+ mmal_buf->pts); - - if (status) { - /* error in transfer */ -@@ -328,7 +339,7 @@ static void buffer_cb(struct vchiq_mmal_ - return; - } - -- if (length == 0) { -+ if (mmal_buf->length == 0) { - /* stream ended */ - if (dev->capture.frame_count) { - /* empty buffer whilst capturing - expected to be an -@@ -344,7 +355,8 @@ static void buffer_cb(struct vchiq_mmal_ - &dev->capture.frame_count, - sizeof(dev->capture.frame_count)); - } -- if (vchiq_mmal_submit_buffer(instance, port, buf)) -+ if (vchiq_mmal_submit_buffer(instance, port, -+ &buf->mmal)) - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, - "Failed to return EOS buffer"); - } else { -@@ -371,14 +383,14 @@ static void buffer_cb(struct vchiq_mmal_ - buf->vb.vb2_buf.timestamp); - } else if (mmal_buf->pts != 0) { - ktime_t timestamp; -- s64 runtime_us = pts - -+ s64 runtime_us = mmal_buf->pts - - dev->capture.vc_start_timestamp; - timestamp = ktime_add_us(dev->capture.kernel_start_ts, - runtime_us); - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, - "Convert start time %llu and %llu with offset %llu to %llu\n", - ktime_to_ns(dev->capture.kernel_start_ts), -- dev->capture.vc_start_timestamp, pts, -+ dev->capture.vc_start_timestamp, mmal_buf->pts, - ktime_to_ns(timestamp)); - if (timestamp < dev->capture.last_timestamp) { - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -@@ -407,8 +419,8 @@ static void buffer_cb(struct vchiq_mmal_ - buf->vb.sequence = dev->capture.sequence++; - buf->vb.field = V4L2_FIELD_NONE; - -- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length); -- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) -+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, mmal_buf->length); -+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) - buf->vb.flags |= V4L2_BUF_FLAG_KEYFRAME; - - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, -@@ -416,7 +428,7 @@ static void buffer_cb(struct vchiq_mmal_ - dev->capture.last_timestamp); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - -- if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS && -+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS && - is_capturing(dev)) { - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, - "Grab another frame as buffer has EOS"); -@@ -500,14 +512,16 @@ static void buffer_queue(struct vb2_buff - { - struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); -- struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb); -+ struct vb2_mmal_buffer *buf = -+ container_of(vb2, struct vb2_mmal_buffer, vb); - int ret; - - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, - "%s: dev:%p buf:%p, idx %u\n", - __func__, dev, buf, vb2->vb2_buf.index); - -- ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf); -+ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, -+ &buf->mmal); - if (ret < 0) - v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n", - __func__); -@@ -621,7 +635,7 @@ static void stop_streaming(struct vb2_qu - dev->capture.frame_count = 0; - - /* ensure a format has actually been set */ -- if (!dev->capture.port) { -+ if (!port) { - v4l2_err(&dev->v4l2_dev, - "no capture port - stream not started?\n"); - return; -@@ -641,11 +655,11 @@ static void stop_streaming(struct vb2_qu - - /* disable the connection from camera to encoder */ - ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port); -- if (!ret && dev->capture.camera_port != dev->capture.port) { -+ if (!ret && dev->capture.camera_port != port) { - v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, - "disabling port\n"); -- ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port); -- } else if (dev->capture.camera_port != dev->capture.port) { -+ ret = vchiq_mmal_port_disable(dev->instance, port); -+ } else if (dev->capture.camera_port != port) { - v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n", - ret); - } -@@ -1947,7 +1961,7 @@ static int bcm2835_mmal_probe(struct pla - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - q->drv_priv = dev; -- q->buf_struct_size = sizeof(struct mmal_buffer); -+ q->buf_struct_size = sizeof(struct vb2_mmal_buffer); - q->ops = &bm2835_mmal_video_qops; - q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -@@ -49,6 +49,11 @@ struct mmal_buffer { - unsigned long buffer_size; /* size of allocated buffer */ - - struct mmal_msg_context *msg_context; -+ -+ unsigned long length; -+ u32 mmal_flags; -+ s64 dts; -+ s64 pts; - }; - - /* */ ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -258,17 +258,25 @@ static void buffer_work_cb(struct work_s - { - struct mmal_msg_context *msg_context = - container_of(work, struct mmal_msg_context, u.bulk.work); -+ struct mmal_buffer *buffer = msg_context->u.bulk.buffer; -+ -+ if (!buffer) { -+ pr_err("%s: ctx: %p, No mmal buffer to pass details\n", -+ __func__, msg_context); -+ return; -+ } -+ -+ buffer->length = msg_context->u.bulk.buffer_used; -+ buffer->mmal_flags = msg_context->u.bulk.mmal_flags; -+ buffer->dts = msg_context->u.bulk.dts; -+ buffer->pts = msg_context->u.bulk.pts; - - atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); - - msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, - msg_context->u.bulk.port, - msg_context->u.bulk.status, -- msg_context->u.bulk.buffer, -- msg_context->u.bulk.buffer_used, -- msg_context->u.bulk.mmal_flags, -- msg_context->u.bulk.dts, -- msg_context->u.bulk.pts); -+ msg_context->u.bulk.buffer); - } - - /* workqueue scheduled callback to handle receiving buffers -@@ -1326,11 +1334,14 @@ static int port_disable(struct vchiq_mma - mmalbuf = list_entry(buf_head, struct mmal_buffer, - list); - list_del(buf_head); -- if (port->buffer_cb) -+ if (port->buffer_cb) { -+ mmalbuf->length = 0; -+ mmalbuf->mmal_flags = 0; -+ mmalbuf->dts = MMAL_TIME_UNKNOWN; -+ mmalbuf->pts = MMAL_TIME_UNKNOWN; - port->buffer_cb(instance, -- port, 0, mmalbuf, 0, 0, -- MMAL_TIME_UNKNOWN, -- MMAL_TIME_UNKNOWN); -+ port, 0, mmalbuf); -+ } - } - - spin_unlock_irqrestore(&port->slock, flags); ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -44,8 +44,7 @@ struct vchiq_mmal_port; - typedef void (*vchiq_mmal_buffer_cb)( - struct vchiq_mmal_instance *instance, - struct vchiq_mmal_port *port, -- int status, struct mmal_buffer *buffer, -- unsigned long length, u32 mmal_flags, s64 dts, s64 pts); -+ int status, struct mmal_buffer *buffer); - - struct vchiq_mmal_port { - u32 enabled:1; diff --git a/target/linux/bcm27xx/patches-5.4/950-0170-staging-vc04_services-Support-sending-data-to-MMAL-p.patch b/target/linux/bcm27xx/patches-5.4/950-0170-staging-vc04_services-Support-sending-data-to-MMAL-p.patch new file mode 100644 index 0000000000..5dec3c4127 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0170-staging-vc04_services-Support-sending-data-to-MMAL-p.patch @@ -0,0 +1,42 @@ +From f3f0945b19a90b194b2886a4fe5b092b4a3f7b3b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 24 Sep 2018 18:26:02 +0100 +Subject: [PATCH] staging: vc04_services: Support sending data to MMAL + ports + +Add the ability to send data to ports. This only supports +zero copy mode as the required bulk transfer setup calls +are not done. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -427,11 +427,19 @@ buffer_from_host(struct vchiq_mmal_insta + m.u.buffer_from_host.buffer_header.data = + (u32)(unsigned long)buf->buffer; + m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; +- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */ +- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */ +- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */ +- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; +- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; ++ if (port->type == MMAL_PORT_TYPE_OUTPUT) { ++ m.u.buffer_from_host.buffer_header.length = 0; ++ m.u.buffer_from_host.buffer_header.offset = 0; ++ m.u.buffer_from_host.buffer_header.flags = 0; ++ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; ++ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; ++ } else { ++ m.u.buffer_from_host.buffer_header.length = buf->length; ++ m.u.buffer_from_host.buffer_header.offset = 0; ++ m.u.buffer_from_host.buffer_header.flags = buf->mmal_flags; ++ m.u.buffer_from_host.buffer_header.pts = buf->pts; ++ m.u.buffer_from_host.buffer_header.dts = buf->dts; ++ } + + /* clear buffer type sepecific data */ + memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, diff --git a/target/linux/bcm27xx/patches-5.4/950-0171-staging-mmal-vchiq-Add-support-for-event-callbacks.patch b/target/linux/bcm27xx/patches-5.4/950-0171-staging-mmal-vchiq-Add-support-for-event-callbacks.patch deleted file mode 100644 index 125f9d552e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0171-staging-mmal-vchiq-Add-support-for-event-callbacks.patch +++ /dev/null @@ -1,356 +0,0 @@ -From 10f4396064d55253a9af8ec3856519bbe606ddf4 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 24 Sep 2018 18:15:38 +0100 -Subject: [PATCH] staging: mmal-vchiq: Add support for event callbacks. - -(Preparation for the codec driver). -The codec uses the event mechanism to report things such as -resolution changes. It is signalled by the cmd field of the buffer -being non-zero. - -Add support for passing this information out to the client. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/vchiq-mmal/mmal-common.h | 1 + - .../vc04_services/vchiq-mmal/mmal-msg.h | 35 ++++ - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 170 ++++++++++++++++-- - .../vc04_services/vchiq-mmal/mmal-vchiq.h | 4 + - 4 files changed, 196 insertions(+), 14 deletions(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -@@ -50,6 +50,7 @@ struct mmal_buffer { - - struct mmal_msg_context *msg_context; - -+ u32 cmd; /* MMAL command. 0=data. */ - unsigned long length; - u32 mmal_flags; - s64 dts; ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h -@@ -346,6 +346,41 @@ struct mmal_msg_port_parameter_get_reply - /* event messages */ - #define MMAL_WORKER_EVENT_SPACE 256 - -+/* Four CC's for events */ -+#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24)) -+ -+#define MMAL_EVENT_ERROR MMAL_FOURCC('E', 'R', 'R', 'O') -+#define MMAL_EVENT_EOS MMAL_FOURCC('E', 'E', 'O', 'S') -+#define MMAL_EVENT_FORMAT_CHANGED MMAL_FOURCC('E', 'F', 'C', 'H') -+#define MMAL_EVENT_PARAMETER_CHANGED MMAL_FOURCC('E', 'P', 'C', 'H') -+ -+/* Structs for each of the event message payloads */ -+struct mmal_msg_event_eos { -+ u32 port_type; /**< Type of port that received the end of stream */ -+ u32 port_index; /**< Index of port that received the end of stream */ -+}; -+ -+/** Format changed event data. */ -+struct mmal_msg_event_format_changed { -+ /* Minimum size of buffers the port requires */ -+ u32 buffer_size_min; -+ /* Minimum number of buffers the port requires */ -+ u32 buffer_num_min; -+ /* Size of buffers the port recommends for optimal performance. -+ * A value of zero means no special recommendation. -+ */ -+ u32 buffer_size_recommended; -+ /* Number of buffers the port recommends for optimal -+ * performance. A value of zero means no special recommendation. -+ */ -+ u32 buffer_num_recommended; -+ -+ u32 es_ptr; -+ struct mmal_es_format format; -+ union mmal_es_specific_format es; -+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; -+}; -+ - struct mmal_msg_event_to_host { - u32 client_component; /* component context */ - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -150,6 +150,8 @@ struct mmal_msg_context { - /* Presentation and Decode timestamps */ - s64 pts; - s64 dts; -+ /* MMAL buffer command flag */ -+ u32 cmd; - - int status; /* context status */ - -@@ -237,18 +239,6 @@ release_msg_context(struct mmal_msg_cont - kfree(msg_context); - } - --/* deals with receipt of event to host message */ --static void event_to_host_cb(struct vchiq_mmal_instance *instance, -- struct mmal_msg *msg, u32 msg_len) --{ -- pr_debug("unhandled event\n"); -- pr_debug("component:%u port type:%d num:%d cmd:0x%x length:%d\n", -- msg->u.event_to_host.client_component, -- msg->u.event_to_host.port_type, -- msg->u.event_to_host.port_num, -- msg->u.event_to_host.cmd, msg->u.event_to_host.length); --} -- - /* workqueue scheduled callback - * - * we do this because it is important we do not call any other vchiq -@@ -270,13 +260,18 @@ static void buffer_work_cb(struct work_s - buffer->mmal_flags = msg_context->u.bulk.mmal_flags; - buffer->dts = msg_context->u.bulk.dts; - buffer->pts = msg_context->u.bulk.pts; -+ buffer->cmd = msg_context->u.bulk.cmd; - -- atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); -+ if (!buffer->cmd) -+ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu); - - msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance, - msg_context->u.bulk.port, - msg_context->u.bulk.status, - msg_context->u.bulk.buffer); -+ -+ if (buffer->cmd) -+ mutex_unlock(&msg_context->u.bulk.port->event_context_mutex); - } - - /* workqueue scheduled callback to handle receiving buffers -@@ -355,6 +350,7 @@ static int bulk_receive(struct vchiq_mma - msg_context->u.bulk.buffer_used = rd_len; - msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts; - msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts; -+ msg_context->u.bulk.cmd = msg->u.buffer_from_host.buffer_header.cmd; - - queue_work(msg_context->instance->bulk_wq, - &msg_context->u.bulk.buffer_to_host_work); -@@ -456,6 +452,103 @@ buffer_from_host(struct vchiq_mmal_insta - return ret; - } - -+/* deals with receipt of event to host message */ -+static void event_to_host_cb(struct vchiq_mmal_instance *instance, -+ struct mmal_msg *msg, u32 msg_len) -+{ -+ /* FIXME: Not going to work on 64 bit */ -+ struct vchiq_mmal_component *component = -+ (struct vchiq_mmal_component *)msg->u.event_to_host.client_component; -+ struct vchiq_mmal_port *port = NULL; -+ struct mmal_msg_context *msg_context; -+ u32 port_num = msg->u.event_to_host.port_num; -+ -+ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) { -+ pr_err("%s: MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n", -+ __func__); -+ return; -+ } -+ -+ switch (msg->u.event_to_host.port_type) { -+ case MMAL_PORT_TYPE_CONTROL: -+ if (port_num) { -+ pr_err("%s: port_num of %u >= number of ports 1", -+ __func__, port_num); -+ return; -+ } -+ port = &component->control; -+ break; -+ case MMAL_PORT_TYPE_INPUT: -+ if (port_num >= component->inputs) { -+ pr_err("%s: port_num of %u >= number of ports %u", -+ __func__, port_num, -+ port_num >= component->inputs); -+ return; -+ } -+ port = &component->input[port_num]; -+ break; -+ case MMAL_PORT_TYPE_OUTPUT: -+ if (port_num >= component->outputs) { -+ pr_err("%s: port_num of %u >= number of ports %u", -+ __func__, port_num, -+ port_num >= component->outputs); -+ return; -+ } -+ port = &component->output[port_num]; -+ break; -+ case MMAL_PORT_TYPE_CLOCK: -+ if (port_num >= component->clocks) { -+ pr_err("%s: port_num of %u >= number of ports %u", -+ __func__, port_num, -+ port_num >= component->clocks); -+ return; -+ } -+ port = &component->clock[port_num]; -+ break; -+ default: -+ break; -+ } -+ -+ if (!mutex_trylock(&port->event_context_mutex)) { -+ pr_err("dropping event 0x%x\n", msg->u.event_to_host.cmd); -+ return; -+ } -+ msg_context = port->event_context; -+ -+ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) { -+ /* message reception had an error */ -+ //pr_warn -+ pr_err("%s: error %d in reply\n", __func__, msg->h.status); -+ -+ msg_context->u.bulk.status = msg->h.status; -+ } else if (msg->u.event_to_host.length > MMAL_WORKER_EVENT_SPACE) { -+ /* data is not in message, queue a bulk receive */ -+ pr_err("%s: payload not in message - bulk receive??! NOT SUPPORTED\n", -+ __func__); -+ msg_context->u.bulk.status = -1; -+ } else { -+ memcpy(msg_context->u.bulk.buffer->buffer, -+ msg->u.event_to_host.data, -+ msg->u.event_to_host.length); -+ -+ msg_context->u.bulk.buffer_used = -+ msg->u.event_to_host.length; -+ -+ msg_context->u.bulk.mmal_flags = 0; -+ msg_context->u.bulk.dts = MMAL_TIME_UNKNOWN; -+ msg_context->u.bulk.pts = MMAL_TIME_UNKNOWN; -+ msg_context->u.bulk.cmd = msg->u.event_to_host.cmd; -+ -+ pr_debug("event component:%u port type:%d num:%d cmd:0x%x length:%d\n", -+ msg->u.event_to_host.client_component, -+ msg->u.event_to_host.port_type, -+ msg->u.event_to_host.port_num, -+ msg->u.event_to_host.cmd, msg->u.event_to_host.length); -+ } -+ -+ schedule_work(&msg_context->u.bulk.work); -+} -+ - /* deals with receipt of buffer to host message */ - static void buffer_to_host_cb(struct vchiq_mmal_instance *instance, - struct mmal_msg *msg, u32 msg_len) -@@ -1339,6 +1432,7 @@ static int port_disable(struct vchiq_mma - mmalbuf->mmal_flags = 0; - mmalbuf->dts = MMAL_TIME_UNKNOWN; - mmalbuf->pts = MMAL_TIME_UNKNOWN; -+ mmalbuf->cmd = 0; - port->buffer_cb(instance, - port, 0, mmalbuf); - } -@@ -1640,6 +1734,43 @@ int mmal_vchi_buffer_cleanup(struct mmal - } - EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); - -+static void init_event_context(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port) -+{ -+ struct mmal_msg_context *ctx = get_msg_context(instance); -+ -+ mutex_init(&port->event_context_mutex); -+ -+ port->event_context = ctx; -+ ctx->u.bulk.instance = instance; -+ ctx->u.bulk.port = port; -+ ctx->u.bulk.buffer = -+ kzalloc(sizeof(*ctx->u.bulk.buffer), GFP_KERNEL); -+ if (!ctx->u.bulk.buffer) -+ goto release_msg_context; -+ ctx->u.bulk.buffer->buffer = kzalloc(MMAL_WORKER_EVENT_SPACE, -+ GFP_KERNEL); -+ if (!ctx->u.bulk.buffer->buffer) -+ goto release_buffer; -+ -+ INIT_WORK(&ctx->u.bulk.work, buffer_work_cb); -+ return; -+ -+release_buffer: -+ kfree(ctx->u.bulk.buffer); -+release_msg_context: -+ release_msg_context(ctx); -+} -+ -+static void free_event_context(struct vchiq_mmal_port *port) -+{ -+ struct mmal_msg_context *ctx = port->event_context; -+ -+ kfree(ctx->u.bulk.buffer->buffer); -+ kfree(ctx->u.bulk.buffer); -+ release_msg_context(ctx); -+} -+ - /* Initialise a mmal component and its ports - * - */ -@@ -1683,6 +1814,7 @@ int vchiq_mmal_component_init(struct vch - ret = port_info_get(instance, &component->control); - if (ret < 0) - goto release_component; -+ init_event_context(instance, &component->control); - - for (idx = 0; idx < component->inputs; idx++) { - component->input[idx].type = MMAL_PORT_TYPE_INPUT; -@@ -1693,6 +1825,7 @@ int vchiq_mmal_component_init(struct vch - ret = port_info_get(instance, &component->input[idx]); - if (ret < 0) - goto release_component; -+ init_event_context(instance, &component->input[idx]); - } - - for (idx = 0; idx < component->outputs; idx++) { -@@ -1704,6 +1837,7 @@ int vchiq_mmal_component_init(struct vch - ret = port_info_get(instance, &component->output[idx]); - if (ret < 0) - goto release_component; -+ init_event_context(instance, &component->output[idx]); - } - - for (idx = 0; idx < component->clocks; idx++) { -@@ -1715,6 +1849,7 @@ int vchiq_mmal_component_init(struct vch - ret = port_info_get(instance, &component->clock[idx]); - if (ret < 0) - goto release_component; -+ init_event_context(instance, &component->clock[idx]); - } - - *component_out = component; -@@ -1740,7 +1875,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i - int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, - struct vchiq_mmal_component *component) - { -- int ret; -+ int ret, idx; - - if (mutex_lock_interruptible(&instance->vchiq_mutex)) - return -EINTR; -@@ -1752,6 +1887,13 @@ int vchiq_mmal_component_finalise(struct - - component->in_use = 0; - -+ for (idx = 0; idx < component->inputs; idx++) -+ free_event_context(&component->input[idx]); -+ for (idx = 0; idx < component->outputs; idx++) -+ free_event_context(&component->output[idx]); -+ for (idx = 0; idx < component->clocks; idx++) -+ free_event_context(&component->clock[idx]); -+ - mutex_unlock(&instance->vchiq_mutex); - - return ret; ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -78,6 +78,10 @@ struct vchiq_mmal_port { - vchiq_mmal_buffer_cb buffer_cb; - /* callback context */ - void *cb_ctx; -+ -+ /* ensure serialised use of the one event context structure */ -+ struct mutex event_context_mutex; -+ struct mmal_msg_context *event_context; - }; - - struct vchiq_mmal_component { diff --git a/target/linux/bcm27xx/patches-5.4/950-0171-staging-vc04_services-Fixup-vchiq-mmal-include-order.patch b/target/linux/bcm27xx/patches-5.4/950-0171-staging-vc04_services-Fixup-vchiq-mmal-include-order.patch new file mode 100644 index 0000000000..7dd50f75bf --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0171-staging-vc04_services-Fixup-vchiq-mmal-include-order.patch @@ -0,0 +1,36 @@ +From 0932bf176e846b6c7666671670b017fcd7e915e8 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 25 Sep 2018 16:57:40 +0100 +Subject: [PATCH] staging: vc04_services: Fixup vchiq-mmal include + ordering + +There were dependencies on including the headers in the correct +order. Fix up the headers so that they include the other +headers that they depend on themselves. + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h | 1 + + drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h +@@ -38,6 +38,7 @@ + #include "mmal-msg-common.h" + #include "mmal-msg-format.h" + #include "mmal-msg-port.h" ++#include "mmal-vchiq.h" + + enum mmal_msg_type { + MMAL_MSG_TYPE_QUIT = 1, +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -16,6 +16,7 @@ + #ifndef MMAL_VCHIQ_H + #define MMAL_VCHIQ_H + ++#include "mmal-common.h" + #include "mmal-msg-format.h" + + #define MAX_PORT_COUNT 4 diff --git a/target/linux/bcm27xx/patches-5.4/950-0172-staging-vc04_services-Add-new-vc-sm-cma-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0172-staging-vc04_services-Add-new-vc-sm-cma-driver.patch new file mode 100644 index 0000000000..d1d3df0890 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0172-staging-vc04_services-Add-new-vc-sm-cma-driver.patch @@ -0,0 +1,3175 @@ +From 878c0bfd0c5f2dc0ef04874b1cba915cf208ca8f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 25 Sep 2018 10:27:11 +0100 +Subject: [PATCH] staging: vc04_services: Add new vc-sm-cma driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This new driver allows contiguous memory blocks to be imported +into the VideoCore VPU memory map, and manages the lifetime of +those objects, only releasing the source dmabuf once the VPU has +confirmed it has finished with it. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Correct DMA configuration. + +Now that VCHIQ is setting up the DMA configuration as our +parent device, don't try to configure it during probe. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Use a void* pointer as the handle within the kernel + +The driver was using an unsigned int as the handle to the outside world, +and doing a nasty cast to the struct dmabuf when handed it back. +This breaks badly with a 64 bit kernel where the pointer doesn't fit +in an unsigned int. + +Switch to using a void* within the kernel. Reality is that it is +a struct dma_buf*, but advertising it as such to other drivers seems +to encourage the use of it as such, and I'm not sure on the implications +of that. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Fix up for 64bit builds + +There were a number of logging lines that were using +inappropriate formatting under 64bit kernels. + +The kernel_id field passed to/from the VPU was being +abused for storing the struct vc_sm_buffer *. +This breaks with 64bit kernels, so change to using an IDR. + +Signed-off-by: Dave Stevenson + +staging: vc_sm_cma: Remove erroneous misc_deregister + +Code from the misc /dev node was still present in +bcm2835_vc_sm_cma_remove, which caused a NULL deref. +Remove it. + +See #2885. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Remove the debugfs directory on remove + +Without removing that, reloading the driver fails. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Use devm_ allocs for sm_state. + +Use managed allocations for sm_state, removing reliance on +manual management. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Don't fail if debugfs calls fail. + +Return codes from debugfs calls should never alter the +flow of the main code. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Ensure mutex and idr are destroyed + +map_lock and kernelid_map are created in probe, but not released +in release should the vcsm service not connect (eg running the +cutdown firmware). + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Remove obsolete comment and make function static + +Removes obsolete comment about wanting to pass a function +pointer into mmal-vchiq as we now do. +As the function is passed as a function pointer, the function itself +can be static. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Add in allocation for VPU requests. + +Module has to change from tristate to bool as all CMA functions +are boolean. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Update TODO. + +The driver is already a platform driver, so that can be +deleted from the TODO. +There are no known issues that need to be resolved. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Add in userspace allocation API + +Replacing the functionality from the older vc-sm driver, +add in a userspace API that allows allocation of buffers, +and importing of dma-bufs. +The driver hands out dma-buf fds, therefore much of the +handling around lifespan and odd mmaps from the old driver +goes away. + +Signed-off-by: Dave Stevenson + +staging: vcsm-cma: Add cache control ioctls + +The old driver allowed for direct cache manipulation and that +was used by various clients. Replicate here. + +Signed-off-by: Dave Stevenson + +staging: vcsm-cma: Alter dev node permissions to 0666 + +Until the udev rules are updated, open up access to this node by +default. + +Signed-off-by: Dave Stevenson + +staging: vcsm-cma: Drop logging level on messages in vc_sm_release_resource + +They weren't errors but were logged as such. + +Signed-off-by: Dave Stevenson + +staging: vcsm-cma: Fixup the alloc code handling of kernel_id + +The allocation code had been copied in from an old branch prior +to having added the IDR for 64bit support. It was therefore pushing +a pointer into the kernel_id field instead of an IDR handle, the +lookup therefore failed, and we never released the buffer. + +Signed-off-by: Dave Stevenson + +staging: vcsm-cma: Remove cache manipulation ioctl from ARM64 + +The cache flushing ioctls are used by the Pi3 HEVC hw-assisted +decoder as it needs finer grained flushing control than dma_ops +allow. +These cache calls are not present for ARM64, therefore disable +them. We are not actively supporting 64bit kernels at present, +and the use case of the HEVC decoder is fairly limited. + +Signed-off-by: Dave Stevenson + +staging: vcsm-cma: Rework to use dma APIs, not CMA + +Due to a misunderstanding of the DMA mapping APIs, I made +the wrong decision on how to implement this. + +Rework to use dma_alloc_coherent instead of the CMA +API. This also allows it to be built as a module easily. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Fix the few remaining coding style issues + +Fix a few minor checkpatch complaints to make the driver clean + +Signed-off-by: Dave Stevenson + +staging: vc04_services: fix compiling in separate directory + +The vc04_services Makefiles do not respect the O=path argument +correctly: include paths in CFLAGS are given relatively to object path, +not source path. Compiling in a separate directory yields #include +errors. + +Signed-off-by: Marek Behún + +vc-sm-cma: Fix compatibility ioctl + +This code path hasn't been used previously. +Fixed up after testing with kodi on 32-bit userland and 64-bit kernel + +Signed-off-by: popcornmix +--- + drivers/staging/vc04_services/Kconfig | 1 + + drivers/staging/vc04_services/Makefile | 1 + + .../vc04_services/bcm2835-camera/Makefile | 4 +- + .../staging/vc04_services/vc-sm-cma/Kconfig | 10 + + .../staging/vc04_services/vc-sm-cma/Makefile | 8 + + drivers/staging/vc04_services/vc-sm-cma/TODO | 1 + + .../staging/vc04_services/vc-sm-cma/vc_sm.c | 1774 +++++++++++++++++ + .../staging/vc04_services/vc-sm-cma/vc_sm.h | 84 + + .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 505 +++++ + .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 63 + + .../vc04_services/vc-sm-cma/vc_sm_defs.h | 300 +++ + .../vc04_services/vc-sm-cma/vc_sm_knl.h | 28 + + .../staging/vc04_services/vchiq-mmal/Makefile | 2 +- + include/linux/broadcom/vc_sm_cma_ioctl.h | 114 ++ + 14 files changed, 2892 insertions(+), 3 deletions(-) + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Kconfig + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Makefile + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/TODO + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.c + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.h + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h + create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h + create mode 100644 include/linux/broadcom/vc_sm_cma_ioctl.h + +--- a/drivers/staging/vc04_services/Kconfig ++++ b/drivers/staging/vc04_services/Kconfig +@@ -23,6 +23,7 @@ source "drivers/staging/vc04_services/bc + + source "drivers/staging/vc04_services/bcm2835-camera/Kconfig" + source "drivers/staging/vc04_services/vchiq-mmal/Kconfig" ++source "drivers/staging/vc04_services/vc-sm-cma/Kconfig" + + endif + +--- a/drivers/staging/vc04_services/Makefile ++++ b/drivers/staging/vc04_services/Makefile +@@ -13,6 +13,7 @@ vchiq-objs := \ + obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ + obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ + obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ ++obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/ + + ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000 + +--- a/drivers/staging/vc04_services/bcm2835-camera/Makefile ++++ b/drivers/staging/vc04_services/bcm2835-camera/Makefile +@@ -7,6 +7,6 @@ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v + + ccflags-y += \ + -I $(srctree)/$(src)/.. \ +- -Idrivers/staging/vc04_services \ +- -Idrivers/staging/vc04_services/vchiq-mmal \ ++ -I$(srctree)/drivers/staging/vc04_services \ ++ -I$(srctree)/drivers/staging/vc04_services/vchiq-mmal \ + -D__VCCOREVER__=0x04000000 +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig +@@ -0,0 +1,10 @@ ++config BCM_VC_SM_CMA ++ tristate "VideoCore Shared Memory (CMA) driver" ++ depends on BCM2835_VCHIQ ++ select RBTREE ++ select DMA_SHARED_BUFFER ++ help ++ Say Y here to enable the shared memory interface that ++ supports sharing dmabufs with VideoCore. ++ This operates over the VCHIQ interface to a service ++ running on VideoCore. +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile +@@ -0,0 +1,8 @@ ++ccflags-y += -I$(srctree)/drivers/staging/vc04_services -I$(srctree)/drivers/staging/vc04_services/interface/vchi -I$(srctree)/drivers/staging/vc04_services/interface/vchiq_arm ++# -I"drivers/staging/android/ion/" -I"$(srctree)/fs/" ++ccflags-y += -D__VCCOREVER__=0 ++ ++vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \ ++ vc_sm.o vc_sm_cma_vchi.o ++ ++obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/TODO +@@ -0,0 +1 @@ ++No currently outstanding tasks except some clean-up. +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c +@@ -0,0 +1,1774 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * VideoCore Shared Memory driver using CMA. ++ * ++ * Copyright: 2018, Raspberry Pi (Trading) Ltd ++ * Dave Stevenson ++ * ++ * Based on vmcs_sm driver from Broadcom Corporation for some API, ++ * and taking some code for buffer allocation and dmabuf handling from ++ * videobuf2. ++ * ++ * ++ * This driver has 3 main uses: ++ * 1) Allocating buffers for the kernel or userspace that can be shared with the ++ * VPU. ++ * 2) Importing dmabufs from elsewhere for sharing with the VPU. ++ * 3) Allocating buffers for use by the VPU. ++ * ++ * In the first and second cases the native handle is a dmabuf. Releasing the ++ * resource inherently comes from releasing the dmabuf, and this will trigger ++ * unmapping on the VPU. The underlying allocation and our buffer structure are ++ * retained until the VPU has confirmed that it has finished with it. ++ * ++ * For the VPU allocations the VPU is responsible for triggering the release, ++ * and therefore the released message decrements the dma_buf refcount (with the ++ * VPU mapping having already been marked as released). ++ */ ++ ++/* ---- Include Files ----------------------------------------------------- */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vchiq_connected.h" ++#include "vc_sm_cma_vchi.h" ++ ++#include "vc_sm.h" ++#include "vc_sm_knl.h" ++#include ++ ++/* ---- Private Constants and Types --------------------------------------- */ ++ ++#define DEVICE_NAME "vcsm-cma" ++#define DEVICE_MINOR 0 ++ ++#define VC_SM_RESOURCE_NAME_DEFAULT "sm-host-resource" ++ ++#define VC_SM_DIR_ROOT_NAME "vcsm-cma" ++#define VC_SM_STATE "state" ++ ++/* Private file data associated with each opened device. */ ++struct vc_sm_privdata_t { ++ pid_t pid; /* PID of creator. */ ++ ++ int restart_sys; /* Tracks restart on interrupt. */ ++ enum vc_sm_msg_type int_action; /* Interrupted action. */ ++ u32 int_trans_id; /* Interrupted transaction. */ ++}; ++ ++typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v); ++struct sm_pde_t { ++ VC_SM_SHOW show; /* Debug fs function hookup. */ ++ struct dentry *dir_entry; /* Debug fs directory entry. */ ++ void *priv_data; /* Private data */ ++}; ++ ++/* Global state information. */ ++struct sm_state_t { ++ struct platform_device *pdev; ++ ++ struct miscdevice misc_dev; ++ ++ struct sm_instance *sm_handle; /* Handle for videocore service. */ ++ ++ spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */ ++ struct idr kernelid_map; ++ ++ struct mutex map_lock; /* Global map lock. */ ++ struct list_head buffer_list; /* List of buffer. */ ++ ++ struct vc_sm_privdata_t *data_knl; /* Kernel internal data tracking. */ ++ struct vc_sm_privdata_t *vpu_allocs; /* All allocations from the VPU */ ++ struct dentry *dir_root; /* Debug fs entries root. */ ++ struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */ ++ ++ bool require_released_callback; /* VPU will send a released msg when it ++ * has finished with a resource. ++ */ ++ u32 int_trans_id; /* Interrupted transaction. */ ++}; ++ ++struct vc_sm_dma_buf_attachment { ++ struct device *dev; ++ struct sg_table sg_table; ++ struct list_head list; ++ enum dma_data_direction dma_dir; ++}; ++ ++/* ---- Private Variables ----------------------------------------------- */ ++ ++static struct sm_state_t *sm_state; ++static int sm_inited; ++ ++/* ---- Private Function Prototypes -------------------------------------- */ ++ ++/* ---- Private Functions ------------------------------------------------ */ ++ ++static int get_kernel_id(struct vc_sm_buffer *buffer) ++{ ++ int handle; ++ ++ spin_lock(&sm_state->kernelid_map_lock); ++ handle = idr_alloc(&sm_state->kernelid_map, buffer, 0, 0, GFP_KERNEL); ++ spin_unlock(&sm_state->kernelid_map_lock); ++ ++ return handle; ++} ++ ++static struct vc_sm_buffer *lookup_kernel_id(int handle) ++{ ++ return idr_find(&sm_state->kernelid_map, handle); ++} ++ ++static void free_kernel_id(int handle) ++{ ++ spin_lock(&sm_state->kernelid_map_lock); ++ idr_remove(&sm_state->kernelid_map, handle); ++ spin_unlock(&sm_state->kernelid_map_lock); ++} ++ ++static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v) ++{ ++ struct sm_pde_t *sm_pde; ++ ++ sm_pde = (struct sm_pde_t *)(s->private); ++ ++ if (sm_pde && sm_pde->show) ++ sm_pde->show(s, v); ++ ++ return 0; ++} ++ ++static int vc_sm_cma_single_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, vc_sm_cma_seq_file_show, inode->i_private); ++} ++ ++static const struct file_operations vc_sm_cma_debug_fs_fops = { ++ .open = vc_sm_cma_single_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int vc_sm_cma_global_state_show(struct seq_file *s, void *v) ++{ ++ struct vc_sm_buffer *resource = NULL; ++ int resource_count = 0; ++ ++ if (!sm_state) ++ return 0; ++ ++ seq_printf(s, "\nVC-ServiceHandle %p\n", sm_state->sm_handle); ++ ++ /* Log all applicable mapping(s). */ ++ ++ mutex_lock(&sm_state->map_lock); ++ seq_puts(s, "\nResources\n"); ++ if (!list_empty(&sm_state->buffer_list)) { ++ list_for_each_entry(resource, &sm_state->buffer_list, ++ global_buffer_list) { ++ resource_count++; ++ ++ seq_printf(s, "\nResource %p\n", ++ resource); ++ seq_printf(s, " NAME %s\n", ++ resource->name); ++ seq_printf(s, " SIZE %zu\n", ++ resource->size); ++ seq_printf(s, " DMABUF %p\n", ++ resource->dma_buf); ++ if (resource->imported) { ++ seq_printf(s, " ATTACH %p\n", ++ resource->import.attach); ++ seq_printf(s, " SGT %p\n", ++ resource->import.sgt); ++ } else { ++ seq_printf(s, " SGT %p\n", ++ resource->alloc.sg_table); ++ } ++ seq_printf(s, " DMA_ADDR %pad\n", ++ &resource->dma_addr); ++ seq_printf(s, " VC_HANDLE %08x\n", ++ resource->vc_handle); ++ seq_printf(s, " VC_MAPPING %d\n", ++ resource->vpu_state); ++ } ++ } ++ seq_printf(s, "\n\nTotal resource count: %d\n\n", resource_count); ++ ++ mutex_unlock(&sm_state->map_lock); ++ ++ return 0; ++} ++ ++/* ++ * Adds a buffer to the private data list which tracks all the allocated ++ * data. ++ */ ++static void vc_sm_add_resource(struct vc_sm_privdata_t *privdata, ++ struct vc_sm_buffer *buffer) ++{ ++ mutex_lock(&sm_state->map_lock); ++ list_add(&buffer->global_buffer_list, &sm_state->buffer_list); ++ mutex_unlock(&sm_state->map_lock); ++ ++ pr_debug("[%s]: added buffer %p (name %s, size %zu)\n", ++ __func__, buffer, buffer->name, buffer->size); ++} ++ ++/* ++ * Cleans up imported dmabuf. ++ */ ++static void vc_sm_clean_up_dmabuf(struct vc_sm_buffer *buffer) ++{ ++ if (!buffer->imported) ++ return; ++ ++ /* Handle cleaning up imported dmabufs */ ++ mutex_lock(&buffer->lock); ++ if (buffer->import.sgt) { ++ dma_buf_unmap_attachment(buffer->import.attach, ++ buffer->import.sgt, ++ DMA_BIDIRECTIONAL); ++ buffer->import.sgt = NULL; ++ } ++ if (buffer->import.attach) { ++ dma_buf_detach(buffer->dma_buf, buffer->import.attach); ++ buffer->import.attach = NULL; ++ } ++ mutex_unlock(&buffer->lock); ++} ++ ++/* ++ * Instructs VPU to decrement the refcount on a buffer. ++ */ ++static void vc_sm_vpu_free(struct vc_sm_buffer *buffer) ++{ ++ if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) { ++ struct vc_sm_free_t free = { buffer->vc_handle, 0 }; ++ int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free, ++ &sm_state->int_trans_id); ++ if (status != 0 && status != -EINTR) { ++ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n", ++ __func__, status, sm_state->int_trans_id); ++ } ++ ++ if (sm_state->require_released_callback) { ++ /* Need to wait for the VPU to confirm the free. */ ++ ++ /* Retain a reference on this until the VPU has ++ * released it ++ */ ++ buffer->vpu_state = VPU_UNMAPPING; ++ } else { ++ buffer->vpu_state = VPU_NOT_MAPPED; ++ buffer->vc_handle = 0; ++ } ++ } ++} ++ ++/* ++ * Release an allocation. ++ * All refcounting is done via the dma buf object. ++ * ++ * Must be called with the mutex held. The function will either release the ++ * mutex (if defering the release) or destroy it. The caller must therefore not ++ * reuse the buffer on return. ++ */ ++static void vc_sm_release_resource(struct vc_sm_buffer *buffer) ++{ ++ pr_debug("[%s]: buffer %p (name %s, size %zu), imported %u\n", ++ __func__, buffer, buffer->name, buffer->size, ++ buffer->imported); ++ ++ if (buffer->vc_handle) { ++ /* We've sent the unmap request but not had the response. */ ++ pr_debug("[%s]: Waiting for VPU unmap response on %p\n", ++ __func__, buffer); ++ goto defer; ++ } ++ if (buffer->in_use) { ++ /* dmabuf still in use - we await the release */ ++ pr_debug("[%s]: buffer %p is still in use\n", __func__, buffer); ++ goto defer; ++ } ++ ++ /* Release the allocation (whether imported dmabuf or CMA allocation) */ ++ if (buffer->imported) { ++ if (buffer->import.dma_buf) ++ dma_buf_put(buffer->import.dma_buf); ++ else ++ pr_err("%s: Imported dmabuf already been put for buf %p\n", ++ __func__, buffer); ++ buffer->import.dma_buf = NULL; ++ } else { ++ dma_free_coherent(&sm_state->pdev->dev, buffer->size, ++ buffer->cookie, buffer->dma_addr); ++ } ++ ++ /* Free our buffer. Start by removing it from the list */ ++ mutex_lock(&sm_state->map_lock); ++ list_del(&buffer->global_buffer_list); ++ mutex_unlock(&sm_state->map_lock); ++ ++ pr_debug("%s: Release our allocation - done\n", __func__); ++ mutex_unlock(&buffer->lock); ++ ++ mutex_destroy(&buffer->lock); ++ ++ kfree(buffer); ++ return; ++ ++defer: ++ mutex_unlock(&buffer->lock); ++} ++ ++/* Create support for private data tracking. */ ++static struct vc_sm_privdata_t *vc_sm_cma_create_priv_data(pid_t id) ++{ ++ char alloc_name[32]; ++ struct vc_sm_privdata_t *file_data = NULL; ++ ++ /* Allocate private structure. */ ++ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL); ++ ++ if (!file_data) ++ return NULL; ++ ++ snprintf(alloc_name, sizeof(alloc_name), "%d", id); ++ ++ file_data->pid = id; ++ ++ return file_data; ++} ++ ++/* Dma buf operations for use with our own allocations */ ++ ++static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf, ++ struct dma_buf_attachment *attachment) ++ ++{ ++ struct vc_sm_dma_buf_attachment *a; ++ struct sg_table *sgt; ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ struct scatterlist *rd, *wr; ++ int ret, i; ++ ++ a = kzalloc(sizeof(*a), GFP_KERNEL); ++ if (!a) ++ return -ENOMEM; ++ ++ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment); ++ ++ mutex_lock(&buf->lock); ++ ++ INIT_LIST_HEAD(&a->list); ++ ++ sgt = &a->sg_table; ++ ++ /* Copy the buf->base_sgt scatter list to the attachment, as we can't ++ * map the same scatter list to multiple attachments at the same time. ++ */ ++ ret = sg_alloc_table(sgt, buf->alloc.sg_table->orig_nents, GFP_KERNEL); ++ if (ret) { ++ kfree(a); ++ return -ENOMEM; ++ } ++ ++ rd = buf->alloc.sg_table->sgl; ++ wr = sgt->sgl; ++ for (i = 0; i < sgt->orig_nents; ++i) { ++ sg_set_page(wr, sg_page(rd), rd->length, rd->offset); ++ rd = sg_next(rd); ++ wr = sg_next(wr); ++ } ++ ++ a->dma_dir = DMA_NONE; ++ attachment->priv = a; ++ ++ list_add(&a->list, &buf->attachments); ++ mutex_unlock(&buf->lock); ++ ++ return 0; ++} ++ ++static void vc_sm_dma_buf_detach(struct dma_buf *dmabuf, ++ struct dma_buf_attachment *attachment) ++{ ++ struct vc_sm_dma_buf_attachment *a = attachment->priv; ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ struct sg_table *sgt; ++ ++ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment); ++ if (!a) ++ return; ++ ++ sgt = &a->sg_table; ++ ++ /* release the scatterlist cache */ ++ if (a->dma_dir != DMA_NONE) ++ dma_unmap_sg(attachment->dev, sgt->sgl, sgt->orig_nents, ++ a->dma_dir); ++ sg_free_table(sgt); ++ ++ mutex_lock(&buf->lock); ++ list_del(&a->list); ++ mutex_unlock(&buf->lock); ++ ++ kfree(a); ++} ++ ++static struct sg_table *vc_sm_map_dma_buf(struct dma_buf_attachment *attachment, ++ enum dma_data_direction direction) ++{ ++ struct vc_sm_dma_buf_attachment *a = attachment->priv; ++ /* stealing dmabuf mutex to serialize map/unmap operations */ ++ struct mutex *lock = &attachment->dmabuf->lock; ++ struct sg_table *table; ++ ++ mutex_lock(lock); ++ pr_debug("%s attachment %p\n", __func__, attachment); ++ table = &a->sg_table; ++ ++ /* return previously mapped sg table */ ++ if (a->dma_dir == direction) { ++ mutex_unlock(lock); ++ return table; ++ } ++ ++ /* release any previous cache */ ++ if (a->dma_dir != DMA_NONE) { ++ dma_unmap_sg(attachment->dev, table->sgl, table->orig_nents, ++ a->dma_dir); ++ a->dma_dir = DMA_NONE; ++ } ++ ++ /* mapping to the client with new direction */ ++ table->nents = dma_map_sg(attachment->dev, table->sgl, ++ table->orig_nents, direction); ++ if (!table->nents) { ++ pr_err("failed to map scatterlist\n"); ++ mutex_unlock(lock); ++ return ERR_PTR(-EIO); ++ } ++ ++ a->dma_dir = direction; ++ mutex_unlock(lock); ++ ++ pr_debug("%s attachment %p\n", __func__, attachment); ++ return table; ++} ++ ++static void vc_sm_unmap_dma_buf(struct dma_buf_attachment *attachment, ++ struct sg_table *table, ++ enum dma_data_direction direction) ++{ ++ pr_debug("%s attachment %p\n", __func__, attachment); ++ dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction); ++} ++ ++static int vc_sm_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ int ret; ++ ++ pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf, ++ buf, vma->vm_start); ++ ++ mutex_lock(&buf->lock); ++ ++ /* now map it to userspace */ ++ vma->vm_pgoff = 0; ++ ++ ret = dma_mmap_coherent(&sm_state->pdev->dev, vma, buf->cookie, ++ buf->dma_addr, buf->size); ++ ++ if (ret) { ++ pr_err("Remapping memory failed, error: %d\n", ret); ++ return ret; ++ } ++ ++ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; ++ ++ mutex_unlock(&buf->lock); ++ ++ if (ret) ++ pr_err("%s: failure mapping buffer to userspace\n", ++ __func__); ++ ++ return ret; ++} ++ ++static void vc_sm_dma_buf_release(struct dma_buf *dmabuf) ++{ ++ struct vc_sm_buffer *buffer; ++ ++ if (!dmabuf) ++ return; ++ ++ buffer = (struct vc_sm_buffer *)dmabuf->priv; ++ ++ mutex_lock(&buffer->lock); ++ ++ pr_debug("%s dmabuf %p, buffer %p\n", __func__, dmabuf, buffer); ++ ++ buffer->in_use = 0; ++ ++ /* Unmap on the VPU */ ++ vc_sm_vpu_free(buffer); ++ pr_debug("%s vpu_free done\n", __func__); ++ ++ /* Unmap our dma_buf object (the vc_sm_buffer remains until released ++ * on the VPU). ++ */ ++ vc_sm_clean_up_dmabuf(buffer); ++ pr_debug("%s clean_up dmabuf done\n", __func__); ++ ++ /* buffer->lock will be destroyed by vc_sm_release_resource if finished ++ * with, otherwise unlocked. Do NOT unlock here. ++ */ ++ vc_sm_release_resource(buffer); ++ pr_debug("%s done\n", __func__); ++} ++ ++static int vc_sm_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, ++ enum dma_data_direction direction) ++{ ++ struct vc_sm_buffer *buf; ++ struct vc_sm_dma_buf_attachment *a; ++ ++ if (!dmabuf) ++ return -EFAULT; ++ ++ buf = dmabuf->priv; ++ if (!buf) ++ return -EFAULT; ++ ++ mutex_lock(&buf->lock); ++ ++ list_for_each_entry(a, &buf->attachments, list) { ++ dma_sync_sg_for_cpu(a->dev, a->sg_table.sgl, ++ a->sg_table.nents, direction); ++ } ++ mutex_unlock(&buf->lock); ++ ++ return 0; ++} ++ ++static int vc_sm_dma_buf_end_cpu_access(struct dma_buf *dmabuf, ++ enum dma_data_direction direction) ++{ ++ struct vc_sm_buffer *buf; ++ struct vc_sm_dma_buf_attachment *a; ++ ++ if (!dmabuf) ++ return -EFAULT; ++ buf = dmabuf->priv; ++ if (!buf) ++ return -EFAULT; ++ ++ mutex_lock(&buf->lock); ++ ++ list_for_each_entry(a, &buf->attachments, list) { ++ dma_sync_sg_for_device(a->dev, a->sg_table.sgl, ++ a->sg_table.nents, direction); ++ } ++ mutex_unlock(&buf->lock); ++ ++ return 0; ++} ++ ++static void *vc_sm_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset) ++{ ++ /* FIXME */ ++ return NULL; ++} ++ ++static void vc_sm_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset, ++ void *ptr) ++{ ++ /* FIXME */ ++} ++ ++static const struct dma_buf_ops dma_buf_ops = { ++ .map_dma_buf = vc_sm_map_dma_buf, ++ .unmap_dma_buf = vc_sm_unmap_dma_buf, ++ .mmap = vc_sm_dmabuf_mmap, ++ .release = vc_sm_dma_buf_release, ++ .attach = vc_sm_dma_buf_attach, ++ .detach = vc_sm_dma_buf_detach, ++ .begin_cpu_access = vc_sm_dma_buf_begin_cpu_access, ++ .end_cpu_access = vc_sm_dma_buf_end_cpu_access, ++ .map = vc_sm_dma_buf_kmap, ++ .unmap = vc_sm_dma_buf_kunmap, ++}; ++ ++/* Dma_buf operations for chaining through to an imported dma_buf */ ++ ++static ++int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf, ++ struct dma_buf_attachment *attachment) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ if (!buf->imported) ++ return -EINVAL; ++ return buf->import.dma_buf->ops->attach(buf->import.dma_buf, ++ attachment); ++} ++ ++static ++void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf, ++ struct dma_buf_attachment *attachment) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ if (!buf->imported) ++ return; ++ buf->import.dma_buf->ops->detach(buf->import.dma_buf, attachment); ++} ++ ++static ++struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment, ++ enum dma_data_direction direction) ++{ ++ struct vc_sm_buffer *buf = attachment->dmabuf->priv; ++ ++ if (!buf->imported) ++ return NULL; ++ return buf->import.dma_buf->ops->map_dma_buf(attachment, ++ direction); ++} ++ ++static ++void vc_sm_import_unmap_dma_buf(struct dma_buf_attachment *attachment, ++ struct sg_table *table, ++ enum dma_data_direction direction) ++{ ++ struct vc_sm_buffer *buf = attachment->dmabuf->priv; ++ ++ if (!buf->imported) ++ return; ++ buf->import.dma_buf->ops->unmap_dma_buf(attachment, table, direction); ++} ++ ++static ++int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ pr_debug("%s: mmap dma_buf %p, buf %p, imported db %p\n", __func__, ++ dmabuf, buf, buf->import.dma_buf); ++ if (!buf->imported) { ++ pr_err("%s: mmap dma_buf %p- not an imported buffer\n", ++ __func__, dmabuf); ++ return -EINVAL; ++ } ++ return buf->import.dma_buf->ops->mmap(buf->import.dma_buf, vma); ++} ++ ++static ++void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf); ++ mutex_lock(&buf->lock); ++ if (!buf->imported) ++ return; ++ ++ buf->in_use = 0; ++ ++ vc_sm_vpu_free(buf); ++ ++ vc_sm_release_resource(buf); ++} ++ ++static ++void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf, ++ unsigned long offset) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ if (!buf->imported) ++ return NULL; ++ return buf->import.dma_buf->ops->map(buf->import.dma_buf, offset); ++} ++ ++static ++void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf, ++ unsigned long offset, void *ptr) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ if (!buf->imported) ++ return; ++ buf->import.dma_buf->ops->unmap(buf->import.dma_buf, offset, ptr); ++} ++ ++static ++int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, ++ enum dma_data_direction direction) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ if (!buf->imported) ++ return -EINVAL; ++ return buf->import.dma_buf->ops->begin_cpu_access(buf->import.dma_buf, ++ direction); ++} ++ ++static ++int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf, ++ enum dma_data_direction direction) ++{ ++ struct vc_sm_buffer *buf = dmabuf->priv; ++ ++ if (!buf->imported) ++ return -EINVAL; ++ return buf->import.dma_buf->ops->end_cpu_access(buf->import.dma_buf, ++ direction); ++} ++ ++static const struct dma_buf_ops dma_buf_import_ops = { ++ .map_dma_buf = vc_sm_import_map_dma_buf, ++ .unmap_dma_buf = vc_sm_import_unmap_dma_buf, ++ .mmap = vc_sm_import_dmabuf_mmap, ++ .release = vc_sm_import_dma_buf_release, ++ .attach = vc_sm_import_dma_buf_attach, ++ .detach = vc_sm_import_dma_buf_detatch, ++ .begin_cpu_access = vc_sm_import_dma_buf_begin_cpu_access, ++ .end_cpu_access = vc_sm_import_dma_buf_end_cpu_access, ++ .map = vc_sm_import_dma_buf_kmap, ++ .unmap = vc_sm_import_dma_buf_kunmap, ++}; ++ ++/* Import a dma_buf to be shared with VC. */ ++int ++vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private, ++ struct dma_buf *dma_buf, ++ int fd, ++ struct dma_buf **imported_buf) ++{ ++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); ++ struct vc_sm_buffer *buffer = NULL; ++ struct vc_sm_import import = { }; ++ struct vc_sm_import_result result = { }; ++ struct dma_buf_attachment *attach = NULL; ++ struct sg_table *sgt = NULL; ++ dma_addr_t dma_addr; ++ int ret = 0; ++ int status; ++ ++ /* Setup our allocation parameters */ ++ pr_debug("%s: importing dma_buf %p/fd %d\n", __func__, dma_buf, fd); ++ ++ if (fd < 0) ++ get_dma_buf(dma_buf); ++ else ++ dma_buf = dma_buf_get(fd); ++ ++ if (!dma_buf) ++ return -EINVAL; ++ ++ attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev); ++ if (IS_ERR(attach)) { ++ ret = PTR_ERR(attach); ++ goto error; ++ } ++ ++ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); ++ if (IS_ERR(sgt)) { ++ ret = PTR_ERR(sgt); ++ goto error; ++ } ++ ++ /* Verify that the address block is contiguous */ ++ if (sgt->nents != 1) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ /* Allocate local buffer to track this allocation. */ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (!buffer) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ import.type = VC_SM_ALLOC_NON_CACHED; ++ dma_addr = sg_dma_address(sgt->sgl); ++ import.addr = (u32)dma_addr; ++ if ((import.addr & 0xC0000000) != 0xC0000000) { ++ pr_err("%s: Expecting an uncached alias for dma_addr %pad\n", ++ __func__, &dma_addr); ++ import.addr |= 0xC0000000; ++ } ++ import.size = sg_dma_len(sgt->sgl); ++ import.allocator = current->tgid; ++ import.kernel_id = get_kernel_id(buffer); ++ ++ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT, ++ sizeof(VC_SM_RESOURCE_NAME_DEFAULT)); ++ ++ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u.\n", ++ __func__, import.name, import.type, &dma_addr, import.size); ++ ++ /* Allocate the videocore buffer. */ ++ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result, ++ &sm_state->int_trans_id); ++ if (status == -EINTR) { ++ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n", ++ __func__, sm_state->int_trans_id); ++ ret = -ERESTARTSYS; ++ private->restart_sys = -EINTR; ++ private->int_action = VC_SM_MSG_TYPE_IMPORT; ++ goto error; ++ } else if (status || !result.res_handle) { ++ pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n", ++ __func__, status, sm_state->int_trans_id); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ mutex_init(&buffer->lock); ++ INIT_LIST_HEAD(&buffer->attachments); ++ memcpy(buffer->name, import.name, ++ min(sizeof(buffer->name), sizeof(import.name) - 1)); ++ ++ /* Keep track of the buffer we created. */ ++ buffer->private = private; ++ buffer->vc_handle = result.res_handle; ++ buffer->size = import.size; ++ buffer->vpu_state = VPU_MAPPED; ++ ++ buffer->imported = 1; ++ buffer->import.dma_buf = dma_buf; ++ ++ buffer->import.attach = attach; ++ buffer->import.sgt = sgt; ++ buffer->dma_addr = dma_addr; ++ buffer->in_use = 1; ++ buffer->kernel_id = import.kernel_id; ++ ++ /* ++ * We're done - we need to export a new dmabuf chaining through most ++ * functions, but enabling us to release our own internal references ++ * here. ++ */ ++ exp_info.ops = &dma_buf_import_ops; ++ exp_info.size = import.size; ++ exp_info.flags = O_RDWR; ++ exp_info.priv = buffer; ++ ++ buffer->dma_buf = dma_buf_export(&exp_info); ++ if (IS_ERR(buffer->dma_buf)) { ++ ret = PTR_ERR(buffer->dma_buf); ++ goto error; ++ } ++ ++ vc_sm_add_resource(private, buffer); ++ ++ *imported_buf = buffer->dma_buf; ++ ++ return 0; ++ ++error: ++ if (result.res_handle) { ++ struct vc_sm_free_t free = { result.res_handle, 0 }; ++ ++ vc_sm_cma_vchi_free(sm_state->sm_handle, &free, ++ &sm_state->int_trans_id); ++ } ++ free_kernel_id(import.kernel_id); ++ kfree(buffer); ++ if (sgt) ++ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); ++ if (attach) ++ dma_buf_detach(dma_buf, attach); ++ dma_buf_put(dma_buf); ++ return ret; ++} ++ ++static int vc_sm_cma_vpu_alloc(u32 size, u32 align, const char *name, ++ u32 mem_handle, struct vc_sm_buffer **ret_buffer) ++{ ++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); ++ struct vc_sm_buffer *buffer = NULL; ++ struct sg_table *sgt; ++ int aligned_size; ++ int ret = 0; ++ ++ /* Align to the user requested align */ ++ aligned_size = ALIGN(size, align); ++ /* and then to a page boundary */ ++ aligned_size = PAGE_ALIGN(aligned_size); ++ ++ if (!aligned_size) ++ return -EINVAL; ++ ++ /* Allocate local buffer to track this allocation. */ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ mutex_init(&buffer->lock); ++ /* Acquire the mutex as vc_sm_release_resource will release it in the ++ * error path. ++ */ ++ mutex_lock(&buffer->lock); ++ ++ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev, ++ aligned_size, &buffer->dma_addr, ++ GFP_KERNEL); ++ if (!buffer->cookie) { ++ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n", ++ __func__, aligned_size); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ pr_debug("[%s]: alloc of %d bytes success\n", ++ __func__, aligned_size); ++ ++ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie, ++ buffer->dma_addr, buffer->size); ++ if (ret < 0) { ++ pr_err("failed to get scatterlist from DMA API\n"); ++ kfree(sgt); ++ ret = -ENOMEM; ++ goto error; ++ } ++ buffer->alloc.sg_table = sgt; ++ ++ INIT_LIST_HEAD(&buffer->attachments); ++ ++ memcpy(buffer->name, name, ++ min(sizeof(buffer->name), strlen(name))); ++ ++ exp_info.ops = &dma_buf_ops; ++ exp_info.size = aligned_size; ++ exp_info.flags = O_RDWR; ++ exp_info.priv = buffer; ++ ++ buffer->dma_buf = dma_buf_export(&exp_info); ++ if (IS_ERR(buffer->dma_buf)) { ++ ret = PTR_ERR(buffer->dma_buf); ++ goto error; ++ } ++ buffer->dma_addr = (u32)sg_dma_address(buffer->alloc.sg_table->sgl); ++ if ((buffer->dma_addr & 0xC0000000) != 0xC0000000) { ++ pr_warn_once("%s: Expecting an uncached alias for dma_addr %pad\n", ++ __func__, &buffer->dma_addr); ++ buffer->dma_addr |= 0xC0000000; ++ } ++ buffer->private = sm_state->vpu_allocs; ++ ++ buffer->vc_handle = mem_handle; ++ buffer->vpu_state = VPU_MAPPED; ++ buffer->vpu_allocated = 1; ++ buffer->size = size; ++ /* ++ * Create an ID that will be passed along with our message so ++ * that when we service the release reply, we can look up which ++ * resource is being released. ++ */ ++ buffer->kernel_id = get_kernel_id(buffer); ++ ++ vc_sm_add_resource(sm_state->vpu_allocs, buffer); ++ ++ mutex_unlock(&buffer->lock); ++ ++ *ret_buffer = buffer; ++ return 0; ++error: ++ if (buffer) ++ vc_sm_release_resource(buffer); ++ return ret; ++} ++ ++static void ++vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply, ++ int reply_len) ++{ ++ switch (reply->trans_id & ~0x80000000) { ++ case VC_SM_MSG_TYPE_CLIENT_VERSION: ++ { ++ /* Acknowledge that the firmware supports the version command */ ++ pr_debug("%s: firmware acked version msg. Require release cb\n", ++ __func__); ++ sm_state->require_released_callback = true; ++ } ++ break; ++ case VC_SM_MSG_TYPE_RELEASED: ++ { ++ struct vc_sm_released *release = (struct vc_sm_released *)reply; ++ struct vc_sm_buffer *buffer = ++ lookup_kernel_id(release->kernel_id); ++ if (!buffer) { ++ pr_err("%s: VC released a buffer that is already released, kernel_id %d\n", ++ __func__, release->kernel_id); ++ break; ++ } ++ mutex_lock(&buffer->lock); ++ ++ pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n", ++ __func__, release->addr, release->size, ++ release->kernel_id, release->vc_handle); ++ ++ buffer->vc_handle = 0; ++ buffer->vpu_state = VPU_NOT_MAPPED; ++ free_kernel_id(release->kernel_id); ++ ++ if (buffer->vpu_allocated) { ++ /* VPU allocation, so release the dmabuf which will ++ * trigger the clean up. ++ */ ++ mutex_unlock(&buffer->lock); ++ dma_buf_put(buffer->dma_buf); ++ } else { ++ vc_sm_release_resource(buffer); ++ } ++ } ++ break; ++ case VC_SM_MSG_TYPE_VC_MEM_REQUEST: ++ { ++ struct vc_sm_buffer *buffer = NULL; ++ struct vc_sm_vc_mem_request *req = ++ (struct vc_sm_vc_mem_request *)reply; ++ struct vc_sm_vc_mem_request_result reply; ++ int ret; ++ ++ pr_debug("%s: Request %u bytes of memory, align %d name %s, trans_id %08x\n", ++ __func__, req->size, req->align, req->name, ++ req->trans_id); ++ ret = vc_sm_cma_vpu_alloc(req->size, req->align, req->name, ++ req->vc_handle, &buffer); ++ ++ reply.trans_id = req->trans_id; ++ if (!ret) { ++ reply.addr = buffer->dma_addr; ++ reply.kernel_id = buffer->kernel_id; ++ pr_debug("%s: Allocated resource buffer %p, addr %pad\n", ++ __func__, buffer, &buffer->dma_addr); ++ } else { ++ pr_err("%s: Allocation failed size %u, name %s, vc_handle %u\n", ++ __func__, req->size, req->name, req->vc_handle); ++ reply.addr = 0; ++ reply.kernel_id = 0; ++ } ++ vc_sm_vchi_client_vc_mem_req_reply(sm_state->sm_handle, &reply, ++ &sm_state->int_trans_id); ++ break; ++ } ++ break; ++ default: ++ pr_err("%s: Unknown vpu cmd %x\n", __func__, reply->trans_id); ++ break; ++ } ++} ++ ++/* Userspace handling */ ++/* ++ * Open the device. Creates a private state to help track all allocation ++ * associated with this device. ++ */ ++static int vc_sm_cma_open(struct inode *inode, struct file *file) ++{ ++ /* Make sure the device was started properly. */ ++ if (!sm_state) { ++ pr_err("[%s]: invalid device\n", __func__); ++ return -EPERM; ++ } ++ ++ file->private_data = vc_sm_cma_create_priv_data(current->tgid); ++ if (!file->private_data) { ++ pr_err("[%s]: failed to create data tracker\n", __func__); ++ ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Close the vcsm-cma device. ++ * All allocations are file descriptors to the dmabuf objects, so we will get ++ * the clean up request on those as those are cleaned up. ++ */ ++static int vc_sm_cma_release(struct inode *inode, struct file *file) ++{ ++ struct vc_sm_privdata_t *file_data = ++ (struct vc_sm_privdata_t *)file->private_data; ++ int ret = 0; ++ ++ /* Make sure the device was started properly. */ ++ if (!sm_state || !file_data) { ++ pr_err("[%s]: invalid device\n", __func__); ++ ret = -EPERM; ++ goto out; ++ } ++ ++ pr_debug("[%s]: using private data %p\n", __func__, file_data); ++ ++ /* Terminate the private data. */ ++ kfree(file_data); ++ ++out: ++ return ret; ++} ++ ++/* ++ * Allocate a shared memory handle and block. ++ * Allocation is from CMA, and then imported into the VPU mappings. ++ */ ++int vc_sm_cma_ioctl_alloc(struct vc_sm_privdata_t *private, ++ struct vc_sm_cma_ioctl_alloc *ioparam) ++{ ++ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); ++ struct vc_sm_buffer *buffer = NULL; ++ struct vc_sm_import import = { 0 }; ++ struct vc_sm_import_result result = { 0 }; ++ struct dma_buf *dmabuf = NULL; ++ struct sg_table *sgt; ++ int aligned_size; ++ int ret = 0; ++ int status; ++ int fd = -1; ++ ++ aligned_size = PAGE_ALIGN(ioparam->size); ++ ++ if (!aligned_size) ++ return -EINVAL; ++ ++ /* Allocate local buffer to track this allocation. */ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (!buffer) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev, ++ aligned_size, ++ &buffer->dma_addr, ++ GFP_KERNEL); ++ if (!buffer->cookie) { ++ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n", ++ __func__, aligned_size); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ import.type = VC_SM_ALLOC_NON_CACHED; ++ import.allocator = current->tgid; ++ ++ if (*ioparam->name) ++ memcpy(import.name, ioparam->name, sizeof(import.name) - 1); ++ else ++ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT, ++ sizeof(VC_SM_RESOURCE_NAME_DEFAULT)); ++ ++ mutex_init(&buffer->lock); ++ INIT_LIST_HEAD(&buffer->attachments); ++ memcpy(buffer->name, import.name, ++ min(sizeof(buffer->name), sizeof(import.name) - 1)); ++ ++ exp_info.ops = &dma_buf_ops; ++ exp_info.size = aligned_size; ++ exp_info.flags = O_RDWR; ++ exp_info.priv = buffer; ++ ++ dmabuf = dma_buf_export(&exp_info); ++ if (IS_ERR(dmabuf)) { ++ ret = PTR_ERR(dmabuf); ++ goto error; ++ } ++ buffer->dma_buf = dmabuf; ++ ++ import.addr = buffer->dma_addr; ++ import.size = aligned_size; ++ import.kernel_id = get_kernel_id(buffer); ++ ++ /* Wrap it into a videocore buffer. */ ++ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result, ++ &sm_state->int_trans_id); ++ if (status == -EINTR) { ++ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n", ++ __func__, sm_state->int_trans_id); ++ ret = -ERESTARTSYS; ++ private->restart_sys = -EINTR; ++ private->int_action = VC_SM_MSG_TYPE_IMPORT; ++ goto error; ++ } else if (status || !result.res_handle) { ++ pr_err("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n", ++ __func__, status, sm_state->int_trans_id); ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ /* Keep track of the buffer we created. */ ++ buffer->private = private; ++ buffer->vc_handle = result.res_handle; ++ buffer->size = import.size; ++ buffer->vpu_state = VPU_MAPPED; ++ buffer->kernel_id = import.kernel_id; ++ ++ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie, ++ buffer->dma_addr, buffer->size); ++ if (ret < 0) { ++ /* FIXME: error handling */ ++ pr_err("failed to get scatterlist from DMA API\n"); ++ kfree(sgt); ++ ret = -ENOMEM; ++ goto error; ++ } ++ buffer->alloc.sg_table = sgt; ++ ++ fd = dma_buf_fd(dmabuf, O_CLOEXEC); ++ if (fd < 0) ++ goto error; ++ ++ vc_sm_add_resource(private, buffer); ++ ++ pr_debug("[%s]: Added resource as fd %d, buffer %p, private %p, dma_addr %pad\n", ++ __func__, fd, buffer, private, &buffer->dma_addr); ++ ++ /* We're done */ ++ ioparam->handle = fd; ++ ioparam->vc_handle = buffer->vc_handle; ++ ioparam->dma_addr = buffer->dma_addr; ++ return 0; ++ ++error: ++ pr_err("[%s]: something failed - cleanup. ret %d\n", __func__, ret); ++ ++ if (dmabuf) { ++ /* dmabuf has been exported, therefore allow dmabuf cleanup to ++ * deal with this ++ */ ++ dma_buf_put(dmabuf); ++ } else { ++ /* No dmabuf, therefore just free the buffer here */ ++ if (buffer->cookie) ++ dma_free_coherent(&sm_state->pdev->dev, buffer->size, ++ buffer->cookie, buffer->dma_addr); ++ kfree(buffer); ++ } ++ return ret; ++} ++ ++#ifndef CONFIG_ARM64 ++/* Converts VCSM_CACHE_OP_* to an operating function. */ ++static void (*cache_op_to_func(const unsigned int cache_op)) ++ (const void*, const void*) ++{ ++ switch (cache_op) { ++ case VC_SM_CACHE_OP_NOP: ++ return NULL; ++ ++ case VC_SM_CACHE_OP_INV: ++ return dmac_inv_range; ++ ++ case VC_SM_CACHE_OP_CLEAN: ++ return dmac_clean_range; ++ ++ case VC_SM_CACHE_OP_FLUSH: ++ return dmac_flush_range; ++ ++ default: ++ pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op); ++ return NULL; ++ } ++} ++ ++/* ++ * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed). ++ */ ++static int clean_invalid_contig_2d(const void __user *addr, ++ const size_t block_count, ++ const size_t block_size, ++ const size_t stride, ++ const unsigned int cache_op) ++{ ++ size_t i; ++ void (*op_fn)(const void *start, const void *end); ++ ++ if (!block_size) { ++ pr_err("[%s]: size cannot be 0\n", __func__); ++ return -EINVAL; ++ } ++ ++ op_fn = cache_op_to_func(cache_op); ++ if (!op_fn) ++ return -EINVAL; ++ ++ for (i = 0; i < block_count; i ++, addr += stride) ++ op_fn(addr, addr + block_size); ++ ++ return 0; ++} ++ ++static int vc_sm_cma_clean_invalid2(unsigned int cmdnr, unsigned long arg) ++{ ++ struct vc_sm_cma_ioctl_clean_invalid2 ioparam; ++ struct vc_sm_cma_ioctl_clean_invalid_block *block = NULL; ++ int i, ret = 0; ++ ++ /* Get parameter data. */ ++ if (copy_from_user(&ioparam, (void *)arg, sizeof(ioparam))) { ++ pr_err("[%s]: failed to copy-from-user header for cmd %x\n", ++ __func__, cmdnr); ++ return -EFAULT; ++ } ++ block = kmalloc(ioparam.op_count * sizeof(*block), GFP_KERNEL); ++ if (!block) ++ return -EFAULT; ++ ++ if (copy_from_user(block, (void *)(arg + sizeof(ioparam)), ++ ioparam.op_count * sizeof(*block)) != 0) { ++ pr_err("[%s]: failed to copy-from-user payload for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ for (i = 0; i < ioparam.op_count; i++) { ++ const struct vc_sm_cma_ioctl_clean_invalid_block * const op = ++ block + i; ++ ++ if (op->invalidate_mode == VC_SM_CACHE_OP_NOP) ++ continue; ++ ++ ret = clean_invalid_contig_2d((void __user *)op->start_address, ++ op->block_count, op->block_size, ++ op->inter_block_stride, ++ op->invalidate_mode); ++ if (ret) ++ break; ++ } ++out: ++ kfree(block); ++ ++ return ret; ++} ++#endif ++ ++static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret = 0; ++ unsigned int cmdnr = _IOC_NR(cmd); ++ struct vc_sm_privdata_t *file_data = ++ (struct vc_sm_privdata_t *)file->private_data; ++ ++ /* Validate we can work with this device. */ ++ if (!sm_state || !file_data) { ++ pr_err("[%s]: invalid device\n", __func__); ++ return -EPERM; ++ } ++ ++ /* Action is a re-post of a previously interrupted action? */ ++ if (file_data->restart_sys == -EINTR) { ++ struct vc_sm_action_clean_t action_clean; ++ ++ pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n", ++ __func__, file_data->int_action, ++ file_data->int_trans_id); ++ ++ action_clean.res_action = file_data->int_action; ++ action_clean.action_trans_id = file_data->int_trans_id; ++ ++ file_data->restart_sys = 0; ++ } ++ ++ /* Now process the command. */ ++ switch (cmdnr) { ++ /* New memory allocation. ++ */ ++ case VC_SM_CMA_CMD_ALLOC: ++ { ++ struct vc_sm_cma_ioctl_alloc ioparam; ++ ++ /* Get the parameter data. */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ break; ++ } ++ ++ ret = vc_sm_cma_ioctl_alloc(file_data, &ioparam); ++ if (!ret && ++ (copy_to_user((void *)arg, &ioparam, ++ sizeof(ioparam)) != 0)) { ++ /* FIXME: Release allocation */ ++ pr_err("[%s]: failed to copy-to-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ } ++ break; ++ } ++ ++ case VC_SM_CMA_CMD_IMPORT_DMABUF: ++ { ++ struct vc_sm_cma_ioctl_import_dmabuf ioparam; ++ struct dma_buf *new_dmabuf; ++ ++ /* Get the parameter data. */ ++ if (copy_from_user ++ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { ++ pr_err("[%s]: failed to copy-from-user for cmd %x\n", ++ __func__, cmdnr); ++ ret = -EFAULT; ++ break; ++ } ++ ++ ret = vc_sm_cma_import_dmabuf_internal(file_data, ++ NULL, ++ ioparam.dmabuf_fd, ++ &new_dmabuf); ++ ++ if (!ret) { ++ struct vc_sm_buffer *buf = new_dmabuf->priv; ++ ++ ioparam.size = buf->size; ++ ioparam.handle = dma_buf_fd(new_dmabuf, ++ O_CLOEXEC); ++ ioparam.vc_handle = buf->vc_handle; ++ ioparam.dma_addr = buf->dma_addr; ++ ++ if (ioparam.handle < 0 || ++ (copy_to_user((void *)arg, &ioparam, ++ sizeof(ioparam)) != 0)) { ++ dma_buf_put(new_dmabuf); ++ /* FIXME: Release allocation */ ++ ret = -EFAULT; ++ } ++ } ++ break; ++ } ++ ++#ifndef CONFIG_ARM64 ++ /* ++ * Flush/Invalidate the cache for a given mapping. ++ * Blocks must be pinned (i.e. accessed) before this call. ++ */ ++ case VC_SM_CMA_CMD_CLEAN_INVALID2: ++ ret = vc_sm_cma_clean_invalid2(cmdnr, arg); ++ break; ++#endif ++ ++ default: ++ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr, ++ current->tgid, file_data->pid); ++ ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_COMPAT ++struct vc_sm_cma_ioctl_clean_invalid2_32 { ++ u32 op_count; ++ struct vc_sm_cma_ioctl_clean_invalid_block_32 { ++ u16 invalidate_mode; ++ u16 block_count; ++ compat_uptr_t start_address; ++ u32 block_size; ++ u32 inter_block_stride; ++ } s[0]; ++}; ++ ++#define VC_SM_CMA_CMD_CLEAN_INVALID2_32\ ++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\ ++ struct vc_sm_cma_ioctl_clean_invalid2_32) ++ ++static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ switch (cmd) { ++ case VC_SM_CMA_CMD_CLEAN_INVALID2_32: ++ /* FIXME */ ++ return -EINVAL; ++ ++ default: ++ return vc_sm_cma_ioctl(file, cmd, arg); ++ } ++} ++#endif ++ ++/* Device operations that we managed in this driver. */ ++static const struct file_operations vc_sm_ops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = vc_sm_cma_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = vc_sm_cma_compat_ioctl, ++#endif ++ .open = vc_sm_cma_open, ++ .release = vc_sm_cma_release, ++}; ++ ++/* Driver load/unload functions */ ++/* Videocore connected. */ ++static void vc_sm_connected_init(void) ++{ ++ int ret; ++ VCHI_INSTANCE_T vchi_instance; ++ struct vc_sm_version version; ++ struct vc_sm_result_t version_result; ++ ++ pr_info("[%s]: start\n", __func__); ++ ++ /* ++ * Initialize and create a VCHI connection for the shared memory service ++ * running on videocore. ++ */ ++ ret = vchi_initialise(&vchi_instance); ++ if (ret) { ++ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n", ++ __func__, ret); ++ ++ return; ++ } ++ ++ ret = vchi_connect(vchi_instance); ++ if (ret) { ++ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n", ++ __func__, ret); ++ ++ return; ++ } ++ ++ /* Initialize an instance of the shared memory service. */ ++ sm_state->sm_handle = vc_sm_cma_vchi_init(vchi_instance, 1, ++ vc_sm_vpu_event); ++ if (!sm_state->sm_handle) { ++ pr_err("[%s]: failed to initialize shared memory service\n", ++ __func__); ++ ++ return; ++ } ++ ++ /* Create a debug fs directory entry (root). */ ++ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL); ++ ++ sm_state->dir_state.show = &vc_sm_cma_global_state_show; ++ sm_state->dir_state.dir_entry = ++ debugfs_create_file(VC_SM_STATE, 0444, sm_state->dir_root, ++ &sm_state->dir_state, ++ &vc_sm_cma_debug_fs_fops); ++ ++ INIT_LIST_HEAD(&sm_state->buffer_list); ++ ++ /* Create a shared memory device. */ ++ sm_state->misc_dev.minor = MISC_DYNAMIC_MINOR; ++ sm_state->misc_dev.name = DEVICE_NAME; ++ sm_state->misc_dev.fops = &vc_sm_ops; ++ sm_state->misc_dev.parent = NULL; ++ /* Temporarily set as 666 until udev rules have been sorted */ ++ sm_state->misc_dev.mode = 0666; ++ ret = misc_register(&sm_state->misc_dev); ++ if (ret) { ++ pr_err("vcsm-cma: failed to register misc device.\n"); ++ goto err_remove_debugfs; ++ } ++ ++ sm_state->data_knl = vc_sm_cma_create_priv_data(0); ++ if (!sm_state->data_knl) { ++ pr_err("[%s]: failed to create kernel private data tracker\n", ++ __func__); ++ goto err_remove_misc_dev; ++ } ++ ++ version.version = 2; ++ ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version, ++ &version_result, ++ &sm_state->int_trans_id); ++ if (ret) { ++ pr_err("[%s]: Failed to send version request %d\n", __func__, ++ ret); ++ } ++ ++ /* Done! */ ++ sm_inited = 1; ++ pr_info("[%s]: installed successfully\n", __func__); ++ return; ++ ++err_remove_misc_dev: ++ misc_deregister(&sm_state->misc_dev); ++err_remove_debugfs: ++ debugfs_remove_recursive(sm_state->dir_root); ++ vc_sm_cma_vchi_stop(&sm_state->sm_handle); ++} ++ ++/* Driver loading. */ ++static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev) ++{ ++ pr_info("%s: Videocore shared memory driver\n", __func__); ++ ++ sm_state = devm_kzalloc(&pdev->dev, sizeof(*sm_state), GFP_KERNEL); ++ if (!sm_state) ++ return -ENOMEM; ++ sm_state->pdev = pdev; ++ mutex_init(&sm_state->map_lock); ++ ++ spin_lock_init(&sm_state->kernelid_map_lock); ++ idr_init_base(&sm_state->kernelid_map, 1); ++ ++ pdev->dev.dma_parms = devm_kzalloc(&pdev->dev, ++ sizeof(*pdev->dev.dma_parms), ++ GFP_KERNEL); ++ /* dma_set_max_seg_size checks if dma_parms is NULL. */ ++ dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); ++ ++ vchiq_add_connected_callback(vc_sm_connected_init); ++ return 0; ++} ++ ++/* Driver unloading. */ ++static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev) ++{ ++ pr_debug("[%s]: start\n", __func__); ++ if (sm_inited) { ++ misc_deregister(&sm_state->misc_dev); ++ ++ /* Remove all proc entries. */ ++ debugfs_remove_recursive(sm_state->dir_root); ++ ++ /* Stop the videocore shared memory service. */ ++ vc_sm_cma_vchi_stop(&sm_state->sm_handle); ++ } ++ ++ if (sm_state) { ++ idr_destroy(&sm_state->kernelid_map); ++ ++ /* Free the memory for the state structure. */ ++ mutex_destroy(&sm_state->map_lock); ++ } ++ ++ pr_debug("[%s]: end\n", __func__); ++ return 0; ++} ++ ++/* Kernel API calls */ ++/* Get an internal resource handle mapped from the external one. */ ++int vc_sm_cma_int_handle(void *handle) ++{ ++ struct dma_buf *dma_buf = (struct dma_buf *)handle; ++ struct vc_sm_buffer *buf; ++ ++ /* Validate we can work with this device. */ ++ if (!sm_state || !handle) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return 0; ++ } ++ ++ buf = (struct vc_sm_buffer *)dma_buf->priv; ++ return buf->vc_handle; ++} ++EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle); ++ ++/* Free a previously allocated shared memory handle and block. */ ++int vc_sm_cma_free(void *handle) ++{ ++ struct dma_buf *dma_buf = (struct dma_buf *)handle; ++ ++ /* Validate we can work with this device. */ ++ if (!sm_state || !handle) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return -EPERM; ++ } ++ ++ pr_debug("%s: handle %p/dmabuf %p\n", __func__, handle, dma_buf); ++ ++ dma_buf_put(dma_buf); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(vc_sm_cma_free); ++ ++/* Import a dmabuf to be shared with VC. */ ++int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, void **handle) ++{ ++ struct dma_buf *new_dma_buf; ++ struct vc_sm_buffer *buf; ++ int ret; ++ ++ /* Validate we can work with this device. */ ++ if (!sm_state || !src_dmabuf || !handle) { ++ pr_err("[%s]: invalid input\n", __func__); ++ return -EPERM; ++ } ++ ++ ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf, ++ -1, &new_dma_buf); ++ ++ if (!ret) { ++ pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf); ++ buf = (struct vc_sm_buffer *)new_dma_buf->priv; ++ ++ /* Assign valid handle at this time.*/ ++ *handle = new_dma_buf; ++ } else { ++ /* ++ * succeeded in importing the dma_buf, but then ++ * failed to look it up again. How? ++ * Release the fd again. ++ */ ++ pr_err("%s: imported vc_sm_cma_get_buffer failed %d\n", ++ __func__, ret); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(vc_sm_cma_import_dmabuf); ++ ++static struct platform_driver bcm2835_vcsm_cma_driver = { ++ .probe = bcm2835_vc_sm_cma_probe, ++ .remove = bcm2835_vc_sm_cma_remove, ++ .driver = { ++ .name = DEVICE_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(bcm2835_vcsm_cma_driver); ++ ++MODULE_AUTHOR("Dave Stevenson"); ++MODULE_DESCRIPTION("VideoCore CMA Shared Memory Driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:vcsm-cma"); +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h +@@ -0,0 +1,84 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++/* ++ * VideoCore Shared Memory driver using CMA. ++ * ++ * Copyright: 2018, Raspberry Pi (Trading) Ltd ++ * ++ */ ++ ++#ifndef VC_SM_H ++#define VC_SM_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define VC_SM_MAX_NAME_LEN 32 ++ ++enum vc_sm_vpu_mapping_state { ++ VPU_NOT_MAPPED, ++ VPU_MAPPED, ++ VPU_UNMAPPING ++}; ++ ++struct vc_sm_alloc_data { ++ unsigned long num_pages; ++ void *priv_virt; ++ struct sg_table *sg_table; ++}; ++ ++struct vc_sm_imported { ++ struct dma_buf *dma_buf; ++ struct dma_buf_attachment *attach; ++ struct sg_table *sgt; ++}; ++ ++struct vc_sm_buffer { ++ struct list_head global_buffer_list; /* Global list of buffers. */ ++ ++ /* Index in the kernel_id idr so that we can find the ++ * mmal_msg_context again when servicing the VCHI reply. ++ */ ++ int kernel_id; ++ ++ size_t size; ++ ++ /* Lock over all the following state for this buffer */ ++ struct mutex lock; ++ struct list_head attachments; ++ ++ char name[VC_SM_MAX_NAME_LEN]; ++ ++ int in_use:1; /* Kernel is still using this resource */ ++ int imported:1; /* Imported dmabuf */ ++ ++ enum vc_sm_vpu_mapping_state vpu_state; ++ u32 vc_handle; /* VideoCore handle for this buffer */ ++ int vpu_allocated; /* ++ * The VPU made this allocation. Release the ++ * local dma_buf when the VPU releases the ++ * resource. ++ */ ++ ++ /* DMABUF related fields */ ++ struct dma_buf *dma_buf; ++ dma_addr_t dma_addr; ++ void *cookie; ++ ++ struct vc_sm_privdata_t *private; ++ ++ union { ++ struct vc_sm_alloc_data alloc; ++ struct vc_sm_imported import; ++ }; ++}; ++ ++#endif +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c +@@ -0,0 +1,505 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * VideoCore Shared Memory CMA allocator ++ * ++ * Copyright: 2018, Raspberry Pi (Trading) Ltd ++ * Copyright 2011-2012 Broadcom Corporation. All rights reserved. ++ * ++ * Based on vmcs_sm driver from Broadcom Corporation. ++ * ++ */ ++ ++/* ---- Include Files ----------------------------------------------------- */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vc_sm_cma_vchi.h" ++ ++#define VC_SM_VER 1 ++#define VC_SM_MIN_VER 0 ++ ++/* ---- Private Constants and Types -------------------------------------- */ ++ ++/* Command blocks come from a pool */ ++#define SM_MAX_NUM_CMD_RSP_BLKS 32 ++ ++struct sm_cmd_rsp_blk { ++ struct list_head head; /* To create lists */ ++ /* To be signaled when the response is there */ ++ struct completion cmplt; ++ ++ u16 id; ++ u16 length; ++ ++ u8 msg[VC_SM_MAX_MSG_LEN]; ++ ++ uint32_t wait:1; ++ uint32_t sent:1; ++ uint32_t alloc:1; ++ ++}; ++ ++struct sm_instance { ++ u32 num_connections; ++ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS]; ++ struct task_struct *io_thread; ++ struct completion io_cmplt; ++ ++ vpu_event_cb vpu_event; ++ ++ /* Mutex over the following lists */ ++ struct mutex lock; ++ u32 trans_id; ++ struct list_head cmd_list; ++ struct list_head rsp_list; ++ struct list_head dead_list; ++ ++ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS]; ++ ++ /* Mutex over the free_list */ ++ struct mutex free_lock; ++ struct list_head free_list; ++ ++ struct semaphore free_sema; ++ ++}; ++ ++/* ---- Private Variables ------------------------------------------------ */ ++ ++/* ---- Private Function Prototypes -------------------------------------- */ ++ ++/* ---- Private Functions ------------------------------------------------ */ ++static int ++bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, ++ void *data, ++ unsigned int size) ++{ ++ return vchi_queue_kernel_message(handle, ++ data, ++ size); ++} ++ ++static struct ++sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance, ++ enum vc_sm_msg_type id, void *msg, ++ u32 size, int wait) ++{ ++ struct sm_cmd_rsp_blk *blk; ++ struct vc_sm_msg_hdr_t *hdr; ++ ++ if (down_interruptible(&instance->free_sema)) { ++ blk = kmalloc(sizeof(*blk), GFP_KERNEL); ++ if (!blk) ++ return NULL; ++ ++ blk->alloc = 1; ++ init_completion(&blk->cmplt); ++ } else { ++ mutex_lock(&instance->free_lock); ++ blk = ++ list_first_entry(&instance->free_list, ++ struct sm_cmd_rsp_blk, head); ++ list_del(&blk->head); ++ mutex_unlock(&instance->free_lock); ++ } ++ ++ blk->sent = 0; ++ blk->wait = wait; ++ blk->length = sizeof(*hdr) + size; ++ ++ hdr = (struct vc_sm_msg_hdr_t *)blk->msg; ++ hdr->type = id; ++ mutex_lock(&instance->lock); ++ instance->trans_id++; ++ /* ++ * Retain the top bit for identifying asynchronous events, or VPU cmds. ++ */ ++ instance->trans_id &= ~0x80000000; ++ hdr->trans_id = instance->trans_id; ++ blk->id = instance->trans_id; ++ mutex_unlock(&instance->lock); ++ ++ if (size) ++ memcpy(hdr->body, msg, size); ++ ++ return blk; ++} ++ ++static void ++vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk) ++{ ++ if (blk->alloc) { ++ kfree(blk); ++ return; ++ } ++ ++ mutex_lock(&instance->free_lock); ++ list_add(&blk->head, &instance->free_list); ++ mutex_unlock(&instance->free_lock); ++ up(&instance->free_sema); ++} ++ ++static void vc_sm_cma_vchi_rx_ack(struct sm_instance *instance, ++ struct sm_cmd_rsp_blk *cmd, ++ struct vc_sm_result_t *reply, ++ u32 reply_len) ++{ ++ mutex_lock(&instance->lock); ++ list_for_each_entry(cmd, ++ &instance->rsp_list, ++ head) { ++ if (cmd->id == reply->trans_id) ++ break; ++ } ++ mutex_unlock(&instance->lock); ++ ++ if (&cmd->head == &instance->rsp_list) { ++ //pr_debug("%s: received response %u, throw away...", ++ pr_err("%s: received response %u, throw away...", ++ __func__, ++ reply->trans_id); ++ } else if (reply_len > sizeof(cmd->msg)) { ++ pr_err("%s: reply too big (%u) %u, throw away...", ++ __func__, reply_len, ++ reply->trans_id); ++ } else { ++ memcpy(cmd->msg, reply, ++ reply_len); ++ complete(&cmd->cmplt); ++ } ++} ++ ++static int vc_sm_cma_vchi_videocore_io(void *arg) ++{ ++ struct sm_instance *instance = arg; ++ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp; ++ struct vc_sm_result_t *reply; ++ u32 reply_len; ++ s32 status; ++ int svc_use = 1; ++ ++ while (1) { ++ if (svc_use) ++ vchi_service_release(instance->vchi_handle[0]); ++ svc_use = 0; ++ ++ if (wait_for_completion_interruptible(&instance->io_cmplt)) ++ continue; ++ ++ vchi_service_use(instance->vchi_handle[0]); ++ svc_use = 1; ++ ++ do { ++ /* ++ * Get new command and move it to response list ++ */ ++ mutex_lock(&instance->lock); ++ if (list_empty(&instance->cmd_list)) { ++ /* no more commands to process */ ++ mutex_unlock(&instance->lock); ++ break; ++ } ++ cmd = list_first_entry(&instance->cmd_list, ++ struct sm_cmd_rsp_blk, head); ++ list_move(&cmd->head, &instance->rsp_list); ++ cmd->sent = 1; ++ mutex_unlock(&instance->lock); ++ ++ /* Send the command */ ++ status = ++ bcm2835_vchi_msg_queue(instance->vchi_handle[0], ++ cmd->msg, cmd->length); ++ if (status) { ++ pr_err("%s: failed to queue message (%d)", ++ __func__, status); ++ } ++ ++ /* If no reply is needed then we're done */ ++ if (!cmd->wait) { ++ mutex_lock(&instance->lock); ++ list_del(&cmd->head); ++ mutex_unlock(&instance->lock); ++ vc_vchi_cmd_delete(instance, cmd); ++ continue; ++ } ++ ++ if (status) { ++ complete(&cmd->cmplt); ++ continue; ++ } ++ ++ } while (1); ++ ++ while (!vchi_msg_peek(instance->vchi_handle[0], (void **)&reply, ++ &reply_len, VCHI_FLAGS_NONE)) { ++ if (reply->trans_id & 0x80000000) { ++ /* Async event or cmd from the VPU */ ++ if (instance->vpu_event) ++ instance->vpu_event(instance, reply, ++ reply_len); ++ } else { ++ vc_sm_cma_vchi_rx_ack(instance, cmd, reply, ++ reply_len); ++ } ++ ++ vchi_msg_remove(instance->vchi_handle[0]); ++ } ++ ++ /* Go through the dead list and free them */ ++ mutex_lock(&instance->lock); ++ list_for_each_entry_safe(cmd, cmd_tmp, &instance->dead_list, ++ head) { ++ list_del(&cmd->head); ++ vc_vchi_cmd_delete(instance, cmd); ++ } ++ mutex_unlock(&instance->lock); ++ } ++ ++ return 0; ++} ++ ++static void vc_sm_cma_vchi_callback(void *param, ++ const VCHI_CALLBACK_REASON_T reason, ++ void *msg_handle) ++{ ++ struct sm_instance *instance = param; ++ ++ (void)msg_handle; ++ ++ switch (reason) { ++ case VCHI_CALLBACK_MSG_AVAILABLE: ++ complete(&instance->io_cmplt); ++ break; ++ ++ case VCHI_CALLBACK_SERVICE_CLOSED: ++ pr_info("%s: service CLOSED!!", __func__); ++ default: ++ break; ++ } ++} ++ ++struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance, ++ unsigned int num_connections, ++ vpu_event_cb vpu_event) ++{ ++ u32 i; ++ struct sm_instance *instance; ++ int status; ++ ++ pr_debug("%s: start", __func__); ++ ++ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) { ++ pr_err("%s: unsupported number of connections %u (max=%u)", ++ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS); ++ ++ goto err_null; ++ } ++ /* Allocate memory for this instance */ ++ instance = kzalloc(sizeof(*instance), GFP_KERNEL); ++ ++ /* Misc initialisations */ ++ mutex_init(&instance->lock); ++ init_completion(&instance->io_cmplt); ++ INIT_LIST_HEAD(&instance->cmd_list); ++ INIT_LIST_HEAD(&instance->rsp_list); ++ INIT_LIST_HEAD(&instance->dead_list); ++ INIT_LIST_HEAD(&instance->free_list); ++ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS); ++ mutex_init(&instance->free_lock); ++ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) { ++ init_completion(&instance->free_blk[i].cmplt); ++ list_add(&instance->free_blk[i].head, &instance->free_list); ++ } ++ ++ /* Open the VCHI service connections */ ++ instance->num_connections = num_connections; ++ for (i = 0; i < num_connections; i++) { ++ struct service_creation params = { ++ .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER), ++ .service_id = VC_SM_SERVER_NAME, ++ .callback = vc_sm_cma_vchi_callback, ++ .callback_param = instance, ++ }; ++ ++ status = vchi_service_open(vchi_instance, ++ ¶ms, &instance->vchi_handle[i]); ++ if (status) { ++ pr_err("%s: failed to open VCHI service (%d)", ++ __func__, status); ++ ++ goto err_close_services; ++ } ++ } ++ ++ /* Create the thread which takes care of all io to/from videoocore. */ ++ instance->io_thread = kthread_create(&vc_sm_cma_vchi_videocore_io, ++ (void *)instance, "SMIO"); ++ if (!instance->io_thread) { ++ pr_err("%s: failed to create SMIO thread", __func__); ++ ++ goto err_close_services; ++ } ++ instance->vpu_event = vpu_event; ++ set_user_nice(instance->io_thread, -10); ++ wake_up_process(instance->io_thread); ++ ++ pr_debug("%s: success - instance %p", __func__, instance); ++ return instance; ++ ++err_close_services: ++ for (i = 0; i < instance->num_connections; i++) { ++ if (instance->vchi_handle[i]) ++ vchi_service_close(instance->vchi_handle[i]); ++ } ++ kfree(instance); ++err_null: ++ pr_debug("%s: FAILED", __func__); ++ return NULL; ++} ++ ++int vc_sm_cma_vchi_stop(struct sm_instance **handle) ++{ ++ struct sm_instance *instance; ++ u32 i; ++ ++ if (!handle) { ++ pr_err("%s: invalid pointer to handle %p", __func__, handle); ++ goto lock; ++ } ++ ++ if (!*handle) { ++ pr_err("%s: invalid handle %p", __func__, *handle); ++ goto lock; ++ } ++ ++ instance = *handle; ++ ++ /* Close all VCHI service connections */ ++ for (i = 0; i < instance->num_connections; i++) { ++ s32 success; ++ ++ vchi_service_use(instance->vchi_handle[i]); ++ ++ success = vchi_service_close(instance->vchi_handle[i]); ++ } ++ ++ kfree(instance); ++ ++ *handle = NULL; ++ return 0; ++ ++lock: ++ return -EINVAL; ++} ++ ++static int vc_sm_cma_vchi_send_msg(struct sm_instance *handle, ++ enum vc_sm_msg_type msg_id, void *msg, ++ u32 msg_size, void *result, u32 result_size, ++ u32 *cur_trans_id, u8 wait_reply) ++{ ++ int status = 0; ++ struct sm_instance *instance = handle; ++ struct sm_cmd_rsp_blk *cmd_blk; ++ ++ if (!handle) { ++ pr_err("%s: invalid handle", __func__); ++ return -EINVAL; ++ } ++ if (!msg) { ++ pr_err("%s: invalid msg pointer", __func__); ++ return -EINVAL; ++ } ++ ++ cmd_blk = ++ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply); ++ if (!cmd_blk) { ++ pr_err("[%s]: failed to allocate global tracking resource", ++ __func__); ++ return -ENOMEM; ++ } ++ ++ if (cur_trans_id) ++ *cur_trans_id = cmd_blk->id; ++ ++ mutex_lock(&instance->lock); ++ list_add_tail(&cmd_blk->head, &instance->cmd_list); ++ mutex_unlock(&instance->lock); ++ complete(&instance->io_cmplt); ++ ++ if (!wait_reply) ++ /* We're done */ ++ return 0; ++ ++ /* Wait for the response */ ++ if (wait_for_completion_interruptible(&cmd_blk->cmplt)) { ++ mutex_lock(&instance->lock); ++ if (!cmd_blk->sent) { ++ list_del(&cmd_blk->head); ++ mutex_unlock(&instance->lock); ++ vc_vchi_cmd_delete(instance, cmd_blk); ++ return -ENXIO; ++ } ++ ++ list_move(&cmd_blk->head, &instance->dead_list); ++ mutex_unlock(&instance->lock); ++ complete(&instance->io_cmplt); ++ return -EINTR; /* We're done */ ++ } ++ ++ if (result && result_size) { ++ memcpy(result, cmd_blk->msg, result_size); ++ } else { ++ struct vc_sm_result_t *res = ++ (struct vc_sm_result_t *)cmd_blk->msg; ++ status = (res->success == 0) ? 0 : -ENXIO; ++ } ++ ++ mutex_lock(&instance->lock); ++ list_del(&cmd_blk->head); ++ mutex_unlock(&instance->lock); ++ vc_vchi_cmd_delete(instance, cmd_blk); ++ return status; ++} ++ ++int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg, ++ u32 *cur_trans_id) ++{ ++ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_FREE, ++ msg, sizeof(*msg), 0, 0, cur_trans_id, 0); ++} ++ ++int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg, ++ struct vc_sm_import_result *result, u32 *cur_trans_id) ++{ ++ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_IMPORT, ++ msg, sizeof(*msg), result, sizeof(*result), ++ cur_trans_id, 1); ++} ++ ++int vc_sm_cma_vchi_client_version(struct sm_instance *handle, ++ struct vc_sm_version *msg, ++ struct vc_sm_result_t *result, ++ u32 *cur_trans_id) ++{ ++ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_CLIENT_VERSION, ++ //msg, sizeof(*msg), result, sizeof(*result), ++ //cur_trans_id, 1); ++ msg, sizeof(*msg), NULL, 0, ++ cur_trans_id, 0); ++} ++ ++int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle, ++ struct vc_sm_vc_mem_request_result *msg, ++ uint32_t *cur_trans_id) ++{ ++ return vc_sm_cma_vchi_send_msg(handle, ++ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY, ++ msg, sizeof(*msg), 0, 0, cur_trans_id, ++ 0); ++} +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h +@@ -0,0 +1,63 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++/* ++ * VideoCore Shared Memory CMA allocator ++ * ++ * Copyright: 2018, Raspberry Pi (Trading) Ltd ++ * Copyright 2011-2012 Broadcom Corporation. All rights reserved. ++ * ++ * Based on vmcs_sm driver from Broadcom Corporation. ++ * ++ */ ++ ++#ifndef __VC_SM_CMA_VCHI_H__INCLUDED__ ++#define __VC_SM_CMA_VCHI_H__INCLUDED__ ++ ++#include "interface/vchi/vchi.h" ++ ++#include "vc_sm_defs.h" ++ ++/* ++ * Forward declare. ++ */ ++struct sm_instance; ++ ++typedef void (*vpu_event_cb)(struct sm_instance *instance, ++ struct vc_sm_result_t *reply, int reply_len); ++ ++/* ++ * Initialize the shared memory service, opens up vchi connection to talk to it. ++ */ ++struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance, ++ unsigned int num_connections, ++ vpu_event_cb vpu_event); ++ ++/* ++ * Terminates the shared memory service. ++ */ ++int vc_sm_cma_vchi_stop(struct sm_instance **handle); ++ ++/* ++ * Ask the shared memory service to free up some memory that was previously ++ * allocated by the vc_sm_cma_vchi_alloc function call. ++ */ ++int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg, ++ u32 *cur_trans_id); ++ ++/* ++ * Import a contiguous block of memory and wrap it in a GPU MEM_HANDLE_T. ++ */ ++int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg, ++ struct vc_sm_import_result *result, ++ u32 *cur_trans_id); ++ ++int vc_sm_cma_vchi_client_version(struct sm_instance *handle, ++ struct vc_sm_version *msg, ++ struct vc_sm_result_t *result, ++ u32 *cur_trans_id); ++ ++int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle, ++ struct vc_sm_vc_mem_request_result *msg, ++ uint32_t *cur_trans_id); ++ ++#endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */ +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h +@@ -0,0 +1,300 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++/* ++ * VideoCore Shared Memory CMA allocator ++ * ++ * Copyright: 2018, Raspberry Pi (Trading) Ltd ++ * ++ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation. ++ * All IPC messages are copied across to this file, even if the vc-sm-cma ++ * driver is not currently using them. ++ * ++ **************************************************************************** ++ */ ++ ++#ifndef __VC_SM_DEFS_H__INCLUDED__ ++#define __VC_SM_DEFS_H__INCLUDED__ ++ ++/* FourCC code used for VCHI connection */ ++#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM") ++ ++/* Maximum message length */ ++#define VC_SM_MAX_MSG_LEN (sizeof(union vc_sm_msg_union_t) + \ ++ sizeof(struct vc_sm_msg_hdr_t)) ++#define VC_SM_MAX_RSP_LEN (sizeof(union vc_sm_msg_union_t)) ++ ++/* Resource name maximum size */ ++#define VC_SM_RESOURCE_NAME 32 ++ ++/* ++ * Version to be reported to the VPU ++ * VPU assumes 0 (aka 1) which does not require the released callback, nor ++ * expect the client to handle VC_MEM_REQUESTS. ++ * Version 2 requires the released callback, and must support VC_MEM_REQUESTS. ++ */ ++#define VC_SM_PROTOCOL_VERSION 2 ++ ++enum vc_sm_msg_type { ++ /* Message types supported for HOST->VC direction */ ++ ++ /* Allocate shared memory block */ ++ VC_SM_MSG_TYPE_ALLOC, ++ /* Lock allocated shared memory block */ ++ VC_SM_MSG_TYPE_LOCK, ++ /* Unlock allocated shared memory block */ ++ VC_SM_MSG_TYPE_UNLOCK, ++ /* Unlock allocated shared memory block, do not answer command */ ++ VC_SM_MSG_TYPE_UNLOCK_NOANS, ++ /* Free shared memory block */ ++ VC_SM_MSG_TYPE_FREE, ++ /* Resize a shared memory block */ ++ VC_SM_MSG_TYPE_RESIZE, ++ /* Walk the allocated shared memory block(s) */ ++ VC_SM_MSG_TYPE_WALK_ALLOC, ++ ++ /* A previously applied action will need to be reverted */ ++ VC_SM_MSG_TYPE_ACTION_CLEAN, ++ ++ /* ++ * Import a physical address and wrap into a MEM_HANDLE_T. ++ * Release with VC_SM_MSG_TYPE_FREE. ++ */ ++ VC_SM_MSG_TYPE_IMPORT, ++ /* ++ *Tells VC the protocol version supported by this client. ++ * 2 supports the async/cmd messages from the VPU for final release ++ * of memory, and for VC allocations. ++ */ ++ VC_SM_MSG_TYPE_CLIENT_VERSION, ++ /* Response to VC request for memory */ ++ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY, ++ ++ /* ++ * Asynchronous/cmd messages supported for VC->HOST direction. ++ * Signalled by setting the top bit in vc_sm_result_t trans_id. ++ */ ++ ++ /* ++ * VC has finished with an imported memory allocation. ++ * Release any Linux reference counts on the underlying block. ++ */ ++ VC_SM_MSG_TYPE_RELEASED, ++ /* VC request for memory */ ++ VC_SM_MSG_TYPE_VC_MEM_REQUEST, ++ ++ VC_SM_MSG_TYPE_MAX ++}; ++ ++/* Type of memory to be allocated */ ++enum vc_sm_alloc_type_t { ++ VC_SM_ALLOC_CACHED, ++ VC_SM_ALLOC_NON_CACHED, ++}; ++ ++/* Message header for all messages in HOST->VC direction */ ++struct vc_sm_msg_hdr_t { ++ u32 type; ++ u32 trans_id; ++ u8 body[0]; ++ ++}; ++ ++/* Request to allocate memory (HOST->VC) */ ++struct vc_sm_alloc_t { ++ /* type of memory to allocate */ ++ enum vc_sm_alloc_type_t type; ++ /* byte amount of data to allocate per unit */ ++ u32 base_unit; ++ /* number of unit to allocate */ ++ u32 num_unit; ++ /* alignment to be applied on allocation */ ++ u32 alignment; ++ /* identity of who allocated this block */ ++ u32 allocator; ++ /* resource name (for easier tracking on vc side) */ ++ char name[VC_SM_RESOURCE_NAME]; ++ ++}; ++ ++/* Result of a requested memory allocation (VC->HOST) */ ++struct vc_sm_alloc_result_t { ++ /* Transaction identifier */ ++ u32 trans_id; ++ ++ /* Resource handle */ ++ u32 res_handle; ++ /* Pointer to resource buffer */ ++ u32 res_mem; ++ /* Resource base size (bytes) */ ++ u32 res_base_size; ++ /* Resource number */ ++ u32 res_num; ++ ++}; ++ ++/* Request to free a previously allocated memory (HOST->VC) */ ++struct vc_sm_free_t { ++ /* Resource handle (returned from alloc) */ ++ u32 res_handle; ++ /* Resource buffer (returned from alloc) */ ++ u32 res_mem; ++ ++}; ++ ++/* Request to lock a previously allocated memory (HOST->VC) */ ++struct vc_sm_lock_unlock_t { ++ /* Resource handle (returned from alloc) */ ++ u32 res_handle; ++ /* Resource buffer (returned from alloc) */ ++ u32 res_mem; ++ ++}; ++ ++/* Request to resize a previously allocated memory (HOST->VC) */ ++struct vc_sm_resize_t { ++ /* Resource handle (returned from alloc) */ ++ u32 res_handle; ++ /* Resource buffer (returned from alloc) */ ++ u32 res_mem; ++ /* Resource *new* size requested (bytes) */ ++ u32 res_new_size; ++ ++}; ++ ++/* Result of a requested memory lock (VC->HOST) */ ++struct vc_sm_lock_result_t { ++ /* Transaction identifier */ ++ u32 trans_id; ++ ++ /* Resource handle */ ++ u32 res_handle; ++ /* Pointer to resource buffer */ ++ u32 res_mem; ++ /* ++ * Pointer to former resource buffer if the memory ++ * was reallocated ++ */ ++ u32 res_old_mem; ++ ++}; ++ ++/* Generic result for a request (VC->HOST) */ ++struct vc_sm_result_t { ++ /* Transaction identifier */ ++ u32 trans_id; ++ ++ s32 success; ++ ++}; ++ ++/* Request to revert a previously applied action (HOST->VC) */ ++struct vc_sm_action_clean_t { ++ /* Action of interest */ ++ enum vc_sm_msg_type res_action; ++ /* Transaction identifier for the action of interest */ ++ u32 action_trans_id; ++ ++}; ++ ++/* Request to remove all data associated with a given allocator (HOST->VC) */ ++struct vc_sm_free_all_t { ++ /* Allocator identifier */ ++ u32 allocator; ++}; ++ ++/* Request to import memory (HOST->VC) */ ++struct vc_sm_import { ++ /* type of memory to allocate */ ++ enum vc_sm_alloc_type_t type; ++ /* pointer to the VC (ie physical) address of the allocated memory */ ++ u32 addr; ++ /* size of buffer */ ++ u32 size; ++ /* opaque handle returned in RELEASED messages */ ++ u32 kernel_id; ++ /* Allocator identifier */ ++ u32 allocator; ++ /* resource name (for easier tracking on vc side) */ ++ char name[VC_SM_RESOURCE_NAME]; ++}; ++ ++/* Result of a requested memory import (VC->HOST) */ ++struct vc_sm_import_result { ++ /* Transaction identifier */ ++ u32 trans_id; ++ ++ /* Resource handle */ ++ u32 res_handle; ++}; ++ ++/* Notification that VC has finished with an allocation (VC->HOST) */ ++struct vc_sm_released { ++ /* cmd type / trans_id */ ++ u32 cmd; ++ ++ /* pointer to the VC (ie physical) address of the allocated memory */ ++ u32 addr; ++ /* size of buffer */ ++ u32 size; ++ /* opaque handle returned in RELEASED messages */ ++ u32 kernel_id; ++ u32 vc_handle; ++}; ++ ++/* ++ * Client informing VC as to the protocol version it supports. ++ * >=2 requires the released callback, and supports VC asking for memory. ++ * Failure means that the firmware doesn't support this call, and therefore the ++ * client should either fail, or NOT rely on getting the released callback. ++ */ ++struct vc_sm_version { ++ u32 version; ++}; ++ ++/* Request FROM VideoCore for some memory */ ++struct vc_sm_vc_mem_request { ++ /* cmd type */ ++ u32 cmd; ++ ++ /* trans_id (from VPU) */ ++ u32 trans_id; ++ /* size of buffer */ ++ u32 size; ++ /* alignment of buffer */ ++ u32 align; ++ /* resource name (for easier tracking) */ ++ char name[VC_SM_RESOURCE_NAME]; ++ /* VPU handle for the resource */ ++ u32 vc_handle; ++}; ++ ++/* Response from the kernel to provide the VPU with some memory */ ++struct vc_sm_vc_mem_request_result { ++ /* Transaction identifier for the VPU */ ++ u32 trans_id; ++ /* pointer to the physical address of the allocated memory */ ++ u32 addr; ++ /* opaque handle returned in RELEASED messages */ ++ u32 kernel_id; ++}; ++ ++/* Union of ALL messages */ ++union vc_sm_msg_union_t { ++ struct vc_sm_alloc_t alloc; ++ struct vc_sm_alloc_result_t alloc_result; ++ struct vc_sm_free_t free; ++ struct vc_sm_lock_unlock_t lock_unlock; ++ struct vc_sm_action_clean_t action_clean; ++ struct vc_sm_resize_t resize; ++ struct vc_sm_lock_result_t lock_result; ++ struct vc_sm_result_t result; ++ struct vc_sm_free_all_t free_all; ++ struct vc_sm_import import; ++ struct vc_sm_import_result import_result; ++ struct vc_sm_version version; ++ struct vc_sm_released released; ++ struct vc_sm_vc_mem_request vc_request; ++ struct vc_sm_vc_mem_request_result vc_request_result; ++}; ++ ++#endif /* __VC_SM_DEFS_H__INCLUDED__ */ +--- /dev/null ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++/* ++ * VideoCore Shared Memory CMA allocator ++ * ++ * Copyright: 2018, Raspberry Pi (Trading) Ltd ++ * ++ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation. ++ * ++ */ ++ ++#ifndef __VC_SM_KNL_H__INCLUDED__ ++#define __VC_SM_KNL_H__INCLUDED__ ++ ++#if !defined(__KERNEL__) ++#error "This interface is for kernel use only..." ++#endif ++ ++/* Free a previously allocated or imported shared memory handle and block. */ ++int vc_sm_cma_free(void *handle); ++ ++/* Get an internal resource handle mapped from the external one. */ ++int vc_sm_cma_int_handle(void *handle); ++ ++/* Import a block of memory into the GPU space. */ ++int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, void **handle); ++ ++#endif /* __VC_SM_KNL_H__INCLUDED__ */ +--- a/drivers/staging/vc04_services/vchiq-mmal/Makefile ++++ b/drivers/staging/vc04_services/vchiq-mmal/Makefile +@@ -4,5 +4,5 @@ bcm2835-mmal-vchiq-objs := mmal-vchiq.o + obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += bcm2835-mmal-vchiq.o + + ccflags-y += \ +- -Idrivers/staging/vc04_services \ ++ -I$(srctree)/drivers/staging/vc04_services \ + -D__VCCOREVER__=0x04000000 +--- /dev/null ++++ b/include/linux/broadcom/vc_sm_cma_ioctl.h +@@ -0,0 +1,114 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++/* ++ * Copyright 2019 Raspberry Pi (Trading) Ltd. All rights reserved. ++ * ++ * Based on vmcs_sm_ioctl.h Copyright Broadcom Corporation. ++ */ ++ ++#ifndef __VC_SM_CMA_IOCTL_H ++#define __VC_SM_CMA_IOCTL_H ++ ++/* ---- Include Files ---------------------------------------------------- */ ++ ++#if defined(__KERNEL__) ++#include /* Needed for standard types */ ++#else ++#include ++#endif ++ ++#include ++ ++/* ---- Constants and Types ---------------------------------------------- */ ++ ++#define VC_SM_CMA_RESOURCE_NAME 32 ++#define VC_SM_CMA_RESOURCE_NAME_DEFAULT "sm-host-resource" ++ ++/* Type define used to create unique IOCTL number */ ++#define VC_SM_CMA_MAGIC_TYPE 'J' ++ ++/* IOCTL commands on /dev/vc-sm-cma */ ++enum vc_sm_cma_cmd_e { ++ VC_SM_CMA_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */ ++ ++ VC_SM_CMA_CMD_IMPORT_DMABUF, ++ ++ VC_SM_CMA_CMD_CLEAN_INVALID2, ++ ++ VC_SM_CMA_CMD_LAST /* Do not delete */ ++}; ++ ++/* Cache type supported, conveniently matches the user space definition in ++ * user-vcsm.h. ++ */ ++enum vc_sm_cma_cache_e { ++ VC_SM_CMA_CACHE_NONE, ++ VC_SM_CMA_CACHE_HOST, ++ VC_SM_CMA_CACHE_VC, ++ VC_SM_CMA_CACHE_BOTH, ++}; ++ ++/* IOCTL Data structures */ ++struct vc_sm_cma_ioctl_alloc { ++ /* user -> kernel */ ++ __u32 size; ++ __u32 num; ++ __u32 cached; /* enum vc_sm_cma_cache_e */ ++ __u32 pad; ++ __u8 name[VC_SM_CMA_RESOURCE_NAME]; ++ ++ /* kernel -> user */ ++ __s32 handle; ++ __u32 vc_handle; ++ __u64 dma_addr; ++}; ++ ++struct vc_sm_cma_ioctl_import_dmabuf { ++ /* user -> kernel */ ++ __s32 dmabuf_fd; ++ __u32 cached; /* enum vc_sm_cma_cache_e */ ++ __u8 name[VC_SM_CMA_RESOURCE_NAME]; ++ ++ /* kernel -> user */ ++ __s32 handle; ++ __u32 vc_handle; ++ __u32 size; ++ __u32 pad; ++ __u64 dma_addr; ++}; ++ ++/* ++ * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2 ++ * invalidate_mode. ++ */ ++#define VC_SM_CACHE_OP_NOP 0x00 ++#define VC_SM_CACHE_OP_INV 0x01 ++#define VC_SM_CACHE_OP_CLEAN 0x02 ++#define VC_SM_CACHE_OP_FLUSH 0x03 ++ ++struct vc_sm_cma_ioctl_clean_invalid2 { ++ __u32 op_count; ++ __u32 pad; ++ struct vc_sm_cma_ioctl_clean_invalid_block { ++ __u32 invalidate_mode; ++ __u32 block_count; ++ void * __user start_address; ++ __u32 block_size; ++ __u32 inter_block_stride; ++ } s[0]; ++}; ++ ++/* IOCTL numbers */ ++#define VC_SM_CMA_IOCTL_MEM_ALLOC\ ++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\ ++ struct vc_sm_cma_ioctl_alloc) ++ ++#define VC_SM_CMA_IOCTL_MEM_IMPORT_DMABUF\ ++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\ ++ struct vc_sm_cma_ioctl_import_dmabuf) ++ ++#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\ ++ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\ ++ struct vc_sm_cma_ioctl_clean_invalid2) ++ ++#endif /* __VC_SM_CMA_IOCTL_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0172-staging-vc04_services-Support-sending-data-to-MMAL-p.patch b/target/linux/bcm27xx/patches-5.4/950-0172-staging-vc04_services-Support-sending-data-to-MMAL-p.patch deleted file mode 100644 index 5dec3c4127..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0172-staging-vc04_services-Support-sending-data-to-MMAL-p.patch +++ /dev/null @@ -1,42 +0,0 @@ -From f3f0945b19a90b194b2886a4fe5b092b4a3f7b3b Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 24 Sep 2018 18:26:02 +0100 -Subject: [PATCH] staging: vc04_services: Support sending data to MMAL - ports - -Add the ability to send data to ports. This only supports -zero copy mode as the required bulk transfer setup calls -are not done. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 18 +++++++++++++----- - 1 file changed, 13 insertions(+), 5 deletions(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -427,11 +427,19 @@ buffer_from_host(struct vchiq_mmal_insta - m.u.buffer_from_host.buffer_header.data = - (u32)(unsigned long)buf->buffer; - m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; -- m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */ -- m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */ -- m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */ -- m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; -- m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; -+ if (port->type == MMAL_PORT_TYPE_OUTPUT) { -+ m.u.buffer_from_host.buffer_header.length = 0; -+ m.u.buffer_from_host.buffer_header.offset = 0; -+ m.u.buffer_from_host.buffer_header.flags = 0; -+ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN; -+ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN; -+ } else { -+ m.u.buffer_from_host.buffer_header.length = buf->length; -+ m.u.buffer_from_host.buffer_header.offset = 0; -+ m.u.buffer_from_host.buffer_header.flags = buf->mmal_flags; -+ m.u.buffer_from_host.buffer_header.pts = buf->pts; -+ m.u.buffer_from_host.buffer_header.dts = buf->dts; -+ } - - /* clear buffer type sepecific data */ - memset(&m.u.buffer_from_host.buffer_header_type_specific, 0, diff --git a/target/linux/bcm27xx/patches-5.4/950-0173-staging-vc04_services-Fixup-vchiq-mmal-include-order.patch b/target/linux/bcm27xx/patches-5.4/950-0173-staging-vc04_services-Fixup-vchiq-mmal-include-order.patch deleted file mode 100644 index 7dd50f75bf..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0173-staging-vc04_services-Fixup-vchiq-mmal-include-order.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0932bf176e846b6c7666671670b017fcd7e915e8 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 25 Sep 2018 16:57:40 +0100 -Subject: [PATCH] staging: vc04_services: Fixup vchiq-mmal include - ordering - -There were dependencies on including the headers in the correct -order. Fix up the headers so that they include the other -headers that they depend on themselves. - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h | 1 + - drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + - 2 files changed, 2 insertions(+) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-msg.h -@@ -38,6 +38,7 @@ - #include "mmal-msg-common.h" - #include "mmal-msg-format.h" - #include "mmal-msg-port.h" -+#include "mmal-vchiq.h" - - enum mmal_msg_type { - MMAL_MSG_TYPE_QUIT = 1, ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -16,6 +16,7 @@ - #ifndef MMAL_VCHIQ_H - #define MMAL_VCHIQ_H - -+#include "mmal-common.h" - #include "mmal-msg-format.h" - - #define MAX_PORT_COUNT 4 diff --git a/target/linux/bcm27xx/patches-5.4/950-0173-staging-vc04_services-Use-vc-sm-cma-to-support-zero-.patch b/target/linux/bcm27xx/patches-5.4/950-0173-staging-vc04_services-Use-vc-sm-cma-to-support-zero-.patch new file mode 100644 index 0000000000..62cce8a94e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0173-staging-vc04_services-Use-vc-sm-cma-to-support-zero-.patch @@ -0,0 +1,177 @@ +From 511b809d5b227b179acca537cba85e2bdff87b94 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 25 Sep 2018 16:07:55 +0100 +Subject: [PATCH] staging: vc04_services: Use vc-sm-cma to support zero + copy + +With the vc-sm-cma driver we can support zero copy of buffers between +the kernel and VPU. Add this support to vchiq-mmal. + +Signed-off-by: Dave Stevenson + +staging: vc-sm-cma: Use a void* pointer as the handle within the kernel + +The driver was using an unsigned int as the handle to the outside world, +and doing a nasty cast to the struct dmabuf when handed it back. +This breaks badly with a 64 bit kernel where the pointer doesn't fit +in an unsigned int. + +Switch to using a void* within the kernel. Reality is that it is +a struct dma_buf*, but advertising it as such to other drivers seems +to encourage the use of it as such, and I'm not sure on the implications +of that. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/vchiq-mmal/Kconfig | 1 + + .../vc04_services/vchiq-mmal/mmal-common.h | 4 ++ + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 66 ++++++++++++++++++- + .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + + 4 files changed, 70 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/Kconfig ++++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig +@@ -2,6 +2,7 @@ config BCM2835_VCHIQ_MMAL + tristate "BCM2835 MMAL VCHIQ service" + depends on (ARCH_BCM2835 || COMPILE_TEST) + select BCM2835_VCHIQ ++ select BCM_VC_SM_CMA + help + Enables the MMAL API over VCHIQ as used for the + majority of the multimedia services on VideoCore. +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h +@@ -50,6 +50,10 @@ struct mmal_buffer { + + struct mmal_msg_context *msg_context; + ++ struct dma_buf *dma_buf;/* Exported dmabuf fd from videobuf2 */ ++ void *vcsm_handle; /* VCSM handle having imported the dmabuf */ ++ u32 vc_handle; /* VC handle to that dmabuf */ ++ + u32 cmd; /* MMAL command. 0=data. */ + unsigned long length; + u32 mmal_flags; +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -26,9 +26,12 @@ + #include + + #include "mmal-common.h" ++#include "mmal-parameters.h" + #include "mmal-vchiq.h" + #include "mmal-msg.h" + ++#include "vc-sm-cma/vc_sm_knl.h" ++ + #define USE_VCHIQ_ARM + #include "interface/vchi/vchi.h" + +@@ -424,8 +427,13 @@ buffer_from_host(struct vchiq_mmal_insta + + /* buffer header */ + m.u.buffer_from_host.buffer_header.cmd = 0; +- m.u.buffer_from_host.buffer_header.data = +- (u32)(unsigned long)buf->buffer; ++ if (port->zero_copy) { ++ m.u.buffer_from_host.buffer_header.data = buf->vc_handle; ++ } else { ++ m.u.buffer_from_host.buffer_header.data = ++ (u32)(unsigned long)buf->buffer; ++ } ++ + m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; + if (port->type == MMAL_PORT_TYPE_OUTPUT) { + m.u.buffer_from_host.buffer_header.length = 0; +@@ -590,6 +598,22 @@ static void buffer_to_host_cb(struct vch + + msg_context->u.bulk.status = msg->h.status; + ++ } else if (msg->u.buffer_from_host.is_zero_copy) { ++ /* ++ * Zero copy buffer, so nothing to do. ++ * Copy buffer info and make callback. ++ */ ++ msg_context->u.bulk.buffer_used = ++ msg->u.buffer_from_host.buffer_header.length; ++ msg_context->u.bulk.mmal_flags = ++ msg->u.buffer_from_host.buffer_header.flags; ++ msg_context->u.bulk.dts = ++ msg->u.buffer_from_host.buffer_header.dts; ++ msg_context->u.bulk.pts = ++ msg->u.buffer_from_host.buffer_header.pts; ++ msg_context->u.bulk.cmd = ++ msg->u.buffer_from_host.buffer_header.cmd; ++ + } else if (msg->u.buffer_from_host.buffer_header.length == 0) { + /* empty buffer */ + if (msg->u.buffer_from_host.buffer_header.flags & +@@ -1537,6 +1561,9 @@ int vchiq_mmal_port_parameter_set(struct + + mutex_unlock(&instance->vchiq_mutex); + ++ if (parameter == MMAL_PARAMETER_ZERO_COPY && !ret) ++ port->zero_copy = !!(*(bool *)value); ++ + return ret; + } + EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set); +@@ -1705,6 +1732,31 @@ int vchiq_mmal_submit_buffer(struct vchi + unsigned long flags = 0; + int ret; + ++ /* ++ * We really want to do this in mmal_vchi_buffer_init but can't as ++ * videobuf2 won't let us have the dmabuf there. ++ */ ++ if (port->zero_copy && buffer->dma_buf && !buffer->vcsm_handle) { ++ pr_debug("%s: import dmabuf %p\n", __func__, buffer->dma_buf); ++ ret = vc_sm_cma_import_dmabuf(buffer->dma_buf, ++ &buffer->vcsm_handle); ++ if (ret) { ++ pr_err("%s: vc_sm_import_dmabuf_fd failed, ret %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ buffer->vc_handle = vc_sm_cma_int_handle(buffer->vcsm_handle); ++ if (!buffer->vc_handle) { ++ pr_err("%s: vc_sm_int_handle failed %d\n", ++ __func__, ret); ++ vc_sm_cma_free(buffer->vcsm_handle); ++ return ret; ++ } ++ pr_debug("%s: import dmabuf %p - got vc handle %08X\n", ++ __func__, buffer->dma_buf, buffer->vc_handle); ++ } ++ + ret = buffer_from_host(instance, port, buffer); + if (ret == -EINVAL) { + /* Port is disabled. Queue for when it is enabled. */ +@@ -1738,6 +1790,16 @@ int mmal_vchi_buffer_cleanup(struct mmal + release_msg_context(msg_context); + buf->msg_context = NULL; + ++ if (buf->vcsm_handle) { ++ int ret; ++ ++ pr_debug("%s: vc_sm_cma_free on handle %p\n", __func__, ++ buf->vcsm_handle); ++ ret = vc_sm_cma_free(buf->vcsm_handle); ++ if (ret) ++ pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret); ++ buf->vcsm_handle = 0; ++ } + return 0; + } + EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -49,6 +49,7 @@ typedef void (*vchiq_mmal_buffer_cb)( + + struct vchiq_mmal_port { + u32 enabled:1; ++ u32 zero_copy:1; + u32 handle; + u32 type; /* port type, cached to use on port info set */ + u32 index; /* port index, cached to use on port info set */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0174-media-videobuf2-Allow-exporting-of-a-struct-dmabuf.patch b/target/linux/bcm27xx/patches-5.4/950-0174-media-videobuf2-Allow-exporting-of-a-struct-dmabuf.patch new file mode 100644 index 0000000000..74d03540ad --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0174-media-videobuf2-Allow-exporting-of-a-struct-dmabuf.patch @@ -0,0 +1,83 @@ +From 74ac8bd3b5c6ed23308341fa41681db6a3b45c46 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 29 Oct 2018 17:57:45 +0000 +Subject: [PATCH] media: videobuf2: Allow exporting of a struct dmabuf + +videobuf2 only allowed exporting a dmabuf as a file descriptor, +but there are instances where having the struct dma_buf is +useful within the kernel. + +Split the current implementation into two, one step which +exports a struct dma_buf, and the second which converts that +into an fd. + +Signed-off-by: Dave Stevenson +--- + .../media/common/videobuf2/videobuf2-core.c | 21 ++++++++++++++++--- + include/media/videobuf2-core.h | 15 +++++++++++++ + 2 files changed, 33 insertions(+), 3 deletions(-) + +--- a/drivers/media/common/videobuf2/videobuf2-core.c ++++ b/drivers/media/common/videobuf2/videobuf2-core.c +@@ -2073,12 +2073,12 @@ static int __find_plane_by_offset(struct + return -EINVAL; + } + +-int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, +- unsigned int index, unsigned int plane, unsigned int flags) ++int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type, ++ unsigned int index, unsigned int plane, ++ unsigned int flags, struct dma_buf **dmabuf) + { + struct vb2_buffer *vb = NULL; + struct vb2_plane *vb_plane; +- int ret; + struct dma_buf *dbuf; + + if (q->memory != VB2_MEMORY_MMAP) { +@@ -2128,6 +2128,21 @@ int vb2_core_expbuf(struct vb2_queue *q, + return -EINVAL; + } + ++ *dmabuf = dbuf; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(vb2_core_expbuf_dmabuf); ++ ++int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, ++ unsigned int index, unsigned int plane, unsigned int flags) ++{ ++ struct dma_buf *dbuf; ++ int ret; ++ ++ ret = vb2_core_expbuf_dmabuf(q, type, index, plane, flags, &dbuf); ++ if (ret) ++ return ret; ++ + ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE); + if (ret < 0) { + dprintk(3, "buffer %d, plane %d failed to export (%d)\n", +--- a/include/media/videobuf2-core.h ++++ b/include/media/videobuf2-core.h +@@ -870,6 +870,21 @@ int vb2_core_streamon(struct vb2_queue * + int vb2_core_streamoff(struct vb2_queue *q, unsigned int type); + + /** ++ * vb2_core_expbuf_dmabuf() - Export a buffer as a dma_buf structure ++ * @q: videobuf2 queue ++ * @type: buffer type ++ * @index: id number of the buffer ++ * @plane: index of the plane to be exported, 0 for single plane queues ++ * @flags: flags for newly created file, currently only O_CLOEXEC is ++ * supported, refer to manual of open syscall for more details ++ * @dmabuf: Returns the dmabuf pointer ++ * ++ */ ++int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type, ++ unsigned int index, unsigned int plane, ++ unsigned int flags, struct dma_buf **dmabuf); ++ ++/** + * vb2_core_expbuf() - Export a buffer as a file descriptor. + * @q: pointer to &struct vb2_queue with videobuf2 queue. + * @fd: pointer to the file descriptor associated with DMABUF diff --git a/target/linux/bcm27xx/patches-5.4/950-0174-staging-vc04_services-Add-new-vc-sm-cma-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0174-staging-vc04_services-Add-new-vc-sm-cma-driver.patch deleted file mode 100644 index d1d3df0890..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0174-staging-vc04_services-Add-new-vc-sm-cma-driver.patch +++ /dev/null @@ -1,3175 +0,0 @@ -From 878c0bfd0c5f2dc0ef04874b1cba915cf208ca8f Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 25 Sep 2018 10:27:11 +0100 -Subject: [PATCH] staging: vc04_services: Add new vc-sm-cma driver -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This new driver allows contiguous memory blocks to be imported -into the VideoCore VPU memory map, and manages the lifetime of -those objects, only releasing the source dmabuf once the VPU has -confirmed it has finished with it. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Correct DMA configuration. - -Now that VCHIQ is setting up the DMA configuration as our -parent device, don't try to configure it during probe. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Use a void* pointer as the handle within the kernel - -The driver was using an unsigned int as the handle to the outside world, -and doing a nasty cast to the struct dmabuf when handed it back. -This breaks badly with a 64 bit kernel where the pointer doesn't fit -in an unsigned int. - -Switch to using a void* within the kernel. Reality is that it is -a struct dma_buf*, but advertising it as such to other drivers seems -to encourage the use of it as such, and I'm not sure on the implications -of that. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Fix up for 64bit builds - -There were a number of logging lines that were using -inappropriate formatting under 64bit kernels. - -The kernel_id field passed to/from the VPU was being -abused for storing the struct vc_sm_buffer *. -This breaks with 64bit kernels, so change to using an IDR. - -Signed-off-by: Dave Stevenson - -staging: vc_sm_cma: Remove erroneous misc_deregister - -Code from the misc /dev node was still present in -bcm2835_vc_sm_cma_remove, which caused a NULL deref. -Remove it. - -See #2885. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Remove the debugfs directory on remove - -Without removing that, reloading the driver fails. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Use devm_ allocs for sm_state. - -Use managed allocations for sm_state, removing reliance on -manual management. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Don't fail if debugfs calls fail. - -Return codes from debugfs calls should never alter the -flow of the main code. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Ensure mutex and idr are destroyed - -map_lock and kernelid_map are created in probe, but not released -in release should the vcsm service not connect (eg running the -cutdown firmware). - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Remove obsolete comment and make function static - -Removes obsolete comment about wanting to pass a function -pointer into mmal-vchiq as we now do. -As the function is passed as a function pointer, the function itself -can be static. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Add in allocation for VPU requests. - -Module has to change from tristate to bool as all CMA functions -are boolean. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Update TODO. - -The driver is already a platform driver, so that can be -deleted from the TODO. -There are no known issues that need to be resolved. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Add in userspace allocation API - -Replacing the functionality from the older vc-sm driver, -add in a userspace API that allows allocation of buffers, -and importing of dma-bufs. -The driver hands out dma-buf fds, therefore much of the -handling around lifespan and odd mmaps from the old driver -goes away. - -Signed-off-by: Dave Stevenson - -staging: vcsm-cma: Add cache control ioctls - -The old driver allowed for direct cache manipulation and that -was used by various clients. Replicate here. - -Signed-off-by: Dave Stevenson - -staging: vcsm-cma: Alter dev node permissions to 0666 - -Until the udev rules are updated, open up access to this node by -default. - -Signed-off-by: Dave Stevenson - -staging: vcsm-cma: Drop logging level on messages in vc_sm_release_resource - -They weren't errors but were logged as such. - -Signed-off-by: Dave Stevenson - -staging: vcsm-cma: Fixup the alloc code handling of kernel_id - -The allocation code had been copied in from an old branch prior -to having added the IDR for 64bit support. It was therefore pushing -a pointer into the kernel_id field instead of an IDR handle, the -lookup therefore failed, and we never released the buffer. - -Signed-off-by: Dave Stevenson - -staging: vcsm-cma: Remove cache manipulation ioctl from ARM64 - -The cache flushing ioctls are used by the Pi3 HEVC hw-assisted -decoder as it needs finer grained flushing control than dma_ops -allow. -These cache calls are not present for ARM64, therefore disable -them. We are not actively supporting 64bit kernels at present, -and the use case of the HEVC decoder is fairly limited. - -Signed-off-by: Dave Stevenson - -staging: vcsm-cma: Rework to use dma APIs, not CMA - -Due to a misunderstanding of the DMA mapping APIs, I made -the wrong decision on how to implement this. - -Rework to use dma_alloc_coherent instead of the CMA -API. This also allows it to be built as a module easily. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Fix the few remaining coding style issues - -Fix a few minor checkpatch complaints to make the driver clean - -Signed-off-by: Dave Stevenson - -staging: vc04_services: fix compiling in separate directory - -The vc04_services Makefiles do not respect the O=path argument -correctly: include paths in CFLAGS are given relatively to object path, -not source path. Compiling in a separate directory yields #include -errors. - -Signed-off-by: Marek Behún - -vc-sm-cma: Fix compatibility ioctl - -This code path hasn't been used previously. -Fixed up after testing with kodi on 32-bit userland and 64-bit kernel - -Signed-off-by: popcornmix ---- - drivers/staging/vc04_services/Kconfig | 1 + - drivers/staging/vc04_services/Makefile | 1 + - .../vc04_services/bcm2835-camera/Makefile | 4 +- - .../staging/vc04_services/vc-sm-cma/Kconfig | 10 + - .../staging/vc04_services/vc-sm-cma/Makefile | 8 + - drivers/staging/vc04_services/vc-sm-cma/TODO | 1 + - .../staging/vc04_services/vc-sm-cma/vc_sm.c | 1774 +++++++++++++++++ - .../staging/vc04_services/vc-sm-cma/vc_sm.h | 84 + - .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 505 +++++ - .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 63 + - .../vc04_services/vc-sm-cma/vc_sm_defs.h | 300 +++ - .../vc04_services/vc-sm-cma/vc_sm_knl.h | 28 + - .../staging/vc04_services/vchiq-mmal/Makefile | 2 +- - include/linux/broadcom/vc_sm_cma_ioctl.h | 114 ++ - 14 files changed, 2892 insertions(+), 3 deletions(-) - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Kconfig - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Makefile - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/TODO - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.c - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.h - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h - create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h - create mode 100644 include/linux/broadcom/vc_sm_cma_ioctl.h - ---- a/drivers/staging/vc04_services/Kconfig -+++ b/drivers/staging/vc04_services/Kconfig -@@ -23,6 +23,7 @@ source "drivers/staging/vc04_services/bc - - source "drivers/staging/vc04_services/bcm2835-camera/Kconfig" - source "drivers/staging/vc04_services/vchiq-mmal/Kconfig" -+source "drivers/staging/vc04_services/vc-sm-cma/Kconfig" - - endif - ---- a/drivers/staging/vc04_services/Makefile -+++ b/drivers/staging/vc04_services/Makefile -@@ -13,6 +13,7 @@ vchiq-objs := \ - obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ - obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ - obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ -+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/ - - ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000 - ---- a/drivers/staging/vc04_services/bcm2835-camera/Makefile -+++ b/drivers/staging/vc04_services/bcm2835-camera/Makefile -@@ -7,6 +7,6 @@ obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v - - ccflags-y += \ - -I $(srctree)/$(src)/.. \ -- -Idrivers/staging/vc04_services \ -- -Idrivers/staging/vc04_services/vchiq-mmal \ -+ -I$(srctree)/drivers/staging/vc04_services \ -+ -I$(srctree)/drivers/staging/vc04_services/vchiq-mmal \ - -D__VCCOREVER__=0x04000000 ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig -@@ -0,0 +1,10 @@ -+config BCM_VC_SM_CMA -+ tristate "VideoCore Shared Memory (CMA) driver" -+ depends on BCM2835_VCHIQ -+ select RBTREE -+ select DMA_SHARED_BUFFER -+ help -+ Say Y here to enable the shared memory interface that -+ supports sharing dmabufs with VideoCore. -+ This operates over the VCHIQ interface to a service -+ running on VideoCore. ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile -@@ -0,0 +1,8 @@ -+ccflags-y += -I$(srctree)/drivers/staging/vc04_services -I$(srctree)/drivers/staging/vc04_services/interface/vchi -I$(srctree)/drivers/staging/vc04_services/interface/vchiq_arm -+# -I"drivers/staging/android/ion/" -I"$(srctree)/fs/" -+ccflags-y += -D__VCCOREVER__=0 -+ -+vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \ -+ vc_sm.o vc_sm_cma_vchi.o -+ -+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/TODO -@@ -0,0 +1 @@ -+No currently outstanding tasks except some clean-up. ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c -@@ -0,0 +1,1774 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * VideoCore Shared Memory driver using CMA. -+ * -+ * Copyright: 2018, Raspberry Pi (Trading) Ltd -+ * Dave Stevenson -+ * -+ * Based on vmcs_sm driver from Broadcom Corporation for some API, -+ * and taking some code for buffer allocation and dmabuf handling from -+ * videobuf2. -+ * -+ * -+ * This driver has 3 main uses: -+ * 1) Allocating buffers for the kernel or userspace that can be shared with the -+ * VPU. -+ * 2) Importing dmabufs from elsewhere for sharing with the VPU. -+ * 3) Allocating buffers for use by the VPU. -+ * -+ * In the first and second cases the native handle is a dmabuf. Releasing the -+ * resource inherently comes from releasing the dmabuf, and this will trigger -+ * unmapping on the VPU. The underlying allocation and our buffer structure are -+ * retained until the VPU has confirmed that it has finished with it. -+ * -+ * For the VPU allocations the VPU is responsible for triggering the release, -+ * and therefore the released message decrements the dma_buf refcount (with the -+ * VPU mapping having already been marked as released). -+ */ -+ -+/* ---- Include Files ----------------------------------------------------- */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "vchiq_connected.h" -+#include "vc_sm_cma_vchi.h" -+ -+#include "vc_sm.h" -+#include "vc_sm_knl.h" -+#include -+ -+/* ---- Private Constants and Types --------------------------------------- */ -+ -+#define DEVICE_NAME "vcsm-cma" -+#define DEVICE_MINOR 0 -+ -+#define VC_SM_RESOURCE_NAME_DEFAULT "sm-host-resource" -+ -+#define VC_SM_DIR_ROOT_NAME "vcsm-cma" -+#define VC_SM_STATE "state" -+ -+/* Private file data associated with each opened device. */ -+struct vc_sm_privdata_t { -+ pid_t pid; /* PID of creator. */ -+ -+ int restart_sys; /* Tracks restart on interrupt. */ -+ enum vc_sm_msg_type int_action; /* Interrupted action. */ -+ u32 int_trans_id; /* Interrupted transaction. */ -+}; -+ -+typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v); -+struct sm_pde_t { -+ VC_SM_SHOW show; /* Debug fs function hookup. */ -+ struct dentry *dir_entry; /* Debug fs directory entry. */ -+ void *priv_data; /* Private data */ -+}; -+ -+/* Global state information. */ -+struct sm_state_t { -+ struct platform_device *pdev; -+ -+ struct miscdevice misc_dev; -+ -+ struct sm_instance *sm_handle; /* Handle for videocore service. */ -+ -+ spinlock_t kernelid_map_lock; /* Spinlock protecting kernelid_map */ -+ struct idr kernelid_map; -+ -+ struct mutex map_lock; /* Global map lock. */ -+ struct list_head buffer_list; /* List of buffer. */ -+ -+ struct vc_sm_privdata_t *data_knl; /* Kernel internal data tracking. */ -+ struct vc_sm_privdata_t *vpu_allocs; /* All allocations from the VPU */ -+ struct dentry *dir_root; /* Debug fs entries root. */ -+ struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */ -+ -+ bool require_released_callback; /* VPU will send a released msg when it -+ * has finished with a resource. -+ */ -+ u32 int_trans_id; /* Interrupted transaction. */ -+}; -+ -+struct vc_sm_dma_buf_attachment { -+ struct device *dev; -+ struct sg_table sg_table; -+ struct list_head list; -+ enum dma_data_direction dma_dir; -+}; -+ -+/* ---- Private Variables ----------------------------------------------- */ -+ -+static struct sm_state_t *sm_state; -+static int sm_inited; -+ -+/* ---- Private Function Prototypes -------------------------------------- */ -+ -+/* ---- Private Functions ------------------------------------------------ */ -+ -+static int get_kernel_id(struct vc_sm_buffer *buffer) -+{ -+ int handle; -+ -+ spin_lock(&sm_state->kernelid_map_lock); -+ handle = idr_alloc(&sm_state->kernelid_map, buffer, 0, 0, GFP_KERNEL); -+ spin_unlock(&sm_state->kernelid_map_lock); -+ -+ return handle; -+} -+ -+static struct vc_sm_buffer *lookup_kernel_id(int handle) -+{ -+ return idr_find(&sm_state->kernelid_map, handle); -+} -+ -+static void free_kernel_id(int handle) -+{ -+ spin_lock(&sm_state->kernelid_map_lock); -+ idr_remove(&sm_state->kernelid_map, handle); -+ spin_unlock(&sm_state->kernelid_map_lock); -+} -+ -+static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v) -+{ -+ struct sm_pde_t *sm_pde; -+ -+ sm_pde = (struct sm_pde_t *)(s->private); -+ -+ if (sm_pde && sm_pde->show) -+ sm_pde->show(s, v); -+ -+ return 0; -+} -+ -+static int vc_sm_cma_single_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, vc_sm_cma_seq_file_show, inode->i_private); -+} -+ -+static const struct file_operations vc_sm_cma_debug_fs_fops = { -+ .open = vc_sm_cma_single_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static int vc_sm_cma_global_state_show(struct seq_file *s, void *v) -+{ -+ struct vc_sm_buffer *resource = NULL; -+ int resource_count = 0; -+ -+ if (!sm_state) -+ return 0; -+ -+ seq_printf(s, "\nVC-ServiceHandle %p\n", sm_state->sm_handle); -+ -+ /* Log all applicable mapping(s). */ -+ -+ mutex_lock(&sm_state->map_lock); -+ seq_puts(s, "\nResources\n"); -+ if (!list_empty(&sm_state->buffer_list)) { -+ list_for_each_entry(resource, &sm_state->buffer_list, -+ global_buffer_list) { -+ resource_count++; -+ -+ seq_printf(s, "\nResource %p\n", -+ resource); -+ seq_printf(s, " NAME %s\n", -+ resource->name); -+ seq_printf(s, " SIZE %zu\n", -+ resource->size); -+ seq_printf(s, " DMABUF %p\n", -+ resource->dma_buf); -+ if (resource->imported) { -+ seq_printf(s, " ATTACH %p\n", -+ resource->import.attach); -+ seq_printf(s, " SGT %p\n", -+ resource->import.sgt); -+ } else { -+ seq_printf(s, " SGT %p\n", -+ resource->alloc.sg_table); -+ } -+ seq_printf(s, " DMA_ADDR %pad\n", -+ &resource->dma_addr); -+ seq_printf(s, " VC_HANDLE %08x\n", -+ resource->vc_handle); -+ seq_printf(s, " VC_MAPPING %d\n", -+ resource->vpu_state); -+ } -+ } -+ seq_printf(s, "\n\nTotal resource count: %d\n\n", resource_count); -+ -+ mutex_unlock(&sm_state->map_lock); -+ -+ return 0; -+} -+ -+/* -+ * Adds a buffer to the private data list which tracks all the allocated -+ * data. -+ */ -+static void vc_sm_add_resource(struct vc_sm_privdata_t *privdata, -+ struct vc_sm_buffer *buffer) -+{ -+ mutex_lock(&sm_state->map_lock); -+ list_add(&buffer->global_buffer_list, &sm_state->buffer_list); -+ mutex_unlock(&sm_state->map_lock); -+ -+ pr_debug("[%s]: added buffer %p (name %s, size %zu)\n", -+ __func__, buffer, buffer->name, buffer->size); -+} -+ -+/* -+ * Cleans up imported dmabuf. -+ */ -+static void vc_sm_clean_up_dmabuf(struct vc_sm_buffer *buffer) -+{ -+ if (!buffer->imported) -+ return; -+ -+ /* Handle cleaning up imported dmabufs */ -+ mutex_lock(&buffer->lock); -+ if (buffer->import.sgt) { -+ dma_buf_unmap_attachment(buffer->import.attach, -+ buffer->import.sgt, -+ DMA_BIDIRECTIONAL); -+ buffer->import.sgt = NULL; -+ } -+ if (buffer->import.attach) { -+ dma_buf_detach(buffer->dma_buf, buffer->import.attach); -+ buffer->import.attach = NULL; -+ } -+ mutex_unlock(&buffer->lock); -+} -+ -+/* -+ * Instructs VPU to decrement the refcount on a buffer. -+ */ -+static void vc_sm_vpu_free(struct vc_sm_buffer *buffer) -+{ -+ if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) { -+ struct vc_sm_free_t free = { buffer->vc_handle, 0 }; -+ int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free, -+ &sm_state->int_trans_id); -+ if (status != 0 && status != -EINTR) { -+ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n", -+ __func__, status, sm_state->int_trans_id); -+ } -+ -+ if (sm_state->require_released_callback) { -+ /* Need to wait for the VPU to confirm the free. */ -+ -+ /* Retain a reference on this until the VPU has -+ * released it -+ */ -+ buffer->vpu_state = VPU_UNMAPPING; -+ } else { -+ buffer->vpu_state = VPU_NOT_MAPPED; -+ buffer->vc_handle = 0; -+ } -+ } -+} -+ -+/* -+ * Release an allocation. -+ * All refcounting is done via the dma buf object. -+ * -+ * Must be called with the mutex held. The function will either release the -+ * mutex (if defering the release) or destroy it. The caller must therefore not -+ * reuse the buffer on return. -+ */ -+static void vc_sm_release_resource(struct vc_sm_buffer *buffer) -+{ -+ pr_debug("[%s]: buffer %p (name %s, size %zu), imported %u\n", -+ __func__, buffer, buffer->name, buffer->size, -+ buffer->imported); -+ -+ if (buffer->vc_handle) { -+ /* We've sent the unmap request but not had the response. */ -+ pr_debug("[%s]: Waiting for VPU unmap response on %p\n", -+ __func__, buffer); -+ goto defer; -+ } -+ if (buffer->in_use) { -+ /* dmabuf still in use - we await the release */ -+ pr_debug("[%s]: buffer %p is still in use\n", __func__, buffer); -+ goto defer; -+ } -+ -+ /* Release the allocation (whether imported dmabuf or CMA allocation) */ -+ if (buffer->imported) { -+ if (buffer->import.dma_buf) -+ dma_buf_put(buffer->import.dma_buf); -+ else -+ pr_err("%s: Imported dmabuf already been put for buf %p\n", -+ __func__, buffer); -+ buffer->import.dma_buf = NULL; -+ } else { -+ dma_free_coherent(&sm_state->pdev->dev, buffer->size, -+ buffer->cookie, buffer->dma_addr); -+ } -+ -+ /* Free our buffer. Start by removing it from the list */ -+ mutex_lock(&sm_state->map_lock); -+ list_del(&buffer->global_buffer_list); -+ mutex_unlock(&sm_state->map_lock); -+ -+ pr_debug("%s: Release our allocation - done\n", __func__); -+ mutex_unlock(&buffer->lock); -+ -+ mutex_destroy(&buffer->lock); -+ -+ kfree(buffer); -+ return; -+ -+defer: -+ mutex_unlock(&buffer->lock); -+} -+ -+/* Create support for private data tracking. */ -+static struct vc_sm_privdata_t *vc_sm_cma_create_priv_data(pid_t id) -+{ -+ char alloc_name[32]; -+ struct vc_sm_privdata_t *file_data = NULL; -+ -+ /* Allocate private structure. */ -+ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL); -+ -+ if (!file_data) -+ return NULL; -+ -+ snprintf(alloc_name, sizeof(alloc_name), "%d", id); -+ -+ file_data->pid = id; -+ -+ return file_data; -+} -+ -+/* Dma buf operations for use with our own allocations */ -+ -+static int vc_sm_dma_buf_attach(struct dma_buf *dmabuf, -+ struct dma_buf_attachment *attachment) -+ -+{ -+ struct vc_sm_dma_buf_attachment *a; -+ struct sg_table *sgt; -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ struct scatterlist *rd, *wr; -+ int ret, i; -+ -+ a = kzalloc(sizeof(*a), GFP_KERNEL); -+ if (!a) -+ return -ENOMEM; -+ -+ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment); -+ -+ mutex_lock(&buf->lock); -+ -+ INIT_LIST_HEAD(&a->list); -+ -+ sgt = &a->sg_table; -+ -+ /* Copy the buf->base_sgt scatter list to the attachment, as we can't -+ * map the same scatter list to multiple attachments at the same time. -+ */ -+ ret = sg_alloc_table(sgt, buf->alloc.sg_table->orig_nents, GFP_KERNEL); -+ if (ret) { -+ kfree(a); -+ return -ENOMEM; -+ } -+ -+ rd = buf->alloc.sg_table->sgl; -+ wr = sgt->sgl; -+ for (i = 0; i < sgt->orig_nents; ++i) { -+ sg_set_page(wr, sg_page(rd), rd->length, rd->offset); -+ rd = sg_next(rd); -+ wr = sg_next(wr); -+ } -+ -+ a->dma_dir = DMA_NONE; -+ attachment->priv = a; -+ -+ list_add(&a->list, &buf->attachments); -+ mutex_unlock(&buf->lock); -+ -+ return 0; -+} -+ -+static void vc_sm_dma_buf_detach(struct dma_buf *dmabuf, -+ struct dma_buf_attachment *attachment) -+{ -+ struct vc_sm_dma_buf_attachment *a = attachment->priv; -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ struct sg_table *sgt; -+ -+ pr_debug("%s dmabuf %p attachment %p\n", __func__, dmabuf, attachment); -+ if (!a) -+ return; -+ -+ sgt = &a->sg_table; -+ -+ /* release the scatterlist cache */ -+ if (a->dma_dir != DMA_NONE) -+ dma_unmap_sg(attachment->dev, sgt->sgl, sgt->orig_nents, -+ a->dma_dir); -+ sg_free_table(sgt); -+ -+ mutex_lock(&buf->lock); -+ list_del(&a->list); -+ mutex_unlock(&buf->lock); -+ -+ kfree(a); -+} -+ -+static struct sg_table *vc_sm_map_dma_buf(struct dma_buf_attachment *attachment, -+ enum dma_data_direction direction) -+{ -+ struct vc_sm_dma_buf_attachment *a = attachment->priv; -+ /* stealing dmabuf mutex to serialize map/unmap operations */ -+ struct mutex *lock = &attachment->dmabuf->lock; -+ struct sg_table *table; -+ -+ mutex_lock(lock); -+ pr_debug("%s attachment %p\n", __func__, attachment); -+ table = &a->sg_table; -+ -+ /* return previously mapped sg table */ -+ if (a->dma_dir == direction) { -+ mutex_unlock(lock); -+ return table; -+ } -+ -+ /* release any previous cache */ -+ if (a->dma_dir != DMA_NONE) { -+ dma_unmap_sg(attachment->dev, table->sgl, table->orig_nents, -+ a->dma_dir); -+ a->dma_dir = DMA_NONE; -+ } -+ -+ /* mapping to the client with new direction */ -+ table->nents = dma_map_sg(attachment->dev, table->sgl, -+ table->orig_nents, direction); -+ if (!table->nents) { -+ pr_err("failed to map scatterlist\n"); -+ mutex_unlock(lock); -+ return ERR_PTR(-EIO); -+ } -+ -+ a->dma_dir = direction; -+ mutex_unlock(lock); -+ -+ pr_debug("%s attachment %p\n", __func__, attachment); -+ return table; -+} -+ -+static void vc_sm_unmap_dma_buf(struct dma_buf_attachment *attachment, -+ struct sg_table *table, -+ enum dma_data_direction direction) -+{ -+ pr_debug("%s attachment %p\n", __func__, attachment); -+ dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction); -+} -+ -+static int vc_sm_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ int ret; -+ -+ pr_debug("%s dmabuf %p, buf %p, vm_start %08lX\n", __func__, dmabuf, -+ buf, vma->vm_start); -+ -+ mutex_lock(&buf->lock); -+ -+ /* now map it to userspace */ -+ vma->vm_pgoff = 0; -+ -+ ret = dma_mmap_coherent(&sm_state->pdev->dev, vma, buf->cookie, -+ buf->dma_addr, buf->size); -+ -+ if (ret) { -+ pr_err("Remapping memory failed, error: %d\n", ret); -+ return ret; -+ } -+ -+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; -+ -+ mutex_unlock(&buf->lock); -+ -+ if (ret) -+ pr_err("%s: failure mapping buffer to userspace\n", -+ __func__); -+ -+ return ret; -+} -+ -+static void vc_sm_dma_buf_release(struct dma_buf *dmabuf) -+{ -+ struct vc_sm_buffer *buffer; -+ -+ if (!dmabuf) -+ return; -+ -+ buffer = (struct vc_sm_buffer *)dmabuf->priv; -+ -+ mutex_lock(&buffer->lock); -+ -+ pr_debug("%s dmabuf %p, buffer %p\n", __func__, dmabuf, buffer); -+ -+ buffer->in_use = 0; -+ -+ /* Unmap on the VPU */ -+ vc_sm_vpu_free(buffer); -+ pr_debug("%s vpu_free done\n", __func__); -+ -+ /* Unmap our dma_buf object (the vc_sm_buffer remains until released -+ * on the VPU). -+ */ -+ vc_sm_clean_up_dmabuf(buffer); -+ pr_debug("%s clean_up dmabuf done\n", __func__); -+ -+ /* buffer->lock will be destroyed by vc_sm_release_resource if finished -+ * with, otherwise unlocked. Do NOT unlock here. -+ */ -+ vc_sm_release_resource(buffer); -+ pr_debug("%s done\n", __func__); -+} -+ -+static int vc_sm_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, -+ enum dma_data_direction direction) -+{ -+ struct vc_sm_buffer *buf; -+ struct vc_sm_dma_buf_attachment *a; -+ -+ if (!dmabuf) -+ return -EFAULT; -+ -+ buf = dmabuf->priv; -+ if (!buf) -+ return -EFAULT; -+ -+ mutex_lock(&buf->lock); -+ -+ list_for_each_entry(a, &buf->attachments, list) { -+ dma_sync_sg_for_cpu(a->dev, a->sg_table.sgl, -+ a->sg_table.nents, direction); -+ } -+ mutex_unlock(&buf->lock); -+ -+ return 0; -+} -+ -+static int vc_sm_dma_buf_end_cpu_access(struct dma_buf *dmabuf, -+ enum dma_data_direction direction) -+{ -+ struct vc_sm_buffer *buf; -+ struct vc_sm_dma_buf_attachment *a; -+ -+ if (!dmabuf) -+ return -EFAULT; -+ buf = dmabuf->priv; -+ if (!buf) -+ return -EFAULT; -+ -+ mutex_lock(&buf->lock); -+ -+ list_for_each_entry(a, &buf->attachments, list) { -+ dma_sync_sg_for_device(a->dev, a->sg_table.sgl, -+ a->sg_table.nents, direction); -+ } -+ mutex_unlock(&buf->lock); -+ -+ return 0; -+} -+ -+static void *vc_sm_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset) -+{ -+ /* FIXME */ -+ return NULL; -+} -+ -+static void vc_sm_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset, -+ void *ptr) -+{ -+ /* FIXME */ -+} -+ -+static const struct dma_buf_ops dma_buf_ops = { -+ .map_dma_buf = vc_sm_map_dma_buf, -+ .unmap_dma_buf = vc_sm_unmap_dma_buf, -+ .mmap = vc_sm_dmabuf_mmap, -+ .release = vc_sm_dma_buf_release, -+ .attach = vc_sm_dma_buf_attach, -+ .detach = vc_sm_dma_buf_detach, -+ .begin_cpu_access = vc_sm_dma_buf_begin_cpu_access, -+ .end_cpu_access = vc_sm_dma_buf_end_cpu_access, -+ .map = vc_sm_dma_buf_kmap, -+ .unmap = vc_sm_dma_buf_kunmap, -+}; -+ -+/* Dma_buf operations for chaining through to an imported dma_buf */ -+ -+static -+int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf, -+ struct dma_buf_attachment *attachment) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ if (!buf->imported) -+ return -EINVAL; -+ return buf->import.dma_buf->ops->attach(buf->import.dma_buf, -+ attachment); -+} -+ -+static -+void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf, -+ struct dma_buf_attachment *attachment) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ if (!buf->imported) -+ return; -+ buf->import.dma_buf->ops->detach(buf->import.dma_buf, attachment); -+} -+ -+static -+struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment, -+ enum dma_data_direction direction) -+{ -+ struct vc_sm_buffer *buf = attachment->dmabuf->priv; -+ -+ if (!buf->imported) -+ return NULL; -+ return buf->import.dma_buf->ops->map_dma_buf(attachment, -+ direction); -+} -+ -+static -+void vc_sm_import_unmap_dma_buf(struct dma_buf_attachment *attachment, -+ struct sg_table *table, -+ enum dma_data_direction direction) -+{ -+ struct vc_sm_buffer *buf = attachment->dmabuf->priv; -+ -+ if (!buf->imported) -+ return; -+ buf->import.dma_buf->ops->unmap_dma_buf(attachment, table, direction); -+} -+ -+static -+int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ pr_debug("%s: mmap dma_buf %p, buf %p, imported db %p\n", __func__, -+ dmabuf, buf, buf->import.dma_buf); -+ if (!buf->imported) { -+ pr_err("%s: mmap dma_buf %p- not an imported buffer\n", -+ __func__, dmabuf); -+ return -EINVAL; -+ } -+ return buf->import.dma_buf->ops->mmap(buf->import.dma_buf, vma); -+} -+ -+static -+void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf); -+ mutex_lock(&buf->lock); -+ if (!buf->imported) -+ return; -+ -+ buf->in_use = 0; -+ -+ vc_sm_vpu_free(buf); -+ -+ vc_sm_release_resource(buf); -+} -+ -+static -+void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf, -+ unsigned long offset) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ if (!buf->imported) -+ return NULL; -+ return buf->import.dma_buf->ops->map(buf->import.dma_buf, offset); -+} -+ -+static -+void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf, -+ unsigned long offset, void *ptr) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ if (!buf->imported) -+ return; -+ buf->import.dma_buf->ops->unmap(buf->import.dma_buf, offset, ptr); -+} -+ -+static -+int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, -+ enum dma_data_direction direction) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ if (!buf->imported) -+ return -EINVAL; -+ return buf->import.dma_buf->ops->begin_cpu_access(buf->import.dma_buf, -+ direction); -+} -+ -+static -+int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf, -+ enum dma_data_direction direction) -+{ -+ struct vc_sm_buffer *buf = dmabuf->priv; -+ -+ if (!buf->imported) -+ return -EINVAL; -+ return buf->import.dma_buf->ops->end_cpu_access(buf->import.dma_buf, -+ direction); -+} -+ -+static const struct dma_buf_ops dma_buf_import_ops = { -+ .map_dma_buf = vc_sm_import_map_dma_buf, -+ .unmap_dma_buf = vc_sm_import_unmap_dma_buf, -+ .mmap = vc_sm_import_dmabuf_mmap, -+ .release = vc_sm_import_dma_buf_release, -+ .attach = vc_sm_import_dma_buf_attach, -+ .detach = vc_sm_import_dma_buf_detatch, -+ .begin_cpu_access = vc_sm_import_dma_buf_begin_cpu_access, -+ .end_cpu_access = vc_sm_import_dma_buf_end_cpu_access, -+ .map = vc_sm_import_dma_buf_kmap, -+ .unmap = vc_sm_import_dma_buf_kunmap, -+}; -+ -+/* Import a dma_buf to be shared with VC. */ -+int -+vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private, -+ struct dma_buf *dma_buf, -+ int fd, -+ struct dma_buf **imported_buf) -+{ -+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); -+ struct vc_sm_buffer *buffer = NULL; -+ struct vc_sm_import import = { }; -+ struct vc_sm_import_result result = { }; -+ struct dma_buf_attachment *attach = NULL; -+ struct sg_table *sgt = NULL; -+ dma_addr_t dma_addr; -+ int ret = 0; -+ int status; -+ -+ /* Setup our allocation parameters */ -+ pr_debug("%s: importing dma_buf %p/fd %d\n", __func__, dma_buf, fd); -+ -+ if (fd < 0) -+ get_dma_buf(dma_buf); -+ else -+ dma_buf = dma_buf_get(fd); -+ -+ if (!dma_buf) -+ return -EINVAL; -+ -+ attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev); -+ if (IS_ERR(attach)) { -+ ret = PTR_ERR(attach); -+ goto error; -+ } -+ -+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); -+ if (IS_ERR(sgt)) { -+ ret = PTR_ERR(sgt); -+ goto error; -+ } -+ -+ /* Verify that the address block is contiguous */ -+ if (sgt->nents != 1) { -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ /* Allocate local buffer to track this allocation. */ -+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); -+ if (!buffer) { -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ import.type = VC_SM_ALLOC_NON_CACHED; -+ dma_addr = sg_dma_address(sgt->sgl); -+ import.addr = (u32)dma_addr; -+ if ((import.addr & 0xC0000000) != 0xC0000000) { -+ pr_err("%s: Expecting an uncached alias for dma_addr %pad\n", -+ __func__, &dma_addr); -+ import.addr |= 0xC0000000; -+ } -+ import.size = sg_dma_len(sgt->sgl); -+ import.allocator = current->tgid; -+ import.kernel_id = get_kernel_id(buffer); -+ -+ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT, -+ sizeof(VC_SM_RESOURCE_NAME_DEFAULT)); -+ -+ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %pad, size %u.\n", -+ __func__, import.name, import.type, &dma_addr, import.size); -+ -+ /* Allocate the videocore buffer. */ -+ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result, -+ &sm_state->int_trans_id); -+ if (status == -EINTR) { -+ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n", -+ __func__, sm_state->int_trans_id); -+ ret = -ERESTARTSYS; -+ private->restart_sys = -EINTR; -+ private->int_action = VC_SM_MSG_TYPE_IMPORT; -+ goto error; -+ } else if (status || !result.res_handle) { -+ pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n", -+ __func__, status, sm_state->int_trans_id); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ mutex_init(&buffer->lock); -+ INIT_LIST_HEAD(&buffer->attachments); -+ memcpy(buffer->name, import.name, -+ min(sizeof(buffer->name), sizeof(import.name) - 1)); -+ -+ /* Keep track of the buffer we created. */ -+ buffer->private = private; -+ buffer->vc_handle = result.res_handle; -+ buffer->size = import.size; -+ buffer->vpu_state = VPU_MAPPED; -+ -+ buffer->imported = 1; -+ buffer->import.dma_buf = dma_buf; -+ -+ buffer->import.attach = attach; -+ buffer->import.sgt = sgt; -+ buffer->dma_addr = dma_addr; -+ buffer->in_use = 1; -+ buffer->kernel_id = import.kernel_id; -+ -+ /* -+ * We're done - we need to export a new dmabuf chaining through most -+ * functions, but enabling us to release our own internal references -+ * here. -+ */ -+ exp_info.ops = &dma_buf_import_ops; -+ exp_info.size = import.size; -+ exp_info.flags = O_RDWR; -+ exp_info.priv = buffer; -+ -+ buffer->dma_buf = dma_buf_export(&exp_info); -+ if (IS_ERR(buffer->dma_buf)) { -+ ret = PTR_ERR(buffer->dma_buf); -+ goto error; -+ } -+ -+ vc_sm_add_resource(private, buffer); -+ -+ *imported_buf = buffer->dma_buf; -+ -+ return 0; -+ -+error: -+ if (result.res_handle) { -+ struct vc_sm_free_t free = { result.res_handle, 0 }; -+ -+ vc_sm_cma_vchi_free(sm_state->sm_handle, &free, -+ &sm_state->int_trans_id); -+ } -+ free_kernel_id(import.kernel_id); -+ kfree(buffer); -+ if (sgt) -+ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); -+ if (attach) -+ dma_buf_detach(dma_buf, attach); -+ dma_buf_put(dma_buf); -+ return ret; -+} -+ -+static int vc_sm_cma_vpu_alloc(u32 size, u32 align, const char *name, -+ u32 mem_handle, struct vc_sm_buffer **ret_buffer) -+{ -+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); -+ struct vc_sm_buffer *buffer = NULL; -+ struct sg_table *sgt; -+ int aligned_size; -+ int ret = 0; -+ -+ /* Align to the user requested align */ -+ aligned_size = ALIGN(size, align); -+ /* and then to a page boundary */ -+ aligned_size = PAGE_ALIGN(aligned_size); -+ -+ if (!aligned_size) -+ return -EINVAL; -+ -+ /* Allocate local buffer to track this allocation. */ -+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ mutex_init(&buffer->lock); -+ /* Acquire the mutex as vc_sm_release_resource will release it in the -+ * error path. -+ */ -+ mutex_lock(&buffer->lock); -+ -+ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev, -+ aligned_size, &buffer->dma_addr, -+ GFP_KERNEL); -+ if (!buffer->cookie) { -+ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n", -+ __func__, aligned_size); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ pr_debug("[%s]: alloc of %d bytes success\n", -+ __func__, aligned_size); -+ -+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); -+ if (!sgt) { -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie, -+ buffer->dma_addr, buffer->size); -+ if (ret < 0) { -+ pr_err("failed to get scatterlist from DMA API\n"); -+ kfree(sgt); -+ ret = -ENOMEM; -+ goto error; -+ } -+ buffer->alloc.sg_table = sgt; -+ -+ INIT_LIST_HEAD(&buffer->attachments); -+ -+ memcpy(buffer->name, name, -+ min(sizeof(buffer->name), strlen(name))); -+ -+ exp_info.ops = &dma_buf_ops; -+ exp_info.size = aligned_size; -+ exp_info.flags = O_RDWR; -+ exp_info.priv = buffer; -+ -+ buffer->dma_buf = dma_buf_export(&exp_info); -+ if (IS_ERR(buffer->dma_buf)) { -+ ret = PTR_ERR(buffer->dma_buf); -+ goto error; -+ } -+ buffer->dma_addr = (u32)sg_dma_address(buffer->alloc.sg_table->sgl); -+ if ((buffer->dma_addr & 0xC0000000) != 0xC0000000) { -+ pr_warn_once("%s: Expecting an uncached alias for dma_addr %pad\n", -+ __func__, &buffer->dma_addr); -+ buffer->dma_addr |= 0xC0000000; -+ } -+ buffer->private = sm_state->vpu_allocs; -+ -+ buffer->vc_handle = mem_handle; -+ buffer->vpu_state = VPU_MAPPED; -+ buffer->vpu_allocated = 1; -+ buffer->size = size; -+ /* -+ * Create an ID that will be passed along with our message so -+ * that when we service the release reply, we can look up which -+ * resource is being released. -+ */ -+ buffer->kernel_id = get_kernel_id(buffer); -+ -+ vc_sm_add_resource(sm_state->vpu_allocs, buffer); -+ -+ mutex_unlock(&buffer->lock); -+ -+ *ret_buffer = buffer; -+ return 0; -+error: -+ if (buffer) -+ vc_sm_release_resource(buffer); -+ return ret; -+} -+ -+static void -+vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply, -+ int reply_len) -+{ -+ switch (reply->trans_id & ~0x80000000) { -+ case VC_SM_MSG_TYPE_CLIENT_VERSION: -+ { -+ /* Acknowledge that the firmware supports the version command */ -+ pr_debug("%s: firmware acked version msg. Require release cb\n", -+ __func__); -+ sm_state->require_released_callback = true; -+ } -+ break; -+ case VC_SM_MSG_TYPE_RELEASED: -+ { -+ struct vc_sm_released *release = (struct vc_sm_released *)reply; -+ struct vc_sm_buffer *buffer = -+ lookup_kernel_id(release->kernel_id); -+ if (!buffer) { -+ pr_err("%s: VC released a buffer that is already released, kernel_id %d\n", -+ __func__, release->kernel_id); -+ break; -+ } -+ mutex_lock(&buffer->lock); -+ -+ pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n", -+ __func__, release->addr, release->size, -+ release->kernel_id, release->vc_handle); -+ -+ buffer->vc_handle = 0; -+ buffer->vpu_state = VPU_NOT_MAPPED; -+ free_kernel_id(release->kernel_id); -+ -+ if (buffer->vpu_allocated) { -+ /* VPU allocation, so release the dmabuf which will -+ * trigger the clean up. -+ */ -+ mutex_unlock(&buffer->lock); -+ dma_buf_put(buffer->dma_buf); -+ } else { -+ vc_sm_release_resource(buffer); -+ } -+ } -+ break; -+ case VC_SM_MSG_TYPE_VC_MEM_REQUEST: -+ { -+ struct vc_sm_buffer *buffer = NULL; -+ struct vc_sm_vc_mem_request *req = -+ (struct vc_sm_vc_mem_request *)reply; -+ struct vc_sm_vc_mem_request_result reply; -+ int ret; -+ -+ pr_debug("%s: Request %u bytes of memory, align %d name %s, trans_id %08x\n", -+ __func__, req->size, req->align, req->name, -+ req->trans_id); -+ ret = vc_sm_cma_vpu_alloc(req->size, req->align, req->name, -+ req->vc_handle, &buffer); -+ -+ reply.trans_id = req->trans_id; -+ if (!ret) { -+ reply.addr = buffer->dma_addr; -+ reply.kernel_id = buffer->kernel_id; -+ pr_debug("%s: Allocated resource buffer %p, addr %pad\n", -+ __func__, buffer, &buffer->dma_addr); -+ } else { -+ pr_err("%s: Allocation failed size %u, name %s, vc_handle %u\n", -+ __func__, req->size, req->name, req->vc_handle); -+ reply.addr = 0; -+ reply.kernel_id = 0; -+ } -+ vc_sm_vchi_client_vc_mem_req_reply(sm_state->sm_handle, &reply, -+ &sm_state->int_trans_id); -+ break; -+ } -+ break; -+ default: -+ pr_err("%s: Unknown vpu cmd %x\n", __func__, reply->trans_id); -+ break; -+ } -+} -+ -+/* Userspace handling */ -+/* -+ * Open the device. Creates a private state to help track all allocation -+ * associated with this device. -+ */ -+static int vc_sm_cma_open(struct inode *inode, struct file *file) -+{ -+ /* Make sure the device was started properly. */ -+ if (!sm_state) { -+ pr_err("[%s]: invalid device\n", __func__); -+ return -EPERM; -+ } -+ -+ file->private_data = vc_sm_cma_create_priv_data(current->tgid); -+ if (!file->private_data) { -+ pr_err("[%s]: failed to create data tracker\n", __func__); -+ -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Close the vcsm-cma device. -+ * All allocations are file descriptors to the dmabuf objects, so we will get -+ * the clean up request on those as those are cleaned up. -+ */ -+static int vc_sm_cma_release(struct inode *inode, struct file *file) -+{ -+ struct vc_sm_privdata_t *file_data = -+ (struct vc_sm_privdata_t *)file->private_data; -+ int ret = 0; -+ -+ /* Make sure the device was started properly. */ -+ if (!sm_state || !file_data) { -+ pr_err("[%s]: invalid device\n", __func__); -+ ret = -EPERM; -+ goto out; -+ } -+ -+ pr_debug("[%s]: using private data %p\n", __func__, file_data); -+ -+ /* Terminate the private data. */ -+ kfree(file_data); -+ -+out: -+ return ret; -+} -+ -+/* -+ * Allocate a shared memory handle and block. -+ * Allocation is from CMA, and then imported into the VPU mappings. -+ */ -+int vc_sm_cma_ioctl_alloc(struct vc_sm_privdata_t *private, -+ struct vc_sm_cma_ioctl_alloc *ioparam) -+{ -+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info); -+ struct vc_sm_buffer *buffer = NULL; -+ struct vc_sm_import import = { 0 }; -+ struct vc_sm_import_result result = { 0 }; -+ struct dma_buf *dmabuf = NULL; -+ struct sg_table *sgt; -+ int aligned_size; -+ int ret = 0; -+ int status; -+ int fd = -1; -+ -+ aligned_size = PAGE_ALIGN(ioparam->size); -+ -+ if (!aligned_size) -+ return -EINVAL; -+ -+ /* Allocate local buffer to track this allocation. */ -+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); -+ if (!buffer) { -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ buffer->cookie = dma_alloc_coherent(&sm_state->pdev->dev, -+ aligned_size, -+ &buffer->dma_addr, -+ GFP_KERNEL); -+ if (!buffer->cookie) { -+ pr_err("[%s]: dma_alloc_coherent alloc of %d bytes failed\n", -+ __func__, aligned_size); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ import.type = VC_SM_ALLOC_NON_CACHED; -+ import.allocator = current->tgid; -+ -+ if (*ioparam->name) -+ memcpy(import.name, ioparam->name, sizeof(import.name) - 1); -+ else -+ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT, -+ sizeof(VC_SM_RESOURCE_NAME_DEFAULT)); -+ -+ mutex_init(&buffer->lock); -+ INIT_LIST_HEAD(&buffer->attachments); -+ memcpy(buffer->name, import.name, -+ min(sizeof(buffer->name), sizeof(import.name) - 1)); -+ -+ exp_info.ops = &dma_buf_ops; -+ exp_info.size = aligned_size; -+ exp_info.flags = O_RDWR; -+ exp_info.priv = buffer; -+ -+ dmabuf = dma_buf_export(&exp_info); -+ if (IS_ERR(dmabuf)) { -+ ret = PTR_ERR(dmabuf); -+ goto error; -+ } -+ buffer->dma_buf = dmabuf; -+ -+ import.addr = buffer->dma_addr; -+ import.size = aligned_size; -+ import.kernel_id = get_kernel_id(buffer); -+ -+ /* Wrap it into a videocore buffer. */ -+ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result, -+ &sm_state->int_trans_id); -+ if (status == -EINTR) { -+ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n", -+ __func__, sm_state->int_trans_id); -+ ret = -ERESTARTSYS; -+ private->restart_sys = -EINTR; -+ private->int_action = VC_SM_MSG_TYPE_IMPORT; -+ goto error; -+ } else if (status || !result.res_handle) { -+ pr_err("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n", -+ __func__, status, sm_state->int_trans_id); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ /* Keep track of the buffer we created. */ -+ buffer->private = private; -+ buffer->vc_handle = result.res_handle; -+ buffer->size = import.size; -+ buffer->vpu_state = VPU_MAPPED; -+ buffer->kernel_id = import.kernel_id; -+ -+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); -+ if (!sgt) { -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ ret = dma_get_sgtable(&sm_state->pdev->dev, sgt, buffer->cookie, -+ buffer->dma_addr, buffer->size); -+ if (ret < 0) { -+ /* FIXME: error handling */ -+ pr_err("failed to get scatterlist from DMA API\n"); -+ kfree(sgt); -+ ret = -ENOMEM; -+ goto error; -+ } -+ buffer->alloc.sg_table = sgt; -+ -+ fd = dma_buf_fd(dmabuf, O_CLOEXEC); -+ if (fd < 0) -+ goto error; -+ -+ vc_sm_add_resource(private, buffer); -+ -+ pr_debug("[%s]: Added resource as fd %d, buffer %p, private %p, dma_addr %pad\n", -+ __func__, fd, buffer, private, &buffer->dma_addr); -+ -+ /* We're done */ -+ ioparam->handle = fd; -+ ioparam->vc_handle = buffer->vc_handle; -+ ioparam->dma_addr = buffer->dma_addr; -+ return 0; -+ -+error: -+ pr_err("[%s]: something failed - cleanup. ret %d\n", __func__, ret); -+ -+ if (dmabuf) { -+ /* dmabuf has been exported, therefore allow dmabuf cleanup to -+ * deal with this -+ */ -+ dma_buf_put(dmabuf); -+ } else { -+ /* No dmabuf, therefore just free the buffer here */ -+ if (buffer->cookie) -+ dma_free_coherent(&sm_state->pdev->dev, buffer->size, -+ buffer->cookie, buffer->dma_addr); -+ kfree(buffer); -+ } -+ return ret; -+} -+ -+#ifndef CONFIG_ARM64 -+/* Converts VCSM_CACHE_OP_* to an operating function. */ -+static void (*cache_op_to_func(const unsigned int cache_op)) -+ (const void*, const void*) -+{ -+ switch (cache_op) { -+ case VC_SM_CACHE_OP_NOP: -+ return NULL; -+ -+ case VC_SM_CACHE_OP_INV: -+ return dmac_inv_range; -+ -+ case VC_SM_CACHE_OP_CLEAN: -+ return dmac_clean_range; -+ -+ case VC_SM_CACHE_OP_FLUSH: -+ return dmac_flush_range; -+ -+ default: -+ pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op); -+ return NULL; -+ } -+} -+ -+/* -+ * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed). -+ */ -+static int clean_invalid_contig_2d(const void __user *addr, -+ const size_t block_count, -+ const size_t block_size, -+ const size_t stride, -+ const unsigned int cache_op) -+{ -+ size_t i; -+ void (*op_fn)(const void *start, const void *end); -+ -+ if (!block_size) { -+ pr_err("[%s]: size cannot be 0\n", __func__); -+ return -EINVAL; -+ } -+ -+ op_fn = cache_op_to_func(cache_op); -+ if (!op_fn) -+ return -EINVAL; -+ -+ for (i = 0; i < block_count; i ++, addr += stride) -+ op_fn(addr, addr + block_size); -+ -+ return 0; -+} -+ -+static int vc_sm_cma_clean_invalid2(unsigned int cmdnr, unsigned long arg) -+{ -+ struct vc_sm_cma_ioctl_clean_invalid2 ioparam; -+ struct vc_sm_cma_ioctl_clean_invalid_block *block = NULL; -+ int i, ret = 0; -+ -+ /* Get parameter data. */ -+ if (copy_from_user(&ioparam, (void *)arg, sizeof(ioparam))) { -+ pr_err("[%s]: failed to copy-from-user header for cmd %x\n", -+ __func__, cmdnr); -+ return -EFAULT; -+ } -+ block = kmalloc(ioparam.op_count * sizeof(*block), GFP_KERNEL); -+ if (!block) -+ return -EFAULT; -+ -+ if (copy_from_user(block, (void *)(arg + sizeof(ioparam)), -+ ioparam.op_count * sizeof(*block)) != 0) { -+ pr_err("[%s]: failed to copy-from-user payload for cmd %x\n", -+ __func__, cmdnr); -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ for (i = 0; i < ioparam.op_count; i++) { -+ const struct vc_sm_cma_ioctl_clean_invalid_block * const op = -+ block + i; -+ -+ if (op->invalidate_mode == VC_SM_CACHE_OP_NOP) -+ continue; -+ -+ ret = clean_invalid_contig_2d((void __user *)op->start_address, -+ op->block_count, op->block_size, -+ op->inter_block_stride, -+ op->invalidate_mode); -+ if (ret) -+ break; -+ } -+out: -+ kfree(block); -+ -+ return ret; -+} -+#endif -+ -+static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ int ret = 0; -+ unsigned int cmdnr = _IOC_NR(cmd); -+ struct vc_sm_privdata_t *file_data = -+ (struct vc_sm_privdata_t *)file->private_data; -+ -+ /* Validate we can work with this device. */ -+ if (!sm_state || !file_data) { -+ pr_err("[%s]: invalid device\n", __func__); -+ return -EPERM; -+ } -+ -+ /* Action is a re-post of a previously interrupted action? */ -+ if (file_data->restart_sys == -EINTR) { -+ struct vc_sm_action_clean_t action_clean; -+ -+ pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n", -+ __func__, file_data->int_action, -+ file_data->int_trans_id); -+ -+ action_clean.res_action = file_data->int_action; -+ action_clean.action_trans_id = file_data->int_trans_id; -+ -+ file_data->restart_sys = 0; -+ } -+ -+ /* Now process the command. */ -+ switch (cmdnr) { -+ /* New memory allocation. -+ */ -+ case VC_SM_CMA_CMD_ALLOC: -+ { -+ struct vc_sm_cma_ioctl_alloc ioparam; -+ -+ /* Get the parameter data. */ -+ if (copy_from_user -+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { -+ pr_err("[%s]: failed to copy-from-user for cmd %x\n", -+ __func__, cmdnr); -+ ret = -EFAULT; -+ break; -+ } -+ -+ ret = vc_sm_cma_ioctl_alloc(file_data, &ioparam); -+ if (!ret && -+ (copy_to_user((void *)arg, &ioparam, -+ sizeof(ioparam)) != 0)) { -+ /* FIXME: Release allocation */ -+ pr_err("[%s]: failed to copy-to-user for cmd %x\n", -+ __func__, cmdnr); -+ ret = -EFAULT; -+ } -+ break; -+ } -+ -+ case VC_SM_CMA_CMD_IMPORT_DMABUF: -+ { -+ struct vc_sm_cma_ioctl_import_dmabuf ioparam; -+ struct dma_buf *new_dmabuf; -+ -+ /* Get the parameter data. */ -+ if (copy_from_user -+ (&ioparam, (void *)arg, sizeof(ioparam)) != 0) { -+ pr_err("[%s]: failed to copy-from-user for cmd %x\n", -+ __func__, cmdnr); -+ ret = -EFAULT; -+ break; -+ } -+ -+ ret = vc_sm_cma_import_dmabuf_internal(file_data, -+ NULL, -+ ioparam.dmabuf_fd, -+ &new_dmabuf); -+ -+ if (!ret) { -+ struct vc_sm_buffer *buf = new_dmabuf->priv; -+ -+ ioparam.size = buf->size; -+ ioparam.handle = dma_buf_fd(new_dmabuf, -+ O_CLOEXEC); -+ ioparam.vc_handle = buf->vc_handle; -+ ioparam.dma_addr = buf->dma_addr; -+ -+ if (ioparam.handle < 0 || -+ (copy_to_user((void *)arg, &ioparam, -+ sizeof(ioparam)) != 0)) { -+ dma_buf_put(new_dmabuf); -+ /* FIXME: Release allocation */ -+ ret = -EFAULT; -+ } -+ } -+ break; -+ } -+ -+#ifndef CONFIG_ARM64 -+ /* -+ * Flush/Invalidate the cache for a given mapping. -+ * Blocks must be pinned (i.e. accessed) before this call. -+ */ -+ case VC_SM_CMA_CMD_CLEAN_INVALID2: -+ ret = vc_sm_cma_clean_invalid2(cmdnr, arg); -+ break; -+#endif -+ -+ default: -+ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr, -+ current->tgid, file_data->pid); -+ -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+#ifdef CONFIG_COMPAT -+struct vc_sm_cma_ioctl_clean_invalid2_32 { -+ u32 op_count; -+ struct vc_sm_cma_ioctl_clean_invalid_block_32 { -+ u16 invalidate_mode; -+ u16 block_count; -+ compat_uptr_t start_address; -+ u32 block_size; -+ u32 inter_block_stride; -+ } s[0]; -+}; -+ -+#define VC_SM_CMA_CMD_CLEAN_INVALID2_32\ -+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\ -+ struct vc_sm_cma_ioctl_clean_invalid2_32) -+ -+static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ switch (cmd) { -+ case VC_SM_CMA_CMD_CLEAN_INVALID2_32: -+ /* FIXME */ -+ return -EINVAL; -+ -+ default: -+ return vc_sm_cma_ioctl(file, cmd, arg); -+ } -+} -+#endif -+ -+/* Device operations that we managed in this driver. */ -+static const struct file_operations vc_sm_ops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = vc_sm_cma_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = vc_sm_cma_compat_ioctl, -+#endif -+ .open = vc_sm_cma_open, -+ .release = vc_sm_cma_release, -+}; -+ -+/* Driver load/unload functions */ -+/* Videocore connected. */ -+static void vc_sm_connected_init(void) -+{ -+ int ret; -+ VCHI_INSTANCE_T vchi_instance; -+ struct vc_sm_version version; -+ struct vc_sm_result_t version_result; -+ -+ pr_info("[%s]: start\n", __func__); -+ -+ /* -+ * Initialize and create a VCHI connection for the shared memory service -+ * running on videocore. -+ */ -+ ret = vchi_initialise(&vchi_instance); -+ if (ret) { -+ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n", -+ __func__, ret); -+ -+ return; -+ } -+ -+ ret = vchi_connect(vchi_instance); -+ if (ret) { -+ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n", -+ __func__, ret); -+ -+ return; -+ } -+ -+ /* Initialize an instance of the shared memory service. */ -+ sm_state->sm_handle = vc_sm_cma_vchi_init(vchi_instance, 1, -+ vc_sm_vpu_event); -+ if (!sm_state->sm_handle) { -+ pr_err("[%s]: failed to initialize shared memory service\n", -+ __func__); -+ -+ return; -+ } -+ -+ /* Create a debug fs directory entry (root). */ -+ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL); -+ -+ sm_state->dir_state.show = &vc_sm_cma_global_state_show; -+ sm_state->dir_state.dir_entry = -+ debugfs_create_file(VC_SM_STATE, 0444, sm_state->dir_root, -+ &sm_state->dir_state, -+ &vc_sm_cma_debug_fs_fops); -+ -+ INIT_LIST_HEAD(&sm_state->buffer_list); -+ -+ /* Create a shared memory device. */ -+ sm_state->misc_dev.minor = MISC_DYNAMIC_MINOR; -+ sm_state->misc_dev.name = DEVICE_NAME; -+ sm_state->misc_dev.fops = &vc_sm_ops; -+ sm_state->misc_dev.parent = NULL; -+ /* Temporarily set as 666 until udev rules have been sorted */ -+ sm_state->misc_dev.mode = 0666; -+ ret = misc_register(&sm_state->misc_dev); -+ if (ret) { -+ pr_err("vcsm-cma: failed to register misc device.\n"); -+ goto err_remove_debugfs; -+ } -+ -+ sm_state->data_knl = vc_sm_cma_create_priv_data(0); -+ if (!sm_state->data_knl) { -+ pr_err("[%s]: failed to create kernel private data tracker\n", -+ __func__); -+ goto err_remove_misc_dev; -+ } -+ -+ version.version = 2; -+ ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version, -+ &version_result, -+ &sm_state->int_trans_id); -+ if (ret) { -+ pr_err("[%s]: Failed to send version request %d\n", __func__, -+ ret); -+ } -+ -+ /* Done! */ -+ sm_inited = 1; -+ pr_info("[%s]: installed successfully\n", __func__); -+ return; -+ -+err_remove_misc_dev: -+ misc_deregister(&sm_state->misc_dev); -+err_remove_debugfs: -+ debugfs_remove_recursive(sm_state->dir_root); -+ vc_sm_cma_vchi_stop(&sm_state->sm_handle); -+} -+ -+/* Driver loading. */ -+static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev) -+{ -+ pr_info("%s: Videocore shared memory driver\n", __func__); -+ -+ sm_state = devm_kzalloc(&pdev->dev, sizeof(*sm_state), GFP_KERNEL); -+ if (!sm_state) -+ return -ENOMEM; -+ sm_state->pdev = pdev; -+ mutex_init(&sm_state->map_lock); -+ -+ spin_lock_init(&sm_state->kernelid_map_lock); -+ idr_init_base(&sm_state->kernelid_map, 1); -+ -+ pdev->dev.dma_parms = devm_kzalloc(&pdev->dev, -+ sizeof(*pdev->dev.dma_parms), -+ GFP_KERNEL); -+ /* dma_set_max_seg_size checks if dma_parms is NULL. */ -+ dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF); -+ -+ vchiq_add_connected_callback(vc_sm_connected_init); -+ return 0; -+} -+ -+/* Driver unloading. */ -+static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev) -+{ -+ pr_debug("[%s]: start\n", __func__); -+ if (sm_inited) { -+ misc_deregister(&sm_state->misc_dev); -+ -+ /* Remove all proc entries. */ -+ debugfs_remove_recursive(sm_state->dir_root); -+ -+ /* Stop the videocore shared memory service. */ -+ vc_sm_cma_vchi_stop(&sm_state->sm_handle); -+ } -+ -+ if (sm_state) { -+ idr_destroy(&sm_state->kernelid_map); -+ -+ /* Free the memory for the state structure. */ -+ mutex_destroy(&sm_state->map_lock); -+ } -+ -+ pr_debug("[%s]: end\n", __func__); -+ return 0; -+} -+ -+/* Kernel API calls */ -+/* Get an internal resource handle mapped from the external one. */ -+int vc_sm_cma_int_handle(void *handle) -+{ -+ struct dma_buf *dma_buf = (struct dma_buf *)handle; -+ struct vc_sm_buffer *buf; -+ -+ /* Validate we can work with this device. */ -+ if (!sm_state || !handle) { -+ pr_err("[%s]: invalid input\n", __func__); -+ return 0; -+ } -+ -+ buf = (struct vc_sm_buffer *)dma_buf->priv; -+ return buf->vc_handle; -+} -+EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle); -+ -+/* Free a previously allocated shared memory handle and block. */ -+int vc_sm_cma_free(void *handle) -+{ -+ struct dma_buf *dma_buf = (struct dma_buf *)handle; -+ -+ /* Validate we can work with this device. */ -+ if (!sm_state || !handle) { -+ pr_err("[%s]: invalid input\n", __func__); -+ return -EPERM; -+ } -+ -+ pr_debug("%s: handle %p/dmabuf %p\n", __func__, handle, dma_buf); -+ -+ dma_buf_put(dma_buf); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(vc_sm_cma_free); -+ -+/* Import a dmabuf to be shared with VC. */ -+int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, void **handle) -+{ -+ struct dma_buf *new_dma_buf; -+ struct vc_sm_buffer *buf; -+ int ret; -+ -+ /* Validate we can work with this device. */ -+ if (!sm_state || !src_dmabuf || !handle) { -+ pr_err("[%s]: invalid input\n", __func__); -+ return -EPERM; -+ } -+ -+ ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf, -+ -1, &new_dma_buf); -+ -+ if (!ret) { -+ pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf); -+ buf = (struct vc_sm_buffer *)new_dma_buf->priv; -+ -+ /* Assign valid handle at this time.*/ -+ *handle = new_dma_buf; -+ } else { -+ /* -+ * succeeded in importing the dma_buf, but then -+ * failed to look it up again. How? -+ * Release the fd again. -+ */ -+ pr_err("%s: imported vc_sm_cma_get_buffer failed %d\n", -+ __func__, ret); -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(vc_sm_cma_import_dmabuf); -+ -+static struct platform_driver bcm2835_vcsm_cma_driver = { -+ .probe = bcm2835_vc_sm_cma_probe, -+ .remove = bcm2835_vc_sm_cma_remove, -+ .driver = { -+ .name = DEVICE_NAME, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+module_platform_driver(bcm2835_vcsm_cma_driver); -+ -+MODULE_AUTHOR("Dave Stevenson"); -+MODULE_DESCRIPTION("VideoCore CMA Shared Memory Driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:vcsm-cma"); ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h -@@ -0,0 +1,84 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* -+ * VideoCore Shared Memory driver using CMA. -+ * -+ * Copyright: 2018, Raspberry Pi (Trading) Ltd -+ * -+ */ -+ -+#ifndef VC_SM_H -+#define VC_SM_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define VC_SM_MAX_NAME_LEN 32 -+ -+enum vc_sm_vpu_mapping_state { -+ VPU_NOT_MAPPED, -+ VPU_MAPPED, -+ VPU_UNMAPPING -+}; -+ -+struct vc_sm_alloc_data { -+ unsigned long num_pages; -+ void *priv_virt; -+ struct sg_table *sg_table; -+}; -+ -+struct vc_sm_imported { -+ struct dma_buf *dma_buf; -+ struct dma_buf_attachment *attach; -+ struct sg_table *sgt; -+}; -+ -+struct vc_sm_buffer { -+ struct list_head global_buffer_list; /* Global list of buffers. */ -+ -+ /* Index in the kernel_id idr so that we can find the -+ * mmal_msg_context again when servicing the VCHI reply. -+ */ -+ int kernel_id; -+ -+ size_t size; -+ -+ /* Lock over all the following state for this buffer */ -+ struct mutex lock; -+ struct list_head attachments; -+ -+ char name[VC_SM_MAX_NAME_LEN]; -+ -+ int in_use:1; /* Kernel is still using this resource */ -+ int imported:1; /* Imported dmabuf */ -+ -+ enum vc_sm_vpu_mapping_state vpu_state; -+ u32 vc_handle; /* VideoCore handle for this buffer */ -+ int vpu_allocated; /* -+ * The VPU made this allocation. Release the -+ * local dma_buf when the VPU releases the -+ * resource. -+ */ -+ -+ /* DMABUF related fields */ -+ struct dma_buf *dma_buf; -+ dma_addr_t dma_addr; -+ void *cookie; -+ -+ struct vc_sm_privdata_t *private; -+ -+ union { -+ struct vc_sm_alloc_data alloc; -+ struct vc_sm_imported import; -+ }; -+}; -+ -+#endif ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c -@@ -0,0 +1,505 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * VideoCore Shared Memory CMA allocator -+ * -+ * Copyright: 2018, Raspberry Pi (Trading) Ltd -+ * Copyright 2011-2012 Broadcom Corporation. All rights reserved. -+ * -+ * Based on vmcs_sm driver from Broadcom Corporation. -+ * -+ */ -+ -+/* ---- Include Files ----------------------------------------------------- */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "vc_sm_cma_vchi.h" -+ -+#define VC_SM_VER 1 -+#define VC_SM_MIN_VER 0 -+ -+/* ---- Private Constants and Types -------------------------------------- */ -+ -+/* Command blocks come from a pool */ -+#define SM_MAX_NUM_CMD_RSP_BLKS 32 -+ -+struct sm_cmd_rsp_blk { -+ struct list_head head; /* To create lists */ -+ /* To be signaled when the response is there */ -+ struct completion cmplt; -+ -+ u16 id; -+ u16 length; -+ -+ u8 msg[VC_SM_MAX_MSG_LEN]; -+ -+ uint32_t wait:1; -+ uint32_t sent:1; -+ uint32_t alloc:1; -+ -+}; -+ -+struct sm_instance { -+ u32 num_connections; -+ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS]; -+ struct task_struct *io_thread; -+ struct completion io_cmplt; -+ -+ vpu_event_cb vpu_event; -+ -+ /* Mutex over the following lists */ -+ struct mutex lock; -+ u32 trans_id; -+ struct list_head cmd_list; -+ struct list_head rsp_list; -+ struct list_head dead_list; -+ -+ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS]; -+ -+ /* Mutex over the free_list */ -+ struct mutex free_lock; -+ struct list_head free_list; -+ -+ struct semaphore free_sema; -+ -+}; -+ -+/* ---- Private Variables ------------------------------------------------ */ -+ -+/* ---- Private Function Prototypes -------------------------------------- */ -+ -+/* ---- Private Functions ------------------------------------------------ */ -+static int -+bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, -+ void *data, -+ unsigned int size) -+{ -+ return vchi_queue_kernel_message(handle, -+ data, -+ size); -+} -+ -+static struct -+sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance, -+ enum vc_sm_msg_type id, void *msg, -+ u32 size, int wait) -+{ -+ struct sm_cmd_rsp_blk *blk; -+ struct vc_sm_msg_hdr_t *hdr; -+ -+ if (down_interruptible(&instance->free_sema)) { -+ blk = kmalloc(sizeof(*blk), GFP_KERNEL); -+ if (!blk) -+ return NULL; -+ -+ blk->alloc = 1; -+ init_completion(&blk->cmplt); -+ } else { -+ mutex_lock(&instance->free_lock); -+ blk = -+ list_first_entry(&instance->free_list, -+ struct sm_cmd_rsp_blk, head); -+ list_del(&blk->head); -+ mutex_unlock(&instance->free_lock); -+ } -+ -+ blk->sent = 0; -+ blk->wait = wait; -+ blk->length = sizeof(*hdr) + size; -+ -+ hdr = (struct vc_sm_msg_hdr_t *)blk->msg; -+ hdr->type = id; -+ mutex_lock(&instance->lock); -+ instance->trans_id++; -+ /* -+ * Retain the top bit for identifying asynchronous events, or VPU cmds. -+ */ -+ instance->trans_id &= ~0x80000000; -+ hdr->trans_id = instance->trans_id; -+ blk->id = instance->trans_id; -+ mutex_unlock(&instance->lock); -+ -+ if (size) -+ memcpy(hdr->body, msg, size); -+ -+ return blk; -+} -+ -+static void -+vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk) -+{ -+ if (blk->alloc) { -+ kfree(blk); -+ return; -+ } -+ -+ mutex_lock(&instance->free_lock); -+ list_add(&blk->head, &instance->free_list); -+ mutex_unlock(&instance->free_lock); -+ up(&instance->free_sema); -+} -+ -+static void vc_sm_cma_vchi_rx_ack(struct sm_instance *instance, -+ struct sm_cmd_rsp_blk *cmd, -+ struct vc_sm_result_t *reply, -+ u32 reply_len) -+{ -+ mutex_lock(&instance->lock); -+ list_for_each_entry(cmd, -+ &instance->rsp_list, -+ head) { -+ if (cmd->id == reply->trans_id) -+ break; -+ } -+ mutex_unlock(&instance->lock); -+ -+ if (&cmd->head == &instance->rsp_list) { -+ //pr_debug("%s: received response %u, throw away...", -+ pr_err("%s: received response %u, throw away...", -+ __func__, -+ reply->trans_id); -+ } else if (reply_len > sizeof(cmd->msg)) { -+ pr_err("%s: reply too big (%u) %u, throw away...", -+ __func__, reply_len, -+ reply->trans_id); -+ } else { -+ memcpy(cmd->msg, reply, -+ reply_len); -+ complete(&cmd->cmplt); -+ } -+} -+ -+static int vc_sm_cma_vchi_videocore_io(void *arg) -+{ -+ struct sm_instance *instance = arg; -+ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp; -+ struct vc_sm_result_t *reply; -+ u32 reply_len; -+ s32 status; -+ int svc_use = 1; -+ -+ while (1) { -+ if (svc_use) -+ vchi_service_release(instance->vchi_handle[0]); -+ svc_use = 0; -+ -+ if (wait_for_completion_interruptible(&instance->io_cmplt)) -+ continue; -+ -+ vchi_service_use(instance->vchi_handle[0]); -+ svc_use = 1; -+ -+ do { -+ /* -+ * Get new command and move it to response list -+ */ -+ mutex_lock(&instance->lock); -+ if (list_empty(&instance->cmd_list)) { -+ /* no more commands to process */ -+ mutex_unlock(&instance->lock); -+ break; -+ } -+ cmd = list_first_entry(&instance->cmd_list, -+ struct sm_cmd_rsp_blk, head); -+ list_move(&cmd->head, &instance->rsp_list); -+ cmd->sent = 1; -+ mutex_unlock(&instance->lock); -+ -+ /* Send the command */ -+ status = -+ bcm2835_vchi_msg_queue(instance->vchi_handle[0], -+ cmd->msg, cmd->length); -+ if (status) { -+ pr_err("%s: failed to queue message (%d)", -+ __func__, status); -+ } -+ -+ /* If no reply is needed then we're done */ -+ if (!cmd->wait) { -+ mutex_lock(&instance->lock); -+ list_del(&cmd->head); -+ mutex_unlock(&instance->lock); -+ vc_vchi_cmd_delete(instance, cmd); -+ continue; -+ } -+ -+ if (status) { -+ complete(&cmd->cmplt); -+ continue; -+ } -+ -+ } while (1); -+ -+ while (!vchi_msg_peek(instance->vchi_handle[0], (void **)&reply, -+ &reply_len, VCHI_FLAGS_NONE)) { -+ if (reply->trans_id & 0x80000000) { -+ /* Async event or cmd from the VPU */ -+ if (instance->vpu_event) -+ instance->vpu_event(instance, reply, -+ reply_len); -+ } else { -+ vc_sm_cma_vchi_rx_ack(instance, cmd, reply, -+ reply_len); -+ } -+ -+ vchi_msg_remove(instance->vchi_handle[0]); -+ } -+ -+ /* Go through the dead list and free them */ -+ mutex_lock(&instance->lock); -+ list_for_each_entry_safe(cmd, cmd_tmp, &instance->dead_list, -+ head) { -+ list_del(&cmd->head); -+ vc_vchi_cmd_delete(instance, cmd); -+ } -+ mutex_unlock(&instance->lock); -+ } -+ -+ return 0; -+} -+ -+static void vc_sm_cma_vchi_callback(void *param, -+ const VCHI_CALLBACK_REASON_T reason, -+ void *msg_handle) -+{ -+ struct sm_instance *instance = param; -+ -+ (void)msg_handle; -+ -+ switch (reason) { -+ case VCHI_CALLBACK_MSG_AVAILABLE: -+ complete(&instance->io_cmplt); -+ break; -+ -+ case VCHI_CALLBACK_SERVICE_CLOSED: -+ pr_info("%s: service CLOSED!!", __func__); -+ default: -+ break; -+ } -+} -+ -+struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance, -+ unsigned int num_connections, -+ vpu_event_cb vpu_event) -+{ -+ u32 i; -+ struct sm_instance *instance; -+ int status; -+ -+ pr_debug("%s: start", __func__); -+ -+ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) { -+ pr_err("%s: unsupported number of connections %u (max=%u)", -+ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS); -+ -+ goto err_null; -+ } -+ /* Allocate memory for this instance */ -+ instance = kzalloc(sizeof(*instance), GFP_KERNEL); -+ -+ /* Misc initialisations */ -+ mutex_init(&instance->lock); -+ init_completion(&instance->io_cmplt); -+ INIT_LIST_HEAD(&instance->cmd_list); -+ INIT_LIST_HEAD(&instance->rsp_list); -+ INIT_LIST_HEAD(&instance->dead_list); -+ INIT_LIST_HEAD(&instance->free_list); -+ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS); -+ mutex_init(&instance->free_lock); -+ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) { -+ init_completion(&instance->free_blk[i].cmplt); -+ list_add(&instance->free_blk[i].head, &instance->free_list); -+ } -+ -+ /* Open the VCHI service connections */ -+ instance->num_connections = num_connections; -+ for (i = 0; i < num_connections; i++) { -+ struct service_creation params = { -+ .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER), -+ .service_id = VC_SM_SERVER_NAME, -+ .callback = vc_sm_cma_vchi_callback, -+ .callback_param = instance, -+ }; -+ -+ status = vchi_service_open(vchi_instance, -+ ¶ms, &instance->vchi_handle[i]); -+ if (status) { -+ pr_err("%s: failed to open VCHI service (%d)", -+ __func__, status); -+ -+ goto err_close_services; -+ } -+ } -+ -+ /* Create the thread which takes care of all io to/from videoocore. */ -+ instance->io_thread = kthread_create(&vc_sm_cma_vchi_videocore_io, -+ (void *)instance, "SMIO"); -+ if (!instance->io_thread) { -+ pr_err("%s: failed to create SMIO thread", __func__); -+ -+ goto err_close_services; -+ } -+ instance->vpu_event = vpu_event; -+ set_user_nice(instance->io_thread, -10); -+ wake_up_process(instance->io_thread); -+ -+ pr_debug("%s: success - instance %p", __func__, instance); -+ return instance; -+ -+err_close_services: -+ for (i = 0; i < instance->num_connections; i++) { -+ if (instance->vchi_handle[i]) -+ vchi_service_close(instance->vchi_handle[i]); -+ } -+ kfree(instance); -+err_null: -+ pr_debug("%s: FAILED", __func__); -+ return NULL; -+} -+ -+int vc_sm_cma_vchi_stop(struct sm_instance **handle) -+{ -+ struct sm_instance *instance; -+ u32 i; -+ -+ if (!handle) { -+ pr_err("%s: invalid pointer to handle %p", __func__, handle); -+ goto lock; -+ } -+ -+ if (!*handle) { -+ pr_err("%s: invalid handle %p", __func__, *handle); -+ goto lock; -+ } -+ -+ instance = *handle; -+ -+ /* Close all VCHI service connections */ -+ for (i = 0; i < instance->num_connections; i++) { -+ s32 success; -+ -+ vchi_service_use(instance->vchi_handle[i]); -+ -+ success = vchi_service_close(instance->vchi_handle[i]); -+ } -+ -+ kfree(instance); -+ -+ *handle = NULL; -+ return 0; -+ -+lock: -+ return -EINVAL; -+} -+ -+static int vc_sm_cma_vchi_send_msg(struct sm_instance *handle, -+ enum vc_sm_msg_type msg_id, void *msg, -+ u32 msg_size, void *result, u32 result_size, -+ u32 *cur_trans_id, u8 wait_reply) -+{ -+ int status = 0; -+ struct sm_instance *instance = handle; -+ struct sm_cmd_rsp_blk *cmd_blk; -+ -+ if (!handle) { -+ pr_err("%s: invalid handle", __func__); -+ return -EINVAL; -+ } -+ if (!msg) { -+ pr_err("%s: invalid msg pointer", __func__); -+ return -EINVAL; -+ } -+ -+ cmd_blk = -+ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply); -+ if (!cmd_blk) { -+ pr_err("[%s]: failed to allocate global tracking resource", -+ __func__); -+ return -ENOMEM; -+ } -+ -+ if (cur_trans_id) -+ *cur_trans_id = cmd_blk->id; -+ -+ mutex_lock(&instance->lock); -+ list_add_tail(&cmd_blk->head, &instance->cmd_list); -+ mutex_unlock(&instance->lock); -+ complete(&instance->io_cmplt); -+ -+ if (!wait_reply) -+ /* We're done */ -+ return 0; -+ -+ /* Wait for the response */ -+ if (wait_for_completion_interruptible(&cmd_blk->cmplt)) { -+ mutex_lock(&instance->lock); -+ if (!cmd_blk->sent) { -+ list_del(&cmd_blk->head); -+ mutex_unlock(&instance->lock); -+ vc_vchi_cmd_delete(instance, cmd_blk); -+ return -ENXIO; -+ } -+ -+ list_move(&cmd_blk->head, &instance->dead_list); -+ mutex_unlock(&instance->lock); -+ complete(&instance->io_cmplt); -+ return -EINTR; /* We're done */ -+ } -+ -+ if (result && result_size) { -+ memcpy(result, cmd_blk->msg, result_size); -+ } else { -+ struct vc_sm_result_t *res = -+ (struct vc_sm_result_t *)cmd_blk->msg; -+ status = (res->success == 0) ? 0 : -ENXIO; -+ } -+ -+ mutex_lock(&instance->lock); -+ list_del(&cmd_blk->head); -+ mutex_unlock(&instance->lock); -+ vc_vchi_cmd_delete(instance, cmd_blk); -+ return status; -+} -+ -+int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg, -+ u32 *cur_trans_id) -+{ -+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_FREE, -+ msg, sizeof(*msg), 0, 0, cur_trans_id, 0); -+} -+ -+int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg, -+ struct vc_sm_import_result *result, u32 *cur_trans_id) -+{ -+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_IMPORT, -+ msg, sizeof(*msg), result, sizeof(*result), -+ cur_trans_id, 1); -+} -+ -+int vc_sm_cma_vchi_client_version(struct sm_instance *handle, -+ struct vc_sm_version *msg, -+ struct vc_sm_result_t *result, -+ u32 *cur_trans_id) -+{ -+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_CLIENT_VERSION, -+ //msg, sizeof(*msg), result, sizeof(*result), -+ //cur_trans_id, 1); -+ msg, sizeof(*msg), NULL, 0, -+ cur_trans_id, 0); -+} -+ -+int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle, -+ struct vc_sm_vc_mem_request_result *msg, -+ uint32_t *cur_trans_id) -+{ -+ return vc_sm_cma_vchi_send_msg(handle, -+ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY, -+ msg, sizeof(*msg), 0, 0, cur_trans_id, -+ 0); -+} ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h -@@ -0,0 +1,63 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* -+ * VideoCore Shared Memory CMA allocator -+ * -+ * Copyright: 2018, Raspberry Pi (Trading) Ltd -+ * Copyright 2011-2012 Broadcom Corporation. All rights reserved. -+ * -+ * Based on vmcs_sm driver from Broadcom Corporation. -+ * -+ */ -+ -+#ifndef __VC_SM_CMA_VCHI_H__INCLUDED__ -+#define __VC_SM_CMA_VCHI_H__INCLUDED__ -+ -+#include "interface/vchi/vchi.h" -+ -+#include "vc_sm_defs.h" -+ -+/* -+ * Forward declare. -+ */ -+struct sm_instance; -+ -+typedef void (*vpu_event_cb)(struct sm_instance *instance, -+ struct vc_sm_result_t *reply, int reply_len); -+ -+/* -+ * Initialize the shared memory service, opens up vchi connection to talk to it. -+ */ -+struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance, -+ unsigned int num_connections, -+ vpu_event_cb vpu_event); -+ -+/* -+ * Terminates the shared memory service. -+ */ -+int vc_sm_cma_vchi_stop(struct sm_instance **handle); -+ -+/* -+ * Ask the shared memory service to free up some memory that was previously -+ * allocated by the vc_sm_cma_vchi_alloc function call. -+ */ -+int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg, -+ u32 *cur_trans_id); -+ -+/* -+ * Import a contiguous block of memory and wrap it in a GPU MEM_HANDLE_T. -+ */ -+int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg, -+ struct vc_sm_import_result *result, -+ u32 *cur_trans_id); -+ -+int vc_sm_cma_vchi_client_version(struct sm_instance *handle, -+ struct vc_sm_version *msg, -+ struct vc_sm_result_t *result, -+ u32 *cur_trans_id); -+ -+int vc_sm_vchi_client_vc_mem_req_reply(struct sm_instance *handle, -+ struct vc_sm_vc_mem_request_result *msg, -+ uint32_t *cur_trans_id); -+ -+#endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */ ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h -@@ -0,0 +1,300 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* -+ * VideoCore Shared Memory CMA allocator -+ * -+ * Copyright: 2018, Raspberry Pi (Trading) Ltd -+ * -+ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation. -+ * All IPC messages are copied across to this file, even if the vc-sm-cma -+ * driver is not currently using them. -+ * -+ **************************************************************************** -+ */ -+ -+#ifndef __VC_SM_DEFS_H__INCLUDED__ -+#define __VC_SM_DEFS_H__INCLUDED__ -+ -+/* FourCC code used for VCHI connection */ -+#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM") -+ -+/* Maximum message length */ -+#define VC_SM_MAX_MSG_LEN (sizeof(union vc_sm_msg_union_t) + \ -+ sizeof(struct vc_sm_msg_hdr_t)) -+#define VC_SM_MAX_RSP_LEN (sizeof(union vc_sm_msg_union_t)) -+ -+/* Resource name maximum size */ -+#define VC_SM_RESOURCE_NAME 32 -+ -+/* -+ * Version to be reported to the VPU -+ * VPU assumes 0 (aka 1) which does not require the released callback, nor -+ * expect the client to handle VC_MEM_REQUESTS. -+ * Version 2 requires the released callback, and must support VC_MEM_REQUESTS. -+ */ -+#define VC_SM_PROTOCOL_VERSION 2 -+ -+enum vc_sm_msg_type { -+ /* Message types supported for HOST->VC direction */ -+ -+ /* Allocate shared memory block */ -+ VC_SM_MSG_TYPE_ALLOC, -+ /* Lock allocated shared memory block */ -+ VC_SM_MSG_TYPE_LOCK, -+ /* Unlock allocated shared memory block */ -+ VC_SM_MSG_TYPE_UNLOCK, -+ /* Unlock allocated shared memory block, do not answer command */ -+ VC_SM_MSG_TYPE_UNLOCK_NOANS, -+ /* Free shared memory block */ -+ VC_SM_MSG_TYPE_FREE, -+ /* Resize a shared memory block */ -+ VC_SM_MSG_TYPE_RESIZE, -+ /* Walk the allocated shared memory block(s) */ -+ VC_SM_MSG_TYPE_WALK_ALLOC, -+ -+ /* A previously applied action will need to be reverted */ -+ VC_SM_MSG_TYPE_ACTION_CLEAN, -+ -+ /* -+ * Import a physical address and wrap into a MEM_HANDLE_T. -+ * Release with VC_SM_MSG_TYPE_FREE. -+ */ -+ VC_SM_MSG_TYPE_IMPORT, -+ /* -+ *Tells VC the protocol version supported by this client. -+ * 2 supports the async/cmd messages from the VPU for final release -+ * of memory, and for VC allocations. -+ */ -+ VC_SM_MSG_TYPE_CLIENT_VERSION, -+ /* Response to VC request for memory */ -+ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY, -+ -+ /* -+ * Asynchronous/cmd messages supported for VC->HOST direction. -+ * Signalled by setting the top bit in vc_sm_result_t trans_id. -+ */ -+ -+ /* -+ * VC has finished with an imported memory allocation. -+ * Release any Linux reference counts on the underlying block. -+ */ -+ VC_SM_MSG_TYPE_RELEASED, -+ /* VC request for memory */ -+ VC_SM_MSG_TYPE_VC_MEM_REQUEST, -+ -+ VC_SM_MSG_TYPE_MAX -+}; -+ -+/* Type of memory to be allocated */ -+enum vc_sm_alloc_type_t { -+ VC_SM_ALLOC_CACHED, -+ VC_SM_ALLOC_NON_CACHED, -+}; -+ -+/* Message header for all messages in HOST->VC direction */ -+struct vc_sm_msg_hdr_t { -+ u32 type; -+ u32 trans_id; -+ u8 body[0]; -+ -+}; -+ -+/* Request to allocate memory (HOST->VC) */ -+struct vc_sm_alloc_t { -+ /* type of memory to allocate */ -+ enum vc_sm_alloc_type_t type; -+ /* byte amount of data to allocate per unit */ -+ u32 base_unit; -+ /* number of unit to allocate */ -+ u32 num_unit; -+ /* alignment to be applied on allocation */ -+ u32 alignment; -+ /* identity of who allocated this block */ -+ u32 allocator; -+ /* resource name (for easier tracking on vc side) */ -+ char name[VC_SM_RESOURCE_NAME]; -+ -+}; -+ -+/* Result of a requested memory allocation (VC->HOST) */ -+struct vc_sm_alloc_result_t { -+ /* Transaction identifier */ -+ u32 trans_id; -+ -+ /* Resource handle */ -+ u32 res_handle; -+ /* Pointer to resource buffer */ -+ u32 res_mem; -+ /* Resource base size (bytes) */ -+ u32 res_base_size; -+ /* Resource number */ -+ u32 res_num; -+ -+}; -+ -+/* Request to free a previously allocated memory (HOST->VC) */ -+struct vc_sm_free_t { -+ /* Resource handle (returned from alloc) */ -+ u32 res_handle; -+ /* Resource buffer (returned from alloc) */ -+ u32 res_mem; -+ -+}; -+ -+/* Request to lock a previously allocated memory (HOST->VC) */ -+struct vc_sm_lock_unlock_t { -+ /* Resource handle (returned from alloc) */ -+ u32 res_handle; -+ /* Resource buffer (returned from alloc) */ -+ u32 res_mem; -+ -+}; -+ -+/* Request to resize a previously allocated memory (HOST->VC) */ -+struct vc_sm_resize_t { -+ /* Resource handle (returned from alloc) */ -+ u32 res_handle; -+ /* Resource buffer (returned from alloc) */ -+ u32 res_mem; -+ /* Resource *new* size requested (bytes) */ -+ u32 res_new_size; -+ -+}; -+ -+/* Result of a requested memory lock (VC->HOST) */ -+struct vc_sm_lock_result_t { -+ /* Transaction identifier */ -+ u32 trans_id; -+ -+ /* Resource handle */ -+ u32 res_handle; -+ /* Pointer to resource buffer */ -+ u32 res_mem; -+ /* -+ * Pointer to former resource buffer if the memory -+ * was reallocated -+ */ -+ u32 res_old_mem; -+ -+}; -+ -+/* Generic result for a request (VC->HOST) */ -+struct vc_sm_result_t { -+ /* Transaction identifier */ -+ u32 trans_id; -+ -+ s32 success; -+ -+}; -+ -+/* Request to revert a previously applied action (HOST->VC) */ -+struct vc_sm_action_clean_t { -+ /* Action of interest */ -+ enum vc_sm_msg_type res_action; -+ /* Transaction identifier for the action of interest */ -+ u32 action_trans_id; -+ -+}; -+ -+/* Request to remove all data associated with a given allocator (HOST->VC) */ -+struct vc_sm_free_all_t { -+ /* Allocator identifier */ -+ u32 allocator; -+}; -+ -+/* Request to import memory (HOST->VC) */ -+struct vc_sm_import { -+ /* type of memory to allocate */ -+ enum vc_sm_alloc_type_t type; -+ /* pointer to the VC (ie physical) address of the allocated memory */ -+ u32 addr; -+ /* size of buffer */ -+ u32 size; -+ /* opaque handle returned in RELEASED messages */ -+ u32 kernel_id; -+ /* Allocator identifier */ -+ u32 allocator; -+ /* resource name (for easier tracking on vc side) */ -+ char name[VC_SM_RESOURCE_NAME]; -+}; -+ -+/* Result of a requested memory import (VC->HOST) */ -+struct vc_sm_import_result { -+ /* Transaction identifier */ -+ u32 trans_id; -+ -+ /* Resource handle */ -+ u32 res_handle; -+}; -+ -+/* Notification that VC has finished with an allocation (VC->HOST) */ -+struct vc_sm_released { -+ /* cmd type / trans_id */ -+ u32 cmd; -+ -+ /* pointer to the VC (ie physical) address of the allocated memory */ -+ u32 addr; -+ /* size of buffer */ -+ u32 size; -+ /* opaque handle returned in RELEASED messages */ -+ u32 kernel_id; -+ u32 vc_handle; -+}; -+ -+/* -+ * Client informing VC as to the protocol version it supports. -+ * >=2 requires the released callback, and supports VC asking for memory. -+ * Failure means that the firmware doesn't support this call, and therefore the -+ * client should either fail, or NOT rely on getting the released callback. -+ */ -+struct vc_sm_version { -+ u32 version; -+}; -+ -+/* Request FROM VideoCore for some memory */ -+struct vc_sm_vc_mem_request { -+ /* cmd type */ -+ u32 cmd; -+ -+ /* trans_id (from VPU) */ -+ u32 trans_id; -+ /* size of buffer */ -+ u32 size; -+ /* alignment of buffer */ -+ u32 align; -+ /* resource name (for easier tracking) */ -+ char name[VC_SM_RESOURCE_NAME]; -+ /* VPU handle for the resource */ -+ u32 vc_handle; -+}; -+ -+/* Response from the kernel to provide the VPU with some memory */ -+struct vc_sm_vc_mem_request_result { -+ /* Transaction identifier for the VPU */ -+ u32 trans_id; -+ /* pointer to the physical address of the allocated memory */ -+ u32 addr; -+ /* opaque handle returned in RELEASED messages */ -+ u32 kernel_id; -+}; -+ -+/* Union of ALL messages */ -+union vc_sm_msg_union_t { -+ struct vc_sm_alloc_t alloc; -+ struct vc_sm_alloc_result_t alloc_result; -+ struct vc_sm_free_t free; -+ struct vc_sm_lock_unlock_t lock_unlock; -+ struct vc_sm_action_clean_t action_clean; -+ struct vc_sm_resize_t resize; -+ struct vc_sm_lock_result_t lock_result; -+ struct vc_sm_result_t result; -+ struct vc_sm_free_all_t free_all; -+ struct vc_sm_import import; -+ struct vc_sm_import_result import_result; -+ struct vc_sm_version version; -+ struct vc_sm_released released; -+ struct vc_sm_vc_mem_request vc_request; -+ struct vc_sm_vc_mem_request_result vc_request_result; -+}; -+ -+#endif /* __VC_SM_DEFS_H__INCLUDED__ */ ---- /dev/null -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* -+ * VideoCore Shared Memory CMA allocator -+ * -+ * Copyright: 2018, Raspberry Pi (Trading) Ltd -+ * -+ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation. -+ * -+ */ -+ -+#ifndef __VC_SM_KNL_H__INCLUDED__ -+#define __VC_SM_KNL_H__INCLUDED__ -+ -+#if !defined(__KERNEL__) -+#error "This interface is for kernel use only..." -+#endif -+ -+/* Free a previously allocated or imported shared memory handle and block. */ -+int vc_sm_cma_free(void *handle); -+ -+/* Get an internal resource handle mapped from the external one. */ -+int vc_sm_cma_int_handle(void *handle); -+ -+/* Import a block of memory into the GPU space. */ -+int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, void **handle); -+ -+#endif /* __VC_SM_KNL_H__INCLUDED__ */ ---- a/drivers/staging/vc04_services/vchiq-mmal/Makefile -+++ b/drivers/staging/vc04_services/vchiq-mmal/Makefile -@@ -4,5 +4,5 @@ bcm2835-mmal-vchiq-objs := mmal-vchiq.o - obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += bcm2835-mmal-vchiq.o - - ccflags-y += \ -- -Idrivers/staging/vc04_services \ -+ -I$(srctree)/drivers/staging/vc04_services \ - -D__VCCOREVER__=0x04000000 ---- /dev/null -+++ b/include/linux/broadcom/vc_sm_cma_ioctl.h -@@ -0,0 +1,114 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* -+ * Copyright 2019 Raspberry Pi (Trading) Ltd. All rights reserved. -+ * -+ * Based on vmcs_sm_ioctl.h Copyright Broadcom Corporation. -+ */ -+ -+#ifndef __VC_SM_CMA_IOCTL_H -+#define __VC_SM_CMA_IOCTL_H -+ -+/* ---- Include Files ---------------------------------------------------- */ -+ -+#if defined(__KERNEL__) -+#include /* Needed for standard types */ -+#else -+#include -+#endif -+ -+#include -+ -+/* ---- Constants and Types ---------------------------------------------- */ -+ -+#define VC_SM_CMA_RESOURCE_NAME 32 -+#define VC_SM_CMA_RESOURCE_NAME_DEFAULT "sm-host-resource" -+ -+/* Type define used to create unique IOCTL number */ -+#define VC_SM_CMA_MAGIC_TYPE 'J' -+ -+/* IOCTL commands on /dev/vc-sm-cma */ -+enum vc_sm_cma_cmd_e { -+ VC_SM_CMA_CMD_ALLOC = 0x5A, /* Start at 0x5A arbitrarily */ -+ -+ VC_SM_CMA_CMD_IMPORT_DMABUF, -+ -+ VC_SM_CMA_CMD_CLEAN_INVALID2, -+ -+ VC_SM_CMA_CMD_LAST /* Do not delete */ -+}; -+ -+/* Cache type supported, conveniently matches the user space definition in -+ * user-vcsm.h. -+ */ -+enum vc_sm_cma_cache_e { -+ VC_SM_CMA_CACHE_NONE, -+ VC_SM_CMA_CACHE_HOST, -+ VC_SM_CMA_CACHE_VC, -+ VC_SM_CMA_CACHE_BOTH, -+}; -+ -+/* IOCTL Data structures */ -+struct vc_sm_cma_ioctl_alloc { -+ /* user -> kernel */ -+ __u32 size; -+ __u32 num; -+ __u32 cached; /* enum vc_sm_cma_cache_e */ -+ __u32 pad; -+ __u8 name[VC_SM_CMA_RESOURCE_NAME]; -+ -+ /* kernel -> user */ -+ __s32 handle; -+ __u32 vc_handle; -+ __u64 dma_addr; -+}; -+ -+struct vc_sm_cma_ioctl_import_dmabuf { -+ /* user -> kernel */ -+ __s32 dmabuf_fd; -+ __u32 cached; /* enum vc_sm_cma_cache_e */ -+ __u8 name[VC_SM_CMA_RESOURCE_NAME]; -+ -+ /* kernel -> user */ -+ __s32 handle; -+ __u32 vc_handle; -+ __u32 size; -+ __u32 pad; -+ __u64 dma_addr; -+}; -+ -+/* -+ * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2 -+ * invalidate_mode. -+ */ -+#define VC_SM_CACHE_OP_NOP 0x00 -+#define VC_SM_CACHE_OP_INV 0x01 -+#define VC_SM_CACHE_OP_CLEAN 0x02 -+#define VC_SM_CACHE_OP_FLUSH 0x03 -+ -+struct vc_sm_cma_ioctl_clean_invalid2 { -+ __u32 op_count; -+ __u32 pad; -+ struct vc_sm_cma_ioctl_clean_invalid_block { -+ __u32 invalidate_mode; -+ __u32 block_count; -+ void * __user start_address; -+ __u32 block_size; -+ __u32 inter_block_stride; -+ } s[0]; -+}; -+ -+/* IOCTL numbers */ -+#define VC_SM_CMA_IOCTL_MEM_ALLOC\ -+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\ -+ struct vc_sm_cma_ioctl_alloc) -+ -+#define VC_SM_CMA_IOCTL_MEM_IMPORT_DMABUF\ -+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\ -+ struct vc_sm_cma_ioctl_import_dmabuf) -+ -+#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\ -+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\ -+ struct vc_sm_cma_ioctl_clean_invalid2) -+ -+#endif /* __VC_SM_CMA_IOCTL_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0175-staging-vc04_services-Add-a-V4L2-M2M-codec-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0175-staging-vc04_services-Add-a-V4L2-M2M-codec-driver.patch new file mode 100644 index 0000000000..2093cf05cc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0175-staging-vc04_services-Add-a-V4L2-M2M-codec-driver.patch @@ -0,0 +1,2467 @@ +From 6b2e734af2943dbf31bafb4c4c2fb588eec8059f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 25 Sep 2018 14:53:49 +0100 +Subject: [PATCH] staging: vc04_services: Add a V4L2 M2M codec driver + +This adds a V4L2 memory to memory device that wraps the MMAL +video decode and video_encode components for H264 and MJPEG encode +and decode, MPEG4, H263, and VP8 decode (and MPEG2 decode +if the appropriate licence has been purchased). + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/Kconfig | 1 + + drivers/staging/vc04_services/Makefile | 9 +- + .../vc04_services/bcm2835-codec/Kconfig | 11 + + .../vc04_services/bcm2835-codec/Makefile | 8 + + .../staging/vc04_services/bcm2835-codec/TODO | 24 + + .../bcm2835-codec/bcm2835-v4l2-codec.c | 2359 +++++++++++++++++ + 6 files changed, 2408 insertions(+), 4 deletions(-) + create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Kconfig + create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Makefile + create mode 100644 drivers/staging/vc04_services/bcm2835-codec/TODO + create mode 100644 drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c + +--- a/drivers/staging/vc04_services/Kconfig ++++ b/drivers/staging/vc04_services/Kconfig +@@ -24,6 +24,7 @@ source "drivers/staging/vc04_services/bc + source "drivers/staging/vc04_services/bcm2835-camera/Kconfig" + source "drivers/staging/vc04_services/vchiq-mmal/Kconfig" + source "drivers/staging/vc04_services/vc-sm-cma/Kconfig" ++source "drivers/staging/vc04_services/bcm2835-codec/Kconfig" + + endif + +--- a/drivers/staging/vc04_services/Makefile ++++ b/drivers/staging/vc04_services/Makefile +@@ -10,10 +10,11 @@ vchiq-objs := \ + interface/vchiq_arm/vchiq_util.o \ + interface/vchiq_arm/vchiq_connected.o \ + +-obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ +-obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ +-obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ +-obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/ ++obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ ++obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ ++obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ ++obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/ ++obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec/ + + ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000 + +--- /dev/null ++++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig +@@ -0,0 +1,11 @@ ++config VIDEO_CODEC_BCM2835 ++ tristate "BCM2835 Video codec support" ++ depends on MEDIA_SUPPORT ++ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) ++ select BCM2835_VCHIQ_MMAL ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_MEM2MEM_DEV ++ help ++ Say Y here to enable the V4L2 video codecs for ++ Broadcom BCM2835 SoC. This operates over the VCHIQ interface ++ to a service running on VideoCore. +--- /dev/null ++++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0 ++bcm2835-codec-objs := bcm2835-v4l2-codec.o ++ ++obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o ++ ++ccflags-y += \ ++ -Idrivers/staging/vc04_services \ ++ -D__VCCOREVER__=0x04000000 +--- /dev/null ++++ b/drivers/staging/vc04_services/bcm2835-codec/TODO +@@ -0,0 +1,24 @@ ++1) Convert to be a platform driver. ++ ++Right now when the module probes, it tries to initialize VCHI and ++errors out if it wasn't ready yet. If bcm2835-v4l2 was built in, then ++VCHI generally isn't ready because it depends on both the firmware and ++mailbox drivers having already loaded. ++ ++We should have VCHI create a platform device once it's initialized, ++and have this driver bind to it, so that we automatically load the ++v4l2 module after VCHI loads. ++ ++2) Support SELECTION API to define crop region on the image for encode. ++ ++Particularly for resolutions that aren't a multiple of the macroblock ++size, the codec will report a resolution that is a multiple of the macroblock ++size (it has to have the memory to decode into), and then a different crop ++region within that buffer. ++The most common example is 1080P, where the buffer will be 1920x1088 with a ++crop region of 1920x1080. ++ ++3) Refactor so that the component creation is only on queue_setup, not open. ++ ++Fixes v4l2-compliance failure on trying to open 100 instances of the ++device. +\ No newline at end of file +--- /dev/null ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -0,0 +1,2359 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* ++ * A v4l2-mem2mem device that wraps the video codec MMAL component. ++ * ++ * Copyright 2018 Raspberry Pi (Trading) Ltd. ++ * Author: Dave Stevenson (dave.stevenson@raspberrypi.org) ++ * ++ * Loosely based on the vim2m virtual driver by Pawel Osciak ++ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. ++ * Pawel Osciak, ++ * Marek Szyprowski, ++ * ++ * Whilst this driver uses the v4l2_mem2mem framework, it does not need the ++ * scheduling aspects, so will always take the buffers, pass them to the VPU, ++ * and then signal the job as complete. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vchiq-mmal/mmal-encodings.h" ++#include "vchiq-mmal/mmal-msg.h" ++#include "vchiq-mmal/mmal-parameters.h" ++#include "vchiq-mmal/mmal-vchiq.h" ++ ++/* ++ * Default /dev/videoN node numbers for decode and encode. ++ * Deliberately avoid the very low numbers as these are often taken by webcams ++ * etc, and simple apps tend to only go for /dev/video0. ++ */ ++static int decode_video_nr = 10; ++module_param(decode_video_nr, int, 0644); ++MODULE_PARM_DESC(decode_video_nr, "decoder video device number"); ++ ++static int encode_video_nr = 11; ++module_param(encode_video_nr, int, 0644); ++MODULE_PARM_DESC(encode_video_nr, "encoder video device number"); ++ ++static unsigned int debug; ++module_param(debug, uint, 0644); ++MODULE_PARM_DESC(debug, "activates debug info (0-3)"); ++ ++#define MIN_W 32 ++#define MIN_H 32 ++#define MAX_W 1920 ++#define MAX_H 1088 ++#define BPL_ALIGN 32 ++#define DEFAULT_WIDTH 640 ++#define DEFAULT_HEIGHT 480 ++/* ++ * The unanswered question - what is the maximum size of a compressed frame? ++ * V4L2 mandates that the encoded frame must fit in a single buffer. Sizing ++ * that buffer is a compromise between wasting memory and risking not fitting. ++ * The 1080P version of Big Buck Bunny has some frames that exceed 512kB. ++ * Adopt a moderately arbitrary split at 720P for switching between 512 and ++ * 768kB buffers. ++ */ ++#define DEF_COMP_BUF_SIZE_GREATER_720P (768 << 10) ++#define DEF_COMP_BUF_SIZE_720P_OR_LESS (512 << 10) ++ ++/* Flags that indicate a format can be used for capture/output */ ++#define MEM2MEM_CAPTURE BIT(0) ++#define MEM2MEM_OUTPUT BIT(1) ++ ++#define MEM2MEM_NAME "bcm2835-codec" ++ ++struct bcm2835_codec_fmt { ++ u32 fourcc; ++ int depth; ++ int bytesperline_align; ++ u32 flags; ++ u32 mmal_fmt; ++ bool decode_only; ++ bool encode_only; ++ int size_multiplier_x2; ++}; ++ ++/* Supported raw pixel formats. Those supported for both encode and decode ++ * must come first, with those only supported for decode coming after (there ++ * are no formats supported for encode only). ++ */ ++static struct bcm2835_codec_fmt raw_formats[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_I420, ++ .size_multiplier_x2 = 3, ++ }, { ++ .fourcc = V4L2_PIX_FMT_YVU420, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_YV12, ++ .size_multiplier_x2 = 3, ++ }, { ++ .fourcc = V4L2_PIX_FMT_NV12, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_NV12, ++ .size_multiplier_x2 = 3, ++ }, { ++ .fourcc = V4L2_PIX_FMT_NV21, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_NV21, ++ .size_multiplier_x2 = 3, ++ }, { ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_RGB16, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_YUYV, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_YUYV, ++ .encode_only = true, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_UYVY, ++ .encode_only = true, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_YVYU, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_YVYU, ++ .encode_only = true, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_VYUY, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_VYUY, ++ .encode_only = true, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .depth = 24, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_RGB24, ++ .encode_only = true, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_BGR24, ++ .depth = 24, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BGR24, ++ .encode_only = true, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_BGR32, ++ .depth = 32, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BGRA, ++ .encode_only = true, ++ .size_multiplier_x2 = 2, ++ }, ++}; ++ ++/* Supported encoded formats. Those supported for both encode and decode ++ * must come first, with those only supported for decode coming after (there ++ * are no formats supported for encode only). ++ */ ++static struct bcm2835_codec_fmt encoded_formats[] = { ++ { ++ .fourcc = V4L2_PIX_FMT_H264, ++ .depth = 0, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal_fmt = MMAL_ENCODING_H264, ++ }, { ++ .fourcc = V4L2_PIX_FMT_MJPEG, ++ .depth = 0, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal_fmt = MMAL_ENCODING_MJPEG, ++ }, { ++ .fourcc = V4L2_PIX_FMT_MPEG4, ++ .depth = 0, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal_fmt = MMAL_ENCODING_MP4V, ++ .decode_only = true, ++ }, { ++ .fourcc = V4L2_PIX_FMT_H263, ++ .depth = 0, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal_fmt = MMAL_ENCODING_H263, ++ .decode_only = true, ++ }, { ++ .fourcc = V4L2_PIX_FMT_MPEG2, ++ .depth = 0, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal_fmt = MMAL_ENCODING_MP2V, ++ .decode_only = true, ++ }, { ++ .fourcc = V4L2_PIX_FMT_VP8, ++ .depth = 0, ++ .flags = V4L2_FMT_FLAG_COMPRESSED, ++ .mmal_fmt = MMAL_ENCODING_VP8, ++ .decode_only = true, ++ }, ++ /* ++ * This list couold include VP6 and Theorafor decode, but V4L2 doesn't ++ * support them. ++ */ ++}; ++ ++struct bcm2835_codec_fmt_list { ++ struct bcm2835_codec_fmt *list; ++ unsigned int num_entries; ++}; ++ ++#define RAW_LIST 0 ++#define ENCODED_LIST 1 ++ ++struct bcm2835_codec_fmt_list formats[] = { ++ { ++ .list = raw_formats, ++ .num_entries = ARRAY_SIZE(raw_formats), ++ }, { ++ .list = encoded_formats, ++ .num_entries = ARRAY_SIZE(encoded_formats), ++ }, ++}; ++ ++struct m2m_mmal_buffer { ++ struct v4l2_m2m_buffer m2m; ++ struct mmal_buffer mmal; ++}; ++ ++/* Per-queue, driver-specific private data */ ++struct bcm2835_codec_q_data { ++ /* ++ * These parameters should be treated as gospel, with everything else ++ * being determined from them. ++ */ ++ /* Buffer width/height */ ++ unsigned int bytesperline; ++ unsigned int height; ++ /* Crop size used for selection handling */ ++ unsigned int crop_width; ++ unsigned int crop_height; ++ bool selection_set; ++ ++ unsigned int sizeimage; ++ unsigned int sequence; ++ struct bcm2835_codec_fmt *fmt; ++ ++ /* One extra buffer header so we can send an EOS. */ ++ struct m2m_mmal_buffer eos_buffer; ++ bool eos_buffer_in_use; /* debug only */ ++}; ++ ++enum { ++ V4L2_M2M_SRC = 0, ++ V4L2_M2M_DST = 1, ++}; ++ ++static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode, ++ bool capture) ++{ ++ return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST]; ++} ++ ++static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture) ++{ ++ return &get_format_list(decode, capture)->list[0]; ++} ++ ++static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode, ++ bool capture) ++{ ++ struct bcm2835_codec_fmt *fmt; ++ unsigned int k; ++ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); ++ ++ for (k = 0; k < fmts->num_entries; k++) { ++ fmt = &fmts->list[k]; ++ if (fmt->fourcc == f->fmt.pix.pixelformat) ++ break; ++ } ++ ++ /* ++ * Some compressed formats are only supported for decoding, not ++ * encoding. ++ */ ++ if (!decode && fmts->list[k].decode_only) ++ return NULL; ++ ++ /* Some pixel formats are only supported for encoding, not decoding. */ ++ if (decode && fmts->list[k].encode_only) ++ return NULL; ++ ++ if (k == fmts->num_entries) ++ return NULL; ++ ++ return &fmts->list[k]; ++} ++ ++struct bcm2835_codec_dev { ++ struct platform_device *pdev; ++ ++ /* v4l2 devices */ ++ struct v4l2_device v4l2_dev; ++ struct video_device vfd; ++ /* mutex for the v4l2 device */ ++ struct mutex dev_mutex; ++ atomic_t num_inst; ++ ++ /* allocated mmal instance and components */ ++ bool decode; /* Is this instance a decoder? */ ++ struct vchiq_mmal_instance *instance; ++ ++ struct v4l2_m2m_dev *m2m_dev; ++}; ++ ++struct bcm2835_codec_ctx { ++ struct v4l2_fh fh; ++ struct bcm2835_codec_dev *dev; ++ ++ struct v4l2_ctrl_handler hdl; ++ ++ struct vchiq_mmal_component *component; ++ bool component_enabled; ++ ++ enum v4l2_colorspace colorspace; ++ enum v4l2_ycbcr_encoding ycbcr_enc; ++ enum v4l2_xfer_func xfer_func; ++ enum v4l2_quantization quant; ++ ++ /* Source and destination queue data */ ++ struct bcm2835_codec_q_data q_data[2]; ++ s32 bitrate; ++ ++ bool aborting; ++ int num_ip_buffers; ++ int num_op_buffers; ++ struct completion frame_cmplt; ++}; ++ ++struct bcm2835_codec_driver { ++ struct bcm2835_codec_dev *encode; ++ struct bcm2835_codec_dev *decode; ++}; ++ ++static inline struct bcm2835_codec_ctx *file2ctx(struct file *file) ++{ ++ return container_of(file->private_data, struct bcm2835_codec_ctx, fh); ++} ++ ++static struct bcm2835_codec_q_data *get_q_data(struct bcm2835_codec_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ return &ctx->q_data[V4L2_M2M_SRC]; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ return &ctx->q_data[V4L2_M2M_DST]; ++ default: ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", ++ __func__, type); ++ break; ++ } ++ return NULL; ++} ++ ++static struct vchiq_mmal_port *get_port_data(struct bcm2835_codec_ctx *ctx, ++ enum v4l2_buf_type type) ++{ ++ if (!ctx->component) ++ return NULL; ++ ++ switch (type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ return &ctx->component->input[0]; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ return &ctx->component->output[0]; ++ default: ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", ++ __func__, type); ++ break; ++ } ++ return NULL; ++} ++ ++/* ++ * mem2mem callbacks ++ */ ++ ++/** ++ * job_ready() - check whether an instance is ready to be scheduled to run ++ */ ++static int job_ready(void *priv) ++{ ++ struct bcm2835_codec_ctx *ctx = priv; ++ ++ if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && ++ !v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) ++ return 0; ++ ++ return 1; ++} ++ ++static void job_abort(void *priv) ++{ ++ struct bcm2835_codec_ctx *ctx = priv; ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s\n", __func__); ++ /* Will cancel the transaction in the next interrupt handler */ ++ ctx->aborting = 1; ++} ++ ++static inline unsigned int get_sizeimage(int bpl, int height, ++ struct bcm2835_codec_fmt *fmt) ++{ ++ return (bpl * height * fmt->size_multiplier_x2) >> 1; ++} ++ ++static inline unsigned int get_bytesperline(int width, ++ struct bcm2835_codec_fmt *fmt) ++{ ++ return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align); ++} ++ ++static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx, ++ bool decode, ++ struct bcm2835_codec_q_data *q_data, ++ struct vchiq_mmal_port *port) ++{ ++ port->format.encoding = q_data->fmt->mmal_fmt; ++ ++ if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) { ++ /* Raw image format - set width/height */ ++ port->es.video.width = q_data->bytesperline / ++ (q_data->fmt->depth >> 3); ++ port->es.video.height = q_data->height; ++ port->es.video.crop.width = q_data->crop_width; ++ port->es.video.crop.height = q_data->crop_height; ++ port->es.video.frame_rate.num = 0; ++ port->es.video.frame_rate.den = 1; ++ } else { ++ /* Compressed format - leave resolution as 0 for decode */ ++ if (decode) { ++ port->es.video.width = 0; ++ port->es.video.height = 0; ++ port->es.video.crop.width = 0; ++ port->es.video.crop.height = 0; ++ } else { ++ port->es.video.width = q_data->crop_width; ++ port->es.video.height = q_data->height; ++ port->es.video.crop.width = q_data->crop_width; ++ port->es.video.crop.height = q_data->crop_height; ++ port->format.bitrate = ctx->bitrate; ++ } ++ port->es.video.frame_rate.num = 0; ++ port->es.video.frame_rate.den = 1; ++ } ++ port->es.video.crop.x = 0; ++ port->es.video.crop.y = 0; ++ ++ port->current_buffer.size = q_data->sizeimage; ++}; ++ ++static void ip_buffer_cb(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, int status, ++ struct mmal_buffer *mmal_buf) ++{ ++ struct bcm2835_codec_ctx *ctx = port->cb_ctx/*, *curr_ctx*/; ++ struct m2m_mmal_buffer *buf = ++ container_of(mmal_buf, struct m2m_mmal_buffer, mmal); ++ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: port %p buf %p length %lu, flags %x\n", ++ __func__, port, mmal_buf, mmal_buf->length, ++ mmal_buf->mmal_flags); ++ ++ if (buf == &ctx->q_data[V4L2_M2M_SRC].eos_buffer) { ++ /* Do we need to add lcoking to prevent multiple submission of ++ * the EOS, and therefore handle mutliple return here? ++ */ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: eos buffer returned.\n", ++ __func__); ++ ctx->q_data[V4L2_M2M_SRC].eos_buffer_in_use = false; ++ return; ++ } ++ ++ if (status) { ++ /* error in transfer */ ++ if (buf) ++ /* there was a buffer with the error so return it */ ++ vb2_buffer_done(&buf->m2m.vb.vb2_buf, ++ VB2_BUF_STATE_ERROR); ++ return; ++ } ++ if (mmal_buf->cmd) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Not expecting cmd msgs on ip callback - %08x\n", ++ __func__, mmal_buf->cmd); ++ /* ++ * CHECKME: Should we return here. The buffer shouldn't have a ++ * message context or vb2 buf associated. ++ */ ++ } ++ ++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: no error. Return buffer %p\n", ++ __func__, &buf->m2m.vb.vb2_buf); ++ vb2_buffer_done(&buf->m2m.vb.vb2_buf, VB2_BUF_STATE_DONE); ++ ++ ctx->num_ip_buffers++; ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d input buffers\n", ++ __func__, ctx->num_ip_buffers); ++ ++ if (!port->enabled) ++ complete(&ctx->frame_cmplt); ++} ++ ++static void queue_res_chg_event(struct bcm2835_codec_ctx *ctx) ++{ ++ static const struct v4l2_event ev_src_ch = { ++ .type = V4L2_EVENT_SOURCE_CHANGE, ++ .u.src_change.changes = ++ V4L2_EVENT_SRC_CH_RESOLUTION, ++ }; ++ ++ v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); ++} ++ ++static void send_eos_event(struct bcm2835_codec_ctx *ctx) ++{ ++ static const struct v4l2_event ev = { ++ .type = V4L2_EVENT_EOS, ++ }; ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Sending EOS event\n"); ++ ++ v4l2_event_queue_fh(&ctx->fh, &ev); ++} ++ ++static void color_mmal2v4l(struct bcm2835_codec_ctx *ctx, u32 mmal_color_space) ++{ ++ switch (mmal_color_space) { ++ case MMAL_COLOR_SPACE_ITUR_BT601: ++ ctx->colorspace = V4L2_COLORSPACE_REC709; ++ ctx->xfer_func = V4L2_XFER_FUNC_709; ++ ctx->ycbcr_enc = V4L2_YCBCR_ENC_601; ++ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE; ++ break; ++ ++ case MMAL_COLOR_SPACE_ITUR_BT709: ++ ctx->colorspace = V4L2_COLORSPACE_REC709; ++ ctx->xfer_func = V4L2_XFER_FUNC_709; ++ ctx->ycbcr_enc = V4L2_YCBCR_ENC_709; ++ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE; ++ break; ++ } ++} ++ ++static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx, ++ struct mmal_buffer *mmal_buf) ++{ ++ struct bcm2835_codec_q_data *q_data; ++ struct mmal_msg_event_format_changed *format = ++ (struct mmal_msg_event_format_changed *)mmal_buf->buffer; ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed: buff size min %u, rec %u, buff num min %u, rec %u\n", ++ __func__, ++ format->buffer_size_min, ++ format->buffer_size_recommended, ++ format->buffer_num_min, ++ format->buffer_num_recommended ++ ); ++ if (format->format.type != MMAL_ES_TYPE_VIDEO) { ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed but not video %u\n", ++ __func__, format->format.type); ++ return; ++ } ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed to %ux%u, crop %ux%u, colourspace %08X\n", ++ __func__, format->es.video.width, format->es.video.height, ++ format->es.video.crop.width, format->es.video.crop.height, ++ format->es.video.color_space); ++ ++ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); ++ q_data->crop_width = format->es.video.crop.width; ++ q_data->crop_height = format->es.video.crop.height; ++ q_data->bytesperline = format->es.video.crop.width; ++ q_data->height = format->es.video.height; ++ q_data->sizeimage = format->buffer_size_min; ++ if (format->es.video.color_space) ++ color_mmal2v4l(ctx, format->es.video.color_space); ++ ++ queue_res_chg_event(ctx); ++} ++ ++static void op_buffer_cb(struct vchiq_mmal_instance *instance, ++ struct vchiq_mmal_port *port, int status, ++ struct mmal_buffer *mmal_buf) ++{ ++ struct bcm2835_codec_ctx *ctx = port->cb_ctx; ++ struct m2m_mmal_buffer *buf; ++ struct vb2_v4l2_buffer *vb2; ++ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, ++ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n", ++ __func__, status, mmal_buf, mmal_buf->length, ++ mmal_buf->mmal_flags, mmal_buf->pts); ++ ++ if (status) { ++ /* error in transfer */ ++ if (vb2) { ++ /* there was a buffer with the error so return it */ ++ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR); ++ } ++ return; ++ } ++ ++ if (mmal_buf->cmd) { ++ switch (mmal_buf->cmd) { ++ case MMAL_EVENT_FORMAT_CHANGED: ++ { ++ handle_fmt_changed(ctx, mmal_buf); ++ break; ++ } ++ default: ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Unexpected event on output callback - %08x\n", ++ __func__, mmal_buf->cmd); ++ break; ++ } ++ return; ++ } ++ ++ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal); ++ vb2 = &buf->m2m.vb; ++ ++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n", ++ __func__, mmal_buf->length, mmal_buf->mmal_flags, ++ vb2->vb2_buf.index); ++ ++ if (mmal_buf->length == 0) { ++ /* stream ended, or buffer being returned during disable. */ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: Empty buffer - flags %04x", ++ __func__, mmal_buf->mmal_flags); ++ if (!mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) { ++ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR); ++ if (!port->enabled) ++ complete(&ctx->frame_cmplt); ++ return; ++ } ++ } ++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) { ++ /* EOS packet from the VPU */ ++ send_eos_event(ctx); ++ vb2->flags |= V4L2_BUF_FLAG_LAST; ++ } ++ ++ vb2->vb2_buf.timestamp = mmal_buf->pts; ++ ++ vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length); ++ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) ++ vb2->flags |= V4L2_BUF_FLAG_KEYFRAME; ++ ++ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_DONE); ++ ctx->num_op_buffers++; ++ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d output buffers\n", ++ __func__, ctx->num_op_buffers); ++ ++ if (!port->enabled) ++ complete(&ctx->frame_cmplt); ++} ++ ++/* vb2_to_mmal_buffer() - converts vb2 buffer header to MMAL ++ * ++ * Copies all the required fields from a VB2 buffer to the MMAL buffer header, ++ * ready for sending to the VPU. ++ */ ++static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf, ++ struct vb2_v4l2_buffer *vb2) ++{ ++ buf->mmal.mmal_flags = 0; ++ if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME) ++ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME; ++ ++ /* ++ * Adding this means that the data must be framed correctly as one frame ++ * per buffer. The underlying decoder has no such requirement, but it ++ * will reduce latency as the bistream parser will be kicked immediately ++ * to parse the frame, rather than relying on its own heuristics for ++ * when to wake up. ++ */ ++ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; ++ ++ buf->mmal.length = vb2->vb2_buf.planes[0].bytesused; ++ /* ++ * Minor ambiguity in the V4L2 spec as to whether passing in a 0 length ++ * buffer, or one with V4L2_BUF_FLAG_LAST set denotes end of stream. ++ * Handle either. ++ */ ++ if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST) ++ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS; ++ ++ buf->mmal.pts = vb2->vb2_buf.timestamp; ++ buf->mmal.dts = MMAL_TIME_UNKNOWN; ++} ++ ++/* device_run() - prepares and starts the device ++ * ++ * This simulates all the immediate preparations required before starting ++ * a device. This will be called by the framework when it decides to schedule ++ * a particular instance. ++ */ ++static void device_run(void *priv) ++{ ++ struct bcm2835_codec_ctx *ctx = priv; ++ struct bcm2835_codec_dev *dev = ctx->dev; ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf; ++ struct v4l2_m2m_buffer *m2m; ++ int ret; ++ ++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: off we go\n", __func__); ++ ++ src_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->out_q_ctx); ++ if (src_buf) { ++ m2m = container_of(src_buf, struct v4l2_m2m_buffer, vb); ++ src_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m); ++ vb2_to_mmal_buffer(src_m2m_buf, src_buf); ++ ++ ret = vchiq_mmal_submit_buffer(dev->instance, ++ &ctx->component->input[0], ++ &src_m2m_buf->mmal); ++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted ip buffer len %lu, pts %llu, flags %04x\n", ++ __func__, src_m2m_buf->mmal.length, ++ src_m2m_buf->mmal.pts, src_m2m_buf->mmal.mmal_flags); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting ip buffer\n", ++ __func__); ++ } ++ ++ dst_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->cap_q_ctx); ++ if (dst_buf) { ++ m2m = container_of(dst_buf, struct v4l2_m2m_buffer, vb); ++ dst_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m); ++ vb2_to_mmal_buffer(dst_m2m_buf, dst_buf); ++ ++ ret = vchiq_mmal_submit_buffer(dev->instance, ++ &ctx->component->output[0], ++ &dst_m2m_buf->mmal); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting op buffer\n", ++ __func__); ++ } ++ ++ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted src %p, dst %p\n", ++ __func__, src_m2m_buf, dst_m2m_buf); ++ ++ /* Complete the job here. */ ++ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); ++} ++ ++/* ++ * video ioctls ++ */ ++static int vidioc_querycap(struct file *file, void *priv, ++ struct v4l2_capability *cap) ++{ ++ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); ++ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); ++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", ++ MEM2MEM_NAME); ++ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; ++ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; ++ return 0; ++} ++ ++static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture) ++{ ++ struct bcm2835_codec_fmt *fmt; ++ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); ++ ++ if (f->index < fmts->num_entries) { ++ /* Format found */ ++ /* Check format isn't a decode only format when encoding */ ++ if (!decode && ++ fmts->list[f->index].decode_only) ++ return -EINVAL; ++ /* Check format isn't a decode only format when encoding */ ++ if (decode && ++ fmts->list[f->index].encode_only) ++ return -EINVAL; ++ ++ fmt = &fmts->list[f->index]; ++ f->pixelformat = fmt->fourcc; ++ f->flags = fmt->flags; ++ return 0; ++ } ++ ++ /* Format not found */ ++ return -EINVAL; ++} ++ ++static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ return enum_fmt(f, ctx->dev->decode, true); ++} ++ ++static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_fmtdesc *f) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ return enum_fmt(f, ctx->dev->decode, false); ++} ++ ++static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f) ++{ ++ struct vb2_queue *vq; ++ struct bcm2835_codec_q_data *q_data; ++ ++ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = get_q_data(ctx, f->type); ++ ++ f->fmt.pix.width = q_data->crop_width; ++ f->fmt.pix.height = q_data->height; ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix.pixelformat = q_data->fmt->fourcc; ++ f->fmt.pix.bytesperline = q_data->bytesperline; ++ f->fmt.pix.sizeimage = q_data->sizeimage; ++ f->fmt.pix.colorspace = ctx->colorspace; ++ f->fmt.pix.xfer_func = ctx->xfer_func; ++ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; ++ f->fmt.pix.quantization = ctx->quant; ++ ++ return 0; ++} ++ ++static int vidioc_g_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ return vidioc_g_fmt(file2ctx(file), f); ++} ++ ++static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ return vidioc_g_fmt(file2ctx(file), f); ++} ++ ++static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt) ++{ ++ /* ++ * The V4L2 specification requires the driver to correct the format ++ * struct if any of the dimensions is unsupported ++ */ ++ if (f->fmt.pix.width > MAX_W) ++ f->fmt.pix.width = MAX_W; ++ if (f->fmt.pix.height > MAX_H) ++ f->fmt.pix.height = MAX_H; ++ ++ if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { ++ /* Only clip min w/h on capture. Treat 0x0 as unknown. */ ++ if (f->fmt.pix.width < MIN_W) ++ f->fmt.pix.width = MIN_W; ++ if (f->fmt.pix.height < MIN_H) ++ f->fmt.pix.height = MIN_H; ++ ++ /* ++ * Buffer must have a vertical alignment of 16 lines. ++ * The selection will reflect any cropping rectangle when only ++ * some of the pixels are active. ++ */ ++ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); ++ ++ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, ++ fmt); ++ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, ++ f->fmt.pix.height, ++ fmt); ++ } else { ++ u32 min_size = f->fmt.pix.width > 1280 || ++ f->fmt.pix.height > 720 ? ++ DEF_COMP_BUF_SIZE_GREATER_720P : ++ DEF_COMP_BUF_SIZE_720P_OR_LESS; ++ ++ f->fmt.pix.bytesperline = 0; ++ if (f->fmt.pix.sizeimage < min_size) ++ f->fmt.pix.sizeimage = min_size; ++ } ++ ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ ++ return 0; ++} ++ ++static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct bcm2835_codec_fmt *fmt; ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ fmt = find_format(f, ctx->dev->decode, true); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, ++ true)->fourcc; ++ fmt = find_format(f, ctx->dev->decode, true); ++ } ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_try_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ struct bcm2835_codec_fmt *fmt; ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ fmt = find_format(f, ctx->dev->decode, false); ++ if (!fmt) { ++ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, ++ false)->fourcc; ++ fmt = find_format(f, ctx->dev->decode, false); ++ } ++ ++ if (!f->fmt.pix.colorspace) ++ f->fmt.pix.colorspace = ctx->colorspace; ++ ++ return vidioc_try_fmt(f, fmt); ++} ++ ++static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, ++ unsigned int requested_height) ++{ ++ struct bcm2835_codec_q_data *q_data; ++ struct vb2_queue *vq; ++ struct vchiq_mmal_port *port; ++ bool update_capture_port = false; ++ int ret; ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", ++ f->type, f->fmt.pix.width, f->fmt.pix.height, ++ f->fmt.pix.pixelformat, f->fmt.pix.sizeimage); ++ ++ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); ++ if (!vq) ++ return -EINVAL; ++ ++ q_data = get_q_data(ctx, f->type); ++ if (!q_data) ++ return -EINVAL; ++ ++ if (vb2_is_busy(vq)) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); ++ return -EBUSY; ++ } ++ ++ q_data->fmt = find_format(f, ctx->dev->decode, ++ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); ++ q_data->crop_width = f->fmt.pix.width; ++ q_data->height = f->fmt.pix.height; ++ if (!q_data->selection_set) ++ q_data->crop_height = requested_height; ++ ++ /* ++ * Copying the behaviour of vicodec which retains a single set of ++ * colorspace parameters for both input and output. ++ */ ++ ctx->colorspace = f->fmt.pix.colorspace; ++ ctx->xfer_func = f->fmt.pix.xfer_func; ++ ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; ++ ctx->quant = f->fmt.pix.quantization; ++ ++ /* All parameters should have been set correctly by try_fmt */ ++ q_data->bytesperline = f->fmt.pix.bytesperline; ++ q_data->sizeimage = f->fmt.pix.sizeimage; ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", ++ q_data->bytesperline, q_data->sizeimage); ++ ++ if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && ++ f->fmt.pix.width && f->fmt.pix.height) { ++ /* ++ * On the decoder, if provided with a resolution on the input ++ * side, then replicate that to the output side. ++ * GStreamer appears not to support V4L2_EVENT_SOURCE_CHANGE, ++ * nor set up a resolution on the output side, therefore ++ * we can't decode anything at a resolution other than the ++ * default one. ++ */ ++ struct bcm2835_codec_q_data *q_data_dst = ++ &ctx->q_data[V4L2_M2M_DST]; ++ ++ q_data_dst->crop_width = q_data->crop_width; ++ q_data_dst->crop_height = q_data->crop_height; ++ q_data_dst->height = ALIGN(q_data->crop_height, 16); ++ ++ q_data_dst->bytesperline = ++ get_bytesperline(f->fmt.pix.width, q_data_dst->fmt); ++ q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, ++ q_data_dst->height, ++ q_data_dst->fmt); ++ update_capture_port = true; ++ } ++ ++ /* If we have a component then setup the port as well */ ++ port = get_port_data(ctx, vq->type); ++ if (!port) ++ return 0; ++ ++ setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port); ++ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port); ++ if (ret) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n", ++ __func__, ret); ++ ret = -EINVAL; ++ } ++ ++ if (q_data->sizeimage < port->minimum_buffer.size) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Current buffer size of %u < min buf size %u - driver mismatch to MMAL\n", ++ __func__, q_data->sizeimage, ++ port->minimum_buffer.size); ++ } ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", ++ f->type, q_data->crop_width, q_data->height, ++ q_data->fmt->fourcc, q_data->sizeimage); ++ ++ if (update_capture_port) { ++ struct vchiq_mmal_port *port_dst = &ctx->component->output[0]; ++ struct bcm2835_codec_q_data *q_data_dst = ++ &ctx->q_data[V4L2_M2M_DST]; ++ ++ setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst, ++ port_dst); ++ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst); ++ if (ret) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n", ++ __func__, ret); ++ ret = -EINVAL; ++ } ++ } ++ return ret; ++} ++ ++static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ unsigned int height = f->fmt.pix.height; ++ int ret; ++ ++ ret = vidioc_try_fmt_vid_cap(file, priv, f); ++ if (ret) ++ return ret; ++ ++ return vidioc_s_fmt(file2ctx(file), f, height); ++} ++ ++static int vidioc_s_fmt_vid_out(struct file *file, void *priv, ++ struct v4l2_format *f) ++{ ++ unsigned int height = f->fmt.pix.height; ++ int ret; ++ ++ ret = vidioc_try_fmt_vid_out(file, priv, f); ++ if (ret) ++ return ret; ++ ++ ret = vidioc_s_fmt(file2ctx(file), f, height); ++ return ret; ++} ++ ++static int vidioc_g_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ struct bcm2835_codec_q_data *q_data; ++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? ++ true : false; ++ ++ if (capture_queue ^ ctx->dev->decode) ++ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ ++ return -EINVAL; ++ ++ q_data = get_q_data(ctx, s->type); ++ if (!q_data) ++ return -EINVAL; ++ ++ if (ctx->dev->decode) { ++ switch (s->target) { ++ case V4L2_SEL_TGT_COMPOSE_DEFAULT: ++ case V4L2_SEL_TGT_COMPOSE: ++ s->r.left = 0; ++ s->r.top = 0; ++ s->r.width = q_data->crop_width; ++ s->r.height = q_data->crop_height; ++ break; ++ case V4L2_SEL_TGT_COMPOSE_BOUNDS: ++ s->r.left = 0; ++ s->r.top = 0; ++ s->r.width = q_data->crop_width; ++ s->r.height = q_data->crop_height; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ switch (s->target) { ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ s->r.top = 0; ++ s->r.left = 0; ++ s->r.width = q_data->bytesperline; ++ s->r.height = q_data->height; ++ break; ++ case V4L2_SEL_TGT_CROP: ++ s->r.top = 0; ++ s->r.left = 0; ++ s->r.width = q_data->crop_width; ++ s->r.height = q_data->crop_height; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int vidioc_s_selection(struct file *file, void *priv, ++ struct v4l2_selection *s) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ struct bcm2835_codec_q_data *q_data = NULL; ++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? ++ true : false; ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n", ++ __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top, ++ s->r.width, s->r.height); ++ ++ if (capture_queue ^ ctx->dev->decode) ++ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ ++ return -EINVAL; ++ ++ q_data = get_q_data(ctx, s->type); ++ if (!q_data) ++ return -EINVAL; ++ ++ if (ctx->dev->decode) { ++ switch (s->target) { ++ case V4L2_SEL_TGT_COMPOSE: ++ /* Accept cropped image */ ++ s->r.left = 0; ++ s->r.top = 0; ++ s->r.width = min(s->r.width, q_data->crop_width); ++ s->r.height = min(s->r.height, q_data->height); ++ q_data->crop_width = s->r.width; ++ q_data->crop_height = s->r.height; ++ q_data->selection_set = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ switch (s->target) { ++ case V4L2_SEL_TGT_CROP: ++ /* Only support crop from (0,0) */ ++ s->r.top = 0; ++ s->r.left = 0; ++ s->r.width = min(s->r.width, q_data->crop_width); ++ s->r.height = min(s->r.height, q_data->crop_height); ++ q_data->crop_width = s->r.width; ++ q_data->crop_height = s->r.height; ++ q_data->selection_set = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int vidioc_subscribe_evt(struct v4l2_fh *fh, ++ const struct v4l2_event_subscription *sub) ++{ ++ switch (sub->type) { ++ case V4L2_EVENT_EOS: ++ return v4l2_event_subscribe(fh, sub, 2, NULL); ++ case V4L2_EVENT_SOURCE_CHANGE: ++ return v4l2_src_change_event_subscribe(fh, sub); ++ default: ++ return v4l2_ctrl_subscribe_event(fh, sub); ++ } ++} ++ ++static int bcm2835_codec_set_level_profile(struct bcm2835_codec_ctx *ctx, ++ struct v4l2_ctrl *ctrl) ++{ ++ struct mmal_parameter_video_profile param; ++ int param_size = sizeof(param); ++ int ret; ++ ++ /* ++ * Level and Profile are set via the same MMAL parameter. ++ * Retrieve the current settings and amend the one that has changed. ++ */ ++ ret = vchiq_mmal_port_parameter_get(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_PROFILE, ++ ¶m, ++ ¶m_size); ++ if (ret) ++ return ret; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: ++ switch (ctrl->val) { ++ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: ++ param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE; ++ break; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: ++ param.profile = ++ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE; ++ break; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: ++ param.profile = MMAL_VIDEO_PROFILE_H264_MAIN; ++ break; ++ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: ++ param.profile = MMAL_VIDEO_PROFILE_H264_HIGH; ++ break; ++ default: ++ /* Should never get here */ ++ break; ++ } ++ break; ++ ++ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: ++ switch (ctrl->val) { ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: ++ param.level = MMAL_VIDEO_LEVEL_H264_1; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1B: ++ param.level = MMAL_VIDEO_LEVEL_H264_1b; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: ++ param.level = MMAL_VIDEO_LEVEL_H264_11; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: ++ param.level = MMAL_VIDEO_LEVEL_H264_12; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: ++ param.level = MMAL_VIDEO_LEVEL_H264_13; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: ++ param.level = MMAL_VIDEO_LEVEL_H264_2; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: ++ param.level = MMAL_VIDEO_LEVEL_H264_21; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: ++ param.level = MMAL_VIDEO_LEVEL_H264_22; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: ++ param.level = MMAL_VIDEO_LEVEL_H264_3; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: ++ param.level = MMAL_VIDEO_LEVEL_H264_31; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: ++ param.level = MMAL_VIDEO_LEVEL_H264_32; ++ break; ++ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: ++ param.level = MMAL_VIDEO_LEVEL_H264_4; ++ break; ++ default: ++ /* Should never get here */ ++ break; ++ } ++ } ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_PROFILE, ++ ¶m, ++ param_size); ++ ++ return ret; ++} ++ ++static int bcm2835_codec_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct bcm2835_codec_ctx *ctx = ++ container_of(ctrl->handler, struct bcm2835_codec_ctx, hdl); ++ int ret = 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_MPEG_VIDEO_BITRATE: ++ ctx->bitrate = ctrl->val; ++ if (!ctx->component) ++ break; ++ ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_VIDEO_BIT_RATE, ++ &ctrl->val, ++ sizeof(ctrl->val)); ++ break; ++ ++ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { ++ u32 bitrate_mode; ++ ++ if (!ctx->component) ++ break; ++ ++ switch (ctrl->val) { ++ default: ++ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: ++ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE; ++ break; ++ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: ++ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT; ++ break; ++ } ++ ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_RATECONTROL, ++ &bitrate_mode, ++ sizeof(bitrate_mode)); ++ break; ++ } ++ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: ++ if (!ctx->component) ++ break; ++ ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, ++ &ctrl->val, ++ sizeof(ctrl->val)); ++ break; ++ ++ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: ++ if (!ctx->component) ++ break; ++ ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_INTRAPERIOD, ++ &ctrl->val, ++ sizeof(ctrl->val)); ++ break; ++ ++ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: ++ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: ++ if (!ctx->component) ++ break; ++ ++ ret = bcm2835_codec_set_level_profile(ctx, ctrl); ++ break; ++ ++ default: ++ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); ++ return -EINVAL; ++ } ++ ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "Failed setting ctrl %08x, ret %d\n", ++ ctrl->id, ret); ++ return ret ? -EINVAL : 0; ++} ++ ++static const struct v4l2_ctrl_ops bcm2835_codec_ctrl_ops = { ++ .s_ctrl = bcm2835_codec_s_ctrl, ++}; ++ ++static int vidioc_try_decoder_cmd(struct file *file, void *priv, ++ struct v4l2_decoder_cmd *cmd) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ if (!ctx->dev->decode) ++ return -EINVAL; ++ ++ switch (cmd->cmd) { ++ case V4L2_DEC_CMD_STOP: ++ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: DEC cmd->flags=%u stop to black not supported", ++ __func__, cmd->flags); ++ return -EINVAL; ++ } ++ break; ++ case V4L2_DEC_CMD_START: ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int vidioc_decoder_cmd(struct file *file, void *priv, ++ struct v4l2_decoder_cmd *cmd) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC]; ++ int ret; ++ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__, ++ cmd->cmd); ++ ret = vidioc_try_decoder_cmd(file, priv, cmd); ++ if (ret) ++ return ret; ++ ++ switch (cmd->cmd) { ++ case V4L2_DEC_CMD_STOP: ++ if (q_data->eos_buffer_in_use) ++ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n"); ++ q_data->eos_buffer_in_use = true; ++ ++ q_data->eos_buffer.mmal.buffer_size = 0; ++ q_data->eos_buffer.mmal.length = 0; ++ q_data->eos_buffer.mmal.mmal_flags = ++ MMAL_BUFFER_HEADER_FLAG_EOS; ++ q_data->eos_buffer.mmal.pts = 0; ++ q_data->eos_buffer.mmal.dts = 0; ++ ++ if (!ctx->component) ++ break; ++ ++ ret = vchiq_mmal_submit_buffer(ctx->dev->instance, ++ &ctx->component->input[0], ++ &q_data->eos_buffer.mmal); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, ++ "%s: EOS buffer submit failed %d\n", ++ __func__, ret); ++ ++ break; ++ ++ case V4L2_DEC_CMD_START: ++ /* Do we need to do anything here? */ ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vidioc_try_encoder_cmd(struct file *file, void *priv, ++ struct v4l2_encoder_cmd *cmd) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ if (ctx->dev->decode) ++ return -EINVAL; ++ ++ switch (cmd->cmd) { ++ case V4L2_ENC_CMD_STOP: ++ break; ++ ++ case V4L2_ENC_CMD_START: ++ /* Do we need to do anything here? */ ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int vidioc_encoder_cmd(struct file *file, void *priv, ++ struct v4l2_encoder_cmd *cmd) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC]; ++ int ret; ++ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__, ++ cmd->cmd); ++ ret = vidioc_try_encoder_cmd(file, priv, cmd); ++ if (ret) ++ return ret; ++ ++ switch (cmd->cmd) { ++ case V4L2_ENC_CMD_STOP: ++ if (q_data->eos_buffer_in_use) ++ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n"); ++ q_data->eos_buffer_in_use = true; ++ ++ q_data->eos_buffer.mmal.buffer_size = 0; ++ q_data->eos_buffer.mmal.length = 0; ++ q_data->eos_buffer.mmal.mmal_flags = ++ MMAL_BUFFER_HEADER_FLAG_EOS; ++ q_data->eos_buffer.mmal.pts = 0; ++ q_data->eos_buffer.mmal.dts = 0; ++ ++ if (!ctx->component) ++ break; ++ ++ ret = vchiq_mmal_submit_buffer(ctx->dev->instance, ++ &ctx->component->input[0], ++ &q_data->eos_buffer.mmal); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, ++ "%s: EOS buffer submit failed %d\n", ++ __func__, ret); ++ ++ break; ++ case V4L2_ENC_CMD_START: ++ /* Do we need to do anything here? */ ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = { ++ .vidioc_querycap = vidioc_querycap, ++ ++ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, ++ ++ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, ++ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, ++ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, ++ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, ++ ++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, ++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, ++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, ++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, ++ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, ++ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, ++ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, ++ ++ .vidioc_streamon = v4l2_m2m_ioctl_streamon, ++ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, ++ ++ .vidioc_g_selection = vidioc_g_selection, ++ .vidioc_s_selection = vidioc_s_selection, ++ ++ .vidioc_subscribe_event = vidioc_subscribe_evt, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++ ++ .vidioc_decoder_cmd = vidioc_decoder_cmd, ++ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, ++ .vidioc_encoder_cmd = vidioc_encoder_cmd, ++ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, ++}; ++ ++static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx) ++{ ++ /* ++ * Query the control handler for the value of the various controls and ++ * set them. ++ */ ++ const u32 control_ids[] = { ++ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, ++ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, ++ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, ++ V4L2_CID_MPEG_VIDEO_H264_LEVEL, ++ V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ }; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(control_ids); i++) { ++ struct v4l2_ctrl *ctrl; ++ ++ ctrl = v4l2_ctrl_find(&ctx->hdl, control_ids[i]); ++ if (ctrl) ++ bcm2835_codec_s_ctrl(ctrl); ++ } ++ ++ return 0; ++} ++ ++static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx) ++{ ++ struct bcm2835_codec_dev *dev = ctx->dev; ++ unsigned int enable = 1; ++ int ret; ++ ++ ret = vchiq_mmal_component_init(dev->instance, dev->decode ? ++ "ril.video_decode" : "ril.video_encode", ++ &ctx->component); ++ if (ret < 0) { ++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n", ++ __func__, dev->decode ? "decode" : "encode"); ++ return -ENOMEM; ++ } ++ ++ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->input[0], ++ MMAL_PARAMETER_ZERO_COPY, &enable, ++ sizeof(enable)); ++ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->output[0], ++ MMAL_PARAMETER_ZERO_COPY, &enable, ++ sizeof(enable)); ++ ++ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC], ++ &ctx->component->input[0]); ++ ++ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST], ++ &ctx->component->output[0]); ++ ++ ret = vchiq_mmal_port_set_format(dev->instance, ++ &ctx->component->input[0]); ++ if (ret < 0) ++ goto destroy_component; ++ ++ ret = vchiq_mmal_port_set_format(dev->instance, ++ &ctx->component->output[0]); ++ if (ret < 0) ++ goto destroy_component; ++ ++ if (dev->decode) { ++ if (ctx->q_data[V4L2_M2M_DST].sizeimage < ++ ctx->component->output[0].minimum_buffer.size) ++ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", ++ ctx->q_data[V4L2_M2M_DST].sizeimage, ++ ctx->component->output[0].minimum_buffer.size); ++ } else { ++ if (ctx->q_data[V4L2_M2M_SRC].sizeimage < ++ ctx->component->output[0].minimum_buffer.size) ++ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", ++ ctx->q_data[V4L2_M2M_SRC].sizeimage, ++ ctx->component->output[0].minimum_buffer.size); ++ ++ /* Now we have a component we can set all the ctrls */ ++ bcm2835_codec_set_ctrls(ctx); ++ } ++ ++ return 0; ++ ++destroy_component: ++ vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component); ++ ++ return ret; ++} ++ ++/* ++ * Queue operations ++ */ ++ ++static int bcm2835_codec_queue_setup(struct vb2_queue *vq, ++ unsigned int *nbuffers, ++ unsigned int *nplanes, ++ unsigned int sizes[], ++ struct device *alloc_devs[]) ++{ ++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vq); ++ struct bcm2835_codec_q_data *q_data; ++ struct vchiq_mmal_port *port; ++ unsigned int size; ++ ++ q_data = get_q_data(ctx, vq->type); ++ if (!q_data) ++ return -EINVAL; ++ ++ if (!ctx->component) ++ if (bcm2835_codec_create_component(ctx)) ++ return -EINVAL; ++ ++ port = get_port_data(ctx, vq->type); ++ ++ size = q_data->sizeimage; ++ ++ if (*nplanes) ++ return sizes[0] < size ? -EINVAL : 0; ++ ++ *nplanes = 1; ++ ++ sizes[0] = size; ++ port->current_buffer.size = size; ++ ++ if (*nbuffers < port->minimum_buffer.num) ++ *nbuffers = port->minimum_buffer.num; ++ /* Add one buffer to take an EOS */ ++ port->current_buffer.num = *nbuffers + 1; ++ ++ return 0; ++} ++ ++static int bcm2835_codec_buf_init(struct vb2_buffer *vb) ++{ ++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); ++ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer, ++ vb); ++ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, ++ m2m); ++ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n", ++ __func__, ctx, vb); ++ buf->mmal.buffer = vb2_plane_vaddr(&buf->m2m.vb.vb2_buf, 0); ++ buf->mmal.buffer_size = vb2_plane_size(&buf->m2m.vb.vb2_buf, 0); ++ ++ mmal_vchi_buffer_init(ctx->dev->instance, &buf->mmal); ++ ++ return 0; ++} ++ ++static int bcm2835_codec_buf_prepare(struct vb2_buffer *vb) ++{ ++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct bcm2835_codec_q_data *q_data; ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct v4l2_m2m_buffer *m2m = container_of(vbuf, struct v4l2_m2m_buffer, ++ vb); ++ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, ++ m2m); ++ int ret; ++ ++ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n", ++ __func__, vb->vb2_queue->type, vb); ++ ++ q_data = get_q_data(ctx, vb->vb2_queue->type); ++ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { ++ if (vbuf->field == V4L2_FIELD_ANY) ++ vbuf->field = V4L2_FIELD_NONE; ++ if (vbuf->field != V4L2_FIELD_NONE) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s field isn't supported\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ ++ if (vb2_plane_size(vb, 0) < q_data->sizeimage) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n", ++ __func__, vb2_plane_size(vb, 0), ++ (long)q_data->sizeimage); ++ return -EINVAL; ++ } ++ ++ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) ++ vb2_set_plane_payload(vb, 0, q_data->sizeimage); ++ ++ /* ++ * We want to do this at init, but vb2_core_expbuf checks that the ++ * index < q->num_buffers, and q->num_buffers only gets updated once ++ * all the buffers are allocated. ++ */ ++ if (!buf->mmal.dma_buf) { ++ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue, ++ vb->vb2_queue->type, vb->index, 0, ++ O_CLOEXEC, &buf->mmal.dma_buf); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n", ++ __func__, vb->index, ret); ++ } else { ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++static void bcm2835_codec_buf_queue(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ ++ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p vbuf->flags %u, seq %u, bytesused %u\n", ++ __func__, vb->vb2_queue->type, vb, vbuf->flags, vbuf->sequence, ++ vb->planes[0].bytesused); ++ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); ++} ++ ++static void bcm2835_codec_buffer_cleanup(struct vb2_buffer *vb) ++{ ++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); ++ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer, ++ vb); ++ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, ++ m2m); ++ ++ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n", ++ __func__, ctx, vb); ++ ++ mmal_vchi_buffer_cleanup(&buf->mmal); ++ ++ if (buf->mmal.dma_buf) { ++ dma_buf_put(buf->mmal.dma_buf); ++ buf->mmal.dma_buf = NULL; ++ } ++} ++ ++static int bcm2835_codec_start_streaming(struct vb2_queue *q, ++ unsigned int count) ++{ ++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q); ++ struct bcm2835_codec_dev *dev = ctx->dev; ++ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type); ++ int ret; ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d count %d\n", ++ __func__, q->type, count); ++ q_data->sequence = 0; ++ ++ if (!ctx->component_enabled) { ++ ret = vchiq_mmal_component_enable(dev->instance, ++ ctx->component); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n", ++ __func__, ret); ++ ctx->component_enabled = true; ++ } ++ ++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ++ /* ++ * Create the EOS buffer. ++ * We only need the MMAL part, and want to NOT attach a memory ++ * buffer to it as it should only take flags. ++ */ ++ memset(&q_data->eos_buffer, 0, sizeof(q_data->eos_buffer)); ++ mmal_vchi_buffer_init(dev->instance, ++ &q_data->eos_buffer.mmal); ++ q_data->eos_buffer_in_use = false; ++ ++ ctx->component->input[0].cb_ctx = ctx; ++ ret = vchiq_mmal_port_enable(dev->instance, ++ &ctx->component->input[0], ++ ip_buffer_cb); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling i/p port, ret %d\n", ++ __func__, ret); ++ } else { ++ ctx->component->output[0].cb_ctx = ctx; ++ ret = vchiq_mmal_port_enable(dev->instance, ++ &ctx->component->output[0], ++ op_buffer_cb); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n", ++ __func__, ret); ++ } ++ return ret; ++} ++ ++static void bcm2835_codec_stop_streaming(struct vb2_queue *q) ++{ ++ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q); ++ struct bcm2835_codec_dev *dev = ctx->dev; ++ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type); ++ struct vchiq_mmal_port *port = get_port_data(ctx, q->type); ++ struct vb2_v4l2_buffer *vbuf; ++ struct vb2_v4l2_buffer *vb2; ++ struct v4l2_m2m_buffer *m2m; ++ struct m2m_mmal_buffer *buf; ++ int ret, i; ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d - return buffers\n", ++ __func__, q->type); ++ ++ init_completion(&ctx->frame_cmplt); ++ ++ /* Clear out all buffers held by m2m framework */ ++ for (;;) { ++ if (V4L2_TYPE_IS_OUTPUT(q->type)) ++ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); ++ else ++ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); ++ if (!vbuf) ++ break; ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: return buffer %p\n", ++ __func__, vbuf); ++ ++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); ++ } ++ ++ /* Disable MMAL port - this will flush buffers back */ ++ ret = vchiq_mmal_port_disable(dev->instance, port); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed disabling %s port, ret %d\n", ++ __func__, V4L2_TYPE_IS_OUTPUT(q->type) ? "i/p" : "o/p", ++ ret); ++ ++ while (atomic_read(&port->buffers_with_vpu)) { ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n", ++ __func__, atomic_read(&port->buffers_with_vpu)); ++ ret = wait_for_completion_timeout(&ctx->frame_cmplt, HZ); ++ if (ret <= 0) { ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n", ++ __func__, ++ atomic_read(&port->buffers_with_vpu)); ++ break; ++ } ++ } ++ ++ /* ++ * Release the VCSM handle here as otherwise REQBUFS(0) aborts because ++ * someone is using the dmabuf before giving the driver a chance to do ++ * anything about it. ++ */ ++ for (i = 0; i < q->num_buffers; i++) { ++ vb2 = to_vb2_v4l2_buffer(q->bufs[i]); ++ m2m = container_of(vb2, struct v4l2_m2m_buffer, vb); ++ buf = container_of(m2m, struct m2m_mmal_buffer, m2m); ++ ++ mmal_vchi_buffer_cleanup(&buf->mmal); ++ if (buf->mmal.dma_buf) { ++ dma_buf_put(buf->mmal.dma_buf); ++ buf->mmal.dma_buf = NULL; ++ } ++ } ++ ++ /* If both ports disabled, then disable the component */ ++ if (!ctx->component->input[0].enabled && ++ !ctx->component->output[0].enabled) { ++ ret = vchiq_mmal_component_disable(dev->instance, ++ ctx->component); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n", ++ __func__, ret); ++ } ++ ++ if (V4L2_TYPE_IS_OUTPUT(q->type)) ++ mmal_vchi_buffer_cleanup(&q_data->eos_buffer.mmal); ++ ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: done\n", __func__); ++} ++ ++static const struct vb2_ops bcm2835_codec_qops = { ++ .queue_setup = bcm2835_codec_queue_setup, ++ .buf_init = bcm2835_codec_buf_init, ++ .buf_prepare = bcm2835_codec_buf_prepare, ++ .buf_queue = bcm2835_codec_buf_queue, ++ .buf_cleanup = bcm2835_codec_buffer_cleanup, ++ .start_streaming = bcm2835_codec_start_streaming, ++ .stop_streaming = bcm2835_codec_stop_streaming, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++}; ++ ++static int queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct bcm2835_codec_ctx *ctx = priv; ++ int ret; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ src_vq->io_modes = VB2_MMAP | VB2_DMABUF; ++ src_vq->drv_priv = ctx; ++ src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); ++ src_vq->ops = &bcm2835_codec_qops; ++ src_vq->mem_ops = &vb2_dma_contig_memops; ++ src_vq->dev = &ctx->dev->pdev->dev; ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->lock = &ctx->dev->dev_mutex; ++ ++ ret = vb2_queue_init(src_vq); ++ if (ret) ++ return ret; ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; ++ dst_vq->drv_priv = ctx; ++ dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); ++ dst_vq->ops = &bcm2835_codec_qops; ++ dst_vq->mem_ops = &vb2_dma_contig_memops; ++ dst_vq->dev = &ctx->dev->pdev->dev; ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->lock = &ctx->dev->dev_mutex; ++ ++ return vb2_queue_init(dst_vq); ++} ++ ++/* ++ * File operations ++ */ ++static int bcm2835_codec_open(struct file *file) ++{ ++ struct bcm2835_codec_dev *dev = video_drvdata(file); ++ struct bcm2835_codec_ctx *ctx = NULL; ++ struct v4l2_ctrl_handler *hdl; ++ int rc = 0; ++ ++ v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n", ++ dev->decode ? "decode" : "encode"); ++ if (mutex_lock_interruptible(&dev->dev_mutex)) { ++ v4l2_err(&dev->v4l2_dev, "Mutex fail\n"); ++ return -ERESTARTSYS; ++ } ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) { ++ rc = -ENOMEM; ++ goto open_unlock; ++ } ++ ++ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false); ++ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true); ++ if (dev->decode) { ++ /* ++ * Input width and height are irrelevant as they will be defined ++ * by the bitstream not the format. Required by V4L2 though. ++ */ ++ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; ++ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; ++ ctx->q_data[V4L2_M2M_SRC].sizeimage = ++ DEF_COMP_BUF_SIZE_720P_OR_LESS; ++ ++ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; ++ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_DST].bytesperline = ++ get_bytesperline(DEFAULT_WIDTH, ++ ctx->q_data[V4L2_M2M_DST].fmt); ++ ctx->q_data[V4L2_M2M_DST].sizeimage = ++ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, ++ ctx->q_data[V4L2_M2M_DST].height, ++ ctx->q_data[V4L2_M2M_DST].fmt); ++ } else { ++ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; ++ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_SRC].bytesperline = ++ get_bytesperline(DEFAULT_WIDTH, ++ ctx->q_data[V4L2_M2M_SRC].fmt); ++ ctx->q_data[V4L2_M2M_SRC].sizeimage = ++ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline, ++ ctx->q_data[V4L2_M2M_SRC].height, ++ ctx->q_data[V4L2_M2M_SRC].fmt); ++ ++ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; ++ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_DST].bytesperline = 0; ++ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_DST].sizeimage = ++ DEF_COMP_BUF_SIZE_720P_OR_LESS; ++ } ++ ++ ctx->colorspace = V4L2_COLORSPACE_REC709; ++ ctx->bitrate = 10 * 1000 * 1000; ++ ++ /* Initialise V4L2 contexts */ ++ v4l2_fh_init(&ctx->fh, video_devdata(file)); ++ file->private_data = &ctx->fh; ++ ctx->dev = dev; ++ hdl = &ctx->hdl; ++ if (!dev->decode) { ++ /* Encode controls */ ++ v4l2_ctrl_handler_init(hdl, 6); ++ ++ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, ++ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, ++ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); ++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_BITRATE, ++ 25 * 1000, 25 * 1000 * 1000, ++ 25 * 1000, 10 * 1000 * 1000); ++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, ++ 0, 1, ++ 1, 0); ++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, ++ 0, 0x7FFFFFFF, ++ 1, 60); ++ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_H264_LEVEL, ++ V4L2_MPEG_VIDEO_H264_LEVEL_4_2, ++ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | ++ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), ++ V4L2_MPEG_VIDEO_H264_LEVEL_4_0); ++ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_H264_PROFILE, ++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, ++ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | ++ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), ++ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); ++ if (hdl->error) { ++ rc = hdl->error; ++ goto free_ctrl_handler; ++ } ++ ctx->fh.ctrl_handler = hdl; ++ v4l2_ctrl_handler_setup(hdl); ++ } ++ ++ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); ++ ++ if (IS_ERR(ctx->fh.m2m_ctx)) { ++ rc = PTR_ERR(ctx->fh.m2m_ctx); ++ ++ goto free_ctrl_handler; ++ } ++ ++ /* Set both queues as buffered as we have buffering in the VPU. That ++ * means that we will be scheduled whenever either an input or output ++ * buffer is available (otherwise one of each are required). ++ */ ++ v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); ++ v4l2_m2m_set_dst_buffered(ctx->fh.m2m_ctx, true); ++ ++ v4l2_fh_add(&ctx->fh); ++ atomic_inc(&dev->num_inst); ++ ++ mutex_unlock(&dev->dev_mutex); ++ return 0; ++ ++free_ctrl_handler: ++ v4l2_ctrl_handler_free(hdl); ++ kfree(ctx); ++open_unlock: ++ mutex_unlock(&dev->dev_mutex); ++ return rc; ++} ++ ++static int bcm2835_codec_release(struct file *file) ++{ ++ struct bcm2835_codec_dev *dev = video_drvdata(file); ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: Releasing instance %p\n", ++ __func__, ctx); ++ ++ v4l2_fh_del(&ctx->fh); ++ v4l2_fh_exit(&ctx->fh); ++ v4l2_ctrl_handler_free(&ctx->hdl); ++ mutex_lock(&dev->dev_mutex); ++ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); ++ ++ if (ctx->component) ++ vchiq_mmal_component_finalise(dev->instance, ctx->component); ++ ++ mutex_unlock(&dev->dev_mutex); ++ kfree(ctx); ++ ++ atomic_dec(&dev->num_inst); ++ ++ return 0; ++} ++ ++static const struct v4l2_file_operations bcm2835_codec_fops = { ++ .owner = THIS_MODULE, ++ .open = bcm2835_codec_open, ++ .release = bcm2835_codec_release, ++ .poll = v4l2_m2m_fop_poll, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = v4l2_m2m_fop_mmap, ++}; ++ ++static const struct video_device bcm2835_codec_videodev = { ++ .name = MEM2MEM_NAME, ++ .vfl_dir = VFL_DIR_M2M, ++ .fops = &bcm2835_codec_fops, ++ .ioctl_ops = &bcm2835_codec_ioctl_ops, ++ .minor = -1, ++ .release = video_device_release_empty, ++}; ++ ++static const struct v4l2_m2m_ops m2m_ops = { ++ .device_run = device_run, ++ .job_ready = job_ready, ++ .job_abort = job_abort, ++}; ++ ++static int bcm2835_codec_create(struct platform_device *pdev, ++ struct bcm2835_codec_dev **new_dev, ++ bool decode) ++{ ++ struct bcm2835_codec_dev *dev; ++ struct video_device *vfd; ++ struct vchiq_mmal_instance *instance = NULL; ++ int video_nr; ++ int ret; ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ dev->pdev = pdev; ++ ++ dev->decode = decode; ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if (ret) ++ return ret; ++ ++ atomic_set(&dev->num_inst, 0); ++ mutex_init(&dev->dev_mutex); ++ ++ dev->vfd = bcm2835_codec_videodev; ++ vfd = &dev->vfd; ++ vfd->lock = &dev->dev_mutex; ++ vfd->v4l2_dev = &dev->v4l2_dev; ++ ++ if (dev->decode) { ++ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); ++ video_nr = decode_video_nr; ++ } else { ++ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); ++ video_nr = encode_video_nr; ++ } ++ ++ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); ++ if (ret) { ++ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); ++ goto unreg_dev; ++ } ++ ++ video_set_drvdata(vfd, dev); ++ snprintf(vfd->name, sizeof(vfd->name), "%s", ++ bcm2835_codec_videodev.name); ++ v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", ++ vfd->num); ++ ++ *new_dev = dev; ++ ++ dev->m2m_dev = v4l2_m2m_init(&m2m_ops); ++ if (IS_ERR(dev->m2m_dev)) { ++ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); ++ ret = PTR_ERR(dev->m2m_dev); ++ goto err_m2m; ++ } ++ ++ ret = vchiq_mmal_init(&instance); ++ if (ret < 0) ++ goto err_m2m; ++ dev->instance = instance; ++ ++ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n", ++ dev->decode ? "decode" : "encode"); ++ return 0; ++ ++err_m2m: ++ v4l2_m2m_release(dev->m2m_dev); ++ video_unregister_device(&dev->vfd); ++unreg_dev: ++ v4l2_device_unregister(&dev->v4l2_dev); ++ ++ return ret; ++} ++ ++static int bcm2835_codec_destroy(struct bcm2835_codec_dev *dev) ++{ ++ if (!dev) ++ return -ENODEV; ++ ++ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); ++ v4l2_m2m_release(dev->m2m_dev); ++ video_unregister_device(&dev->vfd); ++ v4l2_device_unregister(&dev->v4l2_dev); ++ ++ return 0; ++} ++ ++static int bcm2835_codec_probe(struct platform_device *pdev) ++{ ++ struct bcm2835_codec_driver *drv; ++ int ret = 0; ++ ++ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); ++ if (!drv) ++ return -ENOMEM; ++ ++ ret = bcm2835_codec_create(pdev, &drv->encode, false); ++ if (ret) ++ goto out; ++ ++ ret = bcm2835_codec_create(pdev, &drv->decode, true); ++ if (ret) ++ goto out; ++ ++ platform_set_drvdata(pdev, drv); ++ ++ return 0; ++ ++out: ++ if (drv->encode) { ++ bcm2835_codec_destroy(drv->encode); ++ drv->encode = NULL; ++ } ++ return ret; ++} ++ ++static int bcm2835_codec_remove(struct platform_device *pdev) ++{ ++ struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev); ++ ++ bcm2835_codec_destroy(drv->encode); ++ ++ bcm2835_codec_destroy(drv->decode); ++ ++ return 0; ++} ++ ++static struct platform_driver bcm2835_v4l2_codec_driver = { ++ .probe = bcm2835_codec_probe, ++ .remove = bcm2835_codec_remove, ++ .driver = { ++ .name = "bcm2835-codec", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(bcm2835_v4l2_codec_driver); ++ ++MODULE_DESCRIPTION("BCM2835 codec V4L2 driver"); ++MODULE_AUTHOR("Dave Stevenson, "); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("0.0.1"); ++MODULE_ALIAS("platform:bcm2835-codec"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0175-staging-vc04_services-Use-vc-sm-cma-to-support-zero-.patch b/target/linux/bcm27xx/patches-5.4/950-0175-staging-vc04_services-Use-vc-sm-cma-to-support-zero-.patch deleted file mode 100644 index 62cce8a94e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0175-staging-vc04_services-Use-vc-sm-cma-to-support-zero-.patch +++ /dev/null @@ -1,177 +0,0 @@ -From 511b809d5b227b179acca537cba85e2bdff87b94 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 25 Sep 2018 16:07:55 +0100 -Subject: [PATCH] staging: vc04_services: Use vc-sm-cma to support zero - copy - -With the vc-sm-cma driver we can support zero copy of buffers between -the kernel and VPU. Add this support to vchiq-mmal. - -Signed-off-by: Dave Stevenson - -staging: vc-sm-cma: Use a void* pointer as the handle within the kernel - -The driver was using an unsigned int as the handle to the outside world, -and doing a nasty cast to the struct dmabuf when handed it back. -This breaks badly with a 64 bit kernel where the pointer doesn't fit -in an unsigned int. - -Switch to using a void* within the kernel. Reality is that it is -a struct dma_buf*, but advertising it as such to other drivers seems -to encourage the use of it as such, and I'm not sure on the implications -of that. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/vchiq-mmal/Kconfig | 1 + - .../vc04_services/vchiq-mmal/mmal-common.h | 4 ++ - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 66 ++++++++++++++++++- - .../vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + - 4 files changed, 70 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/Kconfig -+++ b/drivers/staging/vc04_services/vchiq-mmal/Kconfig -@@ -2,6 +2,7 @@ config BCM2835_VCHIQ_MMAL - tristate "BCM2835 MMAL VCHIQ service" - depends on (ARCH_BCM2835 || COMPILE_TEST) - select BCM2835_VCHIQ -+ select BCM_VC_SM_CMA - help - Enables the MMAL API over VCHIQ as used for the - majority of the multimedia services on VideoCore. ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-common.h -@@ -50,6 +50,10 @@ struct mmal_buffer { - - struct mmal_msg_context *msg_context; - -+ struct dma_buf *dma_buf;/* Exported dmabuf fd from videobuf2 */ -+ void *vcsm_handle; /* VCSM handle having imported the dmabuf */ -+ u32 vc_handle; /* VC handle to that dmabuf */ -+ - u32 cmd; /* MMAL command. 0=data. */ - unsigned long length; - u32 mmal_flags; ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -26,9 +26,12 @@ - #include - - #include "mmal-common.h" -+#include "mmal-parameters.h" - #include "mmal-vchiq.h" - #include "mmal-msg.h" - -+#include "vc-sm-cma/vc_sm_knl.h" -+ - #define USE_VCHIQ_ARM - #include "interface/vchi/vchi.h" - -@@ -424,8 +427,13 @@ buffer_from_host(struct vchiq_mmal_insta - - /* buffer header */ - m.u.buffer_from_host.buffer_header.cmd = 0; -- m.u.buffer_from_host.buffer_header.data = -- (u32)(unsigned long)buf->buffer; -+ if (port->zero_copy) { -+ m.u.buffer_from_host.buffer_header.data = buf->vc_handle; -+ } else { -+ m.u.buffer_from_host.buffer_header.data = -+ (u32)(unsigned long)buf->buffer; -+ } -+ - m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size; - if (port->type == MMAL_PORT_TYPE_OUTPUT) { - m.u.buffer_from_host.buffer_header.length = 0; -@@ -590,6 +598,22 @@ static void buffer_to_host_cb(struct vch - - msg_context->u.bulk.status = msg->h.status; - -+ } else if (msg->u.buffer_from_host.is_zero_copy) { -+ /* -+ * Zero copy buffer, so nothing to do. -+ * Copy buffer info and make callback. -+ */ -+ msg_context->u.bulk.buffer_used = -+ msg->u.buffer_from_host.buffer_header.length; -+ msg_context->u.bulk.mmal_flags = -+ msg->u.buffer_from_host.buffer_header.flags; -+ msg_context->u.bulk.dts = -+ msg->u.buffer_from_host.buffer_header.dts; -+ msg_context->u.bulk.pts = -+ msg->u.buffer_from_host.buffer_header.pts; -+ msg_context->u.bulk.cmd = -+ msg->u.buffer_from_host.buffer_header.cmd; -+ - } else if (msg->u.buffer_from_host.buffer_header.length == 0) { - /* empty buffer */ - if (msg->u.buffer_from_host.buffer_header.flags & -@@ -1537,6 +1561,9 @@ int vchiq_mmal_port_parameter_set(struct - - mutex_unlock(&instance->vchiq_mutex); - -+ if (parameter == MMAL_PARAMETER_ZERO_COPY && !ret) -+ port->zero_copy = !!(*(bool *)value); -+ - return ret; - } - EXPORT_SYMBOL_GPL(vchiq_mmal_port_parameter_set); -@@ -1705,6 +1732,31 @@ int vchiq_mmal_submit_buffer(struct vchi - unsigned long flags = 0; - int ret; - -+ /* -+ * We really want to do this in mmal_vchi_buffer_init but can't as -+ * videobuf2 won't let us have the dmabuf there. -+ */ -+ if (port->zero_copy && buffer->dma_buf && !buffer->vcsm_handle) { -+ pr_debug("%s: import dmabuf %p\n", __func__, buffer->dma_buf); -+ ret = vc_sm_cma_import_dmabuf(buffer->dma_buf, -+ &buffer->vcsm_handle); -+ if (ret) { -+ pr_err("%s: vc_sm_import_dmabuf_fd failed, ret %d\n", -+ __func__, ret); -+ return ret; -+ } -+ -+ buffer->vc_handle = vc_sm_cma_int_handle(buffer->vcsm_handle); -+ if (!buffer->vc_handle) { -+ pr_err("%s: vc_sm_int_handle failed %d\n", -+ __func__, ret); -+ vc_sm_cma_free(buffer->vcsm_handle); -+ return ret; -+ } -+ pr_debug("%s: import dmabuf %p - got vc handle %08X\n", -+ __func__, buffer->dma_buf, buffer->vc_handle); -+ } -+ - ret = buffer_from_host(instance, port, buffer); - if (ret == -EINVAL) { - /* Port is disabled. Queue for when it is enabled. */ -@@ -1738,6 +1790,16 @@ int mmal_vchi_buffer_cleanup(struct mmal - release_msg_context(msg_context); - buf->msg_context = NULL; - -+ if (buf->vcsm_handle) { -+ int ret; -+ -+ pr_debug("%s: vc_sm_cma_free on handle %p\n", __func__, -+ buf->vcsm_handle); -+ ret = vc_sm_cma_free(buf->vcsm_handle); -+ if (ret) -+ pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret); -+ buf->vcsm_handle = 0; -+ } - return 0; - } - EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -49,6 +49,7 @@ typedef void (*vchiq_mmal_buffer_cb)( - - struct vchiq_mmal_port { - u32 enabled:1; -+ u32 zero_copy:1; - u32 handle; - u32 type; /* port type, cached to use on port info set */ - u32 index; /* port index, cached to use on port info set */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0176-media-videobuf2-Allow-exporting-of-a-struct-dmabuf.patch b/target/linux/bcm27xx/patches-5.4/950-0176-media-videobuf2-Allow-exporting-of-a-struct-dmabuf.patch deleted file mode 100644 index 74d03540ad..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0176-media-videobuf2-Allow-exporting-of-a-struct-dmabuf.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 74ac8bd3b5c6ed23308341fa41681db6a3b45c46 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 29 Oct 2018 17:57:45 +0000 -Subject: [PATCH] media: videobuf2: Allow exporting of a struct dmabuf - -videobuf2 only allowed exporting a dmabuf as a file descriptor, -but there are instances where having the struct dma_buf is -useful within the kernel. - -Split the current implementation into two, one step which -exports a struct dma_buf, and the second which converts that -into an fd. - -Signed-off-by: Dave Stevenson ---- - .../media/common/videobuf2/videobuf2-core.c | 21 ++++++++++++++++--- - include/media/videobuf2-core.h | 15 +++++++++++++ - 2 files changed, 33 insertions(+), 3 deletions(-) - ---- a/drivers/media/common/videobuf2/videobuf2-core.c -+++ b/drivers/media/common/videobuf2/videobuf2-core.c -@@ -2073,12 +2073,12 @@ static int __find_plane_by_offset(struct - return -EINVAL; - } - --int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, -- unsigned int index, unsigned int plane, unsigned int flags) -+int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type, -+ unsigned int index, unsigned int plane, -+ unsigned int flags, struct dma_buf **dmabuf) - { - struct vb2_buffer *vb = NULL; - struct vb2_plane *vb_plane; -- int ret; - struct dma_buf *dbuf; - - if (q->memory != VB2_MEMORY_MMAP) { -@@ -2128,6 +2128,21 @@ int vb2_core_expbuf(struct vb2_queue *q, - return -EINVAL; - } - -+ *dmabuf = dbuf; -+ return 0; -+} -+EXPORT_SYMBOL_GPL(vb2_core_expbuf_dmabuf); -+ -+int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, -+ unsigned int index, unsigned int plane, unsigned int flags) -+{ -+ struct dma_buf *dbuf; -+ int ret; -+ -+ ret = vb2_core_expbuf_dmabuf(q, type, index, plane, flags, &dbuf); -+ if (ret) -+ return ret; -+ - ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE); - if (ret < 0) { - dprintk(3, "buffer %d, plane %d failed to export (%d)\n", ---- a/include/media/videobuf2-core.h -+++ b/include/media/videobuf2-core.h -@@ -870,6 +870,21 @@ int vb2_core_streamon(struct vb2_queue * - int vb2_core_streamoff(struct vb2_queue *q, unsigned int type); - - /** -+ * vb2_core_expbuf_dmabuf() - Export a buffer as a dma_buf structure -+ * @q: videobuf2 queue -+ * @type: buffer type -+ * @index: id number of the buffer -+ * @plane: index of the plane to be exported, 0 for single plane queues -+ * @flags: flags for newly created file, currently only O_CLOEXEC is -+ * supported, refer to manual of open syscall for more details -+ * @dmabuf: Returns the dmabuf pointer -+ * -+ */ -+int vb2_core_expbuf_dmabuf(struct vb2_queue *q, unsigned int type, -+ unsigned int index, unsigned int plane, -+ unsigned int flags, struct dma_buf **dmabuf); -+ -+/** - * vb2_core_expbuf() - Export a buffer as a file descriptor. - * @q: pointer to &struct vb2_queue with videobuf2 queue. - * @fd: pointer to the file descriptor associated with DMABUF diff --git a/target/linux/bcm27xx/patches-5.4/950-0176-staging-mmal-vchiq-Fix-client_component-for-64-bit-k.patch b/target/linux/bcm27xx/patches-5.4/950-0176-staging-mmal-vchiq-Fix-client_component-for-64-bit-k.patch new file mode 100644 index 0000000000..5c64238741 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0176-staging-mmal-vchiq-Fix-client_component-for-64-bit-k.patch @@ -0,0 +1,68 @@ +From 50df0b1532cf88e2ec152caa2cf89af0d0646b4a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 22 Jan 2019 12:04:09 +0000 +Subject: [PATCH] staging: mmal-vchiq: Fix client_component for 64 bit + kernel + +The MMAL client_component field is used with the event +mechanism to allow the client to identify the component for +which the event is generated. +The field is only 32bits in size, therefore we can't use a +pointer to the component in a 64 bit kernel. + +Component handles are already held in an array per VCHI +instance, so use the array index as the client_component handle +to avoid having to create a new IDR for this purpose. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 12 +++++++++--- + .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + + 2 files changed, 10 insertions(+), 3 deletions(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -472,9 +472,9 @@ buffer_from_host(struct vchiq_mmal_insta + static void event_to_host_cb(struct vchiq_mmal_instance *instance, + struct mmal_msg *msg, u32 msg_len) + { +- /* FIXME: Not going to work on 64 bit */ ++ int comp_idx = msg->u.event_to_host.client_component; + struct vchiq_mmal_component *component = +- (struct vchiq_mmal_component *)msg->u.event_to_host.client_component; ++ &instance->component[comp_idx]; + struct vchiq_mmal_port *port = NULL; + struct mmal_msg_context *msg_context; + u32 port_num = msg->u.event_to_host.port_num; +@@ -1073,7 +1073,7 @@ static int create_component(struct vchiq + + /* build component create message */ + m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE; +- m.u.component_create.client_component = (u32)(unsigned long)component; ++ m.u.component_create.client_component = component->client_component; + strncpy(m.u.component_create.name, name, + sizeof(m.u.component_create.name)); + +@@ -1868,6 +1868,12 @@ int vchiq_mmal_component_init(struct vch + goto unlock; + } + ++ /* We need a handle to reference back to our component structure. ++ * Use the array index in instance->component rather than rolling ++ * another IDR. ++ */ ++ component->client_component = idx; ++ + ret = create_component(instance, component, name); + if (ret < 0) { + pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -97,6 +97,7 @@ struct vchiq_mmal_component { + struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */ + struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */ + struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */ ++ u32 client_component; /* Used to ref back to client struct */ + }; + + int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance); diff --git a/target/linux/bcm27xx/patches-5.4/950-0177-clk-clk-bcm2835-Use-zd-when-printing-size_t.patch b/target/linux/bcm27xx/patches-5.4/950-0177-clk-clk-bcm2835-Use-zd-when-printing-size_t.patch new file mode 100644 index 0000000000..c8acb1a378 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0177-clk-clk-bcm2835-Use-zd-when-printing-size_t.patch @@ -0,0 +1,24 @@ +From 608b88a72331d8c3d6561a6a25a2955d211b9c70 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 24 Jan 2019 15:09:28 +0000 +Subject: [PATCH] clk: clk-bcm2835: Use %zd when printing size_t + +The debug text for how many clocks have been registered +uses "%d" with a size_t. Correct it to "%zd". + +Signed-off-by: Dave Stevenson +--- + drivers/clk/bcm/clk-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -2354,7 +2354,7 @@ static int bcm2835_clk_probe(struct plat + return ret; + + /* note that we have registered all the clocks */ +- dev_dbg(dev, "registered %d clocks\n", asize); ++ dev_dbg(dev, "registered %zd clocks\n", asize); + + return 0; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0177-staging-vc04_services-Add-a-V4L2-M2M-codec-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0177-staging-vc04_services-Add-a-V4L2-M2M-codec-driver.patch deleted file mode 100644 index 2093cf05cc..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0177-staging-vc04_services-Add-a-V4L2-M2M-codec-driver.patch +++ /dev/null @@ -1,2467 +0,0 @@ -From 6b2e734af2943dbf31bafb4c4c2fb588eec8059f Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 25 Sep 2018 14:53:49 +0100 -Subject: [PATCH] staging: vc04_services: Add a V4L2 M2M codec driver - -This adds a V4L2 memory to memory device that wraps the MMAL -video decode and video_encode components for H264 and MJPEG encode -and decode, MPEG4, H263, and VP8 decode (and MPEG2 decode -if the appropriate licence has been purchased). - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/Kconfig | 1 + - drivers/staging/vc04_services/Makefile | 9 +- - .../vc04_services/bcm2835-codec/Kconfig | 11 + - .../vc04_services/bcm2835-codec/Makefile | 8 + - .../staging/vc04_services/bcm2835-codec/TODO | 24 + - .../bcm2835-codec/bcm2835-v4l2-codec.c | 2359 +++++++++++++++++ - 6 files changed, 2408 insertions(+), 4 deletions(-) - create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Kconfig - create mode 100644 drivers/staging/vc04_services/bcm2835-codec/Makefile - create mode 100644 drivers/staging/vc04_services/bcm2835-codec/TODO - create mode 100644 drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c - ---- a/drivers/staging/vc04_services/Kconfig -+++ b/drivers/staging/vc04_services/Kconfig -@@ -24,6 +24,7 @@ source "drivers/staging/vc04_services/bc - source "drivers/staging/vc04_services/bcm2835-camera/Kconfig" - source "drivers/staging/vc04_services/vchiq-mmal/Kconfig" - source "drivers/staging/vc04_services/vc-sm-cma/Kconfig" -+source "drivers/staging/vc04_services/bcm2835-codec/Kconfig" - - endif - ---- a/drivers/staging/vc04_services/Makefile -+++ b/drivers/staging/vc04_services/Makefile -@@ -10,10 +10,11 @@ vchiq-objs := \ - interface/vchiq_arm/vchiq_util.o \ - interface/vchiq_arm/vchiq_connected.o \ - --obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ --obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ --obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ --obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/ -+obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/ -+obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/ -+obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/ -+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/ -+obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec/ - - ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000 - ---- /dev/null -+++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig -@@ -0,0 +1,11 @@ -+config VIDEO_CODEC_BCM2835 -+ tristate "BCM2835 Video codec support" -+ depends on MEDIA_SUPPORT -+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) -+ select BCM2835_VCHIQ_MMAL -+ select VIDEOBUF2_DMA_CONTIG -+ select V4L2_MEM2MEM_DEV -+ help -+ Say Y here to enable the V4L2 video codecs for -+ Broadcom BCM2835 SoC. This operates over the VCHIQ interface -+ to a service running on VideoCore. ---- /dev/null -+++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0 -+bcm2835-codec-objs := bcm2835-v4l2-codec.o -+ -+obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o -+ -+ccflags-y += \ -+ -Idrivers/staging/vc04_services \ -+ -D__VCCOREVER__=0x04000000 ---- /dev/null -+++ b/drivers/staging/vc04_services/bcm2835-codec/TODO -@@ -0,0 +1,24 @@ -+1) Convert to be a platform driver. -+ -+Right now when the module probes, it tries to initialize VCHI and -+errors out if it wasn't ready yet. If bcm2835-v4l2 was built in, then -+VCHI generally isn't ready because it depends on both the firmware and -+mailbox drivers having already loaded. -+ -+We should have VCHI create a platform device once it's initialized, -+and have this driver bind to it, so that we automatically load the -+v4l2 module after VCHI loads. -+ -+2) Support SELECTION API to define crop region on the image for encode. -+ -+Particularly for resolutions that aren't a multiple of the macroblock -+size, the codec will report a resolution that is a multiple of the macroblock -+size (it has to have the memory to decode into), and then a different crop -+region within that buffer. -+The most common example is 1080P, where the buffer will be 1920x1088 with a -+crop region of 1920x1080. -+ -+3) Refactor so that the component creation is only on queue_setup, not open. -+ -+Fixes v4l2-compliance failure on trying to open 100 instances of the -+device. -\ No newline at end of file ---- /dev/null -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -0,0 +1,2359 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+/* -+ * A v4l2-mem2mem device that wraps the video codec MMAL component. -+ * -+ * Copyright 2018 Raspberry Pi (Trading) Ltd. -+ * Author: Dave Stevenson (dave.stevenson@raspberrypi.org) -+ * -+ * Loosely based on the vim2m virtual driver by Pawel Osciak -+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. -+ * Pawel Osciak, -+ * Marek Szyprowski, -+ * -+ * Whilst this driver uses the v4l2_mem2mem framework, it does not need the -+ * scheduling aspects, so will always take the buffers, pass them to the VPU, -+ * and then signal the job as complete. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "vchiq-mmal/mmal-encodings.h" -+#include "vchiq-mmal/mmal-msg.h" -+#include "vchiq-mmal/mmal-parameters.h" -+#include "vchiq-mmal/mmal-vchiq.h" -+ -+/* -+ * Default /dev/videoN node numbers for decode and encode. -+ * Deliberately avoid the very low numbers as these are often taken by webcams -+ * etc, and simple apps tend to only go for /dev/video0. -+ */ -+static int decode_video_nr = 10; -+module_param(decode_video_nr, int, 0644); -+MODULE_PARM_DESC(decode_video_nr, "decoder video device number"); -+ -+static int encode_video_nr = 11; -+module_param(encode_video_nr, int, 0644); -+MODULE_PARM_DESC(encode_video_nr, "encoder video device number"); -+ -+static unsigned int debug; -+module_param(debug, uint, 0644); -+MODULE_PARM_DESC(debug, "activates debug info (0-3)"); -+ -+#define MIN_W 32 -+#define MIN_H 32 -+#define MAX_W 1920 -+#define MAX_H 1088 -+#define BPL_ALIGN 32 -+#define DEFAULT_WIDTH 640 -+#define DEFAULT_HEIGHT 480 -+/* -+ * The unanswered question - what is the maximum size of a compressed frame? -+ * V4L2 mandates that the encoded frame must fit in a single buffer. Sizing -+ * that buffer is a compromise between wasting memory and risking not fitting. -+ * The 1080P version of Big Buck Bunny has some frames that exceed 512kB. -+ * Adopt a moderately arbitrary split at 720P for switching between 512 and -+ * 768kB buffers. -+ */ -+#define DEF_COMP_BUF_SIZE_GREATER_720P (768 << 10) -+#define DEF_COMP_BUF_SIZE_720P_OR_LESS (512 << 10) -+ -+/* Flags that indicate a format can be used for capture/output */ -+#define MEM2MEM_CAPTURE BIT(0) -+#define MEM2MEM_OUTPUT BIT(1) -+ -+#define MEM2MEM_NAME "bcm2835-codec" -+ -+struct bcm2835_codec_fmt { -+ u32 fourcc; -+ int depth; -+ int bytesperline_align; -+ u32 flags; -+ u32 mmal_fmt; -+ bool decode_only; -+ bool encode_only; -+ int size_multiplier_x2; -+}; -+ -+/* Supported raw pixel formats. Those supported for both encode and decode -+ * must come first, with those only supported for decode coming after (there -+ * are no formats supported for encode only). -+ */ -+static struct bcm2835_codec_fmt raw_formats[] = { -+ { -+ .fourcc = V4L2_PIX_FMT_YUV420, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_I420, -+ .size_multiplier_x2 = 3, -+ }, { -+ .fourcc = V4L2_PIX_FMT_YVU420, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_YV12, -+ .size_multiplier_x2 = 3, -+ }, { -+ .fourcc = V4L2_PIX_FMT_NV12, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_NV12, -+ .size_multiplier_x2 = 3, -+ }, { -+ .fourcc = V4L2_PIX_FMT_NV21, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_NV21, -+ .size_multiplier_x2 = 3, -+ }, { -+ .fourcc = V4L2_PIX_FMT_RGB565, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_RGB16, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_YUYV, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_YUYV, -+ .encode_only = true, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_UYVY, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_UYVY, -+ .encode_only = true, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_YVYU, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_YVYU, -+ .encode_only = true, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_VYUY, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_VYUY, -+ .encode_only = true, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_RGB24, -+ .depth = 24, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_RGB24, -+ .encode_only = true, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_BGR24, -+ .depth = 24, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BGR24, -+ .encode_only = true, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_BGR32, -+ .depth = 32, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BGRA, -+ .encode_only = true, -+ .size_multiplier_x2 = 2, -+ }, -+}; -+ -+/* Supported encoded formats. Those supported for both encode and decode -+ * must come first, with those only supported for decode coming after (there -+ * are no formats supported for encode only). -+ */ -+static struct bcm2835_codec_fmt encoded_formats[] = { -+ { -+ .fourcc = V4L2_PIX_FMT_H264, -+ .depth = 0, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, -+ .mmal_fmt = MMAL_ENCODING_H264, -+ }, { -+ .fourcc = V4L2_PIX_FMT_MJPEG, -+ .depth = 0, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, -+ .mmal_fmt = MMAL_ENCODING_MJPEG, -+ }, { -+ .fourcc = V4L2_PIX_FMT_MPEG4, -+ .depth = 0, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, -+ .mmal_fmt = MMAL_ENCODING_MP4V, -+ .decode_only = true, -+ }, { -+ .fourcc = V4L2_PIX_FMT_H263, -+ .depth = 0, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, -+ .mmal_fmt = MMAL_ENCODING_H263, -+ .decode_only = true, -+ }, { -+ .fourcc = V4L2_PIX_FMT_MPEG2, -+ .depth = 0, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, -+ .mmal_fmt = MMAL_ENCODING_MP2V, -+ .decode_only = true, -+ }, { -+ .fourcc = V4L2_PIX_FMT_VP8, -+ .depth = 0, -+ .flags = V4L2_FMT_FLAG_COMPRESSED, -+ .mmal_fmt = MMAL_ENCODING_VP8, -+ .decode_only = true, -+ }, -+ /* -+ * This list couold include VP6 and Theorafor decode, but V4L2 doesn't -+ * support them. -+ */ -+}; -+ -+struct bcm2835_codec_fmt_list { -+ struct bcm2835_codec_fmt *list; -+ unsigned int num_entries; -+}; -+ -+#define RAW_LIST 0 -+#define ENCODED_LIST 1 -+ -+struct bcm2835_codec_fmt_list formats[] = { -+ { -+ .list = raw_formats, -+ .num_entries = ARRAY_SIZE(raw_formats), -+ }, { -+ .list = encoded_formats, -+ .num_entries = ARRAY_SIZE(encoded_formats), -+ }, -+}; -+ -+struct m2m_mmal_buffer { -+ struct v4l2_m2m_buffer m2m; -+ struct mmal_buffer mmal; -+}; -+ -+/* Per-queue, driver-specific private data */ -+struct bcm2835_codec_q_data { -+ /* -+ * These parameters should be treated as gospel, with everything else -+ * being determined from them. -+ */ -+ /* Buffer width/height */ -+ unsigned int bytesperline; -+ unsigned int height; -+ /* Crop size used for selection handling */ -+ unsigned int crop_width; -+ unsigned int crop_height; -+ bool selection_set; -+ -+ unsigned int sizeimage; -+ unsigned int sequence; -+ struct bcm2835_codec_fmt *fmt; -+ -+ /* One extra buffer header so we can send an EOS. */ -+ struct m2m_mmal_buffer eos_buffer; -+ bool eos_buffer_in_use; /* debug only */ -+}; -+ -+enum { -+ V4L2_M2M_SRC = 0, -+ V4L2_M2M_DST = 1, -+}; -+ -+static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode, -+ bool capture) -+{ -+ return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST]; -+} -+ -+static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture) -+{ -+ return &get_format_list(decode, capture)->list[0]; -+} -+ -+static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode, -+ bool capture) -+{ -+ struct bcm2835_codec_fmt *fmt; -+ unsigned int k; -+ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); -+ -+ for (k = 0; k < fmts->num_entries; k++) { -+ fmt = &fmts->list[k]; -+ if (fmt->fourcc == f->fmt.pix.pixelformat) -+ break; -+ } -+ -+ /* -+ * Some compressed formats are only supported for decoding, not -+ * encoding. -+ */ -+ if (!decode && fmts->list[k].decode_only) -+ return NULL; -+ -+ /* Some pixel formats are only supported for encoding, not decoding. */ -+ if (decode && fmts->list[k].encode_only) -+ return NULL; -+ -+ if (k == fmts->num_entries) -+ return NULL; -+ -+ return &fmts->list[k]; -+} -+ -+struct bcm2835_codec_dev { -+ struct platform_device *pdev; -+ -+ /* v4l2 devices */ -+ struct v4l2_device v4l2_dev; -+ struct video_device vfd; -+ /* mutex for the v4l2 device */ -+ struct mutex dev_mutex; -+ atomic_t num_inst; -+ -+ /* allocated mmal instance and components */ -+ bool decode; /* Is this instance a decoder? */ -+ struct vchiq_mmal_instance *instance; -+ -+ struct v4l2_m2m_dev *m2m_dev; -+}; -+ -+struct bcm2835_codec_ctx { -+ struct v4l2_fh fh; -+ struct bcm2835_codec_dev *dev; -+ -+ struct v4l2_ctrl_handler hdl; -+ -+ struct vchiq_mmal_component *component; -+ bool component_enabled; -+ -+ enum v4l2_colorspace colorspace; -+ enum v4l2_ycbcr_encoding ycbcr_enc; -+ enum v4l2_xfer_func xfer_func; -+ enum v4l2_quantization quant; -+ -+ /* Source and destination queue data */ -+ struct bcm2835_codec_q_data q_data[2]; -+ s32 bitrate; -+ -+ bool aborting; -+ int num_ip_buffers; -+ int num_op_buffers; -+ struct completion frame_cmplt; -+}; -+ -+struct bcm2835_codec_driver { -+ struct bcm2835_codec_dev *encode; -+ struct bcm2835_codec_dev *decode; -+}; -+ -+static inline struct bcm2835_codec_ctx *file2ctx(struct file *file) -+{ -+ return container_of(file->private_data, struct bcm2835_codec_ctx, fh); -+} -+ -+static struct bcm2835_codec_q_data *get_q_data(struct bcm2835_codec_ctx *ctx, -+ enum v4l2_buf_type type) -+{ -+ switch (type) { -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT: -+ return &ctx->q_data[V4L2_M2M_SRC]; -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: -+ return &ctx->q_data[V4L2_M2M_DST]; -+ default: -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", -+ __func__, type); -+ break; -+ } -+ return NULL; -+} -+ -+static struct vchiq_mmal_port *get_port_data(struct bcm2835_codec_ctx *ctx, -+ enum v4l2_buf_type type) -+{ -+ if (!ctx->component) -+ return NULL; -+ -+ switch (type) { -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT: -+ return &ctx->component->input[0]; -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: -+ return &ctx->component->output[0]; -+ default: -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", -+ __func__, type); -+ break; -+ } -+ return NULL; -+} -+ -+/* -+ * mem2mem callbacks -+ */ -+ -+/** -+ * job_ready() - check whether an instance is ready to be scheduled to run -+ */ -+static int job_ready(void *priv) -+{ -+ struct bcm2835_codec_ctx *ctx = priv; -+ -+ if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && -+ !v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) -+ return 0; -+ -+ return 1; -+} -+ -+static void job_abort(void *priv) -+{ -+ struct bcm2835_codec_ctx *ctx = priv; -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s\n", __func__); -+ /* Will cancel the transaction in the next interrupt handler */ -+ ctx->aborting = 1; -+} -+ -+static inline unsigned int get_sizeimage(int bpl, int height, -+ struct bcm2835_codec_fmt *fmt) -+{ -+ return (bpl * height * fmt->size_multiplier_x2) >> 1; -+} -+ -+static inline unsigned int get_bytesperline(int width, -+ struct bcm2835_codec_fmt *fmt) -+{ -+ return ALIGN((width * fmt->depth) >> 3, fmt->bytesperline_align); -+} -+ -+static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx, -+ bool decode, -+ struct bcm2835_codec_q_data *q_data, -+ struct vchiq_mmal_port *port) -+{ -+ port->format.encoding = q_data->fmt->mmal_fmt; -+ -+ if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) { -+ /* Raw image format - set width/height */ -+ port->es.video.width = q_data->bytesperline / -+ (q_data->fmt->depth >> 3); -+ port->es.video.height = q_data->height; -+ port->es.video.crop.width = q_data->crop_width; -+ port->es.video.crop.height = q_data->crop_height; -+ port->es.video.frame_rate.num = 0; -+ port->es.video.frame_rate.den = 1; -+ } else { -+ /* Compressed format - leave resolution as 0 for decode */ -+ if (decode) { -+ port->es.video.width = 0; -+ port->es.video.height = 0; -+ port->es.video.crop.width = 0; -+ port->es.video.crop.height = 0; -+ } else { -+ port->es.video.width = q_data->crop_width; -+ port->es.video.height = q_data->height; -+ port->es.video.crop.width = q_data->crop_width; -+ port->es.video.crop.height = q_data->crop_height; -+ port->format.bitrate = ctx->bitrate; -+ } -+ port->es.video.frame_rate.num = 0; -+ port->es.video.frame_rate.den = 1; -+ } -+ port->es.video.crop.x = 0; -+ port->es.video.crop.y = 0; -+ -+ port->current_buffer.size = q_data->sizeimage; -+}; -+ -+static void ip_buffer_cb(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, int status, -+ struct mmal_buffer *mmal_buf) -+{ -+ struct bcm2835_codec_ctx *ctx = port->cb_ctx/*, *curr_ctx*/; -+ struct m2m_mmal_buffer *buf = -+ container_of(mmal_buf, struct m2m_mmal_buffer, mmal); -+ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: port %p buf %p length %lu, flags %x\n", -+ __func__, port, mmal_buf, mmal_buf->length, -+ mmal_buf->mmal_flags); -+ -+ if (buf == &ctx->q_data[V4L2_M2M_SRC].eos_buffer) { -+ /* Do we need to add lcoking to prevent multiple submission of -+ * the EOS, and therefore handle mutliple return here? -+ */ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: eos buffer returned.\n", -+ __func__); -+ ctx->q_data[V4L2_M2M_SRC].eos_buffer_in_use = false; -+ return; -+ } -+ -+ if (status) { -+ /* error in transfer */ -+ if (buf) -+ /* there was a buffer with the error so return it */ -+ vb2_buffer_done(&buf->m2m.vb.vb2_buf, -+ VB2_BUF_STATE_ERROR); -+ return; -+ } -+ if (mmal_buf->cmd) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Not expecting cmd msgs on ip callback - %08x\n", -+ __func__, mmal_buf->cmd); -+ /* -+ * CHECKME: Should we return here. The buffer shouldn't have a -+ * message context or vb2 buf associated. -+ */ -+ } -+ -+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: no error. Return buffer %p\n", -+ __func__, &buf->m2m.vb.vb2_buf); -+ vb2_buffer_done(&buf->m2m.vb.vb2_buf, VB2_BUF_STATE_DONE); -+ -+ ctx->num_ip_buffers++; -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d input buffers\n", -+ __func__, ctx->num_ip_buffers); -+ -+ if (!port->enabled) -+ complete(&ctx->frame_cmplt); -+} -+ -+static void queue_res_chg_event(struct bcm2835_codec_ctx *ctx) -+{ -+ static const struct v4l2_event ev_src_ch = { -+ .type = V4L2_EVENT_SOURCE_CHANGE, -+ .u.src_change.changes = -+ V4L2_EVENT_SRC_CH_RESOLUTION, -+ }; -+ -+ v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); -+} -+ -+static void send_eos_event(struct bcm2835_codec_ctx *ctx) -+{ -+ static const struct v4l2_event ev = { -+ .type = V4L2_EVENT_EOS, -+ }; -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Sending EOS event\n"); -+ -+ v4l2_event_queue_fh(&ctx->fh, &ev); -+} -+ -+static void color_mmal2v4l(struct bcm2835_codec_ctx *ctx, u32 mmal_color_space) -+{ -+ switch (mmal_color_space) { -+ case MMAL_COLOR_SPACE_ITUR_BT601: -+ ctx->colorspace = V4L2_COLORSPACE_REC709; -+ ctx->xfer_func = V4L2_XFER_FUNC_709; -+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_601; -+ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE; -+ break; -+ -+ case MMAL_COLOR_SPACE_ITUR_BT709: -+ ctx->colorspace = V4L2_COLORSPACE_REC709; -+ ctx->xfer_func = V4L2_XFER_FUNC_709; -+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_709; -+ ctx->quant = V4L2_QUANTIZATION_LIM_RANGE; -+ break; -+ } -+} -+ -+static void handle_fmt_changed(struct bcm2835_codec_ctx *ctx, -+ struct mmal_buffer *mmal_buf) -+{ -+ struct bcm2835_codec_q_data *q_data; -+ struct mmal_msg_event_format_changed *format = -+ (struct mmal_msg_event_format_changed *)mmal_buf->buffer; -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed: buff size min %u, rec %u, buff num min %u, rec %u\n", -+ __func__, -+ format->buffer_size_min, -+ format->buffer_size_recommended, -+ format->buffer_num_min, -+ format->buffer_num_recommended -+ ); -+ if (format->format.type != MMAL_ES_TYPE_VIDEO) { -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed but not video %u\n", -+ __func__, format->format.type); -+ return; -+ } -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format changed to %ux%u, crop %ux%u, colourspace %08X\n", -+ __func__, format->es.video.width, format->es.video.height, -+ format->es.video.crop.width, format->es.video.crop.height, -+ format->es.video.color_space); -+ -+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); -+ q_data->crop_width = format->es.video.crop.width; -+ q_data->crop_height = format->es.video.crop.height; -+ q_data->bytesperline = format->es.video.crop.width; -+ q_data->height = format->es.video.height; -+ q_data->sizeimage = format->buffer_size_min; -+ if (format->es.video.color_space) -+ color_mmal2v4l(ctx, format->es.video.color_space); -+ -+ queue_res_chg_event(ctx); -+} -+ -+static void op_buffer_cb(struct vchiq_mmal_instance *instance, -+ struct vchiq_mmal_port *port, int status, -+ struct mmal_buffer *mmal_buf) -+{ -+ struct bcm2835_codec_ctx *ctx = port->cb_ctx; -+ struct m2m_mmal_buffer *buf; -+ struct vb2_v4l2_buffer *vb2; -+ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, -+ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n", -+ __func__, status, mmal_buf, mmal_buf->length, -+ mmal_buf->mmal_flags, mmal_buf->pts); -+ -+ if (status) { -+ /* error in transfer */ -+ if (vb2) { -+ /* there was a buffer with the error so return it */ -+ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR); -+ } -+ return; -+ } -+ -+ if (mmal_buf->cmd) { -+ switch (mmal_buf->cmd) { -+ case MMAL_EVENT_FORMAT_CHANGED: -+ { -+ handle_fmt_changed(ctx, mmal_buf); -+ break; -+ } -+ default: -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Unexpected event on output callback - %08x\n", -+ __func__, mmal_buf->cmd); -+ break; -+ } -+ return; -+ } -+ -+ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal); -+ vb2 = &buf->m2m.vb; -+ -+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n", -+ __func__, mmal_buf->length, mmal_buf->mmal_flags, -+ vb2->vb2_buf.index); -+ -+ if (mmal_buf->length == 0) { -+ /* stream ended, or buffer being returned during disable. */ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: Empty buffer - flags %04x", -+ __func__, mmal_buf->mmal_flags); -+ if (!mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) { -+ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_ERROR); -+ if (!port->enabled) -+ complete(&ctx->frame_cmplt); -+ return; -+ } -+ } -+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS) { -+ /* EOS packet from the VPU */ -+ send_eos_event(ctx); -+ vb2->flags |= V4L2_BUF_FLAG_LAST; -+ } -+ -+ vb2->vb2_buf.timestamp = mmal_buf->pts; -+ -+ vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length); -+ if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) -+ vb2->flags |= V4L2_BUF_FLAG_KEYFRAME; -+ -+ vb2_buffer_done(&vb2->vb2_buf, VB2_BUF_STATE_DONE); -+ ctx->num_op_buffers++; -+ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: done %d output buffers\n", -+ __func__, ctx->num_op_buffers); -+ -+ if (!port->enabled) -+ complete(&ctx->frame_cmplt); -+} -+ -+/* vb2_to_mmal_buffer() - converts vb2 buffer header to MMAL -+ * -+ * Copies all the required fields from a VB2 buffer to the MMAL buffer header, -+ * ready for sending to the VPU. -+ */ -+static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf, -+ struct vb2_v4l2_buffer *vb2) -+{ -+ buf->mmal.mmal_flags = 0; -+ if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME) -+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME; -+ -+ /* -+ * Adding this means that the data must be framed correctly as one frame -+ * per buffer. The underlying decoder has no such requirement, but it -+ * will reduce latency as the bistream parser will be kicked immediately -+ * to parse the frame, rather than relying on its own heuristics for -+ * when to wake up. -+ */ -+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; -+ -+ buf->mmal.length = vb2->vb2_buf.planes[0].bytesused; -+ /* -+ * Minor ambiguity in the V4L2 spec as to whether passing in a 0 length -+ * buffer, or one with V4L2_BUF_FLAG_LAST set denotes end of stream. -+ * Handle either. -+ */ -+ if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST) -+ buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS; -+ -+ buf->mmal.pts = vb2->vb2_buf.timestamp; -+ buf->mmal.dts = MMAL_TIME_UNKNOWN; -+} -+ -+/* device_run() - prepares and starts the device -+ * -+ * This simulates all the immediate preparations required before starting -+ * a device. This will be called by the framework when it decides to schedule -+ * a particular instance. -+ */ -+static void device_run(void *priv) -+{ -+ struct bcm2835_codec_ctx *ctx = priv; -+ struct bcm2835_codec_dev *dev = ctx->dev; -+ struct vb2_v4l2_buffer *src_buf, *dst_buf; -+ struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf; -+ struct v4l2_m2m_buffer *m2m; -+ int ret; -+ -+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: off we go\n", __func__); -+ -+ src_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->out_q_ctx); -+ if (src_buf) { -+ m2m = container_of(src_buf, struct v4l2_m2m_buffer, vb); -+ src_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m); -+ vb2_to_mmal_buffer(src_m2m_buf, src_buf); -+ -+ ret = vchiq_mmal_submit_buffer(dev->instance, -+ &ctx->component->input[0], -+ &src_m2m_buf->mmal); -+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted ip buffer len %lu, pts %llu, flags %04x\n", -+ __func__, src_m2m_buf->mmal.length, -+ src_m2m_buf->mmal.pts, src_m2m_buf->mmal.mmal_flags); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting ip buffer\n", -+ __func__); -+ } -+ -+ dst_buf = v4l2_m2m_buf_remove(&ctx->fh.m2m_ctx->cap_q_ctx); -+ if (dst_buf) { -+ m2m = container_of(dst_buf, struct v4l2_m2m_buffer, vb); -+ dst_m2m_buf = container_of(m2m, struct m2m_mmal_buffer, m2m); -+ vb2_to_mmal_buffer(dst_m2m_buf, dst_buf); -+ -+ ret = vchiq_mmal_submit_buffer(dev->instance, -+ &ctx->component->output[0], -+ &dst_m2m_buf->mmal); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed submitting op buffer\n", -+ __func__); -+ } -+ -+ v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: Submitted src %p, dst %p\n", -+ __func__, src_m2m_buf, dst_m2m_buf); -+ -+ /* Complete the job here. */ -+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); -+} -+ -+/* -+ * video ioctls -+ */ -+static int vidioc_querycap(struct file *file, void *priv, -+ struct v4l2_capability *cap) -+{ -+ strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); -+ strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); -+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", -+ MEM2MEM_NAME); -+ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; -+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; -+ return 0; -+} -+ -+static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture) -+{ -+ struct bcm2835_codec_fmt *fmt; -+ struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); -+ -+ if (f->index < fmts->num_entries) { -+ /* Format found */ -+ /* Check format isn't a decode only format when encoding */ -+ if (!decode && -+ fmts->list[f->index].decode_only) -+ return -EINVAL; -+ /* Check format isn't a decode only format when encoding */ -+ if (decode && -+ fmts->list[f->index].encode_only) -+ return -EINVAL; -+ -+ fmt = &fmts->list[f->index]; -+ f->pixelformat = fmt->fourcc; -+ f->flags = fmt->flags; -+ return 0; -+ } -+ -+ /* Format not found */ -+ return -EINVAL; -+} -+ -+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_fmtdesc *f) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ return enum_fmt(f, ctx->dev->decode, true); -+} -+ -+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_fmtdesc *f) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ return enum_fmt(f, ctx->dev->decode, false); -+} -+ -+static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f) -+{ -+ struct vb2_queue *vq; -+ struct bcm2835_codec_q_data *q_data; -+ -+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); -+ if (!vq) -+ return -EINVAL; -+ -+ q_data = get_q_data(ctx, f->type); -+ -+ f->fmt.pix.width = q_data->crop_width; -+ f->fmt.pix.height = q_data->height; -+ f->fmt.pix.field = V4L2_FIELD_NONE; -+ f->fmt.pix.pixelformat = q_data->fmt->fourcc; -+ f->fmt.pix.bytesperline = q_data->bytesperline; -+ f->fmt.pix.sizeimage = q_data->sizeimage; -+ f->fmt.pix.colorspace = ctx->colorspace; -+ f->fmt.pix.xfer_func = ctx->xfer_func; -+ f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; -+ f->fmt.pix.quantization = ctx->quant; -+ -+ return 0; -+} -+ -+static int vidioc_g_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ return vidioc_g_fmt(file2ctx(file), f); -+} -+ -+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ return vidioc_g_fmt(file2ctx(file), f); -+} -+ -+static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt) -+{ -+ /* -+ * The V4L2 specification requires the driver to correct the format -+ * struct if any of the dimensions is unsupported -+ */ -+ if (f->fmt.pix.width > MAX_W) -+ f->fmt.pix.width = MAX_W; -+ if (f->fmt.pix.height > MAX_H) -+ f->fmt.pix.height = MAX_H; -+ -+ if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { -+ /* Only clip min w/h on capture. Treat 0x0 as unknown. */ -+ if (f->fmt.pix.width < MIN_W) -+ f->fmt.pix.width = MIN_W; -+ if (f->fmt.pix.height < MIN_H) -+ f->fmt.pix.height = MIN_H; -+ -+ /* -+ * Buffer must have a vertical alignment of 16 lines. -+ * The selection will reflect any cropping rectangle when only -+ * some of the pixels are active. -+ */ -+ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); -+ -+ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, -+ fmt); -+ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, -+ f->fmt.pix.height, -+ fmt); -+ } else { -+ u32 min_size = f->fmt.pix.width > 1280 || -+ f->fmt.pix.height > 720 ? -+ DEF_COMP_BUF_SIZE_GREATER_720P : -+ DEF_COMP_BUF_SIZE_720P_OR_LESS; -+ -+ f->fmt.pix.bytesperline = 0; -+ if (f->fmt.pix.sizeimage < min_size) -+ f->fmt.pix.sizeimage = min_size; -+ } -+ -+ f->fmt.pix.field = V4L2_FIELD_NONE; -+ -+ return 0; -+} -+ -+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ struct bcm2835_codec_fmt *fmt; -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ fmt = find_format(f, ctx->dev->decode, true); -+ if (!fmt) { -+ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, -+ true)->fourcc; -+ fmt = find_format(f, ctx->dev->decode, true); -+ } -+ -+ return vidioc_try_fmt(f, fmt); -+} -+ -+static int vidioc_try_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ struct bcm2835_codec_fmt *fmt; -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ fmt = find_format(f, ctx->dev->decode, false); -+ if (!fmt) { -+ f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, -+ false)->fourcc; -+ fmt = find_format(f, ctx->dev->decode, false); -+ } -+ -+ if (!f->fmt.pix.colorspace) -+ f->fmt.pix.colorspace = ctx->colorspace; -+ -+ return vidioc_try_fmt(f, fmt); -+} -+ -+static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, -+ unsigned int requested_height) -+{ -+ struct bcm2835_codec_q_data *q_data; -+ struct vb2_queue *vq; -+ struct vchiq_mmal_port *port; -+ bool update_capture_port = false; -+ int ret; -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", -+ f->type, f->fmt.pix.width, f->fmt.pix.height, -+ f->fmt.pix.pixelformat, f->fmt.pix.sizeimage); -+ -+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); -+ if (!vq) -+ return -EINVAL; -+ -+ q_data = get_q_data(ctx, f->type); -+ if (!q_data) -+ return -EINVAL; -+ -+ if (vb2_is_busy(vq)) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); -+ return -EBUSY; -+ } -+ -+ q_data->fmt = find_format(f, ctx->dev->decode, -+ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); -+ q_data->crop_width = f->fmt.pix.width; -+ q_data->height = f->fmt.pix.height; -+ if (!q_data->selection_set) -+ q_data->crop_height = requested_height; -+ -+ /* -+ * Copying the behaviour of vicodec which retains a single set of -+ * colorspace parameters for both input and output. -+ */ -+ ctx->colorspace = f->fmt.pix.colorspace; -+ ctx->xfer_func = f->fmt.pix.xfer_func; -+ ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; -+ ctx->quant = f->fmt.pix.quantization; -+ -+ /* All parameters should have been set correctly by try_fmt */ -+ q_data->bytesperline = f->fmt.pix.bytesperline; -+ q_data->sizeimage = f->fmt.pix.sizeimage; -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", -+ q_data->bytesperline, q_data->sizeimage); -+ -+ if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && -+ f->fmt.pix.width && f->fmt.pix.height) { -+ /* -+ * On the decoder, if provided with a resolution on the input -+ * side, then replicate that to the output side. -+ * GStreamer appears not to support V4L2_EVENT_SOURCE_CHANGE, -+ * nor set up a resolution on the output side, therefore -+ * we can't decode anything at a resolution other than the -+ * default one. -+ */ -+ struct bcm2835_codec_q_data *q_data_dst = -+ &ctx->q_data[V4L2_M2M_DST]; -+ -+ q_data_dst->crop_width = q_data->crop_width; -+ q_data_dst->crop_height = q_data->crop_height; -+ q_data_dst->height = ALIGN(q_data->crop_height, 16); -+ -+ q_data_dst->bytesperline = -+ get_bytesperline(f->fmt.pix.width, q_data_dst->fmt); -+ q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, -+ q_data_dst->height, -+ q_data_dst->fmt); -+ update_capture_port = true; -+ } -+ -+ /* If we have a component then setup the port as well */ -+ port = get_port_data(ctx, vq->type); -+ if (!port) -+ return 0; -+ -+ setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port); -+ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port); -+ if (ret) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n", -+ __func__, ret); -+ ret = -EINVAL; -+ } -+ -+ if (q_data->sizeimage < port->minimum_buffer.size) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Current buffer size of %u < min buf size %u - driver mismatch to MMAL\n", -+ __func__, q_data->sizeimage, -+ port->minimum_buffer.size); -+ } -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Set format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", -+ f->type, q_data->crop_width, q_data->height, -+ q_data->fmt->fourcc, q_data->sizeimage); -+ -+ if (update_capture_port) { -+ struct vchiq_mmal_port *port_dst = &ctx->component->output[0]; -+ struct bcm2835_codec_q_data *q_data_dst = -+ &ctx->q_data[V4L2_M2M_DST]; -+ -+ setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst, -+ port_dst); -+ ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst); -+ if (ret) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n", -+ __func__, ret); -+ ret = -EINVAL; -+ } -+ } -+ return ret; -+} -+ -+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ unsigned int height = f->fmt.pix.height; -+ int ret; -+ -+ ret = vidioc_try_fmt_vid_cap(file, priv, f); -+ if (ret) -+ return ret; -+ -+ return vidioc_s_fmt(file2ctx(file), f, height); -+} -+ -+static int vidioc_s_fmt_vid_out(struct file *file, void *priv, -+ struct v4l2_format *f) -+{ -+ unsigned int height = f->fmt.pix.height; -+ int ret; -+ -+ ret = vidioc_try_fmt_vid_out(file, priv, f); -+ if (ret) -+ return ret; -+ -+ ret = vidioc_s_fmt(file2ctx(file), f, height); -+ return ret; -+} -+ -+static int vidioc_g_selection(struct file *file, void *priv, -+ struct v4l2_selection *s) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ struct bcm2835_codec_q_data *q_data; -+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? -+ true : false; -+ -+ if (capture_queue ^ ctx->dev->decode) -+ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ -+ return -EINVAL; -+ -+ q_data = get_q_data(ctx, s->type); -+ if (!q_data) -+ return -EINVAL; -+ -+ if (ctx->dev->decode) { -+ switch (s->target) { -+ case V4L2_SEL_TGT_COMPOSE_DEFAULT: -+ case V4L2_SEL_TGT_COMPOSE: -+ s->r.left = 0; -+ s->r.top = 0; -+ s->r.width = q_data->crop_width; -+ s->r.height = q_data->crop_height; -+ break; -+ case V4L2_SEL_TGT_COMPOSE_BOUNDS: -+ s->r.left = 0; -+ s->r.top = 0; -+ s->r.width = q_data->crop_width; -+ s->r.height = q_data->crop_height; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } else { -+ switch (s->target) { -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ s->r.top = 0; -+ s->r.left = 0; -+ s->r.width = q_data->bytesperline; -+ s->r.height = q_data->height; -+ break; -+ case V4L2_SEL_TGT_CROP: -+ s->r.top = 0; -+ s->r.left = 0; -+ s->r.width = q_data->crop_width; -+ s->r.height = q_data->crop_height; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static int vidioc_s_selection(struct file *file, void *priv, -+ struct v4l2_selection *s) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ struct bcm2835_codec_q_data *q_data = NULL; -+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? -+ true : false; -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n", -+ __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top, -+ s->r.width, s->r.height); -+ -+ if (capture_queue ^ ctx->dev->decode) -+ /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ -+ return -EINVAL; -+ -+ q_data = get_q_data(ctx, s->type); -+ if (!q_data) -+ return -EINVAL; -+ -+ if (ctx->dev->decode) { -+ switch (s->target) { -+ case V4L2_SEL_TGT_COMPOSE: -+ /* Accept cropped image */ -+ s->r.left = 0; -+ s->r.top = 0; -+ s->r.width = min(s->r.width, q_data->crop_width); -+ s->r.height = min(s->r.height, q_data->height); -+ q_data->crop_width = s->r.width; -+ q_data->crop_height = s->r.height; -+ q_data->selection_set = true; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } else { -+ switch (s->target) { -+ case V4L2_SEL_TGT_CROP: -+ /* Only support crop from (0,0) */ -+ s->r.top = 0; -+ s->r.left = 0; -+ s->r.width = min(s->r.width, q_data->crop_width); -+ s->r.height = min(s->r.height, q_data->crop_height); -+ q_data->crop_width = s->r.width; -+ q_data->crop_height = s->r.height; -+ q_data->selection_set = true; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static int vidioc_subscribe_evt(struct v4l2_fh *fh, -+ const struct v4l2_event_subscription *sub) -+{ -+ switch (sub->type) { -+ case V4L2_EVENT_EOS: -+ return v4l2_event_subscribe(fh, sub, 2, NULL); -+ case V4L2_EVENT_SOURCE_CHANGE: -+ return v4l2_src_change_event_subscribe(fh, sub); -+ default: -+ return v4l2_ctrl_subscribe_event(fh, sub); -+ } -+} -+ -+static int bcm2835_codec_set_level_profile(struct bcm2835_codec_ctx *ctx, -+ struct v4l2_ctrl *ctrl) -+{ -+ struct mmal_parameter_video_profile param; -+ int param_size = sizeof(param); -+ int ret; -+ -+ /* -+ * Level and Profile are set via the same MMAL parameter. -+ * Retrieve the current settings and amend the one that has changed. -+ */ -+ ret = vchiq_mmal_port_parameter_get(ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_PROFILE, -+ ¶m, -+ ¶m_size); -+ if (ret) -+ return ret; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: -+ switch (ctrl->val) { -+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: -+ param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE; -+ break; -+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: -+ param.profile = -+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE; -+ break; -+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: -+ param.profile = MMAL_VIDEO_PROFILE_H264_MAIN; -+ break; -+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: -+ param.profile = MMAL_VIDEO_PROFILE_H264_HIGH; -+ break; -+ default: -+ /* Should never get here */ -+ break; -+ } -+ break; -+ -+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: -+ switch (ctrl->val) { -+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: -+ param.level = MMAL_VIDEO_LEVEL_H264_1; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B: -+ param.level = MMAL_VIDEO_LEVEL_H264_1b; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: -+ param.level = MMAL_VIDEO_LEVEL_H264_11; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: -+ param.level = MMAL_VIDEO_LEVEL_H264_12; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: -+ param.level = MMAL_VIDEO_LEVEL_H264_13; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: -+ param.level = MMAL_VIDEO_LEVEL_H264_2; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: -+ param.level = MMAL_VIDEO_LEVEL_H264_21; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: -+ param.level = MMAL_VIDEO_LEVEL_H264_22; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: -+ param.level = MMAL_VIDEO_LEVEL_H264_3; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: -+ param.level = MMAL_VIDEO_LEVEL_H264_31; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: -+ param.level = MMAL_VIDEO_LEVEL_H264_32; -+ break; -+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: -+ param.level = MMAL_VIDEO_LEVEL_H264_4; -+ break; -+ default: -+ /* Should never get here */ -+ break; -+ } -+ } -+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_PROFILE, -+ ¶m, -+ param_size); -+ -+ return ret; -+} -+ -+static int bcm2835_codec_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct bcm2835_codec_ctx *ctx = -+ container_of(ctrl->handler, struct bcm2835_codec_ctx, hdl); -+ int ret = 0; -+ -+ switch (ctrl->id) { -+ case V4L2_CID_MPEG_VIDEO_BITRATE: -+ ctx->bitrate = ctrl->val; -+ if (!ctx->component) -+ break; -+ -+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_VIDEO_BIT_RATE, -+ &ctrl->val, -+ sizeof(ctrl->val)); -+ break; -+ -+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { -+ u32 bitrate_mode; -+ -+ if (!ctx->component) -+ break; -+ -+ switch (ctrl->val) { -+ default: -+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: -+ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE; -+ break; -+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: -+ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT; -+ break; -+ } -+ -+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_RATECONTROL, -+ &bitrate_mode, -+ sizeof(bitrate_mode)); -+ break; -+ } -+ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: -+ if (!ctx->component) -+ break; -+ -+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, -+ &ctrl->val, -+ sizeof(ctrl->val)); -+ break; -+ -+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: -+ if (!ctx->component) -+ break; -+ -+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_INTRAPERIOD, -+ &ctrl->val, -+ sizeof(ctrl->val)); -+ break; -+ -+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: -+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: -+ if (!ctx->component) -+ break; -+ -+ ret = bcm2835_codec_set_level_profile(ctx, ctrl); -+ break; -+ -+ default: -+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); -+ return -EINVAL; -+ } -+ -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "Failed setting ctrl %08x, ret %d\n", -+ ctrl->id, ret); -+ return ret ? -EINVAL : 0; -+} -+ -+static const struct v4l2_ctrl_ops bcm2835_codec_ctrl_ops = { -+ .s_ctrl = bcm2835_codec_s_ctrl, -+}; -+ -+static int vidioc_try_decoder_cmd(struct file *file, void *priv, -+ struct v4l2_decoder_cmd *cmd) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ if (!ctx->dev->decode) -+ return -EINVAL; -+ -+ switch (cmd->cmd) { -+ case V4L2_DEC_CMD_STOP: -+ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: DEC cmd->flags=%u stop to black not supported", -+ __func__, cmd->flags); -+ return -EINVAL; -+ } -+ break; -+ case V4L2_DEC_CMD_START: -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int vidioc_decoder_cmd(struct file *file, void *priv, -+ struct v4l2_decoder_cmd *cmd) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC]; -+ int ret; -+ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__, -+ cmd->cmd); -+ ret = vidioc_try_decoder_cmd(file, priv, cmd); -+ if (ret) -+ return ret; -+ -+ switch (cmd->cmd) { -+ case V4L2_DEC_CMD_STOP: -+ if (q_data->eos_buffer_in_use) -+ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n"); -+ q_data->eos_buffer_in_use = true; -+ -+ q_data->eos_buffer.mmal.buffer_size = 0; -+ q_data->eos_buffer.mmal.length = 0; -+ q_data->eos_buffer.mmal.mmal_flags = -+ MMAL_BUFFER_HEADER_FLAG_EOS; -+ q_data->eos_buffer.mmal.pts = 0; -+ q_data->eos_buffer.mmal.dts = 0; -+ -+ if (!ctx->component) -+ break; -+ -+ ret = vchiq_mmal_submit_buffer(ctx->dev->instance, -+ &ctx->component->input[0], -+ &q_data->eos_buffer.mmal); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, -+ "%s: EOS buffer submit failed %d\n", -+ __func__, ret); -+ -+ break; -+ -+ case V4L2_DEC_CMD_START: -+ /* Do we need to do anything here? */ -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int vidioc_try_encoder_cmd(struct file *file, void *priv, -+ struct v4l2_encoder_cmd *cmd) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ if (ctx->dev->decode) -+ return -EINVAL; -+ -+ switch (cmd->cmd) { -+ case V4L2_ENC_CMD_STOP: -+ break; -+ -+ case V4L2_ENC_CMD_START: -+ /* Do we need to do anything here? */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int vidioc_encoder_cmd(struct file *file, void *priv, -+ struct v4l2_encoder_cmd *cmd) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ struct bcm2835_codec_q_data *q_data = &ctx->q_data[V4L2_M2M_SRC]; -+ int ret; -+ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s, cmd %u", __func__, -+ cmd->cmd); -+ ret = vidioc_try_encoder_cmd(file, priv, cmd); -+ if (ret) -+ return ret; -+ -+ switch (cmd->cmd) { -+ case V4L2_ENC_CMD_STOP: -+ if (q_data->eos_buffer_in_use) -+ v4l2_err(&ctx->dev->v4l2_dev, "EOS buffers already in use\n"); -+ q_data->eos_buffer_in_use = true; -+ -+ q_data->eos_buffer.mmal.buffer_size = 0; -+ q_data->eos_buffer.mmal.length = 0; -+ q_data->eos_buffer.mmal.mmal_flags = -+ MMAL_BUFFER_HEADER_FLAG_EOS; -+ q_data->eos_buffer.mmal.pts = 0; -+ q_data->eos_buffer.mmal.dts = 0; -+ -+ if (!ctx->component) -+ break; -+ -+ ret = vchiq_mmal_submit_buffer(ctx->dev->instance, -+ &ctx->component->input[0], -+ &q_data->eos_buffer.mmal); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, -+ "%s: EOS buffer submit failed %d\n", -+ __func__, ret); -+ -+ break; -+ case V4L2_ENC_CMD_START: -+ /* Do we need to do anything here? */ -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = { -+ .vidioc_querycap = vidioc_querycap, -+ -+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, -+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, -+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, -+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, -+ -+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, -+ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, -+ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, -+ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, -+ -+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, -+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, -+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, -+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, -+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, -+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, -+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, -+ -+ .vidioc_streamon = v4l2_m2m_ioctl_streamon, -+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, -+ -+ .vidioc_g_selection = vidioc_g_selection, -+ .vidioc_s_selection = vidioc_s_selection, -+ -+ .vidioc_subscribe_event = vidioc_subscribe_evt, -+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -+ -+ .vidioc_decoder_cmd = vidioc_decoder_cmd, -+ .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, -+ .vidioc_encoder_cmd = vidioc_encoder_cmd, -+ .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, -+}; -+ -+static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx) -+{ -+ /* -+ * Query the control handler for the value of the various controls and -+ * set them. -+ */ -+ const u32 control_ids[] = { -+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, -+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, -+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, -+ V4L2_CID_MPEG_VIDEO_H264_LEVEL, -+ V4L2_CID_MPEG_VIDEO_H264_PROFILE, -+ }; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(control_ids); i++) { -+ struct v4l2_ctrl *ctrl; -+ -+ ctrl = v4l2_ctrl_find(&ctx->hdl, control_ids[i]); -+ if (ctrl) -+ bcm2835_codec_s_ctrl(ctrl); -+ } -+ -+ return 0; -+} -+ -+static int bcm2835_codec_create_component(struct bcm2835_codec_ctx *ctx) -+{ -+ struct bcm2835_codec_dev *dev = ctx->dev; -+ unsigned int enable = 1; -+ int ret; -+ -+ ret = vchiq_mmal_component_init(dev->instance, dev->decode ? -+ "ril.video_decode" : "ril.video_encode", -+ &ctx->component); -+ if (ret < 0) { -+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n", -+ __func__, dev->decode ? "decode" : "encode"); -+ return -ENOMEM; -+ } -+ -+ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->input[0], -+ MMAL_PARAMETER_ZERO_COPY, &enable, -+ sizeof(enable)); -+ vchiq_mmal_port_parameter_set(dev->instance, &ctx->component->output[0], -+ MMAL_PARAMETER_ZERO_COPY, &enable, -+ sizeof(enable)); -+ -+ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC], -+ &ctx->component->input[0]); -+ -+ setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST], -+ &ctx->component->output[0]); -+ -+ ret = vchiq_mmal_port_set_format(dev->instance, -+ &ctx->component->input[0]); -+ if (ret < 0) -+ goto destroy_component; -+ -+ ret = vchiq_mmal_port_set_format(dev->instance, -+ &ctx->component->output[0]); -+ if (ret < 0) -+ goto destroy_component; -+ -+ if (dev->decode) { -+ if (ctx->q_data[V4L2_M2M_DST].sizeimage < -+ ctx->component->output[0].minimum_buffer.size) -+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", -+ ctx->q_data[V4L2_M2M_DST].sizeimage, -+ ctx->component->output[0].minimum_buffer.size); -+ } else { -+ if (ctx->q_data[V4L2_M2M_SRC].sizeimage < -+ ctx->component->output[0].minimum_buffer.size) -+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", -+ ctx->q_data[V4L2_M2M_SRC].sizeimage, -+ ctx->component->output[0].minimum_buffer.size); -+ -+ /* Now we have a component we can set all the ctrls */ -+ bcm2835_codec_set_ctrls(ctx); -+ } -+ -+ return 0; -+ -+destroy_component: -+ vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component); -+ -+ return ret; -+} -+ -+/* -+ * Queue operations -+ */ -+ -+static int bcm2835_codec_queue_setup(struct vb2_queue *vq, -+ unsigned int *nbuffers, -+ unsigned int *nplanes, -+ unsigned int sizes[], -+ struct device *alloc_devs[]) -+{ -+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vq); -+ struct bcm2835_codec_q_data *q_data; -+ struct vchiq_mmal_port *port; -+ unsigned int size; -+ -+ q_data = get_q_data(ctx, vq->type); -+ if (!q_data) -+ return -EINVAL; -+ -+ if (!ctx->component) -+ if (bcm2835_codec_create_component(ctx)) -+ return -EINVAL; -+ -+ port = get_port_data(ctx, vq->type); -+ -+ size = q_data->sizeimage; -+ -+ if (*nplanes) -+ return sizes[0] < size ? -EINVAL : 0; -+ -+ *nplanes = 1; -+ -+ sizes[0] = size; -+ port->current_buffer.size = size; -+ -+ if (*nbuffers < port->minimum_buffer.num) -+ *nbuffers = port->minimum_buffer.num; -+ /* Add one buffer to take an EOS */ -+ port->current_buffer.num = *nbuffers + 1; -+ -+ return 0; -+} -+ -+static int bcm2835_codec_buf_init(struct vb2_buffer *vb) -+{ -+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); -+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); -+ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer, -+ vb); -+ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, -+ m2m); -+ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n", -+ __func__, ctx, vb); -+ buf->mmal.buffer = vb2_plane_vaddr(&buf->m2m.vb.vb2_buf, 0); -+ buf->mmal.buffer_size = vb2_plane_size(&buf->m2m.vb.vb2_buf, 0); -+ -+ mmal_vchi_buffer_init(ctx->dev->instance, &buf->mmal); -+ -+ return 0; -+} -+ -+static int bcm2835_codec_buf_prepare(struct vb2_buffer *vb) -+{ -+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); -+ struct bcm2835_codec_q_data *q_data; -+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); -+ struct v4l2_m2m_buffer *m2m = container_of(vbuf, struct v4l2_m2m_buffer, -+ vb); -+ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, -+ m2m); -+ int ret; -+ -+ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n", -+ __func__, vb->vb2_queue->type, vb); -+ -+ q_data = get_q_data(ctx, vb->vb2_queue->type); -+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { -+ if (vbuf->field == V4L2_FIELD_ANY) -+ vbuf->field = V4L2_FIELD_NONE; -+ if (vbuf->field != V4L2_FIELD_NONE) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s field isn't supported\n", -+ __func__); -+ return -EINVAL; -+ } -+ } -+ -+ if (vb2_plane_size(vb, 0) < q_data->sizeimage) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n", -+ __func__, vb2_plane_size(vb, 0), -+ (long)q_data->sizeimage); -+ return -EINVAL; -+ } -+ -+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) -+ vb2_set_plane_payload(vb, 0, q_data->sizeimage); -+ -+ /* -+ * We want to do this at init, but vb2_core_expbuf checks that the -+ * index < q->num_buffers, and q->num_buffers only gets updated once -+ * all the buffers are allocated. -+ */ -+ if (!buf->mmal.dma_buf) { -+ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue, -+ vb->vb2_queue->type, vb->index, 0, -+ O_CLOEXEC, &buf->mmal.dma_buf); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n", -+ __func__, vb->index, ret); -+ } else { -+ ret = 0; -+ } -+ -+ return ret; -+} -+ -+static void bcm2835_codec_buf_queue(struct vb2_buffer *vb) -+{ -+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); -+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); -+ -+ v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p vbuf->flags %u, seq %u, bytesused %u\n", -+ __func__, vb->vb2_queue->type, vb, vbuf->flags, vbuf->sequence, -+ vb->planes[0].bytesused); -+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -+} -+ -+static void bcm2835_codec_buffer_cleanup(struct vb2_buffer *vb) -+{ -+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); -+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb); -+ struct v4l2_m2m_buffer *m2m = container_of(vb2, struct v4l2_m2m_buffer, -+ vb); -+ struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, -+ m2m); -+ -+ v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n", -+ __func__, ctx, vb); -+ -+ mmal_vchi_buffer_cleanup(&buf->mmal); -+ -+ if (buf->mmal.dma_buf) { -+ dma_buf_put(buf->mmal.dma_buf); -+ buf->mmal.dma_buf = NULL; -+ } -+} -+ -+static int bcm2835_codec_start_streaming(struct vb2_queue *q, -+ unsigned int count) -+{ -+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q); -+ struct bcm2835_codec_dev *dev = ctx->dev; -+ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type); -+ int ret; -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d count %d\n", -+ __func__, q->type, count); -+ q_data->sequence = 0; -+ -+ if (!ctx->component_enabled) { -+ ret = vchiq_mmal_component_enable(dev->instance, -+ ctx->component); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n", -+ __func__, ret); -+ ctx->component_enabled = true; -+ } -+ -+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { -+ /* -+ * Create the EOS buffer. -+ * We only need the MMAL part, and want to NOT attach a memory -+ * buffer to it as it should only take flags. -+ */ -+ memset(&q_data->eos_buffer, 0, sizeof(q_data->eos_buffer)); -+ mmal_vchi_buffer_init(dev->instance, -+ &q_data->eos_buffer.mmal); -+ q_data->eos_buffer_in_use = false; -+ -+ ctx->component->input[0].cb_ctx = ctx; -+ ret = vchiq_mmal_port_enable(dev->instance, -+ &ctx->component->input[0], -+ ip_buffer_cb); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling i/p port, ret %d\n", -+ __func__, ret); -+ } else { -+ ctx->component->output[0].cb_ctx = ctx; -+ ret = vchiq_mmal_port_enable(dev->instance, -+ &ctx->component->output[0], -+ op_buffer_cb); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling o/p port, ret %d\n", -+ __func__, ret); -+ } -+ return ret; -+} -+ -+static void bcm2835_codec_stop_streaming(struct vb2_queue *q) -+{ -+ struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(q); -+ struct bcm2835_codec_dev *dev = ctx->dev; -+ struct bcm2835_codec_q_data *q_data = get_q_data(ctx, q->type); -+ struct vchiq_mmal_port *port = get_port_data(ctx, q->type); -+ struct vb2_v4l2_buffer *vbuf; -+ struct vb2_v4l2_buffer *vb2; -+ struct v4l2_m2m_buffer *m2m; -+ struct m2m_mmal_buffer *buf; -+ int ret, i; -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: type: %d - return buffers\n", -+ __func__, q->type); -+ -+ init_completion(&ctx->frame_cmplt); -+ -+ /* Clear out all buffers held by m2m framework */ -+ for (;;) { -+ if (V4L2_TYPE_IS_OUTPUT(q->type)) -+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); -+ else -+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); -+ if (!vbuf) -+ break; -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: return buffer %p\n", -+ __func__, vbuf); -+ -+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); -+ } -+ -+ /* Disable MMAL port - this will flush buffers back */ -+ ret = vchiq_mmal_port_disable(dev->instance, port); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed disabling %s port, ret %d\n", -+ __func__, V4L2_TYPE_IS_OUTPUT(q->type) ? "i/p" : "o/p", -+ ret); -+ -+ while (atomic_read(&port->buffers_with_vpu)) { -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Waiting for buffers to be returned - %d outstanding\n", -+ __func__, atomic_read(&port->buffers_with_vpu)); -+ ret = wait_for_completion_timeout(&ctx->frame_cmplt, HZ); -+ if (ret <= 0) { -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n", -+ __func__, -+ atomic_read(&port->buffers_with_vpu)); -+ break; -+ } -+ } -+ -+ /* -+ * Release the VCSM handle here as otherwise REQBUFS(0) aborts because -+ * someone is using the dmabuf before giving the driver a chance to do -+ * anything about it. -+ */ -+ for (i = 0; i < q->num_buffers; i++) { -+ vb2 = to_vb2_v4l2_buffer(q->bufs[i]); -+ m2m = container_of(vb2, struct v4l2_m2m_buffer, vb); -+ buf = container_of(m2m, struct m2m_mmal_buffer, m2m); -+ -+ mmal_vchi_buffer_cleanup(&buf->mmal); -+ if (buf->mmal.dma_buf) { -+ dma_buf_put(buf->mmal.dma_buf); -+ buf->mmal.dma_buf = NULL; -+ } -+ } -+ -+ /* If both ports disabled, then disable the component */ -+ if (!ctx->component->input[0].enabled && -+ !ctx->component->output[0].enabled) { -+ ret = vchiq_mmal_component_disable(dev->instance, -+ ctx->component); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed enabling component, ret %d\n", -+ __func__, ret); -+ } -+ -+ if (V4L2_TYPE_IS_OUTPUT(q->type)) -+ mmal_vchi_buffer_cleanup(&q_data->eos_buffer.mmal); -+ -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: done\n", __func__); -+} -+ -+static const struct vb2_ops bcm2835_codec_qops = { -+ .queue_setup = bcm2835_codec_queue_setup, -+ .buf_init = bcm2835_codec_buf_init, -+ .buf_prepare = bcm2835_codec_buf_prepare, -+ .buf_queue = bcm2835_codec_buf_queue, -+ .buf_cleanup = bcm2835_codec_buffer_cleanup, -+ .start_streaming = bcm2835_codec_start_streaming, -+ .stop_streaming = bcm2835_codec_stop_streaming, -+ .wait_prepare = vb2_ops_wait_prepare, -+ .wait_finish = vb2_ops_wait_finish, -+}; -+ -+static int queue_init(void *priv, struct vb2_queue *src_vq, -+ struct vb2_queue *dst_vq) -+{ -+ struct bcm2835_codec_ctx *ctx = priv; -+ int ret; -+ -+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; -+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF; -+ src_vq->drv_priv = ctx; -+ src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); -+ src_vq->ops = &bcm2835_codec_qops; -+ src_vq->mem_ops = &vb2_dma_contig_memops; -+ src_vq->dev = &ctx->dev->pdev->dev; -+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; -+ src_vq->lock = &ctx->dev->dev_mutex; -+ -+ ret = vb2_queue_init(src_vq); -+ if (ret) -+ return ret; -+ -+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; -+ dst_vq->drv_priv = ctx; -+ dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); -+ dst_vq->ops = &bcm2835_codec_qops; -+ dst_vq->mem_ops = &vb2_dma_contig_memops; -+ dst_vq->dev = &ctx->dev->pdev->dev; -+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; -+ dst_vq->lock = &ctx->dev->dev_mutex; -+ -+ return vb2_queue_init(dst_vq); -+} -+ -+/* -+ * File operations -+ */ -+static int bcm2835_codec_open(struct file *file) -+{ -+ struct bcm2835_codec_dev *dev = video_drvdata(file); -+ struct bcm2835_codec_ctx *ctx = NULL; -+ struct v4l2_ctrl_handler *hdl; -+ int rc = 0; -+ -+ v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n", -+ dev->decode ? "decode" : "encode"); -+ if (mutex_lock_interruptible(&dev->dev_mutex)) { -+ v4l2_err(&dev->v4l2_dev, "Mutex fail\n"); -+ return -ERESTARTSYS; -+ } -+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) { -+ rc = -ENOMEM; -+ goto open_unlock; -+ } -+ -+ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false); -+ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true); -+ if (dev->decode) { -+ /* -+ * Input width and height are irrelevant as they will be defined -+ * by the bitstream not the format. Required by V4L2 though. -+ */ -+ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; -+ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; -+ ctx->q_data[V4L2_M2M_SRC].sizeimage = -+ DEF_COMP_BUF_SIZE_720P_OR_LESS; -+ -+ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; -+ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_DST].bytesperline = -+ get_bytesperline(DEFAULT_WIDTH, -+ ctx->q_data[V4L2_M2M_DST].fmt); -+ ctx->q_data[V4L2_M2M_DST].sizeimage = -+ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, -+ ctx->q_data[V4L2_M2M_DST].height, -+ ctx->q_data[V4L2_M2M_DST].fmt); -+ } else { -+ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; -+ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_SRC].bytesperline = -+ get_bytesperline(DEFAULT_WIDTH, -+ ctx->q_data[V4L2_M2M_SRC].fmt); -+ ctx->q_data[V4L2_M2M_SRC].sizeimage = -+ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline, -+ ctx->q_data[V4L2_M2M_SRC].height, -+ ctx->q_data[V4L2_M2M_SRC].fmt); -+ -+ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; -+ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_DST].bytesperline = 0; -+ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_DST].sizeimage = -+ DEF_COMP_BUF_SIZE_720P_OR_LESS; -+ } -+ -+ ctx->colorspace = V4L2_COLORSPACE_REC709; -+ ctx->bitrate = 10 * 1000 * 1000; -+ -+ /* Initialise V4L2 contexts */ -+ v4l2_fh_init(&ctx->fh, video_devdata(file)); -+ file->private_data = &ctx->fh; -+ ctx->dev = dev; -+ hdl = &ctx->hdl; -+ if (!dev->decode) { -+ /* Encode controls */ -+ v4l2_ctrl_handler_init(hdl, 6); -+ -+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, -+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, -+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); -+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MPEG_VIDEO_BITRATE, -+ 25 * 1000, 25 * 1000 * 1000, -+ 25 * 1000, 10 * 1000 * 1000); -+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, -+ 0, 1, -+ 1, 0); -+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, -+ 0, 0x7FFFFFFF, -+ 1, 60); -+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MPEG_VIDEO_H264_LEVEL, -+ V4L2_MPEG_VIDEO_H264_LEVEL_4_2, -+ ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | -+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), -+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0); -+ v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MPEG_VIDEO_H264_PROFILE, -+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, -+ ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | -+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | -+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | -+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), -+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); -+ if (hdl->error) { -+ rc = hdl->error; -+ goto free_ctrl_handler; -+ } -+ ctx->fh.ctrl_handler = hdl; -+ v4l2_ctrl_handler_setup(hdl); -+ } -+ -+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); -+ -+ if (IS_ERR(ctx->fh.m2m_ctx)) { -+ rc = PTR_ERR(ctx->fh.m2m_ctx); -+ -+ goto free_ctrl_handler; -+ } -+ -+ /* Set both queues as buffered as we have buffering in the VPU. That -+ * means that we will be scheduled whenever either an input or output -+ * buffer is available (otherwise one of each are required). -+ */ -+ v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); -+ v4l2_m2m_set_dst_buffered(ctx->fh.m2m_ctx, true); -+ -+ v4l2_fh_add(&ctx->fh); -+ atomic_inc(&dev->num_inst); -+ -+ mutex_unlock(&dev->dev_mutex); -+ return 0; -+ -+free_ctrl_handler: -+ v4l2_ctrl_handler_free(hdl); -+ kfree(ctx); -+open_unlock: -+ mutex_unlock(&dev->dev_mutex); -+ return rc; -+} -+ -+static int bcm2835_codec_release(struct file *file) -+{ -+ struct bcm2835_codec_dev *dev = video_drvdata(file); -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: Releasing instance %p\n", -+ __func__, ctx); -+ -+ v4l2_fh_del(&ctx->fh); -+ v4l2_fh_exit(&ctx->fh); -+ v4l2_ctrl_handler_free(&ctx->hdl); -+ mutex_lock(&dev->dev_mutex); -+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); -+ -+ if (ctx->component) -+ vchiq_mmal_component_finalise(dev->instance, ctx->component); -+ -+ mutex_unlock(&dev->dev_mutex); -+ kfree(ctx); -+ -+ atomic_dec(&dev->num_inst); -+ -+ return 0; -+} -+ -+static const struct v4l2_file_operations bcm2835_codec_fops = { -+ .owner = THIS_MODULE, -+ .open = bcm2835_codec_open, -+ .release = bcm2835_codec_release, -+ .poll = v4l2_m2m_fop_poll, -+ .unlocked_ioctl = video_ioctl2, -+ .mmap = v4l2_m2m_fop_mmap, -+}; -+ -+static const struct video_device bcm2835_codec_videodev = { -+ .name = MEM2MEM_NAME, -+ .vfl_dir = VFL_DIR_M2M, -+ .fops = &bcm2835_codec_fops, -+ .ioctl_ops = &bcm2835_codec_ioctl_ops, -+ .minor = -1, -+ .release = video_device_release_empty, -+}; -+ -+static const struct v4l2_m2m_ops m2m_ops = { -+ .device_run = device_run, -+ .job_ready = job_ready, -+ .job_abort = job_abort, -+}; -+ -+static int bcm2835_codec_create(struct platform_device *pdev, -+ struct bcm2835_codec_dev **new_dev, -+ bool decode) -+{ -+ struct bcm2835_codec_dev *dev; -+ struct video_device *vfd; -+ struct vchiq_mmal_instance *instance = NULL; -+ int video_nr; -+ int ret; -+ -+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ dev->pdev = pdev; -+ -+ dev->decode = decode; -+ -+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); -+ if (ret) -+ return ret; -+ -+ atomic_set(&dev->num_inst, 0); -+ mutex_init(&dev->dev_mutex); -+ -+ dev->vfd = bcm2835_codec_videodev; -+ vfd = &dev->vfd; -+ vfd->lock = &dev->dev_mutex; -+ vfd->v4l2_dev = &dev->v4l2_dev; -+ -+ if (dev->decode) { -+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); -+ video_nr = decode_video_nr; -+ } else { -+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); -+ video_nr = encode_video_nr; -+ } -+ -+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); -+ if (ret) { -+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); -+ goto unreg_dev; -+ } -+ -+ video_set_drvdata(vfd, dev); -+ snprintf(vfd->name, sizeof(vfd->name), "%s", -+ bcm2835_codec_videodev.name); -+ v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", -+ vfd->num); -+ -+ *new_dev = dev; -+ -+ dev->m2m_dev = v4l2_m2m_init(&m2m_ops); -+ if (IS_ERR(dev->m2m_dev)) { -+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); -+ ret = PTR_ERR(dev->m2m_dev); -+ goto err_m2m; -+ } -+ -+ ret = vchiq_mmal_init(&instance); -+ if (ret < 0) -+ goto err_m2m; -+ dev->instance = instance; -+ -+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n", -+ dev->decode ? "decode" : "encode"); -+ return 0; -+ -+err_m2m: -+ v4l2_m2m_release(dev->m2m_dev); -+ video_unregister_device(&dev->vfd); -+unreg_dev: -+ v4l2_device_unregister(&dev->v4l2_dev); -+ -+ return ret; -+} -+ -+static int bcm2835_codec_destroy(struct bcm2835_codec_dev *dev) -+{ -+ if (!dev) -+ return -ENODEV; -+ -+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); -+ v4l2_m2m_release(dev->m2m_dev); -+ video_unregister_device(&dev->vfd); -+ v4l2_device_unregister(&dev->v4l2_dev); -+ -+ return 0; -+} -+ -+static int bcm2835_codec_probe(struct platform_device *pdev) -+{ -+ struct bcm2835_codec_driver *drv; -+ int ret = 0; -+ -+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); -+ if (!drv) -+ return -ENOMEM; -+ -+ ret = bcm2835_codec_create(pdev, &drv->encode, false); -+ if (ret) -+ goto out; -+ -+ ret = bcm2835_codec_create(pdev, &drv->decode, true); -+ if (ret) -+ goto out; -+ -+ platform_set_drvdata(pdev, drv); -+ -+ return 0; -+ -+out: -+ if (drv->encode) { -+ bcm2835_codec_destroy(drv->encode); -+ drv->encode = NULL; -+ } -+ return ret; -+} -+ -+static int bcm2835_codec_remove(struct platform_device *pdev) -+{ -+ struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev); -+ -+ bcm2835_codec_destroy(drv->encode); -+ -+ bcm2835_codec_destroy(drv->decode); -+ -+ return 0; -+} -+ -+static struct platform_driver bcm2835_v4l2_codec_driver = { -+ .probe = bcm2835_codec_probe, -+ .remove = bcm2835_codec_remove, -+ .driver = { -+ .name = "bcm2835-codec", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+module_platform_driver(bcm2835_v4l2_codec_driver); -+ -+MODULE_DESCRIPTION("BCM2835 codec V4L2 driver"); -+MODULE_AUTHOR("Dave Stevenson, "); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION("0.0.1"); -+MODULE_ALIAS("platform:bcm2835-codec"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0178-media-ov5647-Use-gpiod_set_value_cansleep.patch b/target/linux/bcm27xx/patches-5.4/950-0178-media-ov5647-Use-gpiod_set_value_cansleep.patch new file mode 100644 index 0000000000..d141349f98 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0178-media-ov5647-Use-gpiod_set_value_cansleep.patch @@ -0,0 +1,54 @@ +From fa219a511fe98237d5126d1e2b5181df5070a179 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 18 Sep 2018 11:08:51 +0100 +Subject: [PATCH] media: ov5647: Use gpiod_set_value_cansleep + +All calls to the gpio library are in contexts that can sleep, +therefore there is no issue with having those GPIOs controlled +by controllers which require sleeping (eg I2C GPIO expanders). + +Switch to using gpiod_set_value_cansleep instead of gpiod_set_value +to avoid triggering the warning in gpiolib should the GPIO +controller need to sleep. + +Signed-off-by: Dave Stevenson +--- + drivers/media/i2c/ov5647.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/media/i2c/ov5647.c ++++ b/drivers/media/i2c/ov5647.c +@@ -373,7 +373,7 @@ static int ov5647_sensor_power(struct v4 + dev_dbg(&client->dev, "OV5647 power on\n"); + + if (ov5647->pwdn) { +- gpiod_set_value(ov5647->pwdn, 0); ++ gpiod_set_value_cansleep(ov5647->pwdn, 0); + msleep(PWDN_ACTIVE_DELAY_MS); + } + +@@ -415,7 +415,7 @@ static int ov5647_sensor_power(struct v4 + + clk_disable_unprepare(ov5647->xclk); + +- gpiod_set_value(ov5647->pwdn, 1); ++ gpiod_set_value_cansleep(ov5647->pwdn, 1); + } + + /* Update the power count. */ +@@ -648,13 +648,13 @@ static int ov5647_probe(struct i2c_clien + goto mutex_remove; + + if (sensor->pwdn) { +- gpiod_set_value(sensor->pwdn, 0); ++ gpiod_set_value_cansleep(sensor->pwdn, 0); + msleep(PWDN_ACTIVE_DELAY_MS); + } + + ret = ov5647_detect(sd); + +- gpiod_set_value(sensor->pwdn, 1); ++ gpiod_set_value_cansleep(sensor->pwdn, 1); + + if (ret < 0) + goto error; diff --git a/target/linux/bcm27xx/patches-5.4/950-0178-staging-mmal-vchiq-Fix-client_component-for-64-bit-k.patch b/target/linux/bcm27xx/patches-5.4/950-0178-staging-mmal-vchiq-Fix-client_component-for-64-bit-k.patch deleted file mode 100644 index 5c64238741..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0178-staging-mmal-vchiq-Fix-client_component-for-64-bit-k.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 50df0b1532cf88e2ec152caa2cf89af0d0646b4a Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 22 Jan 2019 12:04:09 +0000 -Subject: [PATCH] staging: mmal-vchiq: Fix client_component for 64 bit - kernel - -The MMAL client_component field is used with the event -mechanism to allow the client to identify the component for -which the event is generated. -The field is only 32bits in size, therefore we can't use a -pointer to the component in a 64 bit kernel. - -Component handles are already held in an array per VCHI -instance, so use the array index as the client_component handle -to avoid having to create a new IDR for this purpose. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 12 +++++++++--- - .../staging/vc04_services/vchiq-mmal/mmal-vchiq.h | 1 + - 2 files changed, 10 insertions(+), 3 deletions(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -472,9 +472,9 @@ buffer_from_host(struct vchiq_mmal_insta - static void event_to_host_cb(struct vchiq_mmal_instance *instance, - struct mmal_msg *msg, u32 msg_len) - { -- /* FIXME: Not going to work on 64 bit */ -+ int comp_idx = msg->u.event_to_host.client_component; - struct vchiq_mmal_component *component = -- (struct vchiq_mmal_component *)msg->u.event_to_host.client_component; -+ &instance->component[comp_idx]; - struct vchiq_mmal_port *port = NULL; - struct mmal_msg_context *msg_context; - u32 port_num = msg->u.event_to_host.port_num; -@@ -1073,7 +1073,7 @@ static int create_component(struct vchiq - - /* build component create message */ - m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE; -- m.u.component_create.client_component = (u32)(unsigned long)component; -+ m.u.component_create.client_component = component->client_component; - strncpy(m.u.component_create.name, name, - sizeof(m.u.component_create.name)); - -@@ -1868,6 +1868,12 @@ int vchiq_mmal_component_init(struct vch - goto unlock; - } - -+ /* We need a handle to reference back to our component structure. -+ * Use the array index in instance->component rather than rolling -+ * another IDR. -+ */ -+ component->client_component = idx; -+ - ret = create_component(instance, component, name); - if (ret < 0) { - pr_err("%s: failed to create component %d (Not enough GPU mem?)\n", ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -97,6 +97,7 @@ struct vchiq_mmal_component { - struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */ - struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */ - struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */ -+ u32 client_component; /* Used to ref back to client struct */ - }; - - int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance); diff --git a/target/linux/bcm27xx/patches-5.4/950-0179-clk-clk-bcm2835-Use-zd-when-printing-size_t.patch b/target/linux/bcm27xx/patches-5.4/950-0179-clk-clk-bcm2835-Use-zd-when-printing-size_t.patch deleted file mode 100644 index c8acb1a378..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0179-clk-clk-bcm2835-Use-zd-when-printing-size_t.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 608b88a72331d8c3d6561a6a25a2955d211b9c70 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 24 Jan 2019 15:09:28 +0000 -Subject: [PATCH] clk: clk-bcm2835: Use %zd when printing size_t - -The debug text for how many clocks have been registered -uses "%d" with a size_t. Correct it to "%zd". - -Signed-off-by: Dave Stevenson ---- - drivers/clk/bcm/clk-bcm2835.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -2354,7 +2354,7 @@ static int bcm2835_clk_probe(struct plat - return ret; - - /* note that we have registered all the clocks */ -- dev_dbg(dev, "registered %d clocks\n", asize); -+ dev_dbg(dev, "registered %zd clocks\n", asize); - - return 0; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0179-staging-bcm2835-codec-variable-vb2-may-be-used-unini.patch b/target/linux/bcm27xx/patches-5.4/950-0179-staging-bcm2835-codec-variable-vb2-may-be-used-unini.patch new file mode 100644 index 0000000000..ecb867ba89 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0179-staging-bcm2835-codec-variable-vb2-may-be-used-unini.patch @@ -0,0 +1,37 @@ +From ecf1a0cc8481cbfa9c118349930a58ce36605c38 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 24 Jan 2019 16:40:01 +0000 +Subject: [PATCH] staging: bcm2835-codec: variable vb2 may be used + uninitialised + +In op_buffer_cb, the failure path checked whether there was +an associated vb2 buffer before the variable vb2 had been +assigned. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -634,6 +634,9 @@ static void op_buffer_cb(struct vchiq_mm + __func__, status, mmal_buf, mmal_buf->length, + mmal_buf->mmal_flags, mmal_buf->pts); + ++ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal); ++ vb2 = &buf->m2m.vb; ++ + if (status) { + /* error in transfer */ + if (vb2) { +@@ -658,9 +661,6 @@ static void op_buffer_cb(struct vchiq_mm + return; + } + +- buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal); +- vb2 = &buf->m2m.vb; +- + v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n", + __func__, mmal_buf->length, mmal_buf->mmal_flags, + vb2->vb2_buf.index); diff --git a/target/linux/bcm27xx/patches-5.4/950-0180-media-ov5647-Use-gpiod_set_value_cansleep.patch b/target/linux/bcm27xx/patches-5.4/950-0180-media-ov5647-Use-gpiod_set_value_cansleep.patch deleted file mode 100644 index d141349f98..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0180-media-ov5647-Use-gpiod_set_value_cansleep.patch +++ /dev/null @@ -1,54 +0,0 @@ -From fa219a511fe98237d5126d1e2b5181df5070a179 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 18 Sep 2018 11:08:51 +0100 -Subject: [PATCH] media: ov5647: Use gpiod_set_value_cansleep - -All calls to the gpio library are in contexts that can sleep, -therefore there is no issue with having those GPIOs controlled -by controllers which require sleeping (eg I2C GPIO expanders). - -Switch to using gpiod_set_value_cansleep instead of gpiod_set_value -to avoid triggering the warning in gpiolib should the GPIO -controller need to sleep. - -Signed-off-by: Dave Stevenson ---- - drivers/media/i2c/ov5647.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - ---- a/drivers/media/i2c/ov5647.c -+++ b/drivers/media/i2c/ov5647.c -@@ -373,7 +373,7 @@ static int ov5647_sensor_power(struct v4 - dev_dbg(&client->dev, "OV5647 power on\n"); - - if (ov5647->pwdn) { -- gpiod_set_value(ov5647->pwdn, 0); -+ gpiod_set_value_cansleep(ov5647->pwdn, 0); - msleep(PWDN_ACTIVE_DELAY_MS); - } - -@@ -415,7 +415,7 @@ static int ov5647_sensor_power(struct v4 - - clk_disable_unprepare(ov5647->xclk); - -- gpiod_set_value(ov5647->pwdn, 1); -+ gpiod_set_value_cansleep(ov5647->pwdn, 1); - } - - /* Update the power count. */ -@@ -648,13 +648,13 @@ static int ov5647_probe(struct i2c_clien - goto mutex_remove; - - if (sensor->pwdn) { -- gpiod_set_value(sensor->pwdn, 0); -+ gpiod_set_value_cansleep(sensor->pwdn, 0); - msleep(PWDN_ACTIVE_DELAY_MS); - } - - ret = ov5647_detect(sd); - -- gpiod_set_value(sensor->pwdn, 1); -+ gpiod_set_value_cansleep(sensor->pwdn, 1); - - if (ret < 0) - goto error; diff --git a/target/linux/bcm27xx/patches-5.4/950-0180-staging-bcm2835-codec-Fix-potentially-uninitialised-.patch b/target/linux/bcm27xx/patches-5.4/950-0180-staging-bcm2835-codec-Fix-potentially-uninitialised-.patch new file mode 100644 index 0000000000..bfda5a48c9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0180-staging-bcm2835-codec-Fix-potentially-uninitialised-.patch @@ -0,0 +1,25 @@ +From 506734dcc9d76e522d8afbac1d93f61369ed82f9 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 24 Jan 2019 16:36:19 +0000 +Subject: [PATCH] staging: bcm2835-codec: Fix potentially uninitialised + vars + +src_m2m_buf and dst_m2m_buf were printed in log messages +when there are code paths that don't initialise them. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -743,7 +743,7 @@ static void device_run(void *priv) + struct bcm2835_codec_ctx *ctx = priv; + struct bcm2835_codec_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; +- struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf; ++ struct m2m_mmal_buffer *src_m2m_buf = NULL, *dst_m2m_buf = NULL; + struct v4l2_m2m_buffer *m2m; + int ret; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0181-staging-bcm2835-codec-variable-vb2-may-be-used-unini.patch b/target/linux/bcm27xx/patches-5.4/950-0181-staging-bcm2835-codec-variable-vb2-may-be-used-unini.patch deleted file mode 100644 index ecb867ba89..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0181-staging-bcm2835-codec-variable-vb2-may-be-used-unini.patch +++ /dev/null @@ -1,37 +0,0 @@ -From ecf1a0cc8481cbfa9c118349930a58ce36605c38 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 24 Jan 2019 16:40:01 +0000 -Subject: [PATCH] staging: bcm2835-codec: variable vb2 may be used - uninitialised - -In op_buffer_cb, the failure path checked whether there was -an associated vb2 buffer before the variable vb2 had been -assigned. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -634,6 +634,9 @@ static void op_buffer_cb(struct vchiq_mm - __func__, status, mmal_buf, mmal_buf->length, - mmal_buf->mmal_flags, mmal_buf->pts); - -+ buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal); -+ vb2 = &buf->m2m.vb; -+ - if (status) { - /* error in transfer */ - if (vb2) { -@@ -658,9 +661,6 @@ static void op_buffer_cb(struct vchiq_mm - return; - } - -- buf = container_of(mmal_buf, struct m2m_mmal_buffer, mmal); -- vb2 = &buf->m2m.vb; -- - v4l2_dbg(3, debug, &ctx->dev->v4l2_dev, "%s: length %lu, flags %x, idx %u\n", - __func__, mmal_buf->length, mmal_buf->mmal_flags, - vb2->vb2_buf.index); diff --git a/target/linux/bcm27xx/patches-5.4/950-0181-staging-mmal_vchiq-Add-in-the-Bayer-encoding-formats.patch b/target/linux/bcm27xx/patches-5.4/950-0181-staging-mmal_vchiq-Add-in-the-Bayer-encoding-formats.patch new file mode 100644 index 0000000000..715061a917 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0181-staging-mmal_vchiq-Add-in-the-Bayer-encoding-formats.patch @@ -0,0 +1,51 @@ +From daf563329faf04563ea625a6647b5bf58933bb32 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 13 Feb 2019 12:33:29 +0000 +Subject: [PATCH] staging: mmal_vchiq: Add in the Bayer encoding + formats + +The list of formats was copied before Bayer support was added. +The ISP supports Bayer and is being supported by the bcm2835_codec +driver, so add in the encodings for them. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/vchiq-mmal/mmal-encodings.h | 27 +++++++++++++++++++ + 1 file changed, 27 insertions(+) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h +@@ -69,6 +69,33 @@ + */ + #define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V') + ++/* Bayer formats ++ * FourCC values copied from V4L2 where defined. ++ */ ++/* 8 bit per pixel Bayer formats. */ ++#define MMAL_ENCODING_BAYER_SBGGR8 MMAL_FOURCC('B', 'A', '8', '1') ++#define MMAL_ENCODING_BAYER_SGBRG8 MMAL_FOURCC('G', 'B', 'R', 'G') ++#define MMAL_ENCODING_BAYER_SGRBG8 MMAL_FOURCC('G', 'R', 'B', 'G') ++#define MMAL_ENCODING_BAYER_SRGGB8 MMAL_FOURCC('R', 'G', 'G', 'B') ++ ++/* 10 bit per pixel packed Bayer formats. */ ++#define MMAL_ENCODING_BAYER_SBGGR10P MMAL_FOURCC('p', 'B', 'A', 'A') ++#define MMAL_ENCODING_BAYER_SGRBG10P MMAL_FOURCC('p', 'g', 'A', 'A') ++#define MMAL_ENCODING_BAYER_SGBRG10P MMAL_FOURCC('p', 'G', 'A', 'A') ++#define MMAL_ENCODING_BAYER_SRGGB10P MMAL_FOURCC('p', 'R', 'A', 'A') ++ ++/* 12 bit per pixel packed Bayer formats. */ ++#define MMAL_ENCODING_BAYER_SBGGR12P MMAL_FOURCC('p', 'B', '1', '2') ++#define MMAL_ENCODING_BAYER_SGRBG12P MMAL_FOURCC('p', 'g', '1', '2') ++#define MMAL_ENCODING_BAYER_SGBRG12P MMAL_FOURCC('p', 'G', '1', '2') ++#define MMAL_ENCODING_BAYER_SRGGB12P MMAL_FOURCC('p', 'R', '1', '2') ++ ++/* 16 bit per pixel Bayer formats. */ ++#define MMAL_ENCODING_BAYER_SBGGR16 MMAL_FOURCC('B', 'G', '1', '6') ++#define MMAL_ENCODING_BAYER_SGBRG16 MMAL_FOURCC('G', 'B', '1', '6') ++#define MMAL_ENCODING_BAYER_SGRBG16 MMAL_FOURCC('G', 'R', '1', '6') ++#define MMAL_ENCODING_BAYER_SRGGB16 MMAL_FOURCC('R', 'G', '1', '6') ++ + /** An EGL image handle + */ + #define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I') diff --git a/target/linux/bcm27xx/patches-5.4/950-0182-staging-bcm2835-codec-Fix-potentially-uninitialised-.patch b/target/linux/bcm27xx/patches-5.4/950-0182-staging-bcm2835-codec-Fix-potentially-uninitialised-.patch deleted file mode 100644 index bfda5a48c9..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0182-staging-bcm2835-codec-Fix-potentially-uninitialised-.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 506734dcc9d76e522d8afbac1d93f61369ed82f9 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 24 Jan 2019 16:36:19 +0000 -Subject: [PATCH] staging: bcm2835-codec: Fix potentially uninitialised - vars - -src_m2m_buf and dst_m2m_buf were printed in log messages -when there are code paths that don't initialise them. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -743,7 +743,7 @@ static void device_run(void *priv) - struct bcm2835_codec_ctx *ctx = priv; - struct bcm2835_codec_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; -- struct m2m_mmal_buffer *src_m2m_buf, *dst_m2m_buf; -+ struct m2m_mmal_buffer *src_m2m_buf = NULL, *dst_m2m_buf = NULL; - struct v4l2_m2m_buffer *m2m; - int ret; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0182-staging-mmal-vchiq-Always-return-the-param-size-from.patch b/target/linux/bcm27xx/patches-5.4/950-0182-staging-mmal-vchiq-Always-return-the-param-size-from.patch new file mode 100644 index 0000000000..a8c8aebe1c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0182-staging-mmal-vchiq-Always-return-the-param-size-from.patch @@ -0,0 +1,38 @@ +From 2e2b65c1c67b7a918fc381c25f8d5e3f2be2295c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 13 Feb 2019 12:36:56 +0000 +Subject: [PATCH] staging: mmal-vchiq: Always return the param size + from param_get + +mmal-vchiq is a reimplementation of the userland library for MMAL. +When getting a parameter, the client provides the storage and +the size of the storage. The VPU then returns the size of the +parameter that it wished to return, and as much as possible of +that parameter is returned to the client. + +The implementation previously only returned the size provided +by the VPU should it exceed the buffer size. So for parameters +such as the supported encodings list the client had no idea +how much of the provided storage had been populated. + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -1412,11 +1412,12 @@ static int port_parameter_get(struct vch + */ + memcpy(value, &rmsg->u.port_parameter_get_reply.value, + *value_size); +- *value_size = rmsg->u.port_parameter_get_reply.size; + } else { + memcpy(value, &rmsg->u.port_parameter_get_reply.value, + rmsg->u.port_parameter_get_reply.size); + } ++ /* Always report the size of the returned parameter to the caller */ ++ *value_size = rmsg->u.port_parameter_get_reply.size; + + pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, + ret, port->component->handle, port->handle, parameter_id); diff --git a/target/linux/bcm27xx/patches-5.4/950-0183-staging-mmal-vchiq-If-the-VPU-returns-an-error-don-t.patch b/target/linux/bcm27xx/patches-5.4/950-0183-staging-mmal-vchiq-If-the-VPU-returns-an-error-don-t.patch new file mode 100644 index 0000000000..60550ede00 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0183-staging-mmal-vchiq-If-the-VPU-returns-an-error-don-t.patch @@ -0,0 +1,29 @@ +From 8bf13b2aedef0e0ef2250dd612f453e1a923a2d7 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 13 Feb 2019 12:51:03 +0000 +Subject: [PATCH] staging: mmal-vchiq: If the VPU returns an error, + don't negate it + +There is an enum for the errors that the VPU can return. +port_parameter_get was negating that value, but also using -EINVAL +from the Linux error codes. +Pass the VPU error code as positive values. Should the function +need to pass a Linux failure, then return that as negative. + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -1400,7 +1400,8 @@ static int port_parameter_get(struct vch + goto release_msg; + } + +- ret = -rmsg->u.port_parameter_get_reply.status; ++ ret = rmsg->u.port_parameter_get_reply.status; ++ + /* port_parameter_get_reply.size includes the header, + * whilst *value_size doesn't. + */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0183-staging-mmal_vchiq-Add-in-the-Bayer-encoding-formats.patch b/target/linux/bcm27xx/patches-5.4/950-0183-staging-mmal_vchiq-Add-in-the-Bayer-encoding-formats.patch deleted file mode 100644 index 715061a917..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0183-staging-mmal_vchiq-Add-in-the-Bayer-encoding-formats.patch +++ /dev/null @@ -1,51 +0,0 @@ -From daf563329faf04563ea625a6647b5bf58933bb32 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 13 Feb 2019 12:33:29 +0000 -Subject: [PATCH] staging: mmal_vchiq: Add in the Bayer encoding - formats - -The list of formats was copied before Bayer support was added. -The ISP supports Bayer and is being supported by the bcm2835_codec -driver, so add in the encodings for them. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/vchiq-mmal/mmal-encodings.h | 27 +++++++++++++++++++ - 1 file changed, 27 insertions(+) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-encodings.h -@@ -69,6 +69,33 @@ - */ - #define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V') - -+/* Bayer formats -+ * FourCC values copied from V4L2 where defined. -+ */ -+/* 8 bit per pixel Bayer formats. */ -+#define MMAL_ENCODING_BAYER_SBGGR8 MMAL_FOURCC('B', 'A', '8', '1') -+#define MMAL_ENCODING_BAYER_SGBRG8 MMAL_FOURCC('G', 'B', 'R', 'G') -+#define MMAL_ENCODING_BAYER_SGRBG8 MMAL_FOURCC('G', 'R', 'B', 'G') -+#define MMAL_ENCODING_BAYER_SRGGB8 MMAL_FOURCC('R', 'G', 'G', 'B') -+ -+/* 10 bit per pixel packed Bayer formats. */ -+#define MMAL_ENCODING_BAYER_SBGGR10P MMAL_FOURCC('p', 'B', 'A', 'A') -+#define MMAL_ENCODING_BAYER_SGRBG10P MMAL_FOURCC('p', 'g', 'A', 'A') -+#define MMAL_ENCODING_BAYER_SGBRG10P MMAL_FOURCC('p', 'G', 'A', 'A') -+#define MMAL_ENCODING_BAYER_SRGGB10P MMAL_FOURCC('p', 'R', 'A', 'A') -+ -+/* 12 bit per pixel packed Bayer formats. */ -+#define MMAL_ENCODING_BAYER_SBGGR12P MMAL_FOURCC('p', 'B', '1', '2') -+#define MMAL_ENCODING_BAYER_SGRBG12P MMAL_FOURCC('p', 'g', '1', '2') -+#define MMAL_ENCODING_BAYER_SGBRG12P MMAL_FOURCC('p', 'G', '1', '2') -+#define MMAL_ENCODING_BAYER_SRGGB12P MMAL_FOURCC('p', 'R', '1', '2') -+ -+/* 16 bit per pixel Bayer formats. */ -+#define MMAL_ENCODING_BAYER_SBGGR16 MMAL_FOURCC('B', 'G', '1', '6') -+#define MMAL_ENCODING_BAYER_SGBRG16 MMAL_FOURCC('G', 'B', '1', '6') -+#define MMAL_ENCODING_BAYER_SGRBG16 MMAL_FOURCC('G', 'R', '1', '6') -+#define MMAL_ENCODING_BAYER_SRGGB16 MMAL_FOURCC('R', 'G', '1', '6') -+ - /** An EGL image handle - */ - #define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I') diff --git a/target/linux/bcm27xx/patches-5.4/950-0184-staging-bcm2835_codec-Query-supported-formats-from-t.patch b/target/linux/bcm27xx/patches-5.4/950-0184-staging-bcm2835_codec-Query-supported-formats-from-t.patch new file mode 100644 index 0000000000..00c3837c3c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0184-staging-bcm2835_codec-Query-supported-formats-from-t.patch @@ -0,0 +1,727 @@ +From 9f6d3fea405751e39801ae101fe2625efb3c6ca4 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 13 Feb 2019 13:44:00 +0000 +Subject: [PATCH] staging: bcm2835_codec: Query supported formats from + the component + +The driver was previously working with hard coded tables of +which video formats were supported by each component. +The components advertise this information via a MMAL parameter, +so retrieve the information from there during probe, and store +in the state structure for that device. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 455 +++++++++++++----- + 1 file changed, 327 insertions(+), 128 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -88,17 +88,12 @@ struct bcm2835_codec_fmt { + int bytesperline_align; + u32 flags; + u32 mmal_fmt; +- bool decode_only; +- bool encode_only; + int size_multiplier_x2; + }; + +-/* Supported raw pixel formats. Those supported for both encode and decode +- * must come first, with those only supported for decode coming after (there +- * are no formats supported for encode only). +- */ +-static struct bcm2835_codec_fmt raw_formats[] = { ++static const struct bcm2835_codec_fmt supported_formats[] = { + { ++ /* YUV formats */ + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 8, + .bytesperline_align = 32, +@@ -139,7 +134,6 @@ static struct bcm2835_codec_fmt raw_form + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_YUYV, +- .encode_only = true, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, +@@ -147,7 +141,6 @@ static struct bcm2835_codec_fmt raw_form + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_UYVY, +- .encode_only = true, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, +@@ -155,7 +148,6 @@ static struct bcm2835_codec_fmt raw_form + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_YVYU, +- .encode_only = true, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, +@@ -163,15 +155,14 @@ static struct bcm2835_codec_fmt raw_form + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_VYUY, +- .encode_only = true, + .size_multiplier_x2 = 2, + }, { ++ /* RGB formats */ + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_RGB24, +- .encode_only = true, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, +@@ -179,7 +170,6 @@ static struct bcm2835_codec_fmt raw_form + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BGR24, +- .encode_only = true, + .size_multiplier_x2 = 2, + }, { + .fourcc = V4L2_PIX_FMT_BGR32, +@@ -187,17 +177,126 @@ static struct bcm2835_codec_fmt raw_form + .bytesperline_align = 32, + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BGRA, +- .encode_only = true, + .size_multiplier_x2 = 2, +- }, +-}; +- +-/* Supported encoded formats. Those supported for both encode and decode +- * must come first, with those only supported for decode coming after (there +- * are no formats supported for encode only). +- */ +-static struct bcm2835_codec_fmt encoded_formats[] = { +- { ++ }, { ++ /* Bayer formats */ ++ /* 8 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .depth = 8, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8, ++ .size_multiplier_x2 = 2, ++ }, { ++ /* 10 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB10P, ++ .depth = 10, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR10P, ++ .depth = 10, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG10P, ++ .depth = 10, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG10P, ++ .depth = 10, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P, ++ .size_multiplier_x2 = 2, ++ }, { ++ /* 12 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB12P, ++ .depth = 12, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR12P, ++ .depth = 12, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG12P, ++ .depth = 12, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG12P, ++ .depth = 12, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P, ++ .size_multiplier_x2 = 2, ++ }, { ++ /* 16 bit */ ++ .fourcc = V4L2_PIX_FMT_SRGGB16, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR16, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG16, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16, ++ .size_multiplier_x2 = 2, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG16, ++ .depth = 16, ++ .bytesperline_align = 32, ++ .flags = 0, ++ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16, ++ .size_multiplier_x2 = 2, ++ }, { ++ /* Compressed formats */ + .fourcc = V4L2_PIX_FMT_H264, + .depth = 0, + .flags = V4L2_FMT_FLAG_COMPRESSED, +@@ -212,30 +311,22 @@ static struct bcm2835_codec_fmt encoded_ + .depth = 0, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal_fmt = MMAL_ENCODING_MP4V, +- .decode_only = true, + }, { + .fourcc = V4L2_PIX_FMT_H263, + .depth = 0, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal_fmt = MMAL_ENCODING_H263, +- .decode_only = true, + }, { + .fourcc = V4L2_PIX_FMT_MPEG2, + .depth = 0, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal_fmt = MMAL_ENCODING_MP2V, +- .decode_only = true, + }, { + .fourcc = V4L2_PIX_FMT_VP8, + .depth = 0, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .mmal_fmt = MMAL_ENCODING_VP8, +- .decode_only = true, + }, +- /* +- * This list couold include VP6 and Theorafor decode, but V4L2 doesn't +- * support them. +- */ + }; + + struct bcm2835_codec_fmt_list { +@@ -243,19 +334,6 @@ struct bcm2835_codec_fmt_list { + unsigned int num_entries; + }; + +-#define RAW_LIST 0 +-#define ENCODED_LIST 1 +- +-struct bcm2835_codec_fmt_list formats[] = { +- { +- .list = raw_formats, +- .num_entries = ARRAY_SIZE(raw_formats), +- }, { +- .list = encoded_formats, +- .num_entries = ARRAY_SIZE(encoded_formats), +- }, +-}; +- + struct m2m_mmal_buffer { + struct v4l2_m2m_buffer m2m; + struct mmal_buffer mmal; +@@ -284,52 +362,6 @@ struct bcm2835_codec_q_data { + bool eos_buffer_in_use; /* debug only */ + }; + +-enum { +- V4L2_M2M_SRC = 0, +- V4L2_M2M_DST = 1, +-}; +- +-static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode, +- bool capture) +-{ +- return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST]; +-} +- +-static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture) +-{ +- return &get_format_list(decode, capture)->list[0]; +-} +- +-static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode, +- bool capture) +-{ +- struct bcm2835_codec_fmt *fmt; +- unsigned int k; +- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); +- +- for (k = 0; k < fmts->num_entries; k++) { +- fmt = &fmts->list[k]; +- if (fmt->fourcc == f->fmt.pix.pixelformat) +- break; +- } +- +- /* +- * Some compressed formats are only supported for decoding, not +- * encoding. +- */ +- if (!decode && fmts->list[k].decode_only) +- return NULL; +- +- /* Some pixel formats are only supported for encoding, not decoding. */ +- if (decode && fmts->list[k].encode_only) +- return NULL; +- +- if (k == fmts->num_entries) +- return NULL; +- +- return &fmts->list[k]; +-} +- + struct bcm2835_codec_dev { + struct platform_device *pdev; + +@@ -342,6 +374,9 @@ struct bcm2835_codec_dev { + + /* allocated mmal instance and components */ + bool decode; /* Is this instance a decoder? */ ++ /* The list of formats supported on input and output queues. */ ++ struct bcm2835_codec_fmt_list supported_fmts[2]; ++ + struct vchiq_mmal_instance *instance; + + struct v4l2_m2m_dev *m2m_dev; +@@ -374,8 +409,59 @@ struct bcm2835_codec_ctx { + struct bcm2835_codec_driver { + struct bcm2835_codec_dev *encode; + struct bcm2835_codec_dev *decode; ++ struct bcm2835_codec_dev *isp; ++}; ++ ++enum { ++ V4L2_M2M_SRC = 0, ++ V4L2_M2M_DST = 1, + }; + ++static const struct bcm2835_codec_fmt *get_fmt(u32 mmal_fmt) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { ++ if (supported_formats[i].mmal_fmt == mmal_fmt) ++ return &supported_formats[i]; ++ } ++ return NULL; ++} ++ ++static inline ++struct bcm2835_codec_fmt_list *get_format_list(struct bcm2835_codec_dev *dev, ++ bool capture) ++{ ++ return &dev->supported_fmts[capture ? 1 : 0]; ++} ++ ++static ++struct bcm2835_codec_fmt *get_default_format(struct bcm2835_codec_dev *dev, ++ bool capture) ++{ ++ return &dev->supported_fmts[capture ? 1 : 0].list[0]; ++} ++ ++static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, ++ struct bcm2835_codec_dev *dev, ++ bool capture) ++{ ++ struct bcm2835_codec_fmt *fmt; ++ unsigned int k; ++ struct bcm2835_codec_fmt_list *fmts = ++ &dev->supported_fmts[capture ? 1 : 0]; ++ ++ for (k = 0; k < fmts->num_entries; k++) { ++ fmt = &fmts->list[k]; ++ if (fmt->fourcc == f->fmt.pix.pixelformat) ++ break; ++ } ++ if (k == fmts->num_entries) ++ return NULL; ++ ++ return &fmts->list[k]; ++} ++ + static inline struct bcm2835_codec_ctx *file2ctx(struct file *file) + { + return container_of(file->private_data, struct bcm2835_codec_ctx, fh); +@@ -456,7 +542,6 @@ static inline unsigned int get_bytesperl + } + + static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx, +- bool decode, + struct bcm2835_codec_q_data *q_data, + struct vchiq_mmal_port *port) + { +@@ -473,7 +558,7 @@ static void setup_mmal_port_format(struc + port->es.video.frame_rate.den = 1; + } else { + /* Compressed format - leave resolution as 0 for decode */ +- if (decode) { ++ if (ctx->dev->decode) { + port->es.video.width = 0; + port->es.video.height = 0; + port->es.video.crop.width = 0; +@@ -802,22 +887,15 @@ static int vidioc_querycap(struct file * + return 0; + } + +-static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture) ++static int enum_fmt(struct v4l2_fmtdesc *f, struct bcm2835_codec_ctx *ctx, ++ bool capture) + { + struct bcm2835_codec_fmt *fmt; +- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); ++ struct bcm2835_codec_fmt_list *fmts = ++ get_format_list(ctx->dev, capture); + + if (f->index < fmts->num_entries) { + /* Format found */ +- /* Check format isn't a decode only format when encoding */ +- if (!decode && +- fmts->list[f->index].decode_only) +- return -EINVAL; +- /* Check format isn't a decode only format when encoding */ +- if (decode && +- fmts->list[f->index].encode_only) +- return -EINVAL; +- + fmt = &fmts->list[f->index]; + f->pixelformat = fmt->fourcc; + f->flags = fmt->flags; +@@ -833,7 +911,7 @@ static int vidioc_enum_fmt_vid_cap(struc + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- return enum_fmt(f, ctx->dev->decode, true); ++ return enum_fmt(f, ctx, true); + } + + static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, +@@ -841,7 +919,7 @@ static int vidioc_enum_fmt_vid_out(struc + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- return enum_fmt(f, ctx->dev->decode, false); ++ return enum_fmt(f, ctx, false); + } + + static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f) +@@ -933,11 +1011,11 @@ static int vidioc_try_fmt_vid_cap(struct + struct bcm2835_codec_fmt *fmt; + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- fmt = find_format(f, ctx->dev->decode, true); ++ fmt = find_format(f, ctx->dev, true); + if (!fmt) { +- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, ++ f->fmt.pix.pixelformat = get_default_format(ctx->dev, + true)->fourcc; +- fmt = find_format(f, ctx->dev->decode, true); ++ fmt = find_format(f, ctx->dev, true); + } + + return vidioc_try_fmt(f, fmt); +@@ -949,11 +1027,11 @@ static int vidioc_try_fmt_vid_out(struct + struct bcm2835_codec_fmt *fmt; + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- fmt = find_format(f, ctx->dev->decode, false); ++ fmt = find_format(f, ctx->dev, false); + if (!fmt) { +- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, ++ f->fmt.pix.pixelformat = get_default_format(ctx->dev, + false)->fourcc; +- fmt = find_format(f, ctx->dev->decode, false); ++ fmt = find_format(f, ctx->dev, false); + } + + if (!f->fmt.pix.colorspace) +@@ -988,7 +1066,7 @@ static int vidioc_s_fmt(struct bcm2835_c + return -EBUSY; + } + +- q_data->fmt = find_format(f, ctx->dev->decode, ++ q_data->fmt = find_format(f, ctx->dev, + f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); + q_data->crop_width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; +@@ -1041,7 +1119,7 @@ static int vidioc_s_fmt(struct bcm2835_c + if (!port) + return 0; + +- setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port); ++ setup_mmal_port_format(ctx, q_data, port); + ret = vchiq_mmal_port_set_format(ctx->dev->instance, port); + if (ret) { + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n", +@@ -1064,8 +1142,7 @@ static int vidioc_s_fmt(struct bcm2835_c + struct bcm2835_codec_q_data *q_data_dst = + &ctx->q_data[V4L2_M2M_DST]; + +- setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst, +- port_dst); ++ setup_mmal_port_format(ctx, q_data_dst, port_dst); + ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst); + if (ret) { + v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n", +@@ -1636,10 +1713,10 @@ static int bcm2835_codec_create_componen + MMAL_PARAMETER_ZERO_COPY, &enable, + sizeof(enable)); + +- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC], ++ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC], + &ctx->component->input[0]); + +- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST], ++ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST], + &ctx->component->output[0]); + + ret = vchiq_mmal_port_set_format(dev->instance, +@@ -2025,8 +2102,8 @@ static int bcm2835_codec_open(struct fil + goto open_unlock; + } + +- ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false); +- ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true); ++ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false); ++ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true); + if (dev->decode) { + /* + * Input width and height are irrelevant as they will be defined +@@ -2209,13 +2286,130 @@ static const struct v4l2_m2m_ops m2m_ops + .job_abort = job_abort, + }; + ++/* Size of the array to provide to the VPU when asking for the list of supported ++ * formats. ++ * The ISP component currently advertises 33 input formats, so add a small ++ * overhead on that. ++ */ ++#define MAX_SUPPORTED_ENCODINGS 40 ++ ++/* Populate dev->supported_fmts with the formats supported by those ports. */ ++static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev) ++{ ++ struct bcm2835_codec_fmt *list; ++ struct vchiq_mmal_component *component; ++ u32 fourccs[MAX_SUPPORTED_ENCODINGS]; ++ u32 param_size = sizeof(fourccs); ++ unsigned int i, j, num_encodings; ++ int ret; ++ ++ ret = vchiq_mmal_component_init(dev->instance, ++ dev->decode ? ++ "ril.video_decode" : ++ "ril.video_encode", ++ &component); ++ if (ret < 0) { ++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n", ++ __func__); ++ return -ENOMEM; ++ } ++ ++ ret = vchiq_mmal_port_parameter_get(dev->instance, ++ &component->input[0], ++ MMAL_PARAMETER_SUPPORTED_ENCODINGS, ++ &fourccs, ++ ¶m_size); ++ ++ if (ret) { ++ if (ret == MMAL_MSG_STATUS_ENOSPC) { ++ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n", ++ __func__); ++ num_encodings = MAX_SUPPORTED_ENCODINGS; ++ } else { ++ v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n", ++ __func__, ret); ++ ret = -EINVAL; ++ goto destroy_component; ++ } ++ } else { ++ num_encodings = param_size / sizeof(u32); ++ } ++ ++ /* Assume at this stage that all encodings will be supported in V4L2. ++ * Any that aren't supported will waste a very small amount of memory. ++ */ ++ list = devm_kzalloc(&dev->pdev->dev, ++ sizeof(struct bcm2835_codec_fmt) * num_encodings, ++ GFP_KERNEL); ++ if (!list) { ++ ret = -ENOMEM; ++ goto destroy_component; ++ } ++ dev->supported_fmts[0].list = list; ++ ++ for (i = 0, j = 0; i < num_encodings; i++) { ++ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]); ++ ++ if (fmt) { ++ list[j] = *fmt; ++ j++; ++ } ++ } ++ dev->supported_fmts[0].num_entries = j; ++ ++ param_size = sizeof(fourccs); ++ ret = vchiq_mmal_port_parameter_get(dev->instance, ++ &component->output[0], ++ MMAL_PARAMETER_SUPPORTED_ENCODINGS, ++ &fourccs, ++ ¶m_size); ++ ++ if (ret) { ++ if (ret == MMAL_MSG_STATUS_ENOSPC) { ++ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n", ++ __func__); ++ num_encodings = MAX_SUPPORTED_ENCODINGS; ++ } else { ++ ret = -EINVAL; ++ goto destroy_component; ++ } ++ } else { ++ num_encodings = param_size / sizeof(u32); ++ } ++ /* Assume at this stage that all encodings will be supported in V4L2. */ ++ list = devm_kzalloc(&dev->pdev->dev, ++ sizeof(struct bcm2835_codec_fmt) * num_encodings, ++ GFP_KERNEL); ++ if (!list) { ++ ret = -ENOMEM; ++ goto destroy_component; ++ } ++ dev->supported_fmts[1].list = list; ++ ++ for (i = 0, j = 0; i < num_encodings; i++) { ++ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]); ++ ++ if (fmt) { ++ list[j] = *fmt; ++ j++; ++ } ++ } ++ dev->supported_fmts[1].num_entries = j; ++ ++ ret = 0; ++ ++destroy_component: ++ vchiq_mmal_component_finalise(dev->instance, component); ++ ++ return ret; ++} ++ + static int bcm2835_codec_create(struct platform_device *pdev, + struct bcm2835_codec_dev **new_dev, + bool decode) + { + struct bcm2835_codec_dev *dev; + struct video_device *vfd; +- struct vchiq_mmal_instance *instance = NULL; + int video_nr; + int ret; + +@@ -2227,10 +2421,18 @@ static int bcm2835_codec_create(struct p + + dev->decode = decode; + +- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ ret = vchiq_mmal_init(&dev->instance); + if (ret) + return ret; + ++ ret = bcm2835_codec_get_supported_fmts(dev); ++ if (ret) ++ goto vchiq_finalise; ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if (ret) ++ goto vchiq_finalise; ++ + atomic_set(&dev->num_inst, 0); + mutex_init(&dev->dev_mutex); + +@@ -2270,12 +2472,7 @@ static int bcm2835_codec_create(struct p + goto err_m2m; + } + +- ret = vchiq_mmal_init(&instance); +- if (ret < 0) +- goto err_m2m; +- dev->instance = instance; +- +- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n", ++ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", + dev->decode ? "decode" : "encode"); + return 0; + +@@ -2284,7 +2481,8 @@ err_m2m: + video_unregister_device(&dev->vfd); + unreg_dev: + v4l2_device_unregister(&dev->v4l2_dev); +- ++vchiq_finalise: ++ vchiq_mmal_finalise(dev->instance); + return ret; + } + +@@ -2297,6 +2495,7 @@ static int bcm2835_codec_destroy(struct + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(&dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); ++ vchiq_mmal_finalise(dev->instance); + + return 0; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0184-staging-mmal-vchiq-Always-return-the-param-size-from.patch b/target/linux/bcm27xx/patches-5.4/950-0184-staging-mmal-vchiq-Always-return-the-param-size-from.patch deleted file mode 100644 index a8c8aebe1c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0184-staging-mmal-vchiq-Always-return-the-param-size-from.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 2e2b65c1c67b7a918fc381c25f8d5e3f2be2295c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 13 Feb 2019 12:36:56 +0000 -Subject: [PATCH] staging: mmal-vchiq: Always return the param size - from param_get - -mmal-vchiq is a reimplementation of the userland library for MMAL. -When getting a parameter, the client provides the storage and -the size of the storage. The VPU then returns the size of the -parameter that it wished to return, and as much as possible of -that parameter is returned to the client. - -The implementation previously only returned the size provided -by the VPU should it exceed the buffer size. So for parameters -such as the supported encodings list the client had no idea -how much of the provided storage had been populated. - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -1412,11 +1412,12 @@ static int port_parameter_get(struct vch - */ - memcpy(value, &rmsg->u.port_parameter_get_reply.value, - *value_size); -- *value_size = rmsg->u.port_parameter_get_reply.size; - } else { - memcpy(value, &rmsg->u.port_parameter_get_reply.value, - rmsg->u.port_parameter_get_reply.size); - } -+ /* Always report the size of the returned parameter to the caller */ -+ *value_size = rmsg->u.port_parameter_get_reply.size; - - pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, - ret, port->component->handle, port->handle, parameter_id); diff --git a/target/linux/bcm27xx/patches-5.4/950-0185-staging-bcm2835_codec-Add-support-for-the-ISP-as-an-.patch b/target/linux/bcm27xx/patches-5.4/950-0185-staging-bcm2835_codec-Add-support-for-the-ISP-as-an-.patch new file mode 100644 index 0000000000..3bbe6814c3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0185-staging-bcm2835_codec-Add-support-for-the-ISP-as-an-.patch @@ -0,0 +1,384 @@ +From 6fe43df9941cbd4810c4fcd02e49156a85180c16 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 13 Feb 2019 14:07:52 +0000 +Subject: [PATCH] staging: bcm2835_codec: Add support for the ISP as an + M2M device + +The MMAL ISP component can also use this same V4L2 wrapper to +provide a M2M format conversion and resizer. +Instantiate 3 V4L2 devices now, one for each of decode, encode, +and isp. +The ISP currently doesn't expose any controls via V4L2, but this +can be extended in the future. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 132 ++++++++++++------ + 1 file changed, 92 insertions(+), 40 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -54,10 +54,26 @@ static int encode_video_nr = 11; + module_param(encode_video_nr, int, 0644); + MODULE_PARM_DESC(encode_video_nr, "encoder video device number"); + ++static int isp_video_nr = 12; ++module_param(isp_video_nr, int, 0644); ++MODULE_PARM_DESC(isp_video_nr, "isp video device number"); ++ + static unsigned int debug; + module_param(debug, uint, 0644); + MODULE_PARM_DESC(debug, "activates debug info (0-3)"); + ++enum bcm2835_codec_role { ++ DECODE, ++ ENCODE, ++ ISP, ++}; ++ ++static const char * const components[] = { ++ "ril.video_decode", ++ "ril.video_encode", ++ "ril.isp", ++}; ++ + #define MIN_W 32 + #define MIN_H 32 + #define MAX_W 1920 +@@ -373,7 +389,7 @@ struct bcm2835_codec_dev { + atomic_t num_inst; + + /* allocated mmal instance and components */ +- bool decode; /* Is this instance a decoder? */ ++ enum bcm2835_codec_role role; + /* The list of formats supported on input and output queues. */ + struct bcm2835_codec_fmt_list supported_fmts[2]; + +@@ -558,7 +574,7 @@ static void setup_mmal_port_format(struc + port->es.video.frame_rate.den = 1; + } else { + /* Compressed format - leave resolution as 0 for decode */ +- if (ctx->dev->decode) { ++ if (ctx->dev->role == DECODE) { + port->es.video.width = 0; + port->es.video.height = 0; + port->es.video.crop.width = 0; +@@ -1089,7 +1105,8 @@ static int vidioc_s_fmt(struct bcm2835_c + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", + q_data->bytesperline, q_data->sizeimage); + +- if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && ++ if (ctx->dev->role == DECODE && ++ q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && + f->fmt.pix.width && f->fmt.pix.height) { + /* + * On the decoder, if provided with a resolution on the input +@@ -1188,7 +1205,8 @@ static int vidioc_g_selection(struct fil + bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? + true : false; + +- if (capture_queue ^ ctx->dev->decode) ++ if ((ctx->dev->role == DECODE && !capture_queue) || ++ (ctx->dev->role == ENCODE && capture_queue)) + /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ + return -EINVAL; + +@@ -1196,7 +1214,8 @@ static int vidioc_g_selection(struct fil + if (!q_data) + return -EINVAL; + +- if (ctx->dev->decode) { ++ switch (ctx->dev->role) { ++ case DECODE: + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE: +@@ -1214,7 +1233,8 @@ static int vidioc_g_selection(struct fil + default: + return -EINVAL; + } +- } else { ++ break; ++ case ENCODE: + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: +@@ -1232,6 +1252,9 @@ static int vidioc_g_selection(struct fil + default: + return -EINVAL; + } ++ break; ++ case ISP: ++ break; + } + + return 0; +@@ -1249,7 +1272,8 @@ static int vidioc_s_selection(struct fil + __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top, + s->r.width, s->r.height); + +- if (capture_queue ^ ctx->dev->decode) ++ if ((ctx->dev->role == DECODE && !capture_queue) || ++ (ctx->dev->role == ENCODE && capture_queue)) + /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ + return -EINVAL; + +@@ -1257,7 +1281,8 @@ static int vidioc_s_selection(struct fil + if (!q_data) + return -EINVAL; + +- if (ctx->dev->decode) { ++ switch (ctx->dev->role) { ++ case DECODE: + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + /* Accept cropped image */ +@@ -1272,7 +1297,8 @@ static int vidioc_s_selection(struct fil + default: + return -EINVAL; + } +- } else { ++ break; ++ case ENCODE: + switch (s->target) { + case V4L2_SEL_TGT_CROP: + /* Only support crop from (0,0) */ +@@ -1287,6 +1313,9 @@ static int vidioc_s_selection(struct fil + default: + return -EINVAL; + } ++ break; ++ case ISP: ++ break; + } + + return 0; +@@ -1490,7 +1519,7 @@ static int vidioc_try_decoder_cmd(struct + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- if (!ctx->dev->decode) ++ if (ctx->dev->role != DECODE) + return -EINVAL; + + switch (cmd->cmd) { +@@ -1564,7 +1593,7 @@ static int vidioc_try_encoder_cmd(struct + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- if (ctx->dev->decode) ++ if (ctx->dev->role != ENCODE) + return -EINVAL; + + switch (cmd->cmd) { +@@ -1697,12 +1726,11 @@ static int bcm2835_codec_create_componen + unsigned int enable = 1; + int ret; + +- ret = vchiq_mmal_component_init(dev->instance, dev->decode ? +- "ril.video_decode" : "ril.video_encode", ++ ret = vchiq_mmal_component_init(dev->instance, components[dev->role], + &ctx->component); + if (ret < 0) { +- v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n", +- __func__, dev->decode ? "decode" : "encode"); ++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n", ++ __func__, components[dev->role]); + return -ENOMEM; + } + +@@ -1729,13 +1757,7 @@ static int bcm2835_codec_create_componen + if (ret < 0) + goto destroy_component; + +- if (dev->decode) { +- if (ctx->q_data[V4L2_M2M_DST].sizeimage < +- ctx->component->output[0].minimum_buffer.size) +- v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", +- ctx->q_data[V4L2_M2M_DST].sizeimage, +- ctx->component->output[0].minimum_buffer.size); +- } else { ++ if (dev->role == ENCODE) { + if (ctx->q_data[V4L2_M2M_SRC].sizeimage < + ctx->component->output[0].minimum_buffer.size) + v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", +@@ -1744,6 +1766,12 @@ static int bcm2835_codec_create_componen + + /* Now we have a component we can set all the ctrls */ + bcm2835_codec_set_ctrls(ctx); ++ } else { ++ if (ctx->q_data[V4L2_M2M_DST].sizeimage < ++ ctx->component->output[0].minimum_buffer.size) ++ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", ++ ctx->q_data[V4L2_M2M_DST].sizeimage, ++ ctx->component->output[0].minimum_buffer.size); + } + + return 0; +@@ -2090,8 +2118,6 @@ static int bcm2835_codec_open(struct fil + struct v4l2_ctrl_handler *hdl; + int rc = 0; + +- v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n", +- dev->decode ? "decode" : "encode"); + if (mutex_lock_interruptible(&dev->dev_mutex)) { + v4l2_err(&dev->v4l2_dev, "Mutex fail\n"); + return -ERESTARTSYS; +@@ -2104,7 +2130,8 @@ static int bcm2835_codec_open(struct fil + + ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false); + ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true); +- if (dev->decode) { ++ switch (dev->role) { ++ case DECODE: + /* + * Input width and height are irrelevant as they will be defined + * by the bitstream not the format. Required by V4L2 though. +@@ -2126,7 +2153,8 @@ static int bcm2835_codec_open(struct fil + get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, + ctx->q_data[V4L2_M2M_DST].height, + ctx->q_data[V4L2_M2M_DST].fmt); +- } else { ++ break; ++ case ENCODE: + ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; + ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; + ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; +@@ -2144,6 +2172,9 @@ static int bcm2835_codec_open(struct fil + ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; + ctx->q_data[V4L2_M2M_DST].sizeimage = + DEF_COMP_BUF_SIZE_720P_OR_LESS; ++ break; ++ case ISP: ++ break; + } + + ctx->colorspace = V4L2_COLORSPACE_REC709; +@@ -2154,7 +2185,7 @@ static int bcm2835_codec_open(struct fil + file->private_data = &ctx->fh; + ctx->dev = dev; + hdl = &ctx->hdl; +- if (!dev->decode) { ++ if (dev->role == ENCODE) { + /* Encode controls */ + v4l2_ctrl_handler_init(hdl, 6); + +@@ -2303,14 +2334,11 @@ static int bcm2835_codec_get_supported_f + unsigned int i, j, num_encodings; + int ret; + +- ret = vchiq_mmal_component_init(dev->instance, +- dev->decode ? +- "ril.video_decode" : +- "ril.video_encode", ++ ret = vchiq_mmal_component_init(dev->instance, components[dev->role], + &component); + if (ret < 0) { +- v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n", +- __func__); ++ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n", ++ __func__, components[dev->role]); + return -ENOMEM; + } + +@@ -2406,12 +2434,13 @@ destroy_component: + + static int bcm2835_codec_create(struct platform_device *pdev, + struct bcm2835_codec_dev **new_dev, +- bool decode) ++ enum bcm2835_codec_role role) + { + struct bcm2835_codec_dev *dev; + struct video_device *vfd; + int video_nr; + int ret; ++ const static char *roles[] = {"decode", "encode", "isp"}; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) +@@ -2419,7 +2448,7 @@ static int bcm2835_codec_create(struct p + + dev->pdev = pdev; + +- dev->decode = decode; ++ dev->role = role; + + ret = vchiq_mmal_init(&dev->instance); + if (ret) +@@ -2441,14 +2470,27 @@ static int bcm2835_codec_create(struct p + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + +- if (dev->decode) { ++ switch (role) { ++ case DECODE: + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + video_nr = decode_video_nr; +- } else { ++ break; ++ case ENCODE: + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + video_nr = encode_video_nr; ++ break; ++ case ISP: ++ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); ++ video_nr = isp_video_nr; ++ break; ++ default: ++ ret = -EINVAL; ++ goto unreg_dev; + } + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); +@@ -2473,7 +2515,7 @@ static int bcm2835_codec_create(struct p + } + + v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", +- dev->decode ? "decode" : "encode"); ++ roles[role]); + return 0; + + err_m2m: +@@ -2509,11 +2551,15 @@ static int bcm2835_codec_probe(struct pl + if (!drv) + return -ENOMEM; + +- ret = bcm2835_codec_create(pdev, &drv->encode, false); ++ ret = bcm2835_codec_create(pdev, &drv->decode, DECODE); + if (ret) + goto out; + +- ret = bcm2835_codec_create(pdev, &drv->decode, true); ++ ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE); ++ if (ret) ++ goto out; ++ ++ ret = bcm2835_codec_create(pdev, &drv->isp, ISP); + if (ret) + goto out; + +@@ -2526,6 +2572,10 @@ out: + bcm2835_codec_destroy(drv->encode); + drv->encode = NULL; + } ++ if (drv->decode) { ++ bcm2835_codec_destroy(drv->decode); ++ drv->decode = NULL; ++ } + return ret; + } + +@@ -2533,6 +2583,8 @@ static int bcm2835_codec_remove(struct p + { + struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev); + ++ bcm2835_codec_destroy(drv->isp); ++ + bcm2835_codec_destroy(drv->encode); + + bcm2835_codec_destroy(drv->decode); diff --git a/target/linux/bcm27xx/patches-5.4/950-0185-staging-mmal-vchiq-If-the-VPU-returns-an-error-don-t.patch b/target/linux/bcm27xx/patches-5.4/950-0185-staging-mmal-vchiq-If-the-VPU-returns-an-error-don-t.patch deleted file mode 100644 index 60550ede00..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0185-staging-mmal-vchiq-If-the-VPU-returns-an-error-don-t.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 8bf13b2aedef0e0ef2250dd612f453e1a923a2d7 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 13 Feb 2019 12:51:03 +0000 -Subject: [PATCH] staging: mmal-vchiq: If the VPU returns an error, - don't negate it - -There is an enum for the errors that the VPU can return. -port_parameter_get was negating that value, but also using -EINVAL -from the Linux error codes. -Pass the VPU error code as positive values. Should the function -need to pass a Linux failure, then return that as negative. - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -1400,7 +1400,8 @@ static int port_parameter_get(struct vch - goto release_msg; - } - -- ret = -rmsg->u.port_parameter_get_reply.status; -+ ret = rmsg->u.port_parameter_get_reply.status; -+ - /* port_parameter_get_reply.size includes the header, - * whilst *value_size doesn't. - */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0186-staging-bcm2835_codec-Add-an-option-for-ignoring-Bay.patch b/target/linux/bcm27xx/patches-5.4/950-0186-staging-bcm2835_codec-Add-an-option-for-ignoring-Bay.patch new file mode 100644 index 0000000000..911612621c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0186-staging-bcm2835_codec-Add-an-option-for-ignoring-Bay.patch @@ -0,0 +1,179 @@ +From c2740ccf8d92b25940ddda20abd4c4f5b97f235c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 15 Feb 2019 11:36:14 +0000 +Subject: [PATCH] staging: bcm2835_codec: Add an option for ignoring + Bayer formats. + +This is a workaround for GStreamer currently not identifying Bayer +as a raw format, therefore any device that supports it does not +match the criteria for v4l2convert. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 29 ++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -58,6 +58,15 @@ static int isp_video_nr = 12; + module_param(isp_video_nr, int, 0644); + MODULE_PARM_DESC(isp_video_nr, "isp video device number"); + ++/* ++ * Workaround for GStreamer v4l2convert component not considering Bayer formats ++ * as raw, and therefore not considering a V4L2 device that supports them as ++ * as a suitable candidate. ++ */ ++static bool disable_bayer; ++module_param(disable_bayer, bool, 0644); ++MODULE_PARM_DESC(disable_bayer, "Disable support for Bayer formats"); ++ + static unsigned int debug; + module_param(debug, uint, 0644); + MODULE_PARM_DESC(debug, "activates debug info (0-3)"); +@@ -105,6 +114,7 @@ struct bcm2835_codec_fmt { + u32 flags; + u32 mmal_fmt; + int size_multiplier_x2; ++ bool is_bayer; + }; + + static const struct bcm2835_codec_fmt supported_formats[] = { +@@ -203,6 +213,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .depth = 8, +@@ -210,6 +221,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = 8, +@@ -217,6 +229,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .depth = 8, +@@ -224,6 +237,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + /* 10 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB10P, +@@ -232,6 +246,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .depth = 10, +@@ -239,6 +254,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .depth = 10, +@@ -246,6 +262,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .depth = 10, +@@ -253,6 +270,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + /* 12 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB12P, +@@ -261,6 +279,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .depth = 12, +@@ -268,6 +287,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .depth = 12, +@@ -275,6 +295,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .depth = 12, +@@ -282,6 +303,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + /* 16 bit */ + .fourcc = V4L2_PIX_FMT_SRGGB16, +@@ -290,6 +312,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .depth = 16, +@@ -297,6 +320,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .depth = 16, +@@ -304,6 +328,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .depth = 16, +@@ -311,6 +336,7 @@ static const struct bcm2835_codec_fmt su + .flags = 0, + .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16, + .size_multiplier_x2 = 2, ++ .is_bayer = true, + }, { + /* Compressed formats */ + .fourcc = V4L2_PIX_FMT_H264, +@@ -438,7 +464,8 @@ static const struct bcm2835_codec_fmt *g + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { +- if (supported_formats[i].mmal_fmt == mmal_fmt) ++ if (supported_formats[i].mmal_fmt == mmal_fmt && ++ (!disable_bayer || !supported_formats[i].is_bayer)) + return &supported_formats[i]; + } + return NULL; diff --git a/target/linux/bcm27xx/patches-5.4/950-0186-staging-bcm2835_codec-Query-supported-formats-from-t.patch b/target/linux/bcm27xx/patches-5.4/950-0186-staging-bcm2835_codec-Query-supported-formats-from-t.patch deleted file mode 100644 index 00c3837c3c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0186-staging-bcm2835_codec-Query-supported-formats-from-t.patch +++ /dev/null @@ -1,727 +0,0 @@ -From 9f6d3fea405751e39801ae101fe2625efb3c6ca4 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 13 Feb 2019 13:44:00 +0000 -Subject: [PATCH] staging: bcm2835_codec: Query supported formats from - the component - -The driver was previously working with hard coded tables of -which video formats were supported by each component. -The components advertise this information via a MMAL parameter, -so retrieve the information from there during probe, and store -in the state structure for that device. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 455 +++++++++++++----- - 1 file changed, 327 insertions(+), 128 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -88,17 +88,12 @@ struct bcm2835_codec_fmt { - int bytesperline_align; - u32 flags; - u32 mmal_fmt; -- bool decode_only; -- bool encode_only; - int size_multiplier_x2; - }; - --/* Supported raw pixel formats. Those supported for both encode and decode -- * must come first, with those only supported for decode coming after (there -- * are no formats supported for encode only). -- */ --static struct bcm2835_codec_fmt raw_formats[] = { -+static const struct bcm2835_codec_fmt supported_formats[] = { - { -+ /* YUV formats */ - .fourcc = V4L2_PIX_FMT_YUV420, - .depth = 8, - .bytesperline_align = 32, -@@ -139,7 +134,6 @@ static struct bcm2835_codec_fmt raw_form - .bytesperline_align = 32, - .flags = 0, - .mmal_fmt = MMAL_ENCODING_YUYV, -- .encode_only = true, - .size_multiplier_x2 = 2, - }, { - .fourcc = V4L2_PIX_FMT_UYVY, -@@ -147,7 +141,6 @@ static struct bcm2835_codec_fmt raw_form - .bytesperline_align = 32, - .flags = 0, - .mmal_fmt = MMAL_ENCODING_UYVY, -- .encode_only = true, - .size_multiplier_x2 = 2, - }, { - .fourcc = V4L2_PIX_FMT_YVYU, -@@ -155,7 +148,6 @@ static struct bcm2835_codec_fmt raw_form - .bytesperline_align = 32, - .flags = 0, - .mmal_fmt = MMAL_ENCODING_YVYU, -- .encode_only = true, - .size_multiplier_x2 = 2, - }, { - .fourcc = V4L2_PIX_FMT_VYUY, -@@ -163,15 +155,14 @@ static struct bcm2835_codec_fmt raw_form - .bytesperline_align = 32, - .flags = 0, - .mmal_fmt = MMAL_ENCODING_VYUY, -- .encode_only = true, - .size_multiplier_x2 = 2, - }, { -+ /* RGB formats */ - .fourcc = V4L2_PIX_FMT_RGB24, - .depth = 24, - .bytesperline_align = 32, - .flags = 0, - .mmal_fmt = MMAL_ENCODING_RGB24, -- .encode_only = true, - .size_multiplier_x2 = 2, - }, { - .fourcc = V4L2_PIX_FMT_BGR24, -@@ -179,7 +170,6 @@ static struct bcm2835_codec_fmt raw_form - .bytesperline_align = 32, - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BGR24, -- .encode_only = true, - .size_multiplier_x2 = 2, - }, { - .fourcc = V4L2_PIX_FMT_BGR32, -@@ -187,17 +177,126 @@ static struct bcm2835_codec_fmt raw_form - .bytesperline_align = 32, - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BGRA, -- .encode_only = true, - .size_multiplier_x2 = 2, -- }, --}; -- --/* Supported encoded formats. Those supported for both encode and decode -- * must come first, with those only supported for decode coming after (there -- * are no formats supported for encode only). -- */ --static struct bcm2835_codec_fmt encoded_formats[] = { -- { -+ }, { -+ /* Bayer formats */ -+ /* 8 bit */ -+ .fourcc = V4L2_PIX_FMT_SRGGB8, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SBGGR8, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGRBG8, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGBRG8, -+ .depth = 8, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8, -+ .size_multiplier_x2 = 2, -+ }, { -+ /* 10 bit */ -+ .fourcc = V4L2_PIX_FMT_SRGGB10P, -+ .depth = 10, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SBGGR10P, -+ .depth = 10, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGRBG10P, -+ .depth = 10, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGBRG10P, -+ .depth = 10, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P, -+ .size_multiplier_x2 = 2, -+ }, { -+ /* 12 bit */ -+ .fourcc = V4L2_PIX_FMT_SRGGB12P, -+ .depth = 12, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SBGGR12P, -+ .depth = 12, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGRBG12P, -+ .depth = 12, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGBRG12P, -+ .depth = 12, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P, -+ .size_multiplier_x2 = 2, -+ }, { -+ /* 16 bit */ -+ .fourcc = V4L2_PIX_FMT_SRGGB16, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SBGGR16, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGRBG16, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16, -+ .size_multiplier_x2 = 2, -+ }, { -+ .fourcc = V4L2_PIX_FMT_SGBRG16, -+ .depth = 16, -+ .bytesperline_align = 32, -+ .flags = 0, -+ .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16, -+ .size_multiplier_x2 = 2, -+ }, { -+ /* Compressed formats */ - .fourcc = V4L2_PIX_FMT_H264, - .depth = 0, - .flags = V4L2_FMT_FLAG_COMPRESSED, -@@ -212,30 +311,22 @@ static struct bcm2835_codec_fmt encoded_ - .depth = 0, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal_fmt = MMAL_ENCODING_MP4V, -- .decode_only = true, - }, { - .fourcc = V4L2_PIX_FMT_H263, - .depth = 0, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal_fmt = MMAL_ENCODING_H263, -- .decode_only = true, - }, { - .fourcc = V4L2_PIX_FMT_MPEG2, - .depth = 0, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal_fmt = MMAL_ENCODING_MP2V, -- .decode_only = true, - }, { - .fourcc = V4L2_PIX_FMT_VP8, - .depth = 0, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .mmal_fmt = MMAL_ENCODING_VP8, -- .decode_only = true, - }, -- /* -- * This list couold include VP6 and Theorafor decode, but V4L2 doesn't -- * support them. -- */ - }; - - struct bcm2835_codec_fmt_list { -@@ -243,19 +334,6 @@ struct bcm2835_codec_fmt_list { - unsigned int num_entries; - }; - --#define RAW_LIST 0 --#define ENCODED_LIST 1 -- --struct bcm2835_codec_fmt_list formats[] = { -- { -- .list = raw_formats, -- .num_entries = ARRAY_SIZE(raw_formats), -- }, { -- .list = encoded_formats, -- .num_entries = ARRAY_SIZE(encoded_formats), -- }, --}; -- - struct m2m_mmal_buffer { - struct v4l2_m2m_buffer m2m; - struct mmal_buffer mmal; -@@ -284,52 +362,6 @@ struct bcm2835_codec_q_data { - bool eos_buffer_in_use; /* debug only */ - }; - --enum { -- V4L2_M2M_SRC = 0, -- V4L2_M2M_DST = 1, --}; -- --static inline struct bcm2835_codec_fmt_list *get_format_list(bool decode, -- bool capture) --{ -- return decode ^ capture ? &formats[ENCODED_LIST] : &formats[RAW_LIST]; --} -- --static struct bcm2835_codec_fmt *get_default_format(bool decode, bool capture) --{ -- return &get_format_list(decode, capture)->list[0]; --} -- --static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, bool decode, -- bool capture) --{ -- struct bcm2835_codec_fmt *fmt; -- unsigned int k; -- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); -- -- for (k = 0; k < fmts->num_entries; k++) { -- fmt = &fmts->list[k]; -- if (fmt->fourcc == f->fmt.pix.pixelformat) -- break; -- } -- -- /* -- * Some compressed formats are only supported for decoding, not -- * encoding. -- */ -- if (!decode && fmts->list[k].decode_only) -- return NULL; -- -- /* Some pixel formats are only supported for encoding, not decoding. */ -- if (decode && fmts->list[k].encode_only) -- return NULL; -- -- if (k == fmts->num_entries) -- return NULL; -- -- return &fmts->list[k]; --} -- - struct bcm2835_codec_dev { - struct platform_device *pdev; - -@@ -342,6 +374,9 @@ struct bcm2835_codec_dev { - - /* allocated mmal instance and components */ - bool decode; /* Is this instance a decoder? */ -+ /* The list of formats supported on input and output queues. */ -+ struct bcm2835_codec_fmt_list supported_fmts[2]; -+ - struct vchiq_mmal_instance *instance; - - struct v4l2_m2m_dev *m2m_dev; -@@ -374,8 +409,59 @@ struct bcm2835_codec_ctx { - struct bcm2835_codec_driver { - struct bcm2835_codec_dev *encode; - struct bcm2835_codec_dev *decode; -+ struct bcm2835_codec_dev *isp; -+}; -+ -+enum { -+ V4L2_M2M_SRC = 0, -+ V4L2_M2M_DST = 1, - }; - -+static const struct bcm2835_codec_fmt *get_fmt(u32 mmal_fmt) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { -+ if (supported_formats[i].mmal_fmt == mmal_fmt) -+ return &supported_formats[i]; -+ } -+ return NULL; -+} -+ -+static inline -+struct bcm2835_codec_fmt_list *get_format_list(struct bcm2835_codec_dev *dev, -+ bool capture) -+{ -+ return &dev->supported_fmts[capture ? 1 : 0]; -+} -+ -+static -+struct bcm2835_codec_fmt *get_default_format(struct bcm2835_codec_dev *dev, -+ bool capture) -+{ -+ return &dev->supported_fmts[capture ? 1 : 0].list[0]; -+} -+ -+static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, -+ struct bcm2835_codec_dev *dev, -+ bool capture) -+{ -+ struct bcm2835_codec_fmt *fmt; -+ unsigned int k; -+ struct bcm2835_codec_fmt_list *fmts = -+ &dev->supported_fmts[capture ? 1 : 0]; -+ -+ for (k = 0; k < fmts->num_entries; k++) { -+ fmt = &fmts->list[k]; -+ if (fmt->fourcc == f->fmt.pix.pixelformat) -+ break; -+ } -+ if (k == fmts->num_entries) -+ return NULL; -+ -+ return &fmts->list[k]; -+} -+ - static inline struct bcm2835_codec_ctx *file2ctx(struct file *file) - { - return container_of(file->private_data, struct bcm2835_codec_ctx, fh); -@@ -456,7 +542,6 @@ static inline unsigned int get_bytesperl - } - - static void setup_mmal_port_format(struct bcm2835_codec_ctx *ctx, -- bool decode, - struct bcm2835_codec_q_data *q_data, - struct vchiq_mmal_port *port) - { -@@ -473,7 +558,7 @@ static void setup_mmal_port_format(struc - port->es.video.frame_rate.den = 1; - } else { - /* Compressed format - leave resolution as 0 for decode */ -- if (decode) { -+ if (ctx->dev->decode) { - port->es.video.width = 0; - port->es.video.height = 0; - port->es.video.crop.width = 0; -@@ -802,22 +887,15 @@ static int vidioc_querycap(struct file * - return 0; - } - --static int enum_fmt(struct v4l2_fmtdesc *f, bool decode, bool capture) -+static int enum_fmt(struct v4l2_fmtdesc *f, struct bcm2835_codec_ctx *ctx, -+ bool capture) - { - struct bcm2835_codec_fmt *fmt; -- struct bcm2835_codec_fmt_list *fmts = get_format_list(decode, capture); -+ struct bcm2835_codec_fmt_list *fmts = -+ get_format_list(ctx->dev, capture); - - if (f->index < fmts->num_entries) { - /* Format found */ -- /* Check format isn't a decode only format when encoding */ -- if (!decode && -- fmts->list[f->index].decode_only) -- return -EINVAL; -- /* Check format isn't a decode only format when encoding */ -- if (decode && -- fmts->list[f->index].encode_only) -- return -EINVAL; -- - fmt = &fmts->list[f->index]; - f->pixelformat = fmt->fourcc; - f->flags = fmt->flags; -@@ -833,7 +911,7 @@ static int vidioc_enum_fmt_vid_cap(struc - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- return enum_fmt(f, ctx->dev->decode, true); -+ return enum_fmt(f, ctx, true); - } - - static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, -@@ -841,7 +919,7 @@ static int vidioc_enum_fmt_vid_out(struc - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- return enum_fmt(f, ctx->dev->decode, false); -+ return enum_fmt(f, ctx, false); - } - - static int vidioc_g_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f) -@@ -933,11 +1011,11 @@ static int vidioc_try_fmt_vid_cap(struct - struct bcm2835_codec_fmt *fmt; - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- fmt = find_format(f, ctx->dev->decode, true); -+ fmt = find_format(f, ctx->dev, true); - if (!fmt) { -- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, -+ f->fmt.pix.pixelformat = get_default_format(ctx->dev, - true)->fourcc; -- fmt = find_format(f, ctx->dev->decode, true); -+ fmt = find_format(f, ctx->dev, true); - } - - return vidioc_try_fmt(f, fmt); -@@ -949,11 +1027,11 @@ static int vidioc_try_fmt_vid_out(struct - struct bcm2835_codec_fmt *fmt; - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- fmt = find_format(f, ctx->dev->decode, false); -+ fmt = find_format(f, ctx->dev, false); - if (!fmt) { -- f->fmt.pix.pixelformat = get_default_format(ctx->dev->decode, -+ f->fmt.pix.pixelformat = get_default_format(ctx->dev, - false)->fourcc; -- fmt = find_format(f, ctx->dev->decode, false); -+ fmt = find_format(f, ctx->dev, false); - } - - if (!f->fmt.pix.colorspace) -@@ -988,7 +1066,7 @@ static int vidioc_s_fmt(struct bcm2835_c - return -EBUSY; - } - -- q_data->fmt = find_format(f, ctx->dev->decode, -+ q_data->fmt = find_format(f, ctx->dev, - f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); - q_data->crop_width = f->fmt.pix.width; - q_data->height = f->fmt.pix.height; -@@ -1041,7 +1119,7 @@ static int vidioc_s_fmt(struct bcm2835_c - if (!port) - return 0; - -- setup_mmal_port_format(ctx, ctx->dev->decode, q_data, port); -+ setup_mmal_port_format(ctx, q_data, port); - ret = vchiq_mmal_port_set_format(ctx->dev->instance, port); - if (ret) { - v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on port, ret %d\n", -@@ -1064,8 +1142,7 @@ static int vidioc_s_fmt(struct bcm2835_c - struct bcm2835_codec_q_data *q_data_dst = - &ctx->q_data[V4L2_M2M_DST]; - -- setup_mmal_port_format(ctx, ctx->dev->decode, q_data_dst, -- port_dst); -+ setup_mmal_port_format(ctx, q_data_dst, port_dst); - ret = vchiq_mmal_port_set_format(ctx->dev->instance, port_dst); - if (ret) { - v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed vchiq_mmal_port_set_format on output port, ret %d\n", -@@ -1636,10 +1713,10 @@ static int bcm2835_codec_create_componen - MMAL_PARAMETER_ZERO_COPY, &enable, - sizeof(enable)); - -- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_SRC], -+ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_SRC], - &ctx->component->input[0]); - -- setup_mmal_port_format(ctx, dev->decode, &ctx->q_data[V4L2_M2M_DST], -+ setup_mmal_port_format(ctx, &ctx->q_data[V4L2_M2M_DST], - &ctx->component->output[0]); - - ret = vchiq_mmal_port_set_format(dev->instance, -@@ -2025,8 +2102,8 @@ static int bcm2835_codec_open(struct fil - goto open_unlock; - } - -- ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev->decode, false); -- ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev->decode, true); -+ ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false); -+ ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true); - if (dev->decode) { - /* - * Input width and height are irrelevant as they will be defined -@@ -2209,13 +2286,130 @@ static const struct v4l2_m2m_ops m2m_ops - .job_abort = job_abort, - }; - -+/* Size of the array to provide to the VPU when asking for the list of supported -+ * formats. -+ * The ISP component currently advertises 33 input formats, so add a small -+ * overhead on that. -+ */ -+#define MAX_SUPPORTED_ENCODINGS 40 -+ -+/* Populate dev->supported_fmts with the formats supported by those ports. */ -+static int bcm2835_codec_get_supported_fmts(struct bcm2835_codec_dev *dev) -+{ -+ struct bcm2835_codec_fmt *list; -+ struct vchiq_mmal_component *component; -+ u32 fourccs[MAX_SUPPORTED_ENCODINGS]; -+ u32 param_size = sizeof(fourccs); -+ unsigned int i, j, num_encodings; -+ int ret; -+ -+ ret = vchiq_mmal_component_init(dev->instance, -+ dev->decode ? -+ "ril.video_decode" : -+ "ril.video_encode", -+ &component); -+ if (ret < 0) { -+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n", -+ __func__); -+ return -ENOMEM; -+ } -+ -+ ret = vchiq_mmal_port_parameter_get(dev->instance, -+ &component->input[0], -+ MMAL_PARAMETER_SUPPORTED_ENCODINGS, -+ &fourccs, -+ ¶m_size); -+ -+ if (ret) { -+ if (ret == MMAL_MSG_STATUS_ENOSPC) { -+ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n", -+ __func__); -+ num_encodings = MAX_SUPPORTED_ENCODINGS; -+ } else { -+ v4l2_err(&dev->v4l2_dev, "%s: get_param ret %u.\n", -+ __func__, ret); -+ ret = -EINVAL; -+ goto destroy_component; -+ } -+ } else { -+ num_encodings = param_size / sizeof(u32); -+ } -+ -+ /* Assume at this stage that all encodings will be supported in V4L2. -+ * Any that aren't supported will waste a very small amount of memory. -+ */ -+ list = devm_kzalloc(&dev->pdev->dev, -+ sizeof(struct bcm2835_codec_fmt) * num_encodings, -+ GFP_KERNEL); -+ if (!list) { -+ ret = -ENOMEM; -+ goto destroy_component; -+ } -+ dev->supported_fmts[0].list = list; -+ -+ for (i = 0, j = 0; i < num_encodings; i++) { -+ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]); -+ -+ if (fmt) { -+ list[j] = *fmt; -+ j++; -+ } -+ } -+ dev->supported_fmts[0].num_entries = j; -+ -+ param_size = sizeof(fourccs); -+ ret = vchiq_mmal_port_parameter_get(dev->instance, -+ &component->output[0], -+ MMAL_PARAMETER_SUPPORTED_ENCODINGS, -+ &fourccs, -+ ¶m_size); -+ -+ if (ret) { -+ if (ret == MMAL_MSG_STATUS_ENOSPC) { -+ v4l2_err(&dev->v4l2_dev, "%s: port has more encoding than we provided space for. Some are dropped.\n", -+ __func__); -+ num_encodings = MAX_SUPPORTED_ENCODINGS; -+ } else { -+ ret = -EINVAL; -+ goto destroy_component; -+ } -+ } else { -+ num_encodings = param_size / sizeof(u32); -+ } -+ /* Assume at this stage that all encodings will be supported in V4L2. */ -+ list = devm_kzalloc(&dev->pdev->dev, -+ sizeof(struct bcm2835_codec_fmt) * num_encodings, -+ GFP_KERNEL); -+ if (!list) { -+ ret = -ENOMEM; -+ goto destroy_component; -+ } -+ dev->supported_fmts[1].list = list; -+ -+ for (i = 0, j = 0; i < num_encodings; i++) { -+ const struct bcm2835_codec_fmt *fmt = get_fmt(fourccs[i]); -+ -+ if (fmt) { -+ list[j] = *fmt; -+ j++; -+ } -+ } -+ dev->supported_fmts[1].num_entries = j; -+ -+ ret = 0; -+ -+destroy_component: -+ vchiq_mmal_component_finalise(dev->instance, component); -+ -+ return ret; -+} -+ - static int bcm2835_codec_create(struct platform_device *pdev, - struct bcm2835_codec_dev **new_dev, - bool decode) - { - struct bcm2835_codec_dev *dev; - struct video_device *vfd; -- struct vchiq_mmal_instance *instance = NULL; - int video_nr; - int ret; - -@@ -2227,10 +2421,18 @@ static int bcm2835_codec_create(struct p - - dev->decode = decode; - -- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); -+ ret = vchiq_mmal_init(&dev->instance); - if (ret) - return ret; - -+ ret = bcm2835_codec_get_supported_fmts(dev); -+ if (ret) -+ goto vchiq_finalise; -+ -+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); -+ if (ret) -+ goto vchiq_finalise; -+ - atomic_set(&dev->num_inst, 0); - mutex_init(&dev->dev_mutex); - -@@ -2270,12 +2472,7 @@ static int bcm2835_codec_create(struct p - goto err_m2m; - } - -- ret = vchiq_mmal_init(&instance); -- if (ret < 0) -- goto err_m2m; -- dev->instance = instance; -- -- v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s codec\n", -+ v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", - dev->decode ? "decode" : "encode"); - return 0; - -@@ -2284,7 +2481,8 @@ err_m2m: - video_unregister_device(&dev->vfd); - unreg_dev: - v4l2_device_unregister(&dev->v4l2_dev); -- -+vchiq_finalise: -+ vchiq_mmal_finalise(dev->instance); - return ret; - } - -@@ -2297,6 +2495,7 @@ static int bcm2835_codec_destroy(struct - v4l2_m2m_release(dev->m2m_dev); - video_unregister_device(&dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); -+ vchiq_mmal_finalise(dev->instance); - - return 0; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0187-staging-bcm2835_codec-Add-support-for-the-ISP-as-an-.patch b/target/linux/bcm27xx/patches-5.4/950-0187-staging-bcm2835_codec-Add-support-for-the-ISP-as-an-.patch deleted file mode 100644 index 3bbe6814c3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0187-staging-bcm2835_codec-Add-support-for-the-ISP-as-an-.patch +++ /dev/null @@ -1,384 +0,0 @@ -From 6fe43df9941cbd4810c4fcd02e49156a85180c16 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 13 Feb 2019 14:07:52 +0000 -Subject: [PATCH] staging: bcm2835_codec: Add support for the ISP as an - M2M device - -The MMAL ISP component can also use this same V4L2 wrapper to -provide a M2M format conversion and resizer. -Instantiate 3 V4L2 devices now, one for each of decode, encode, -and isp. -The ISP currently doesn't expose any controls via V4L2, but this -can be extended in the future. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 132 ++++++++++++------ - 1 file changed, 92 insertions(+), 40 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -54,10 +54,26 @@ static int encode_video_nr = 11; - module_param(encode_video_nr, int, 0644); - MODULE_PARM_DESC(encode_video_nr, "encoder video device number"); - -+static int isp_video_nr = 12; -+module_param(isp_video_nr, int, 0644); -+MODULE_PARM_DESC(isp_video_nr, "isp video device number"); -+ - static unsigned int debug; - module_param(debug, uint, 0644); - MODULE_PARM_DESC(debug, "activates debug info (0-3)"); - -+enum bcm2835_codec_role { -+ DECODE, -+ ENCODE, -+ ISP, -+}; -+ -+static const char * const components[] = { -+ "ril.video_decode", -+ "ril.video_encode", -+ "ril.isp", -+}; -+ - #define MIN_W 32 - #define MIN_H 32 - #define MAX_W 1920 -@@ -373,7 +389,7 @@ struct bcm2835_codec_dev { - atomic_t num_inst; - - /* allocated mmal instance and components */ -- bool decode; /* Is this instance a decoder? */ -+ enum bcm2835_codec_role role; - /* The list of formats supported on input and output queues. */ - struct bcm2835_codec_fmt_list supported_fmts[2]; - -@@ -558,7 +574,7 @@ static void setup_mmal_port_format(struc - port->es.video.frame_rate.den = 1; - } else { - /* Compressed format - leave resolution as 0 for decode */ -- if (ctx->dev->decode) { -+ if (ctx->dev->role == DECODE) { - port->es.video.width = 0; - port->es.video.height = 0; - port->es.video.crop.width = 0; -@@ -1089,7 +1105,8 @@ static int vidioc_s_fmt(struct bcm2835_c - v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", - q_data->bytesperline, q_data->sizeimage); - -- if (ctx->dev->decode && q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && -+ if (ctx->dev->role == DECODE && -+ q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && - f->fmt.pix.width && f->fmt.pix.height) { - /* - * On the decoder, if provided with a resolution on the input -@@ -1188,7 +1205,8 @@ static int vidioc_g_selection(struct fil - bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? - true : false; - -- if (capture_queue ^ ctx->dev->decode) -+ if ((ctx->dev->role == DECODE && !capture_queue) || -+ (ctx->dev->role == ENCODE && capture_queue)) - /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ - return -EINVAL; - -@@ -1196,7 +1214,8 @@ static int vidioc_g_selection(struct fil - if (!q_data) - return -EINVAL; - -- if (ctx->dev->decode) { -+ switch (ctx->dev->role) { -+ case DECODE: - switch (s->target) { - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE: -@@ -1214,7 +1233,8 @@ static int vidioc_g_selection(struct fil - default: - return -EINVAL; - } -- } else { -+ break; -+ case ENCODE: - switch (s->target) { - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: -@@ -1232,6 +1252,9 @@ static int vidioc_g_selection(struct fil - default: - return -EINVAL; - } -+ break; -+ case ISP: -+ break; - } - - return 0; -@@ -1249,7 +1272,8 @@ static int vidioc_s_selection(struct fil - __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top, - s->r.width, s->r.height); - -- if (capture_queue ^ ctx->dev->decode) -+ if ((ctx->dev->role == DECODE && !capture_queue) || -+ (ctx->dev->role == ENCODE && capture_queue)) - /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ - return -EINVAL; - -@@ -1257,7 +1281,8 @@ static int vidioc_s_selection(struct fil - if (!q_data) - return -EINVAL; - -- if (ctx->dev->decode) { -+ switch (ctx->dev->role) { -+ case DECODE: - switch (s->target) { - case V4L2_SEL_TGT_COMPOSE: - /* Accept cropped image */ -@@ -1272,7 +1297,8 @@ static int vidioc_s_selection(struct fil - default: - return -EINVAL; - } -- } else { -+ break; -+ case ENCODE: - switch (s->target) { - case V4L2_SEL_TGT_CROP: - /* Only support crop from (0,0) */ -@@ -1287,6 +1313,9 @@ static int vidioc_s_selection(struct fil - default: - return -EINVAL; - } -+ break; -+ case ISP: -+ break; - } - - return 0; -@@ -1490,7 +1519,7 @@ static int vidioc_try_decoder_cmd(struct - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- if (!ctx->dev->decode) -+ if (ctx->dev->role != DECODE) - return -EINVAL; - - switch (cmd->cmd) { -@@ -1564,7 +1593,7 @@ static int vidioc_try_encoder_cmd(struct - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- if (ctx->dev->decode) -+ if (ctx->dev->role != ENCODE) - return -EINVAL; - - switch (cmd->cmd) { -@@ -1697,12 +1726,11 @@ static int bcm2835_codec_create_componen - unsigned int enable = 1; - int ret; - -- ret = vchiq_mmal_component_init(dev->instance, dev->decode ? -- "ril.video_decode" : "ril.video_encode", -+ ret = vchiq_mmal_component_init(dev->instance, components[dev->role], - &ctx->component); - if (ret < 0) { -- v4l2_err(&dev->v4l2_dev, "%s: failed to create component for %s\n", -- __func__, dev->decode ? "decode" : "encode"); -+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n", -+ __func__, components[dev->role]); - return -ENOMEM; - } - -@@ -1729,13 +1757,7 @@ static int bcm2835_codec_create_componen - if (ret < 0) - goto destroy_component; - -- if (dev->decode) { -- if (ctx->q_data[V4L2_M2M_DST].sizeimage < -- ctx->component->output[0].minimum_buffer.size) -- v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", -- ctx->q_data[V4L2_M2M_DST].sizeimage, -- ctx->component->output[0].minimum_buffer.size); -- } else { -+ if (dev->role == ENCODE) { - if (ctx->q_data[V4L2_M2M_SRC].sizeimage < - ctx->component->output[0].minimum_buffer.size) - v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", -@@ -1744,6 +1766,12 @@ static int bcm2835_codec_create_componen - - /* Now we have a component we can set all the ctrls */ - bcm2835_codec_set_ctrls(ctx); -+ } else { -+ if (ctx->q_data[V4L2_M2M_DST].sizeimage < -+ ctx->component->output[0].minimum_buffer.size) -+ v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", -+ ctx->q_data[V4L2_M2M_DST].sizeimage, -+ ctx->component->output[0].minimum_buffer.size); - } - - return 0; -@@ -2090,8 +2118,6 @@ static int bcm2835_codec_open(struct fil - struct v4l2_ctrl_handler *hdl; - int rc = 0; - -- v4l2_dbg(1, debug, &dev->v4l2_dev, "Creating instance for %s\n", -- dev->decode ? "decode" : "encode"); - if (mutex_lock_interruptible(&dev->dev_mutex)) { - v4l2_err(&dev->v4l2_dev, "Mutex fail\n"); - return -ERESTARTSYS; -@@ -2104,7 +2130,8 @@ static int bcm2835_codec_open(struct fil - - ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false); - ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true); -- if (dev->decode) { -+ switch (dev->role) { -+ case DECODE: - /* - * Input width and height are irrelevant as they will be defined - * by the bitstream not the format. Required by V4L2 though. -@@ -2126,7 +2153,8 @@ static int bcm2835_codec_open(struct fil - get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, - ctx->q_data[V4L2_M2M_DST].height, - ctx->q_data[V4L2_M2M_DST].fmt); -- } else { -+ break; -+ case ENCODE: - ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; - ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; - ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; -@@ -2144,6 +2172,9 @@ static int bcm2835_codec_open(struct fil - ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; - ctx->q_data[V4L2_M2M_DST].sizeimage = - DEF_COMP_BUF_SIZE_720P_OR_LESS; -+ break; -+ case ISP: -+ break; - } - - ctx->colorspace = V4L2_COLORSPACE_REC709; -@@ -2154,7 +2185,7 @@ static int bcm2835_codec_open(struct fil - file->private_data = &ctx->fh; - ctx->dev = dev; - hdl = &ctx->hdl; -- if (!dev->decode) { -+ if (dev->role == ENCODE) { - /* Encode controls */ - v4l2_ctrl_handler_init(hdl, 6); - -@@ -2303,14 +2334,11 @@ static int bcm2835_codec_get_supported_f - unsigned int i, j, num_encodings; - int ret; - -- ret = vchiq_mmal_component_init(dev->instance, -- dev->decode ? -- "ril.video_decode" : -- "ril.video_encode", -+ ret = vchiq_mmal_component_init(dev->instance, components[dev->role], - &component); - if (ret < 0) { -- v4l2_err(&dev->v4l2_dev, "%s: failed to create component\n", -- __func__); -+ v4l2_err(&dev->v4l2_dev, "%s: failed to create component %s\n", -+ __func__, components[dev->role]); - return -ENOMEM; - } - -@@ -2406,12 +2434,13 @@ destroy_component: - - static int bcm2835_codec_create(struct platform_device *pdev, - struct bcm2835_codec_dev **new_dev, -- bool decode) -+ enum bcm2835_codec_role role) - { - struct bcm2835_codec_dev *dev; - struct video_device *vfd; - int video_nr; - int ret; -+ const static char *roles[] = {"decode", "encode", "isp"}; - - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) -@@ -2419,7 +2448,7 @@ static int bcm2835_codec_create(struct p - - dev->pdev = pdev; - -- dev->decode = decode; -+ dev->role = role; - - ret = vchiq_mmal_init(&dev->instance); - if (ret) -@@ -2441,14 +2470,27 @@ static int bcm2835_codec_create(struct p - vfd->lock = &dev->dev_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - -- if (dev->decode) { -+ switch (role) { -+ case DECODE: - v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); - video_nr = decode_video_nr; -- } else { -+ break; -+ case ENCODE: - v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); - video_nr = encode_video_nr; -+ break; -+ case ISP: -+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); -+ video_nr = isp_video_nr; -+ break; -+ default: -+ ret = -EINVAL; -+ goto unreg_dev; - } - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); -@@ -2473,7 +2515,7 @@ static int bcm2835_codec_create(struct p - } - - v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", -- dev->decode ? "decode" : "encode"); -+ roles[role]); - return 0; - - err_m2m: -@@ -2509,11 +2551,15 @@ static int bcm2835_codec_probe(struct pl - if (!drv) - return -ENOMEM; - -- ret = bcm2835_codec_create(pdev, &drv->encode, false); -+ ret = bcm2835_codec_create(pdev, &drv->decode, DECODE); - if (ret) - goto out; - -- ret = bcm2835_codec_create(pdev, &drv->decode, true); -+ ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE); -+ if (ret) -+ goto out; -+ -+ ret = bcm2835_codec_create(pdev, &drv->isp, ISP); - if (ret) - goto out; - -@@ -2526,6 +2572,10 @@ out: - bcm2835_codec_destroy(drv->encode); - drv->encode = NULL; - } -+ if (drv->decode) { -+ bcm2835_codec_destroy(drv->decode); -+ drv->decode = NULL; -+ } - return ret; - } - -@@ -2533,6 +2583,8 @@ static int bcm2835_codec_remove(struct p - { - struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev); - -+ bcm2835_codec_destroy(drv->isp); -+ - bcm2835_codec_destroy(drv->encode); - - bcm2835_codec_destroy(drv->decode); diff --git a/target/linux/bcm27xx/patches-5.4/950-0187-staging-bcm2835_codec-Fix-handling-of-VB2_MEMORY_DMA.patch b/target/linux/bcm27xx/patches-5.4/950-0187-staging-bcm2835_codec-Fix-handling-of-VB2_MEMORY_DMA.patch new file mode 100644 index 0000000000..f2aeb91620 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0187-staging-bcm2835_codec-Fix-handling-of-VB2_MEMORY_DMA.patch @@ -0,0 +1,186 @@ +From 5dce6c2a033e210ceead1b9ae756905246ae5082 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 15 Feb 2019 11:38:45 +0000 +Subject: [PATCH] staging: bcm2835_codec: Fix handling of + VB2_MEMORY_DMABUF buffers + +If the queue is configured as VB2_MEMORY_DMABUF then vb2_core_expbuf +fails as it ensures the queue is defined as VB2_MEMORY_MMAP. + +Correct the handling so that we unmap the buffer from vcsm and the +VPU on cleanup, and then correctly get the dma buf of the new buffer. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 80 +++++++++++++------ + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 21 +++-- + .../vc04_services/vchiq-mmal/mmal-vchiq.h | 2 + + 3 files changed, 73 insertions(+), 30 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1852,6 +1852,18 @@ static int bcm2835_codec_queue_setup(str + return 0; + } + ++static int bcm2835_codec_mmal_buf_cleanup(struct mmal_buffer *mmal_buf) ++{ ++ mmal_vchi_buffer_cleanup(mmal_buf); ++ ++ if (mmal_buf->dma_buf) { ++ dma_buf_put(mmal_buf->dma_buf); ++ mmal_buf->dma_buf = NULL; ++ } ++ ++ return 0; ++} ++ + static int bcm2835_codec_buf_init(struct vb2_buffer *vb) + { + struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); +@@ -1880,6 +1892,7 @@ static int bcm2835_codec_buf_prepare(str + vb); + struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, + m2m); ++ struct dma_buf *dma_buf; + int ret; + + v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n", +@@ -1906,20 +1919,48 @@ static int bcm2835_codec_buf_prepare(str + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) + vb2_set_plane_payload(vb, 0, q_data->sizeimage); + +- /* +- * We want to do this at init, but vb2_core_expbuf checks that the +- * index < q->num_buffers, and q->num_buffers only gets updated once +- * all the buffers are allocated. +- */ +- if (!buf->mmal.dma_buf) { +- ret = vb2_core_expbuf_dmabuf(vb->vb2_queue, +- vb->vb2_queue->type, vb->index, 0, +- O_CLOEXEC, &buf->mmal.dma_buf); +- if (ret) +- v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n", +- __func__, vb->index, ret); +- } else { ++ switch (vb->memory) { ++ case VB2_MEMORY_DMABUF: ++ dma_buf = dma_buf_get(vb->planes[0].m.fd); ++ ++ if (dma_buf != buf->mmal.dma_buf) { ++ /* dmabuf either hasn't already been mapped, or it has ++ * changed. ++ */ ++ if (buf->mmal.dma_buf) { ++ v4l2_err(&ctx->dev->v4l2_dev, ++ "%s Buffer changed - why did the core not call cleanup?\n", ++ __func__); ++ bcm2835_codec_mmal_buf_cleanup(&buf->mmal); ++ } ++ ++ buf->mmal.dma_buf = dma_buf; ++ } + ret = 0; ++ break; ++ case VB2_MEMORY_MMAP: ++ /* ++ * We want to do this at init, but vb2_core_expbuf checks that ++ * the index < q->num_buffers, and q->num_buffers only gets ++ * updated once all the buffers are allocated. ++ */ ++ if (!buf->mmal.dma_buf) { ++ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue, ++ vb->vb2_queue->type, ++ vb->index, 0, ++ O_CLOEXEC, ++ &buf->mmal.dma_buf); ++ if (ret) ++ v4l2_err(&ctx->dev->v4l2_dev, ++ "%s: Failed to expbuf idx %d, ret %d\n", ++ __func__, vb->index, ret); ++ } else { ++ ret = 0; ++ } ++ break; ++ default: ++ ret = -EINVAL; ++ break; + } + + return ret; +@@ -1948,12 +1989,7 @@ static void bcm2835_codec_buffer_cleanup + v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n", + __func__, ctx, vb); + +- mmal_vchi_buffer_cleanup(&buf->mmal); +- +- if (buf->mmal.dma_buf) { +- dma_buf_put(buf->mmal.dma_buf); +- buf->mmal.dma_buf = NULL; +- } ++ bcm2835_codec_mmal_buf_cleanup(&buf->mmal); + } + + static int bcm2835_codec_start_streaming(struct vb2_queue *q, +@@ -2067,11 +2103,7 @@ static void bcm2835_codec_stop_streaming + m2m = container_of(vb2, struct v4l2_m2m_buffer, vb); + buf = container_of(m2m, struct m2m_mmal_buffer, m2m); + +- mmal_vchi_buffer_cleanup(&buf->mmal); +- if (buf->mmal.dma_buf) { +- dma_buf_put(buf->mmal.dma_buf); +- buf->mmal.dma_buf = NULL; +- } ++ bcm2835_codec_mmal_buf_cleanup(&buf->mmal); + } + + /* If both ports disabled, then disable the component */ +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -1784,13 +1784,9 @@ int mmal_vchi_buffer_init(struct vchiq_m + } + EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init); + +-int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) ++int mmal_vchi_buffer_unmap(struct mmal_buffer *buf) + { +- struct mmal_msg_context *msg_context = buf->msg_context; +- +- if (msg_context) +- release_msg_context(msg_context); +- buf->msg_context = NULL; ++ int ret = 0; + + if (buf->vcsm_handle) { + int ret; +@@ -1802,6 +1798,19 @@ int mmal_vchi_buffer_cleanup(struct mmal + pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret); + buf->vcsm_handle = 0; + } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mmal_vchi_buffer_unmap); ++ ++int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) ++{ ++ struct mmal_msg_context *msg_context = buf->msg_context; ++ ++ if (msg_context) ++ release_msg_context(msg_context); ++ buf->msg_context = NULL; ++ ++ mmal_vchi_buffer_unmap(buf); + return 0; + } + EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h +@@ -167,6 +167,8 @@ int vchiq_mmal_submit_buffer(struct vchi + struct vchiq_mmal_port *port, + struct mmal_buffer *buf); + ++int mmal_vchi_buffer_unmap(struct mmal_buffer *buf); ++ + int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, + struct mmal_buffer *buf); + int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf); diff --git a/target/linux/bcm27xx/patches-5.4/950-0188-staging-bcm2835_codec-Add-an-option-for-ignoring-Bay.patch b/target/linux/bcm27xx/patches-5.4/950-0188-staging-bcm2835_codec-Add-an-option-for-ignoring-Bay.patch deleted file mode 100644 index 911612621c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0188-staging-bcm2835_codec-Add-an-option-for-ignoring-Bay.patch +++ /dev/null @@ -1,179 +0,0 @@ -From c2740ccf8d92b25940ddda20abd4c4f5b97f235c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 15 Feb 2019 11:36:14 +0000 -Subject: [PATCH] staging: bcm2835_codec: Add an option for ignoring - Bayer formats. - -This is a workaround for GStreamer currently not identifying Bayer -as a raw format, therefore any device that supports it does not -match the criteria for v4l2convert. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 29 ++++++++++++++++++- - 1 file changed, 28 insertions(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -58,6 +58,15 @@ static int isp_video_nr = 12; - module_param(isp_video_nr, int, 0644); - MODULE_PARM_DESC(isp_video_nr, "isp video device number"); - -+/* -+ * Workaround for GStreamer v4l2convert component not considering Bayer formats -+ * as raw, and therefore not considering a V4L2 device that supports them as -+ * as a suitable candidate. -+ */ -+static bool disable_bayer; -+module_param(disable_bayer, bool, 0644); -+MODULE_PARM_DESC(disable_bayer, "Disable support for Bayer formats"); -+ - static unsigned int debug; - module_param(debug, uint, 0644); - MODULE_PARM_DESC(debug, "activates debug info (0-3)"); -@@ -105,6 +114,7 @@ struct bcm2835_codec_fmt { - u32 flags; - u32 mmal_fmt; - int size_multiplier_x2; -+ bool is_bayer; - }; - - static const struct bcm2835_codec_fmt supported_formats[] = { -@@ -203,6 +213,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB8, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .depth = 8, -@@ -210,6 +221,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR8, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .depth = 8, -@@ -217,6 +229,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG8, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .depth = 8, -@@ -224,6 +237,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG8, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - /* 10 bit */ - .fourcc = V4L2_PIX_FMT_SRGGB10P, -@@ -232,6 +246,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB10P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR10P, - .depth = 10, -@@ -239,6 +254,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR10P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG10P, - .depth = 10, -@@ -246,6 +262,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG10P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG10P, - .depth = 10, -@@ -253,6 +270,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG10P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - /* 12 bit */ - .fourcc = V4L2_PIX_FMT_SRGGB12P, -@@ -261,6 +279,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB12P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR12P, - .depth = 12, -@@ -268,6 +287,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR12P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG12P, - .depth = 12, -@@ -275,6 +295,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG12P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG12P, - .depth = 12, -@@ -282,6 +303,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG12P, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - /* 16 bit */ - .fourcc = V4L2_PIX_FMT_SRGGB16, -@@ -290,6 +312,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SRGGB16, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR16, - .depth = 16, -@@ -297,6 +320,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SBGGR16, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG16, - .depth = 16, -@@ -304,6 +328,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGRBG16, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG16, - .depth = 16, -@@ -311,6 +336,7 @@ static const struct bcm2835_codec_fmt su - .flags = 0, - .mmal_fmt = MMAL_ENCODING_BAYER_SGBRG16, - .size_multiplier_x2 = 2, -+ .is_bayer = true, - }, { - /* Compressed formats */ - .fourcc = V4L2_PIX_FMT_H264, -@@ -438,7 +464,8 @@ static const struct bcm2835_codec_fmt *g - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(supported_formats); i++) { -- if (supported_formats[i].mmal_fmt == mmal_fmt) -+ if (supported_formats[i].mmal_fmt == mmal_fmt && -+ (!disable_bayer || !supported_formats[i].is_bayer)) - return &supported_formats[i]; - } - return NULL; diff --git a/target/linux/bcm27xx/patches-5.4/950-0188-staging-mmal-vchiq-Update-mmal_parameters.h-with-rec.patch b/target/linux/bcm27xx/patches-5.4/950-0188-staging-mmal-vchiq-Update-mmal_parameters.h-with-rec.patch new file mode 100644 index 0000000000..1198880531 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0188-staging-mmal-vchiq-Update-mmal_parameters.h-with-rec.patch @@ -0,0 +1,56 @@ +From 07ef6940df90334980fa3c888358474aaf5bd0c3 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 18 Feb 2019 15:52:29 +0000 +Subject: [PATCH] staging: mmal-vchiq: Update mmal_parameters.h with + recently defined params + +mmal_parameters.h hasn't been updated to reflect additions made +over the last few years. Update it to reflect the currently +supported parameters. + +Signed-off-by: Dave Stevenson +--- + .../vchiq-mmal/mmal-parameters.h | 32 ++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h +@@ -580,7 +580,37 @@ enum mmal_parameter_video_type { + MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, + + /**< @ref MMAL_PARAMETER_BOOLEAN_T */ +- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER ++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, ++ ++ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_SEI_ENABLE, ++ ++ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */ ++ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, ++ ++ /**< Take a @ref MMAL_PARAMETER_VIDEO_RENDER_STATS_T. */ ++ MMAL_PARAMETER_VIDEO_RENDER_STATS, ++ ++ /**< Take a @ref MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T. */ ++ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE, ++ ++ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS, ++ ++ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING, ++ ++ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS, ++ ++ /**< Takes a @ref MMAL_PARAMETER_SOURCE_PATTERN_T */ ++ MMAL_PARAMETER_VIDEO_SOURCE_PATTERN, ++ ++ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */ ++ MMAL_PARAMETER_VIDEO_ENCODE_SEPARATE_NAL_BUFS, ++ ++ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ ++ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAME_LENGTH, + }; + + /** Valid mirror modes */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0189-staging-bcm2835_codec-Fix-handling-of-VB2_MEMORY_DMA.patch b/target/linux/bcm27xx/patches-5.4/950-0189-staging-bcm2835_codec-Fix-handling-of-VB2_MEMORY_DMA.patch deleted file mode 100644 index f2aeb91620..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0189-staging-bcm2835_codec-Fix-handling-of-VB2_MEMORY_DMA.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 5dce6c2a033e210ceead1b9ae756905246ae5082 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 15 Feb 2019 11:38:45 +0000 -Subject: [PATCH] staging: bcm2835_codec: Fix handling of - VB2_MEMORY_DMABUF buffers - -If the queue is configured as VB2_MEMORY_DMABUF then vb2_core_expbuf -fails as it ensures the queue is defined as VB2_MEMORY_MMAP. - -Correct the handling so that we unmap the buffer from vcsm and the -VPU on cleanup, and then correctly get the dma buf of the new buffer. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 80 +++++++++++++------ - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 21 +++-- - .../vc04_services/vchiq-mmal/mmal-vchiq.h | 2 + - 3 files changed, 73 insertions(+), 30 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1852,6 +1852,18 @@ static int bcm2835_codec_queue_setup(str - return 0; - } - -+static int bcm2835_codec_mmal_buf_cleanup(struct mmal_buffer *mmal_buf) -+{ -+ mmal_vchi_buffer_cleanup(mmal_buf); -+ -+ if (mmal_buf->dma_buf) { -+ dma_buf_put(mmal_buf->dma_buf); -+ mmal_buf->dma_buf = NULL; -+ } -+ -+ return 0; -+} -+ - static int bcm2835_codec_buf_init(struct vb2_buffer *vb) - { - struct bcm2835_codec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); -@@ -1880,6 +1892,7 @@ static int bcm2835_codec_buf_prepare(str - vb); - struct m2m_mmal_buffer *buf = container_of(m2m, struct m2m_mmal_buffer, - m2m); -+ struct dma_buf *dma_buf; - int ret; - - v4l2_dbg(4, debug, &ctx->dev->v4l2_dev, "%s: type: %d ptr %p\n", -@@ -1906,20 +1919,48 @@ static int bcm2835_codec_buf_prepare(str - if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) - vb2_set_plane_payload(vb, 0, q_data->sizeimage); - -- /* -- * We want to do this at init, but vb2_core_expbuf checks that the -- * index < q->num_buffers, and q->num_buffers only gets updated once -- * all the buffers are allocated. -- */ -- if (!buf->mmal.dma_buf) { -- ret = vb2_core_expbuf_dmabuf(vb->vb2_queue, -- vb->vb2_queue->type, vb->index, 0, -- O_CLOEXEC, &buf->mmal.dma_buf); -- if (ret) -- v4l2_err(&ctx->dev->v4l2_dev, "%s: Failed to expbuf idx %d, ret %d\n", -- __func__, vb->index, ret); -- } else { -+ switch (vb->memory) { -+ case VB2_MEMORY_DMABUF: -+ dma_buf = dma_buf_get(vb->planes[0].m.fd); -+ -+ if (dma_buf != buf->mmal.dma_buf) { -+ /* dmabuf either hasn't already been mapped, or it has -+ * changed. -+ */ -+ if (buf->mmal.dma_buf) { -+ v4l2_err(&ctx->dev->v4l2_dev, -+ "%s Buffer changed - why did the core not call cleanup?\n", -+ __func__); -+ bcm2835_codec_mmal_buf_cleanup(&buf->mmal); -+ } -+ -+ buf->mmal.dma_buf = dma_buf; -+ } - ret = 0; -+ break; -+ case VB2_MEMORY_MMAP: -+ /* -+ * We want to do this at init, but vb2_core_expbuf checks that -+ * the index < q->num_buffers, and q->num_buffers only gets -+ * updated once all the buffers are allocated. -+ */ -+ if (!buf->mmal.dma_buf) { -+ ret = vb2_core_expbuf_dmabuf(vb->vb2_queue, -+ vb->vb2_queue->type, -+ vb->index, 0, -+ O_CLOEXEC, -+ &buf->mmal.dma_buf); -+ if (ret) -+ v4l2_err(&ctx->dev->v4l2_dev, -+ "%s: Failed to expbuf idx %d, ret %d\n", -+ __func__, vb->index, ret); -+ } else { -+ ret = 0; -+ } -+ break; -+ default: -+ ret = -EINVAL; -+ break; - } - - return ret; -@@ -1948,12 +1989,7 @@ static void bcm2835_codec_buffer_cleanup - v4l2_dbg(2, debug, &ctx->dev->v4l2_dev, "%s: ctx:%p, vb %p\n", - __func__, ctx, vb); - -- mmal_vchi_buffer_cleanup(&buf->mmal); -- -- if (buf->mmal.dma_buf) { -- dma_buf_put(buf->mmal.dma_buf); -- buf->mmal.dma_buf = NULL; -- } -+ bcm2835_codec_mmal_buf_cleanup(&buf->mmal); - } - - static int bcm2835_codec_start_streaming(struct vb2_queue *q, -@@ -2067,11 +2103,7 @@ static void bcm2835_codec_stop_streaming - m2m = container_of(vb2, struct v4l2_m2m_buffer, vb); - buf = container_of(m2m, struct m2m_mmal_buffer, m2m); - -- mmal_vchi_buffer_cleanup(&buf->mmal); -- if (buf->mmal.dma_buf) { -- dma_buf_put(buf->mmal.dma_buf); -- buf->mmal.dma_buf = NULL; -- } -+ bcm2835_codec_mmal_buf_cleanup(&buf->mmal); - } - - /* If both ports disabled, then disable the component */ ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -1784,13 +1784,9 @@ int mmal_vchi_buffer_init(struct vchiq_m - } - EXPORT_SYMBOL_GPL(mmal_vchi_buffer_init); - --int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) -+int mmal_vchi_buffer_unmap(struct mmal_buffer *buf) - { -- struct mmal_msg_context *msg_context = buf->msg_context; -- -- if (msg_context) -- release_msg_context(msg_context); -- buf->msg_context = NULL; -+ int ret = 0; - - if (buf->vcsm_handle) { - int ret; -@@ -1802,6 +1798,19 @@ int mmal_vchi_buffer_cleanup(struct mmal - pr_err("%s: vcsm_free failed, ret %d\n", __func__, ret); - buf->vcsm_handle = 0; - } -+ return ret; -+} -+EXPORT_SYMBOL_GPL(mmal_vchi_buffer_unmap); -+ -+int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf) -+{ -+ struct mmal_msg_context *msg_context = buf->msg_context; -+ -+ if (msg_context) -+ release_msg_context(msg_context); -+ buf->msg_context = NULL; -+ -+ mmal_vchi_buffer_unmap(buf); - return 0; - } - EXPORT_SYMBOL_GPL(mmal_vchi_buffer_cleanup); ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h -@@ -167,6 +167,8 @@ int vchiq_mmal_submit_buffer(struct vchi - struct vchiq_mmal_port *port, - struct mmal_buffer *buf); - -+int mmal_vchi_buffer_unmap(struct mmal_buffer *buf); -+ - int mmal_vchi_buffer_init(struct vchiq_mmal_instance *instance, - struct mmal_buffer *buf); - int mmal_vchi_buffer_cleanup(struct mmal_buffer *buf); diff --git a/target/linux/bcm27xx/patches-5.4/950-0189-staging-bcm2835_codec-Include-timing-info-in-SPS-hea.patch b/target/linux/bcm27xx/patches-5.4/950-0189-staging-bcm2835_codec-Include-timing-info-in-SPS-hea.patch new file mode 100644 index 0000000000..b552698797 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0189-staging-bcm2835_codec-Include-timing-info-in-SPS-hea.patch @@ -0,0 +1,44 @@ +From fef7ce28d5ae5b38e4914b1cc54742ae16133807 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 18 Feb 2019 15:56:42 +0000 +Subject: [PATCH] staging: bcm2835_codec: Include timing info in SPS + headers + +Inserting timing information into the VUI block of the SPS is +optional with the VPU encoder. +GStreamer appears to require them when using V4L2 M2M, therefore +set the option to enable them from the encoder. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1785,6 +1785,8 @@ static int bcm2835_codec_create_componen + goto destroy_component; + + if (dev->role == ENCODE) { ++ u32 param = 1; ++ + if (ctx->q_data[V4L2_M2M_SRC].sizeimage < + ctx->component->output[0].minimum_buffer.size) + v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", +@@ -1793,6 +1795,16 @@ static int bcm2835_codec_create_componen + + /* Now we have a component we can set all the ctrls */ + bcm2835_codec_set_ctrls(ctx); ++ ++ /* Enable SPS Timing header so framerate information is encoded ++ * in the H264 header. ++ */ ++ vchiq_mmal_port_parameter_set( ++ ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING, ++ ¶m, sizeof(param)); ++ + } else { + if (ctx->q_data[V4L2_M2M_DST].sizeimage < + ctx->component->output[0].minimum_buffer.size) diff --git a/target/linux/bcm27xx/patches-5.4/950-0190-staging-bcm2835-codec-NULL-component-handle-on-queue.patch b/target/linux/bcm27xx/patches-5.4/950-0190-staging-bcm2835-codec-NULL-component-handle-on-queue.patch new file mode 100644 index 0000000000..45ba5acba0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0190-staging-bcm2835-codec-NULL-component-handle-on-queue.patch @@ -0,0 +1,59 @@ +From ee61cd0a1cd42707812e3662c1896f8e0c1155df Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 19 Mar 2019 17:55:09 +0000 +Subject: [PATCH] staging: bcm2835-codec: NULL component handle on + queue_setup failure + +queue_setup tries creating the relevant MMAL component and configures +the input and output ports as we're expecting to start streaming. +If the port configuration failed then it destroyed the component, +but failed to clear the component handle, therefore release tried +destroying the component again. +Adds some logging should the port config fail as well. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1776,13 +1776,21 @@ static int bcm2835_codec_create_componen + + ret = vchiq_mmal_port_set_format(dev->instance, + &ctx->component->input[0]); +- if (ret < 0) ++ if (ret < 0) { ++ v4l2_dbg(1, debug, &dev->v4l2_dev, ++ "%s: vchiq_mmal_port_set_format ip port failed\n", ++ __func__); + goto destroy_component; ++ } + + ret = vchiq_mmal_port_set_format(dev->instance, + &ctx->component->output[0]); +- if (ret < 0) ++ if (ret < 0) { ++ v4l2_dbg(1, debug, &dev->v4l2_dev, ++ "%s: vchiq_mmal_port_set_format op port failed\n", ++ __func__); + goto destroy_component; ++ } + + if (dev->role == ENCODE) { + u32 param = 1; +@@ -1812,11 +1820,14 @@ static int bcm2835_codec_create_componen + ctx->q_data[V4L2_M2M_DST].sizeimage, + ctx->component->output[0].minimum_buffer.size); + } ++ v4l2_dbg(2, debug, &dev->v4l2_dev, "%s: component created as %s\n", ++ __func__, components[dev->role]); + + return 0; + + destroy_component: + vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component); ++ ctx->component = NULL; + + return ret; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0190-staging-mmal-vchiq-Update-mmal_parameters.h-with-rec.patch b/target/linux/bcm27xx/patches-5.4/950-0190-staging-mmal-vchiq-Update-mmal_parameters.h-with-rec.patch deleted file mode 100644 index 1198880531..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0190-staging-mmal-vchiq-Update-mmal_parameters.h-with-rec.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 07ef6940df90334980fa3c888358474aaf5bd0c3 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 18 Feb 2019 15:52:29 +0000 -Subject: [PATCH] staging: mmal-vchiq: Update mmal_parameters.h with - recently defined params - -mmal_parameters.h hasn't been updated to reflect additions made -over the last few years. Update it to reflect the currently -supported parameters. - -Signed-off-by: Dave Stevenson ---- - .../vchiq-mmal/mmal-parameters.h | 32 ++++++++++++++++++- - 1 file changed, 31 insertions(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h -@@ -580,7 +580,37 @@ enum mmal_parameter_video_type { - MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, - - /**< @ref MMAL_PARAMETER_BOOLEAN_T */ -- MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER -+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, -+ -+ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_SEI_ENABLE, -+ -+ /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */ -+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, -+ -+ /**< Take a @ref MMAL_PARAMETER_VIDEO_RENDER_STATS_T. */ -+ MMAL_PARAMETER_VIDEO_RENDER_STATS, -+ -+ /**< Take a @ref MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T. */ -+ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE, -+ -+ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS, -+ -+ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING, -+ -+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS, -+ -+ /**< Takes a @ref MMAL_PARAMETER_SOURCE_PATTERN_T */ -+ MMAL_PARAMETER_VIDEO_SOURCE_PATTERN, -+ -+ /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */ -+ MMAL_PARAMETER_VIDEO_ENCODE_SEPARATE_NAL_BUFS, -+ -+ /**< Takes a @ref MMAL_PARAMETER_UINT32_T */ -+ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAME_LENGTH, - }; - - /** Valid mirror modes */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0191-staging-bcm2835_codec-Clean-up-logging-on-unloading-.patch b/target/linux/bcm27xx/patches-5.4/950-0191-staging-bcm2835_codec-Clean-up-logging-on-unloading-.patch new file mode 100644 index 0000000000..8b110ca42e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0191-staging-bcm2835_codec-Clean-up-logging-on-unloading-.patch @@ -0,0 +1,49 @@ +From 02a4a6aaec65be6d1e8ec4b02d6079c1fbdcfec8 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 8 Mar 2019 11:26:00 +0000 +Subject: [PATCH] staging: bcm2835_codec: Clean up logging on unloading + the driver + +The log line was missing a closing \n, so wasn't added to the +log immediately. +Adds the function of the V4L2 device that is being unregistered +too. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -77,6 +77,12 @@ enum bcm2835_codec_role { + ISP, + }; + ++const static char *roles[] = { ++ "decode", ++ "encode", ++ "isp" ++}; ++ + static const char * const components[] = { + "ril.video_decode", + "ril.video_encode", +@@ -2522,7 +2528,6 @@ static int bcm2835_codec_create(struct p + struct video_device *vfd; + int video_nr; + int ret; +- const static char *roles[] = {"decode", "encode", "isp"}; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) +@@ -2615,7 +2620,8 @@ static int bcm2835_codec_destroy(struct + if (!dev) + return -ENODEV; + +- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); ++ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n", ++ roles[dev->role]); + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(&dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0191-staging-bcm2835_codec-Include-timing-info-in-SPS-hea.patch b/target/linux/bcm27xx/patches-5.4/950-0191-staging-bcm2835_codec-Include-timing-info-in-SPS-hea.patch deleted file mode 100644 index b552698797..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0191-staging-bcm2835_codec-Include-timing-info-in-SPS-hea.patch +++ /dev/null @@ -1,44 +0,0 @@ -From fef7ce28d5ae5b38e4914b1cc54742ae16133807 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 18 Feb 2019 15:56:42 +0000 -Subject: [PATCH] staging: bcm2835_codec: Include timing info in SPS - headers - -Inserting timing information into the VUI block of the SPS is -optional with the VPU encoder. -GStreamer appears to require them when using V4L2 M2M, therefore -set the option to enable them from the encoder. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1785,6 +1785,8 @@ static int bcm2835_codec_create_componen - goto destroy_component; - - if (dev->role == ENCODE) { -+ u32 param = 1; -+ - if (ctx->q_data[V4L2_M2M_SRC].sizeimage < - ctx->component->output[0].minimum_buffer.size) - v4l2_err(&dev->v4l2_dev, "buffer size mismatch sizeimage %u < min size %u\n", -@@ -1793,6 +1795,16 @@ static int bcm2835_codec_create_componen - - /* Now we have a component we can set all the ctrls */ - bcm2835_codec_set_ctrls(ctx); -+ -+ /* Enable SPS Timing header so framerate information is encoded -+ * in the H264 header. -+ */ -+ vchiq_mmal_port_parameter_set( -+ ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING, -+ ¶m, sizeof(param)); -+ - } else { - if (ctx->q_data[V4L2_M2M_DST].sizeimage < - ctx->component->output[0].minimum_buffer.size) diff --git a/target/linux/bcm27xx/patches-5.4/950-0192-staging-bcm2835-codec-NULL-component-handle-on-queue.patch b/target/linux/bcm27xx/patches-5.4/950-0192-staging-bcm2835-codec-NULL-component-handle-on-queue.patch deleted file mode 100644 index 45ba5acba0..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0192-staging-bcm2835-codec-NULL-component-handle-on-queue.patch +++ /dev/null @@ -1,59 +0,0 @@ -From ee61cd0a1cd42707812e3662c1896f8e0c1155df Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 19 Mar 2019 17:55:09 +0000 -Subject: [PATCH] staging: bcm2835-codec: NULL component handle on - queue_setup failure - -queue_setup tries creating the relevant MMAL component and configures -the input and output ports as we're expecting to start streaming. -If the port configuration failed then it destroyed the component, -but failed to clear the component handle, therefore release tried -destroying the component again. -Adds some logging should the port config fail as well. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1776,13 +1776,21 @@ static int bcm2835_codec_create_componen - - ret = vchiq_mmal_port_set_format(dev->instance, - &ctx->component->input[0]); -- if (ret < 0) -+ if (ret < 0) { -+ v4l2_dbg(1, debug, &dev->v4l2_dev, -+ "%s: vchiq_mmal_port_set_format ip port failed\n", -+ __func__); - goto destroy_component; -+ } - - ret = vchiq_mmal_port_set_format(dev->instance, - &ctx->component->output[0]); -- if (ret < 0) -+ if (ret < 0) { -+ v4l2_dbg(1, debug, &dev->v4l2_dev, -+ "%s: vchiq_mmal_port_set_format op port failed\n", -+ __func__); - goto destroy_component; -+ } - - if (dev->role == ENCODE) { - u32 param = 1; -@@ -1812,11 +1820,14 @@ static int bcm2835_codec_create_componen - ctx->q_data[V4L2_M2M_DST].sizeimage, - ctx->component->output[0].minimum_buffer.size); - } -+ v4l2_dbg(2, debug, &dev->v4l2_dev, "%s: component created as %s\n", -+ __func__, components[dev->role]); - - return 0; - - destroy_component: - vchiq_mmal_component_finalise(ctx->dev->instance, ctx->component); -+ ctx->component = NULL; - - return ret; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0192-staging-bcm2835-codec-Refactor-default-resolution-co.patch b/target/linux/bcm27xx/patches-5.4/950-0192-staging-bcm2835-codec-Refactor-default-resolution-co.patch new file mode 100644 index 0000000000..42ab46c1c4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0192-staging-bcm2835-codec-Refactor-default-resolution-co.patch @@ -0,0 +1,154 @@ +From 90ad47170414e19ed6c6dcc3f3c9a68fbc7ad175 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 20 Mar 2019 10:06:51 +0000 +Subject: [PATCH] staging: bcm2835-codec: Refactor default resolution + code + +The default resolution code was different for each role +as compressed formats need to pass bytesperline as 0 and +set up customised buffer sizes. +This is common setup, therefore amend get_sizeimage and +get_bytesperline to do the correct thing whether compressed +or uncompressed. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 103 +++++++----------- + 1 file changed, 40 insertions(+), 63 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -578,10 +578,17 @@ static void job_abort(void *priv) + ctx->aborting = 1; + } + +-static inline unsigned int get_sizeimage(int bpl, int height, ++static inline unsigned int get_sizeimage(int bpl, int width, int height, + struct bcm2835_codec_fmt *fmt) + { +- return (bpl * height * fmt->size_multiplier_x2) >> 1; ++ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { ++ if (width * height > 1280 * 720) ++ return DEF_COMP_BUF_SIZE_GREATER_720P; ++ else ++ return DEF_COMP_BUF_SIZE_720P_OR_LESS; ++ } else { ++ return (bpl * height * fmt->size_multiplier_x2) >> 1; ++ } + } + + static inline unsigned int get_bytesperline(int width, +@@ -1032,22 +1039,13 @@ static int vidioc_try_fmt(struct v4l2_fo + * some of the pixels are active. + */ + f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); +- +- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, +- fmt); +- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, +- f->fmt.pix.height, +- fmt); +- } else { +- u32 min_size = f->fmt.pix.width > 1280 || +- f->fmt.pix.height > 720 ? +- DEF_COMP_BUF_SIZE_GREATER_720P : +- DEF_COMP_BUF_SIZE_720P_OR_LESS; +- +- f->fmt.pix.bytesperline = 0; +- if (f->fmt.pix.sizeimage < min_size) +- f->fmt.pix.sizeimage = min_size; + } ++ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, ++ fmt); ++ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, ++ f->fmt.pix.width, ++ f->fmt.pix.height, ++ fmt); + + f->fmt.pix.field = V4L2_FIELD_NONE; + +@@ -1159,6 +1157,7 @@ static int vidioc_s_fmt(struct bcm2835_c + q_data_dst->bytesperline = + get_bytesperline(f->fmt.pix.width, q_data_dst->fmt); + q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, ++ q_data_dst->crop_width, + q_data_dst->height, + q_data_dst->fmt); + update_capture_port = true; +@@ -2218,52 +2217,30 @@ static int bcm2835_codec_open(struct fil + + ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false); + ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true); +- switch (dev->role) { +- case DECODE: +- /* +- * Input width and height are irrelevant as they will be defined +- * by the bitstream not the format. Required by V4L2 though. +- */ +- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; +- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; +- ctx->q_data[V4L2_M2M_SRC].sizeimage = +- DEF_COMP_BUF_SIZE_720P_OR_LESS; +- +- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; +- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_DST].bytesperline = +- get_bytesperline(DEFAULT_WIDTH, +- ctx->q_data[V4L2_M2M_DST].fmt); +- ctx->q_data[V4L2_M2M_DST].sizeimage = +- get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, +- ctx->q_data[V4L2_M2M_DST].height, +- ctx->q_data[V4L2_M2M_DST].fmt); +- break; +- case ENCODE: +- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; +- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_SRC].bytesperline = +- get_bytesperline(DEFAULT_WIDTH, +- ctx->q_data[V4L2_M2M_SRC].fmt); +- ctx->q_data[V4L2_M2M_SRC].sizeimage = +- get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline, +- ctx->q_data[V4L2_M2M_SRC].height, +- ctx->q_data[V4L2_M2M_SRC].fmt); +- +- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; +- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_DST].bytesperline = 0; +- ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; +- ctx->q_data[V4L2_M2M_DST].sizeimage = +- DEF_COMP_BUF_SIZE_720P_OR_LESS; +- break; +- case ISP: +- break; +- } ++ ++ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; ++ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_SRC].bytesperline = ++ get_bytesperline(DEFAULT_WIDTH, ++ ctx->q_data[V4L2_M2M_SRC].fmt); ++ ctx->q_data[V4L2_M2M_SRC].sizeimage = ++ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline, ++ ctx->q_data[V4L2_M2M_SRC].crop_width, ++ ctx->q_data[V4L2_M2M_SRC].height, ++ ctx->q_data[V4L2_M2M_SRC].fmt); ++ ++ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; ++ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; ++ ctx->q_data[V4L2_M2M_DST].bytesperline = ++ get_bytesperline(DEFAULT_WIDTH, ++ ctx->q_data[V4L2_M2M_DST].fmt); ++ ctx->q_data[V4L2_M2M_DST].sizeimage = ++ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, ++ ctx->q_data[V4L2_M2M_DST].crop_width, ++ ctx->q_data[V4L2_M2M_DST].height, ++ ctx->q_data[V4L2_M2M_DST].fmt); + + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->bitrate = 10 * 1000 * 1000; diff --git a/target/linux/bcm27xx/patches-5.4/950-0193-staging-bcm2835-codec-Correct-port-width-calc-for-tr.patch b/target/linux/bcm27xx/patches-5.4/950-0193-staging-bcm2835-codec-Correct-port-width-calc-for-tr.patch new file mode 100644 index 0000000000..cf57c4cc5f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0193-staging-bcm2835-codec-Correct-port-width-calc-for-tr.patch @@ -0,0 +1,29 @@ +From ecd057b5856ebdc1a9a10f3f4a8fe445bc29623f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 2 May 2019 14:30:24 +0100 +Subject: [PATCH] staging: bcm2835-codec: Correct port width calc for + truncation + +The calculation converting from V4L2 bytesperline to MMAL +width had an operator ordering issue that lead to Bayer raw 10 +(and 12 and 14) setting an incorrect stride for the buffer. +Correct this operation ordering issue. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -605,8 +605,8 @@ static void setup_mmal_port_format(struc + + if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) { + /* Raw image format - set width/height */ +- port->es.video.width = q_data->bytesperline / +- (q_data->fmt->depth >> 3); ++ port->es.video.width = (q_data->bytesperline << 3) / ++ q_data->fmt->depth; + port->es.video.height = q_data->height; + port->es.video.crop.width = q_data->crop_width; + port->es.video.crop.height = q_data->crop_height; diff --git a/target/linux/bcm27xx/patches-5.4/950-0193-staging-bcm2835_codec-Clean-up-logging-on-unloading-.patch b/target/linux/bcm27xx/patches-5.4/950-0193-staging-bcm2835_codec-Clean-up-logging-on-unloading-.patch deleted file mode 100644 index 8b110ca42e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0193-staging-bcm2835_codec-Clean-up-logging-on-unloading-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 02a4a6aaec65be6d1e8ec4b02d6079c1fbdcfec8 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 8 Mar 2019 11:26:00 +0000 -Subject: [PATCH] staging: bcm2835_codec: Clean up logging on unloading - the driver - -The log line was missing a closing \n, so wasn't added to the -log immediately. -Adds the function of the V4L2 device that is being unregistered -too. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -77,6 +77,12 @@ enum bcm2835_codec_role { - ISP, - }; - -+const static char *roles[] = { -+ "decode", -+ "encode", -+ "isp" -+}; -+ - static const char * const components[] = { - "ril.video_decode", - "ril.video_encode", -@@ -2522,7 +2528,6 @@ static int bcm2835_codec_create(struct p - struct video_device *vfd; - int video_nr; - int ret; -- const static char *roles[] = {"decode", "encode", "isp"}; - - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) -@@ -2615,7 +2620,8 @@ static int bcm2835_codec_destroy(struct - if (!dev) - return -ENODEV; - -- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); -+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n", -+ roles[dev->role]); - v4l2_m2m_release(dev->m2m_dev); - video_unregister_device(&dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0194-staging-bcm2835-codec-Refactor-default-resolution-co.patch b/target/linux/bcm27xx/patches-5.4/950-0194-staging-bcm2835-codec-Refactor-default-resolution-co.patch deleted file mode 100644 index 42ab46c1c4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0194-staging-bcm2835-codec-Refactor-default-resolution-co.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 90ad47170414e19ed6c6dcc3f3c9a68fbc7ad175 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 20 Mar 2019 10:06:51 +0000 -Subject: [PATCH] staging: bcm2835-codec: Refactor default resolution - code - -The default resolution code was different for each role -as compressed formats need to pass bytesperline as 0 and -set up customised buffer sizes. -This is common setup, therefore amend get_sizeimage and -get_bytesperline to do the correct thing whether compressed -or uncompressed. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 103 +++++++----------- - 1 file changed, 40 insertions(+), 63 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -578,10 +578,17 @@ static void job_abort(void *priv) - ctx->aborting = 1; - } - --static inline unsigned int get_sizeimage(int bpl, int height, -+static inline unsigned int get_sizeimage(int bpl, int width, int height, - struct bcm2835_codec_fmt *fmt) - { -- return (bpl * height * fmt->size_multiplier_x2) >> 1; -+ if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { -+ if (width * height > 1280 * 720) -+ return DEF_COMP_BUF_SIZE_GREATER_720P; -+ else -+ return DEF_COMP_BUF_SIZE_720P_OR_LESS; -+ } else { -+ return (bpl * height * fmt->size_multiplier_x2) >> 1; -+ } - } - - static inline unsigned int get_bytesperline(int width, -@@ -1032,22 +1039,13 @@ static int vidioc_try_fmt(struct v4l2_fo - * some of the pixels are active. - */ - f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); -- -- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, -- fmt); -- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, -- f->fmt.pix.height, -- fmt); -- } else { -- u32 min_size = f->fmt.pix.width > 1280 || -- f->fmt.pix.height > 720 ? -- DEF_COMP_BUF_SIZE_GREATER_720P : -- DEF_COMP_BUF_SIZE_720P_OR_LESS; -- -- f->fmt.pix.bytesperline = 0; -- if (f->fmt.pix.sizeimage < min_size) -- f->fmt.pix.sizeimage = min_size; - } -+ f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, -+ fmt); -+ f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, -+ f->fmt.pix.width, -+ f->fmt.pix.height, -+ fmt); - - f->fmt.pix.field = V4L2_FIELD_NONE; - -@@ -1159,6 +1157,7 @@ static int vidioc_s_fmt(struct bcm2835_c - q_data_dst->bytesperline = - get_bytesperline(f->fmt.pix.width, q_data_dst->fmt); - q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, -+ q_data_dst->crop_width, - q_data_dst->height, - q_data_dst->fmt); - update_capture_port = true; -@@ -2218,52 +2217,30 @@ static int bcm2835_codec_open(struct fil - - ctx->q_data[V4L2_M2M_SRC].fmt = get_default_format(dev, false); - ctx->q_data[V4L2_M2M_DST].fmt = get_default_format(dev, true); -- switch (dev->role) { -- case DECODE: -- /* -- * Input width and height are irrelevant as they will be defined -- * by the bitstream not the format. Required by V4L2 though. -- */ -- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; -- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; -- ctx->q_data[V4L2_M2M_SRC].sizeimage = -- DEF_COMP_BUF_SIZE_720P_OR_LESS; -- -- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; -- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_DST].bytesperline = -- get_bytesperline(DEFAULT_WIDTH, -- ctx->q_data[V4L2_M2M_DST].fmt); -- ctx->q_data[V4L2_M2M_DST].sizeimage = -- get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, -- ctx->q_data[V4L2_M2M_DST].height, -- ctx->q_data[V4L2_M2M_DST].fmt); -- break; -- case ENCODE: -- ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; -- ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_SRC].bytesperline = -- get_bytesperline(DEFAULT_WIDTH, -- ctx->q_data[V4L2_M2M_SRC].fmt); -- ctx->q_data[V4L2_M2M_SRC].sizeimage = -- get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline, -- ctx->q_data[V4L2_M2M_SRC].height, -- ctx->q_data[V4L2_M2M_SRC].fmt); -- -- ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; -- ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_DST].bytesperline = 0; -- ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; -- ctx->q_data[V4L2_M2M_DST].sizeimage = -- DEF_COMP_BUF_SIZE_720P_OR_LESS; -- break; -- case ISP: -- break; -- } -+ -+ ctx->q_data[V4L2_M2M_SRC].crop_width = DEFAULT_WIDTH; -+ ctx->q_data[V4L2_M2M_SRC].crop_height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_SRC].height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_SRC].bytesperline = -+ get_bytesperline(DEFAULT_WIDTH, -+ ctx->q_data[V4L2_M2M_SRC].fmt); -+ ctx->q_data[V4L2_M2M_SRC].sizeimage = -+ get_sizeimage(ctx->q_data[V4L2_M2M_SRC].bytesperline, -+ ctx->q_data[V4L2_M2M_SRC].crop_width, -+ ctx->q_data[V4L2_M2M_SRC].height, -+ ctx->q_data[V4L2_M2M_SRC].fmt); -+ -+ ctx->q_data[V4L2_M2M_DST].crop_width = DEFAULT_WIDTH; -+ ctx->q_data[V4L2_M2M_DST].crop_height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_DST].height = DEFAULT_HEIGHT; -+ ctx->q_data[V4L2_M2M_DST].bytesperline = -+ get_bytesperline(DEFAULT_WIDTH, -+ ctx->q_data[V4L2_M2M_DST].fmt); -+ ctx->q_data[V4L2_M2M_DST].sizeimage = -+ get_sizeimage(ctx->q_data[V4L2_M2M_DST].bytesperline, -+ ctx->q_data[V4L2_M2M_DST].crop_width, -+ ctx->q_data[V4L2_M2M_DST].height, -+ ctx->q_data[V4L2_M2M_DST].fmt); - - ctx->colorspace = V4L2_COLORSPACE_REC709; - ctx->bitrate = 10 * 1000 * 1000; diff --git a/target/linux/bcm27xx/patches-5.4/950-0194-staging-bcm2835-codec-Remove-height-padding-for-ISP-.patch b/target/linux/bcm27xx/patches-5.4/950-0194-staging-bcm2835-codec-Remove-height-padding-for-ISP-.patch new file mode 100644 index 0000000000..7a94ffa663 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0194-staging-bcm2835-codec-Remove-height-padding-for-ISP-.patch @@ -0,0 +1,61 @@ +From 03b7c70e9164f7b7f0af0cf0b79e689ef97e796b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 2 May 2019 14:32:21 +0100 +Subject: [PATCH] staging: bcm2835-codec: Remove height padding for ISP + role + +The ISP has no need for heights to be a multiple of macroblock +sizes, therefore doesn't require the align on the height. +Remove it for the ISP role. (It is required for the codecs). + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1015,7 +1015,8 @@ static int vidioc_g_fmt_vid_cap(struct f + return vidioc_g_fmt(file2ctx(file), f); + } + +-static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt) ++static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, ++ struct bcm2835_codec_fmt *fmt) + { + /* + * The V4L2 specification requires the driver to correct the format +@@ -1034,11 +1035,13 @@ static int vidioc_try_fmt(struct v4l2_fo + f->fmt.pix.height = MIN_H; + + /* +- * Buffer must have a vertical alignment of 16 lines. ++ * For codecs the buffer must have a vertical alignment of 16 ++ * lines. + * The selection will reflect any cropping rectangle when only + * some of the pixels are active. + */ +- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); ++ if (ctx->dev->role != ISP) ++ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); + } + f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, + fmt); +@@ -1065,7 +1068,7 @@ static int vidioc_try_fmt_vid_cap(struct + fmt = find_format(f, ctx->dev, true); + } + +- return vidioc_try_fmt(f, fmt); ++ return vidioc_try_fmt(ctx, f, fmt); + } + + static int vidioc_try_fmt_vid_out(struct file *file, void *priv, +@@ -1084,7 +1087,7 @@ static int vidioc_try_fmt_vid_out(struct + if (!f->fmt.pix.colorspace) + f->fmt.pix.colorspace = ctx->colorspace; + +- return vidioc_try_fmt(f, fmt); ++ return vidioc_try_fmt(ctx, f, fmt); + } + + static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, diff --git a/target/linux/bcm27xx/patches-5.4/950-0195-staging-bcm2835-codec-Correct-port-width-calc-for-tr.patch b/target/linux/bcm27xx/patches-5.4/950-0195-staging-bcm2835-codec-Correct-port-width-calc-for-tr.patch deleted file mode 100644 index cf57c4cc5f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0195-staging-bcm2835-codec-Correct-port-width-calc-for-tr.patch +++ /dev/null @@ -1,29 +0,0 @@ -From ecd057b5856ebdc1a9a10f3f4a8fe445bc29623f Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 2 May 2019 14:30:24 +0100 -Subject: [PATCH] staging: bcm2835-codec: Correct port width calc for - truncation - -The calculation converting from V4L2 bytesperline to MMAL -width had an operator ordering issue that lead to Bayer raw 10 -(and 12 and 14) setting an incorrect stride for the buffer. -Correct this operation ordering issue. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -605,8 +605,8 @@ static void setup_mmal_port_format(struc - - if (!(q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED)) { - /* Raw image format - set width/height */ -- port->es.video.width = q_data->bytesperline / -- (q_data->fmt->depth >> 3); -+ port->es.video.width = (q_data->bytesperline << 3) / -+ q_data->fmt->depth; - port->es.video.height = q_data->height; - port->es.video.crop.width = q_data->crop_width; - port->es.video.crop.height = q_data->crop_height; diff --git a/target/linux/bcm27xx/patches-5.4/950-0195-staging-mmal-vchiq-Free-the-event-context-for-contro.patch b/target/linux/bcm27xx/patches-5.4/950-0195-staging-mmal-vchiq-Free-the-event-context-for-contro.patch new file mode 100644 index 0000000000..c510e64c47 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0195-staging-mmal-vchiq-Free-the-event-context-for-contro.patch @@ -0,0 +1,28 @@ +From 494d7b63100a1ca9aabeabdf752ecba1c4e5189f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 1 May 2019 13:27:23 +0100 +Subject: [PATCH] staging: mmal-vchiq: Free the event context for + control ports + +vchiq_mmal_component_init calls init_event_context for the +control port, but vchiq_mmal_component_finalise didn't free +it, causing a memory leak.. + +Add the free call. + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -1981,6 +1981,8 @@ int vchiq_mmal_component_finalise(struct + for (idx = 0; idx < component->clocks; idx++) + free_event_context(&component->clock[idx]); + ++ free_event_context(&component->control); ++ + mutex_unlock(&instance->vchiq_mutex); + + return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0196-staging-bcm2835-codec-Remove-height-padding-for-ISP-.patch b/target/linux/bcm27xx/patches-5.4/950-0196-staging-bcm2835-codec-Remove-height-padding-for-ISP-.patch deleted file mode 100644 index 7a94ffa663..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0196-staging-bcm2835-codec-Remove-height-padding-for-ISP-.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 03b7c70e9164f7b7f0af0cf0b79e689ef97e796b Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 2 May 2019 14:32:21 +0100 -Subject: [PATCH] staging: bcm2835-codec: Remove height padding for ISP - role - -The ISP has no need for heights to be a multiple of macroblock -sizes, therefore doesn't require the align on the height. -Remove it for the ISP role. (It is required for the codecs). - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1015,7 +1015,8 @@ static int vidioc_g_fmt_vid_cap(struct f - return vidioc_g_fmt(file2ctx(file), f); - } - --static int vidioc_try_fmt(struct v4l2_format *f, struct bcm2835_codec_fmt *fmt) -+static int vidioc_try_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, -+ struct bcm2835_codec_fmt *fmt) - { - /* - * The V4L2 specification requires the driver to correct the format -@@ -1034,11 +1035,13 @@ static int vidioc_try_fmt(struct v4l2_fo - f->fmt.pix.height = MIN_H; - - /* -- * Buffer must have a vertical alignment of 16 lines. -+ * For codecs the buffer must have a vertical alignment of 16 -+ * lines. - * The selection will reflect any cropping rectangle when only - * some of the pixels are active. - */ -- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); -+ if (ctx->dev->role != ISP) -+ f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); - } - f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, - fmt); -@@ -1065,7 +1068,7 @@ static int vidioc_try_fmt_vid_cap(struct - fmt = find_format(f, ctx->dev, true); - } - -- return vidioc_try_fmt(f, fmt); -+ return vidioc_try_fmt(ctx, f, fmt); - } - - static int vidioc_try_fmt_vid_out(struct file *file, void *priv, -@@ -1084,7 +1087,7 @@ static int vidioc_try_fmt_vid_out(struct - if (!f->fmt.pix.colorspace) - f->fmt.pix.colorspace = ctx->colorspace; - -- return vidioc_try_fmt(f, fmt); -+ return vidioc_try_fmt(ctx, f, fmt); - } - - static int vidioc_s_fmt(struct bcm2835_codec_ctx *ctx, struct v4l2_format *f, diff --git a/target/linux/bcm27xx/patches-5.4/950-0196-staging-mmal-vchiq-Fix-memory-leak-in-error-path.patch b/target/linux/bcm27xx/patches-5.4/950-0196-staging-mmal-vchiq-Fix-memory-leak-in-error-path.patch new file mode 100644 index 0000000000..6e846e4c7d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0196-staging-mmal-vchiq-Fix-memory-leak-in-error-path.patch @@ -0,0 +1,76 @@ +From 20bf522637b3e113d8eb961f9a5d11e4c2d555b6 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 2 May 2019 15:50:01 +0100 +Subject: [PATCH] staging: mmal-vchiq: Fix memory leak in error path + +On error, vchiq_mmal_component_init could leave the +event context allocated for ports. +Clean them up in the error path. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 +++++++++++++------ + 1 file changed, 20 insertions(+), 9 deletions(-) + +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +@@ -1847,9 +1847,26 @@ static void free_event_context(struct vc + { + struct mmal_msg_context *ctx = port->event_context; + ++ if (!ctx) ++ return; ++ + kfree(ctx->u.bulk.buffer->buffer); + kfree(ctx->u.bulk.buffer); + release_msg_context(ctx); ++ port->event_context = NULL; ++} ++ ++static void release_all_event_contexts(struct vchiq_mmal_component *component) ++{ ++ int idx; ++ ++ for (idx = 0; idx < component->inputs; idx++) ++ free_event_context(&component->input[idx]); ++ for (idx = 0; idx < component->outputs; idx++) ++ free_event_context(&component->output[idx]); ++ for (idx = 0; idx < component->clocks; idx++) ++ free_event_context(&component->clock[idx]); ++ free_event_context(&component->control); + } + + /* Initialise a mmal component and its ports +@@ -1947,6 +1964,7 @@ int vchiq_mmal_component_init(struct vch + + release_component: + destroy_component(instance, component); ++ release_all_event_contexts(component); + unlock: + if (component) + component->in_use = 0; +@@ -1962,7 +1980,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i + int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, + struct vchiq_mmal_component *component) + { +- int ret, idx; ++ int ret; + + if (mutex_lock_interruptible(&instance->vchiq_mutex)) + return -EINTR; +@@ -1974,14 +1992,7 @@ int vchiq_mmal_component_finalise(struct + + component->in_use = 0; + +- for (idx = 0; idx < component->inputs; idx++) +- free_event_context(&component->input[idx]); +- for (idx = 0; idx < component->outputs; idx++) +- free_event_context(&component->output[idx]); +- for (idx = 0; idx < component->clocks; idx++) +- free_event_context(&component->clock[idx]); +- +- free_event_context(&component->control); ++ release_all_event_contexts(component); + + mutex_unlock(&instance->vchiq_mutex); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0197-staging-bcm2835-codec-Convert-V4L2-nsec-timestamps-t.patch b/target/linux/bcm27xx/patches-5.4/950-0197-staging-bcm2835-codec-Convert-V4L2-nsec-timestamps-t.patch new file mode 100644 index 0000000000..481ca484d5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0197-staging-bcm2835-codec-Convert-V4L2-nsec-timestamps-t.patch @@ -0,0 +1,46 @@ +From 19a2ab86f47213575ebcde216505623bc65e3918 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 10 May 2019 14:11:58 +0100 +Subject: [PATCH] staging: bcm2835-codec: Convert V4L2 nsec timestamps + to MMAL usec + +V4L2 uses nsecs, whilst MMAL uses usecs, but the code wasn't converting +between them. This upsets video encode rate control. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -823,7 +823,8 @@ static void op_buffer_cb(struct vchiq_mm + vb2->flags |= V4L2_BUF_FLAG_LAST; + } + +- vb2->vb2_buf.timestamp = mmal_buf->pts; ++ /* vb2 timestamps in nsecs, mmal in usecs */ ++ vb2->vb2_buf.timestamp = mmal_buf->pts * 1000; + + vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length); + if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) +@@ -847,6 +848,7 @@ static void op_buffer_cb(struct vchiq_mm + static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf, + struct vb2_v4l2_buffer *vb2) + { ++ u64 pts; + buf->mmal.mmal_flags = 0; + if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME) + buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME; +@@ -869,7 +871,10 @@ static void vb2_to_mmal_buffer(struct m2 + if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST) + buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS; + +- buf->mmal.pts = vb2->vb2_buf.timestamp; ++ /* vb2 timestamps in nsecs, mmal in usecs */ ++ pts = vb2->vb2_buf.timestamp; ++ do_div(pts, 1000); ++ buf->mmal.pts = pts; + buf->mmal.dts = MMAL_TIME_UNKNOWN; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0197-staging-mmal-vchiq-Free-the-event-context-for-contro.patch b/target/linux/bcm27xx/patches-5.4/950-0197-staging-mmal-vchiq-Free-the-event-context-for-contro.patch deleted file mode 100644 index c510e64c47..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0197-staging-mmal-vchiq-Free-the-event-context-for-contro.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 494d7b63100a1ca9aabeabdf752ecba1c4e5189f Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 1 May 2019 13:27:23 +0100 -Subject: [PATCH] staging: mmal-vchiq: Free the event context for - control ports - -vchiq_mmal_component_init calls init_event_context for the -control port, but vchiq_mmal_component_finalise didn't free -it, causing a memory leak.. - -Add the free call. - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -1981,6 +1981,8 @@ int vchiq_mmal_component_finalise(struct - for (idx = 0; idx < component->clocks; idx++) - free_event_context(&component->clock[idx]); - -+ free_event_context(&component->control); -+ - mutex_unlock(&instance->vchiq_mutex); - - return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0198-staging-bcm2835-codec-Add-support-for-setting-S_PARM.patch b/target/linux/bcm27xx/patches-5.4/950-0198-staging-bcm2835-codec-Add-support-for-setting-S_PARM.patch new file mode 100644 index 0000000000..dca6c2402b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0198-staging-bcm2835-codec-Add-support-for-setting-S_PARM.patch @@ -0,0 +1,118 @@ +From 9f1a5a143f0da79813775d9f29608cd4ea2dd01b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 10 May 2019 14:13:11 +0100 +Subject: [PATCH] staging: bcm2835-codec: Add support for setting + S_PARM and G_PARM + +Video encode can use the frame rate for rate control calculations, +therefore plumb it through from V4L2's [S|G]_PARM ioctl. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 52 +++++++++++++++++-- + 1 file changed, 48 insertions(+), 4 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -447,6 +447,8 @@ struct bcm2835_codec_ctx { + /* Source and destination queue data */ + struct bcm2835_codec_q_data q_data[2]; + s32 bitrate; ++ unsigned int framerate_num; ++ unsigned int framerate_denom; + + bool aborting; + int num_ip_buffers; +@@ -610,8 +612,8 @@ static void setup_mmal_port_format(struc + port->es.video.height = q_data->height; + port->es.video.crop.width = q_data->crop_width; + port->es.video.crop.height = q_data->crop_height; +- port->es.video.frame_rate.num = 0; +- port->es.video.frame_rate.den = 1; ++ port->es.video.frame_rate.num = ctx->framerate_num; ++ port->es.video.frame_rate.den = ctx->framerate_denom; + } else { + /* Compressed format - leave resolution as 0 for decode */ + if (ctx->dev->role == DECODE) { +@@ -625,9 +627,9 @@ static void setup_mmal_port_format(struc + port->es.video.crop.width = q_data->crop_width; + port->es.video.crop.height = q_data->crop_height; + port->format.bitrate = ctx->bitrate; ++ port->es.video.frame_rate.num = ctx->framerate_num; ++ port->es.video.frame_rate.den = ctx->framerate_denom; + } +- port->es.video.frame_rate.num = 0; +- port->es.video.frame_rate.den = 1; + } + port->es.video.crop.x = 0; + port->es.video.crop.y = 0; +@@ -1361,6 +1363,41 @@ static int vidioc_s_selection(struct fil + return 0; + } + ++static int vidioc_s_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *parm) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ ctx->framerate_num = ++ parm->parm.output.timeperframe.denominator; ++ ctx->framerate_denom = ++ parm->parm.output.timeperframe.numerator; ++ ++ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; ++ ++ return 0; ++} ++ ++static int vidioc_g_parm(struct file *file, void *priv, ++ struct v4l2_streamparm *parm) ++{ ++ struct bcm2835_codec_ctx *ctx = file2ctx(file); ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; ++ parm->parm.output.timeperframe.denominator = ++ ctx->framerate_num; ++ parm->parm.output.timeperframe.numerator = ++ ctx->framerate_denom; ++ ++ return 0; ++} ++ + static int vidioc_subscribe_evt(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) + { +@@ -1725,6 +1762,9 @@ static const struct v4l2_ioctl_ops bcm28 + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, + ++ .vidioc_g_parm = vidioc_g_parm, ++ .vidioc_s_parm = vidioc_s_parm, ++ + .vidioc_subscribe_event = vidioc_subscribe_evt, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + +@@ -2546,6 +2586,8 @@ static int bcm2835_codec_create(struct p + case DECODE: + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); ++ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + video_nr = decode_video_nr; + break; + case ENCODE: +@@ -2558,6 +2600,8 @@ static int bcm2835_codec_create(struct p + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); ++ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); ++ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + video_nr = isp_video_nr; + break; + default: diff --git a/target/linux/bcm27xx/patches-5.4/950-0198-staging-mmal-vchiq-Fix-memory-leak-in-error-path.patch b/target/linux/bcm27xx/patches-5.4/950-0198-staging-mmal-vchiq-Fix-memory-leak-in-error-path.patch deleted file mode 100644 index 6e846e4c7d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0198-staging-mmal-vchiq-Fix-memory-leak-in-error-path.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 20bf522637b3e113d8eb961f9a5d11e4c2d555b6 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 2 May 2019 15:50:01 +0100 -Subject: [PATCH] staging: mmal-vchiq: Fix memory leak in error path - -On error, vchiq_mmal_component_init could leave the -event context allocated for ports. -Clean them up in the error path. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/vchiq-mmal/mmal-vchiq.c | 29 +++++++++++++------ - 1 file changed, 20 insertions(+), 9 deletions(-) - ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c -@@ -1847,9 +1847,26 @@ static void free_event_context(struct vc - { - struct mmal_msg_context *ctx = port->event_context; - -+ if (!ctx) -+ return; -+ - kfree(ctx->u.bulk.buffer->buffer); - kfree(ctx->u.bulk.buffer); - release_msg_context(ctx); -+ port->event_context = NULL; -+} -+ -+static void release_all_event_contexts(struct vchiq_mmal_component *component) -+{ -+ int idx; -+ -+ for (idx = 0; idx < component->inputs; idx++) -+ free_event_context(&component->input[idx]); -+ for (idx = 0; idx < component->outputs; idx++) -+ free_event_context(&component->output[idx]); -+ for (idx = 0; idx < component->clocks; idx++) -+ free_event_context(&component->clock[idx]); -+ free_event_context(&component->control); - } - - /* Initialise a mmal component and its ports -@@ -1947,6 +1964,7 @@ int vchiq_mmal_component_init(struct vch - - release_component: - destroy_component(instance, component); -+ release_all_event_contexts(component); - unlock: - if (component) - component->in_use = 0; -@@ -1962,7 +1980,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_component_i - int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance, - struct vchiq_mmal_component *component) - { -- int ret, idx; -+ int ret; - - if (mutex_lock_interruptible(&instance->vchiq_mutex)) - return -EINTR; -@@ -1974,14 +1992,7 @@ int vchiq_mmal_component_finalise(struct - - component->in_use = 0; - -- for (idx = 0; idx < component->inputs; idx++) -- free_event_context(&component->input[idx]); -- for (idx = 0; idx < component->outputs; idx++) -- free_event_context(&component->output[idx]); -- for (idx = 0; idx < component->clocks; idx++) -- free_event_context(&component->clock[idx]); -- -- free_event_context(&component->control); -+ release_all_event_contexts(component); - - mutex_unlock(&instance->vchiq_mutex); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0199-Bluetooth-Check-key-sizes-only-when-Secure-Simple-Pa.patch b/target/linux/bcm27xx/patches-5.4/950-0199-Bluetooth-Check-key-sizes-only-when-Secure-Simple-Pa.patch deleted file mode 100644 index 0de55097c5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0199-Bluetooth-Check-key-sizes-only-when-Secure-Simple-Pa.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 3e2981c7e55d75dc93a2f2e9bb6be2b9704c05f5 Mon Sep 17 00:00:00 2001 -From: Marcel Holtmann -Date: Wed, 22 May 2019 09:05:40 +0200 -Subject: [PATCH] Bluetooth: Check key sizes only when Secure Simple - Pairing is enabled - -The encryption is only mandatory to be enforced when both sides are using -Secure Simple Pairing and this means the key size check makes only sense -in that case. - -On legacy Bluetooth 2.0 and earlier devices like mice the encryption was -optional and thus causing an issue if the key size check is not bound to -using Secure Simple Pairing. - -Fixes: d5bb334a8e17 ("Bluetooth: Align minimum encryption key size for LE and BR/EDR connections") -Signed-off-by: Marcel Holtmann -Cc: stable@vger.kernel.org ---- - net/bluetooth/hci_conn.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -1302,8 +1302,13 @@ int hci_conn_check_link_mode(struct hci_ - return 0; - } - -- if (hci_conn_ssp_enabled(conn) && -- !test_bit(HCI_CONN_ENCRYPT, &conn->flags)) -+ /* If Secure Simple Pairing is not enabled, then legacy connection -+ * setup is used and no encryption or key sizes can be enforced. -+ */ -+ if (!hci_conn_ssp_enabled(conn)) -+ return 1; -+ -+ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) - return 0; - - return 1; diff --git a/target/linux/bcm27xx/patches-5.4/950-0199-w1-w1-gpio-Make-GPIO-an-output-for-strong-pullup.patch b/target/linux/bcm27xx/patches-5.4/950-0199-w1-w1-gpio-Make-GPIO-an-output-for-strong-pullup.patch new file mode 100644 index 0000000000..c8d656a1cf --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0199-w1-w1-gpio-Make-GPIO-an-output-for-strong-pullup.patch @@ -0,0 +1,27 @@ +From db2d840e64afb069ae3debab013610cce05ac099 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 12 Jun 2019 17:15:05 +0100 +Subject: [PATCH] w1: w1-gpio: Make GPIO an output for strong pullup + +The logic to drive the data line high to implement a strong pullup +assumed that the pin was already an output - setting a value does +not change an input. + +See: https://github.com/raspberrypi/firmware/issues/1143 + +Signed-off-by: Phil Elwell +--- + drivers/w1/masters/w1-gpio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/w1/masters/w1-gpio.c ++++ b/drivers/w1/masters/w1-gpio.c +@@ -30,7 +30,7 @@ static u8 w1_gpio_set_pullup(void *data, + * This will OVERRIDE open drain emulation and force-pull + * the line high for some time. + */ +- gpiod_set_raw_value(pdata->gpiod, 1); ++ gpiod_direction_output_raw(pdata->gpiod, 1); + msleep(pdata->pullup_duration); + /* + * This will simply set the line as input since we are doing diff --git a/target/linux/bcm27xx/patches-5.4/950-0200-arm-bcm2835-Fix-FIQ-early-ioremap.patch b/target/linux/bcm27xx/patches-5.4/950-0200-arm-bcm2835-Fix-FIQ-early-ioremap.patch new file mode 100644 index 0000000000..1521476de1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0200-arm-bcm2835-Fix-FIQ-early-ioremap.patch @@ -0,0 +1,73 @@ +From 9b9474236597f87247fcf93147598e50f7f02b9e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 20 Feb 2019 08:49:39 +0000 +Subject: [PATCH] arm: bcm2835: Fix FIQ early ioremap + +The ioremapping creates mappings within the vmalloc area. The +equivalent early function, create_mapping, now checks that the +requested explicit virtual address is between VMALLOC_START and +VMALLOC_END. As there is no reason to have any correlation between +the physical and virtual addresses, put the required mappings at +VMALLOC_START and above. + +Signed-off-by: Phil Elwell +--- + arch/arm/mach-bcm/board_bcm2835.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +--- a/arch/arm/mach-bcm/board_bcm2835.c ++++ b/arch/arm/mach-bcm/board_bcm2835.c +@@ -5,17 +5,20 @@ + + #include + #include ++#include + #include + #include + #include + + #include + #include ++#include ++#include + + #include "platsmp.h" + +-#define BCM2835_USB_VIRT_BASE 0xf0980000 +-#define BCM2835_USB_VIRT_MPHI 0xf0006000 ++#define BCM2835_USB_VIRT_BASE (VMALLOC_START) ++#define BCM2835_USB_VIRT_MPHI (VMALLOC_START + 0x10000) + + static void __init bcm2835_init(void) + { +@@ -74,20 +77,26 @@ static int __init bcm2835_map_usb(unsign + + static void __init bcm2835_map_io(void) + { +- const __be32 *ranges; ++ const __be32 *ranges, *address_cells; ++ unsigned long root, addr_cells; + int soc, len; + unsigned long p2b_offset; + + debug_ll_io_init(); + ++ root = of_get_flat_dt_root(); + /* Find out how to map bus to physical address first from soc/ranges */ +- soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc"); ++ soc = of_get_flat_dt_subnode_by_name(root, "soc"); + if (soc < 0) + return; ++ address_cells = of_get_flat_dt_prop(root, "#address-cells", &len); ++ if (!address_cells || len < (sizeof(unsigned long))) ++ return; ++ addr_cells = be32_to_cpu(address_cells[0]); + ranges = of_get_flat_dt_prop(soc, "ranges", &len); +- if (!ranges || len < (sizeof(unsigned long) * 3)) ++ if (!ranges || len < (sizeof(unsigned long) * (2 + addr_cells))) + return; +- p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]); ++ p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[addr_cells]); + + /* Now search for bcm2708-usb node in device tree */ + of_scan_flat_dt(bcm2835_map_usb, &p2b_offset); diff --git a/target/linux/bcm27xx/patches-5.4/950-0200-staging-bcm2835-codec-Convert-V4L2-nsec-timestamps-t.patch b/target/linux/bcm27xx/patches-5.4/950-0200-staging-bcm2835-codec-Convert-V4L2-nsec-timestamps-t.patch deleted file mode 100644 index 481ca484d5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0200-staging-bcm2835-codec-Convert-V4L2-nsec-timestamps-t.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 19a2ab86f47213575ebcde216505623bc65e3918 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 10 May 2019 14:11:58 +0100 -Subject: [PATCH] staging: bcm2835-codec: Convert V4L2 nsec timestamps - to MMAL usec - -V4L2 uses nsecs, whilst MMAL uses usecs, but the code wasn't converting -between them. This upsets video encode rate control. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -823,7 +823,8 @@ static void op_buffer_cb(struct vchiq_mm - vb2->flags |= V4L2_BUF_FLAG_LAST; - } - -- vb2->vb2_buf.timestamp = mmal_buf->pts; -+ /* vb2 timestamps in nsecs, mmal in usecs */ -+ vb2->vb2_buf.timestamp = mmal_buf->pts * 1000; - - vb2_set_plane_payload(&vb2->vb2_buf, 0, mmal_buf->length); - if (mmal_buf->mmal_flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) -@@ -847,6 +848,7 @@ static void op_buffer_cb(struct vchiq_mm - static void vb2_to_mmal_buffer(struct m2m_mmal_buffer *buf, - struct vb2_v4l2_buffer *vb2) - { -+ u64 pts; - buf->mmal.mmal_flags = 0; - if (vb2->flags & V4L2_BUF_FLAG_KEYFRAME) - buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME; -@@ -869,7 +871,10 @@ static void vb2_to_mmal_buffer(struct m2 - if (!buf->mmal.length || vb2->flags & V4L2_BUF_FLAG_LAST) - buf->mmal.mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS; - -- buf->mmal.pts = vb2->vb2_buf.timestamp; -+ /* vb2 timestamps in nsecs, mmal in usecs */ -+ pts = vb2->vb2_buf.timestamp; -+ do_div(pts, 1000); -+ buf->mmal.pts = pts; - buf->mmal.dts = MMAL_TIME_UNKNOWN; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0201-Fix-copy_from_user-if-BCM2835_FAST_MEMCPY-n.patch b/target/linux/bcm27xx/patches-5.4/950-0201-Fix-copy_from_user-if-BCM2835_FAST_MEMCPY-n.patch new file mode 100644 index 0000000000..fc6efceacd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0201-Fix-copy_from_user-if-BCM2835_FAST_MEMCPY-n.patch @@ -0,0 +1,39 @@ +From dc516e6e8dfdaecf01efc7ee643a234191761062 Mon Sep 17 00:00:00 2001 +From: Tim Gover +Date: Thu, 14 Mar 2019 10:16:02 +0000 +Subject: [PATCH] Fix copy_from_user if BCM2835_FAST_MEMCPY=n + +The change which introduced CONFIG_BCM2835_FAST_MEMCPY unconditionally +changed the behaviour of arm_copy_from_user. The page pinning code +is not safe on ARMv7 if LPAE & high memory is enabled and causes +crashes which look like PTE corruption. + +Make __copy_from_user_memcpy conditional on CONFIG_2835_FAST_MEMCPY=y +which is really an ARMv6 / Pi1 optimization and not necessary on newer +ARM processors. +--- + arch/arm/lib/uaccess_with_memcpy.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/arm/lib/uaccess_with_memcpy.c ++++ b/arch/arm/lib/uaccess_with_memcpy.c +@@ -254,6 +254,7 @@ arm_copy_to_user(void __user *to, const + unsigned long __must_check + arm_copy_from_user(void *to, const void __user *from, unsigned long n) + { ++#ifdef CONFIG_BCM2835_FAST_MEMCPY + /* + * This test is stubbed out of the main function above to keep + * the overhead for small copies low by avoiding a large +@@ -268,6 +269,11 @@ arm_copy_from_user(void *to, const void + } else { + n = __copy_from_user_memcpy(to, from, n); + } ++#else ++ unsigned long ua_flags = uaccess_save_and_enable(); ++ n = __copy_from_user_std(to, from, n); ++ uaccess_restore(ua_flags); ++#endif + return n; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0201-staging-bcm2835-codec-Add-support-for-setting-S_PARM.patch b/target/linux/bcm27xx/patches-5.4/950-0201-staging-bcm2835-codec-Add-support-for-setting-S_PARM.patch deleted file mode 100644 index dca6c2402b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0201-staging-bcm2835-codec-Add-support-for-setting-S_PARM.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 9f1a5a143f0da79813775d9f29608cd4ea2dd01b Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 10 May 2019 14:13:11 +0100 -Subject: [PATCH] staging: bcm2835-codec: Add support for setting - S_PARM and G_PARM - -Video encode can use the frame rate for rate control calculations, -therefore plumb it through from V4L2's [S|G]_PARM ioctl. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 52 +++++++++++++++++-- - 1 file changed, 48 insertions(+), 4 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -447,6 +447,8 @@ struct bcm2835_codec_ctx { - /* Source and destination queue data */ - struct bcm2835_codec_q_data q_data[2]; - s32 bitrate; -+ unsigned int framerate_num; -+ unsigned int framerate_denom; - - bool aborting; - int num_ip_buffers; -@@ -610,8 +612,8 @@ static void setup_mmal_port_format(struc - port->es.video.height = q_data->height; - port->es.video.crop.width = q_data->crop_width; - port->es.video.crop.height = q_data->crop_height; -- port->es.video.frame_rate.num = 0; -- port->es.video.frame_rate.den = 1; -+ port->es.video.frame_rate.num = ctx->framerate_num; -+ port->es.video.frame_rate.den = ctx->framerate_denom; - } else { - /* Compressed format - leave resolution as 0 for decode */ - if (ctx->dev->role == DECODE) { -@@ -625,9 +627,9 @@ static void setup_mmal_port_format(struc - port->es.video.crop.width = q_data->crop_width; - port->es.video.crop.height = q_data->crop_height; - port->format.bitrate = ctx->bitrate; -+ port->es.video.frame_rate.num = ctx->framerate_num; -+ port->es.video.frame_rate.den = ctx->framerate_denom; - } -- port->es.video.frame_rate.num = 0; -- port->es.video.frame_rate.den = 1; - } - port->es.video.crop.x = 0; - port->es.video.crop.y = 0; -@@ -1361,6 +1363,41 @@ static int vidioc_s_selection(struct fil - return 0; - } - -+static int vidioc_s_parm(struct file *file, void *priv, -+ struct v4l2_streamparm *parm) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) -+ return -EINVAL; -+ -+ ctx->framerate_num = -+ parm->parm.output.timeperframe.denominator; -+ ctx->framerate_denom = -+ parm->parm.output.timeperframe.numerator; -+ -+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; -+ -+ return 0; -+} -+ -+static int vidioc_g_parm(struct file *file, void *priv, -+ struct v4l2_streamparm *parm) -+{ -+ struct bcm2835_codec_ctx *ctx = file2ctx(file); -+ -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) -+ return -EINVAL; -+ -+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; -+ parm->parm.output.timeperframe.denominator = -+ ctx->framerate_num; -+ parm->parm.output.timeperframe.numerator = -+ ctx->framerate_denom; -+ -+ return 0; -+} -+ - static int vidioc_subscribe_evt(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) - { -@@ -1725,6 +1762,9 @@ static const struct v4l2_ioctl_ops bcm28 - .vidioc_g_selection = vidioc_g_selection, - .vidioc_s_selection = vidioc_s_selection, - -+ .vidioc_g_parm = vidioc_g_parm, -+ .vidioc_s_parm = vidioc_s_parm, -+ - .vidioc_subscribe_event = vidioc_subscribe_evt, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - -@@ -2546,6 +2586,8 @@ static int bcm2835_codec_create(struct p - case DECODE: - v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); -+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); - video_nr = decode_video_nr; - break; - case ENCODE: -@@ -2558,6 +2600,8 @@ static int bcm2835_codec_create(struct p - v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); -+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); -+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); - video_nr = isp_video_nr; - break; - default: diff --git a/target/linux/bcm27xx/patches-5.4/950-0202-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch b/target/linux/bcm27xx/patches-5.4/950-0202-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch new file mode 100644 index 0000000000..d4ff3165b3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0202-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch @@ -0,0 +1,77 @@ +From 417e4745f7470ca8b9809056485eb7a81305019b Mon Sep 17 00:00:00 2001 +From: Jim Quinlan +Date: Mon, 15 Jan 2018 18:28:39 -0500 +Subject: [PATCH] dt-bindings: pci: Add DT docs for Brcmstb PCIe device + +The DT bindings description of the Brcmstb PCIe device is described. This +node can be used by almost all Broadcom settop box chips, using +ARM, ARM64, or MIPS CPU architectures. + +Signed-off-by: Jim Quinlan +--- + .../devicetree/bindings/pci/brcmstb-pcie.txt | 59 +++++++++++++++++++ + 1 file changed, 59 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt +@@ -0,0 +1,59 @@ ++Brcmstb PCIe Host Controller Device Tree Bindings ++ ++Required Properties: ++- compatible ++ "brcm,bcm7425-pcie" -- for 7425 family MIPS-based SOCs. ++ "brcm,bcm7435-pcie" -- for 7435 family MIPS-based SOCs. ++ "brcm,bcm7445-pcie" -- for 7445 and later ARM based SOCs (not including ++ the 7278). ++ "brcm,bcm7278-pcie" -- for 7278 family ARM-based SOCs. ++ ++- reg -- the register start address and length for the PCIe reg block. ++- interrupts -- two interrupts are specified; the first interrupt is for ++ the PCI host controller and the second is for MSI if the built-in ++ MSI controller is to be used. ++- interrupt-names -- names of the interrupts (above): "pcie" and "msi". ++- #address-cells -- set to <3>. ++- #size-cells -- set to <2>. ++- #interrupt-cells: set to <1>. ++- interrupt-map-mask and interrupt-map, standard PCI properties to define the ++ mapping of the PCIe interface to interrupt numbers. ++- ranges: ranges for the PCI memory and I/O regions. ++- linux,pci-domain -- should be unique per host controller. ++ ++Optional Properties: ++- clocks -- phandle of pcie clock. ++- clock-names -- set to "sw_pcie" if clocks is used. ++- dma-ranges -- Specifies the inbound memory mapping regions when ++ an "identity map" is not possible. ++- msi-controller -- this property is typically specified to have the ++ PCIe controller use its internal MSI controller. ++- msi-parent -- set to use an external MSI interrupt controller. ++- brcm,enable-ssc -- (boolean) indicates usage of spread-spectrum clocking. ++- max-link-speed -- (integer) indicates desired generation of link: ++ 1 => 2.5 Gbps (gen1), 2 => 5.0 Gbps (gen2), 3 => 8.0 Gbps (gen3). ++ ++Example Node: ++ ++pcie0: pcie@f0460000 { ++ reg = <0x0 0xf0460000 0x0 0x9310>; ++ interrupts = <0x0 0x0 0x4>; ++ compatible = "brcm,bcm7445-pcie"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges = <0x02000000 0x00000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x08000000 ++ 0x02000000 0x00000000 0x08000000 0x00000000 0xc8000000 0x00000000 0x08000000>; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &intc 0 47 3 ++ 0 0 0 2 &intc 0 48 3 ++ 0 0 0 3 &intc 0 49 3 ++ 0 0 0 4 &intc 0 50 3>; ++ clocks = <&sw_pcie0>; ++ clock-names = "sw_pcie"; ++ msi-parent = <&pcie0>; /* use PCIe's internal MSI controller */ ++ msi-controller; /* use PCIe's internal MSI controller */ ++ brcm,ssc; ++ max-link-speed = <1>; ++ linux,pci-domain = <0>; ++ }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0202-w1-w1-gpio-Make-GPIO-an-output-for-strong-pullup.patch b/target/linux/bcm27xx/patches-5.4/950-0202-w1-w1-gpio-Make-GPIO-an-output-for-strong-pullup.patch deleted file mode 100644 index c8d656a1cf..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0202-w1-w1-gpio-Make-GPIO-an-output-for-strong-pullup.patch +++ /dev/null @@ -1,27 +0,0 @@ -From db2d840e64afb069ae3debab013610cce05ac099 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 12 Jun 2019 17:15:05 +0100 -Subject: [PATCH] w1: w1-gpio: Make GPIO an output for strong pullup - -The logic to drive the data line high to implement a strong pullup -assumed that the pin was already an output - setting a value does -not change an input. - -See: https://github.com/raspberrypi/firmware/issues/1143 - -Signed-off-by: Phil Elwell ---- - drivers/w1/masters/w1-gpio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/w1/masters/w1-gpio.c -+++ b/drivers/w1/masters/w1-gpio.c -@@ -30,7 +30,7 @@ static u8 w1_gpio_set_pullup(void *data, - * This will OVERRIDE open drain emulation and force-pull - * the line high for some time. - */ -- gpiod_set_raw_value(pdata->gpiod, 1); -+ gpiod_direction_output_raw(pdata->gpiod, 1); - msleep(pdata->pullup_duration); - /* - * This will simply set the line as input since we are doing diff --git a/target/linux/bcm27xx/patches-5.4/950-0203-arm-bcm2835-DMA-can-only-address-1GB.patch b/target/linux/bcm27xx/patches-5.4/950-0203-arm-bcm2835-DMA-can-only-address-1GB.patch new file mode 100644 index 0000000000..86ad707b95 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0203-arm-bcm2835-DMA-can-only-address-1GB.patch @@ -0,0 +1,25 @@ +From 67b31f71da2c251860dc6ddeffc5d15f8a74c675 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 29 May 2019 15:47:42 +0100 +Subject: [PATCH] arm: bcm2835: DMA can only address 1GB + +The legacy peripherals can only address the first gigabyte of RAM, so +ensure that DMA allocations are restricted to that region. + +Signed-off-by: Phil Elwell +--- + arch/arm/mach-bcm/board_bcm2835.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/arm/mach-bcm/board_bcm2835.c ++++ b/arch/arm/mach-bcm/board_bcm2835.c +@@ -114,6 +114,9 @@ static const char * const bcm2835_compat + }; + + DT_MACHINE_START(BCM2835, "BCM2835") ++#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) ++ .dma_zone_size = SZ_1G, ++#endif + .map_io = bcm2835_map_io, + .init_machine = bcm2835_init, + .dt_compat = bcm2835_compat, diff --git a/target/linux/bcm27xx/patches-5.4/950-0203-arm-bcm2835-Fix-FIQ-early-ioremap.patch b/target/linux/bcm27xx/patches-5.4/950-0203-arm-bcm2835-Fix-FIQ-early-ioremap.patch deleted file mode 100644 index 1521476de1..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0203-arm-bcm2835-Fix-FIQ-early-ioremap.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 9b9474236597f87247fcf93147598e50f7f02b9e Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 20 Feb 2019 08:49:39 +0000 -Subject: [PATCH] arm: bcm2835: Fix FIQ early ioremap - -The ioremapping creates mappings within the vmalloc area. The -equivalent early function, create_mapping, now checks that the -requested explicit virtual address is between VMALLOC_START and -VMALLOC_END. As there is no reason to have any correlation between -the physical and virtual addresses, put the required mappings at -VMALLOC_START and above. - -Signed-off-by: Phil Elwell ---- - arch/arm/mach-bcm/board_bcm2835.c | 21 +++++++++++++++------ - 1 file changed, 15 insertions(+), 6 deletions(-) - ---- a/arch/arm/mach-bcm/board_bcm2835.c -+++ b/arch/arm/mach-bcm/board_bcm2835.c -@@ -5,17 +5,20 @@ - - #include - #include -+#include - #include - #include - #include - - #include - #include -+#include -+#include - - #include "platsmp.h" - --#define BCM2835_USB_VIRT_BASE 0xf0980000 --#define BCM2835_USB_VIRT_MPHI 0xf0006000 -+#define BCM2835_USB_VIRT_BASE (VMALLOC_START) -+#define BCM2835_USB_VIRT_MPHI (VMALLOC_START + 0x10000) - - static void __init bcm2835_init(void) - { -@@ -74,20 +77,26 @@ static int __init bcm2835_map_usb(unsign - - static void __init bcm2835_map_io(void) - { -- const __be32 *ranges; -+ const __be32 *ranges, *address_cells; -+ unsigned long root, addr_cells; - int soc, len; - unsigned long p2b_offset; - - debug_ll_io_init(); - -+ root = of_get_flat_dt_root(); - /* Find out how to map bus to physical address first from soc/ranges */ -- soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc"); -+ soc = of_get_flat_dt_subnode_by_name(root, "soc"); - if (soc < 0) - return; -+ address_cells = of_get_flat_dt_prop(root, "#address-cells", &len); -+ if (!address_cells || len < (sizeof(unsigned long))) -+ return; -+ addr_cells = be32_to_cpu(address_cells[0]); - ranges = of_get_flat_dt_prop(soc, "ranges", &len); -- if (!ranges || len < (sizeof(unsigned long) * 3)) -+ if (!ranges || len < (sizeof(unsigned long) * (2 + addr_cells))) - return; -- p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]); -+ p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[addr_cells]); - - /* Now search for bcm2708-usb node in device tree */ - of_scan_flat_dt(bcm2835_map_usb, &p2b_offset); diff --git a/target/linux/bcm27xx/patches-5.4/950-0204-Fix-copy_from_user-if-BCM2835_FAST_MEMCPY-n.patch b/target/linux/bcm27xx/patches-5.4/950-0204-Fix-copy_from_user-if-BCM2835_FAST_MEMCPY-n.patch deleted file mode 100644 index fc6efceacd..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0204-Fix-copy_from_user-if-BCM2835_FAST_MEMCPY-n.patch +++ /dev/null @@ -1,39 +0,0 @@ -From dc516e6e8dfdaecf01efc7ee643a234191761062 Mon Sep 17 00:00:00 2001 -From: Tim Gover -Date: Thu, 14 Mar 2019 10:16:02 +0000 -Subject: [PATCH] Fix copy_from_user if BCM2835_FAST_MEMCPY=n - -The change which introduced CONFIG_BCM2835_FAST_MEMCPY unconditionally -changed the behaviour of arm_copy_from_user. The page pinning code -is not safe on ARMv7 if LPAE & high memory is enabled and causes -crashes which look like PTE corruption. - -Make __copy_from_user_memcpy conditional on CONFIG_2835_FAST_MEMCPY=y -which is really an ARMv6 / Pi1 optimization and not necessary on newer -ARM processors. ---- - arch/arm/lib/uaccess_with_memcpy.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/arch/arm/lib/uaccess_with_memcpy.c -+++ b/arch/arm/lib/uaccess_with_memcpy.c -@@ -254,6 +254,7 @@ arm_copy_to_user(void __user *to, const - unsigned long __must_check - arm_copy_from_user(void *to, const void __user *from, unsigned long n) - { -+#ifdef CONFIG_BCM2835_FAST_MEMCPY - /* - * This test is stubbed out of the main function above to keep - * the overhead for small copies low by avoiding a large -@@ -268,6 +269,11 @@ arm_copy_from_user(void *to, const void - } else { - n = __copy_from_user_memcpy(to, from, n); - } -+#else -+ unsigned long ua_flags = uaccess_save_and_enable(); -+ n = __copy_from_user_std(to, from, n); -+ uaccess_restore(ua_flags); -+#endif - return n; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0204-hwrng-iproc-rng200-Add-BCM2838-support.patch b/target/linux/bcm27xx/patches-5.4/950-0204-hwrng-iproc-rng200-Add-BCM2838-support.patch new file mode 100644 index 0000000000..c9eac88066 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0204-hwrng-iproc-rng200-Add-BCM2838-support.patch @@ -0,0 +1,158 @@ +From cbf5cde9c460eae458829a7b357cea6734c4755b Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Sat, 4 May 2019 17:06:15 +0200 +Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support + +The HWRNG on the BCM2838 is compatible to iproc-rng200, so add the +support to this driver instead of bcm2835-rng. + +Signed-off-by: Stefan Wahren +--- + drivers/char/hw_random/Kconfig | 4 +- + drivers/char/hw_random/iproc-rng200.c | 81 +++++++++++++++++++++++++-- + 2 files changed, 79 insertions(+), 6 deletions(-) + +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -90,11 +90,11 @@ config HW_RANDOM_BCM2835 + + config HW_RANDOM_IPROC_RNG200 + tristate "Broadcom iProc/STB RNG200 support" +- depends on ARCH_BCM_IPROC || ARCH_BRCMSTB ++ depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the RNG200 +- hardware found on the Broadcom iProc and STB SoCs. ++ hardware found on the Broadcom iProc, BCM2838 and STB SoCs. + + To compile this driver as a module, choose M here: the + module will be called iproc-rng200 +--- a/drivers/char/hw_random/iproc-rng200.c ++++ b/drivers/char/hw_random/iproc-rng200.c +@@ -29,6 +29,7 @@ + #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF + #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001 + #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000 ++#define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13 + + #define RNG_SOFT_RESET_OFFSET 0x04 + #define RNG_SOFT_RESET 0x00000001 +@@ -36,16 +37,23 @@ + #define RBG_SOFT_RESET_OFFSET 0x08 + #define RBG_SOFT_RESET 0x00000001 + ++#define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C ++ ++#define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10 ++ + #define RNG_INT_STATUS_OFFSET 0x18 + #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000 + #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000 + #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020 + #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001 + ++#define RNG_INT_ENABLE_OFFSET 0x1C ++ + #define RNG_FIFO_DATA_OFFSET 0x20 + + #define RNG_FIFO_COUNT_OFFSET 0x24 + #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF ++#define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8 + + struct iproc_rng200_dev { + struct hwrng rng; +@@ -166,6 +174,64 @@ static int iproc_rng200_init(struct hwrn + return 0; + } + ++static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max, ++ bool wait) ++{ ++ struct iproc_rng200_dev *priv = to_rng_priv(rng); ++ u32 max_words = max / sizeof(u32); ++ u32 num_words, count, val; ++ ++ /* ensure warm up period has elapsed */ ++ while (1) { ++ val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET); ++ if (val > 16) ++ break; ++ cpu_relax(); ++ } ++ ++ /* ensure fifo is not empty */ ++ while (1) { ++ num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) & ++ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK; ++ if (num_words) ++ break; ++ if (!wait) ++ return 0; ++ cpu_relax(); ++ } ++ ++ if (num_words > max_words) ++ num_words = max_words; ++ ++ for (count = 0; count < num_words; count++) { ++ ((u32 *)buf)[count] = ioread32(priv->base + ++ RNG_FIFO_DATA_OFFSET); ++ } ++ ++ return num_words * sizeof(u32); ++} ++ ++static int bcm2838_rng200_init(struct hwrng *rng) ++{ ++ struct iproc_rng200_dev *priv = to_rng_priv(rng); ++ uint32_t val; ++ ++ if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK) ++ return 0; ++ ++ /* initial numbers generated are "less random" so will be discarded */ ++ val = 0x40000; ++ iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET); ++ /* min fifo count to generate full interrupt */ ++ val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT; ++ iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET); ++ /* enable the rng - 1Mhz sample rate */ ++ val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK; ++ iowrite32(val, priv->base + RNG_CTRL_OFFSET); ++ ++ return 0; ++} ++ + static void iproc_rng200_cleanup(struct hwrng *rng) + { + struct iproc_rng200_dev *priv = to_rng_priv(rng); +@@ -202,10 +268,16 @@ static int iproc_rng200_probe(struct pla + return PTR_ERR(priv->base); + } + +- priv->rng.name = "iproc-rng200", +- priv->rng.read = iproc_rng200_read, +- priv->rng.init = iproc_rng200_init, +- priv->rng.cleanup = iproc_rng200_cleanup, ++ priv->rng.name = pdev->name; ++ priv->rng.cleanup = iproc_rng200_cleanup; ++ ++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) { ++ priv->rng.init = bcm2838_rng200_init; ++ priv->rng.read = bcm2838_rng200_read; ++ } else { ++ priv->rng.init = iproc_rng200_init; ++ priv->rng.read = iproc_rng200_read; ++ } + + /* Register driver */ + ret = devm_hwrng_register(dev, &priv->rng); +@@ -223,6 +295,7 @@ static const struct of_device_id iproc_r + { .compatible = "brcm,bcm7211-rng200", }, + { .compatible = "brcm,bcm7278-rng200", }, + { .compatible = "brcm,iproc-rng200", }, ++ { .compatible = "brcm,bcm2838-rng200"}, + {}, + }; + MODULE_DEVICE_TABLE(of, iproc_rng200_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0205-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch b/target/linux/bcm27xx/patches-5.4/950-0205-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch deleted file mode 100644 index d4ff3165b3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0205-dt-bindings-pci-Add-DT-docs-for-Brcmstb-PCIe-device.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 417e4745f7470ca8b9809056485eb7a81305019b Mon Sep 17 00:00:00 2001 -From: Jim Quinlan -Date: Mon, 15 Jan 2018 18:28:39 -0500 -Subject: [PATCH] dt-bindings: pci: Add DT docs for Brcmstb PCIe device - -The DT bindings description of the Brcmstb PCIe device is described. This -node can be used by almost all Broadcom settop box chips, using -ARM, ARM64, or MIPS CPU architectures. - -Signed-off-by: Jim Quinlan ---- - .../devicetree/bindings/pci/brcmstb-pcie.txt | 59 +++++++++++++++++++ - 1 file changed, 59 insertions(+) - create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt -@@ -0,0 +1,59 @@ -+Brcmstb PCIe Host Controller Device Tree Bindings -+ -+Required Properties: -+- compatible -+ "brcm,bcm7425-pcie" -- for 7425 family MIPS-based SOCs. -+ "brcm,bcm7435-pcie" -- for 7435 family MIPS-based SOCs. -+ "brcm,bcm7445-pcie" -- for 7445 and later ARM based SOCs (not including -+ the 7278). -+ "brcm,bcm7278-pcie" -- for 7278 family ARM-based SOCs. -+ -+- reg -- the register start address and length for the PCIe reg block. -+- interrupts -- two interrupts are specified; the first interrupt is for -+ the PCI host controller and the second is for MSI if the built-in -+ MSI controller is to be used. -+- interrupt-names -- names of the interrupts (above): "pcie" and "msi". -+- #address-cells -- set to <3>. -+- #size-cells -- set to <2>. -+- #interrupt-cells: set to <1>. -+- interrupt-map-mask and interrupt-map, standard PCI properties to define the -+ mapping of the PCIe interface to interrupt numbers. -+- ranges: ranges for the PCI memory and I/O regions. -+- linux,pci-domain -- should be unique per host controller. -+ -+Optional Properties: -+- clocks -- phandle of pcie clock. -+- clock-names -- set to "sw_pcie" if clocks is used. -+- dma-ranges -- Specifies the inbound memory mapping regions when -+ an "identity map" is not possible. -+- msi-controller -- this property is typically specified to have the -+ PCIe controller use its internal MSI controller. -+- msi-parent -- set to use an external MSI interrupt controller. -+- brcm,enable-ssc -- (boolean) indicates usage of spread-spectrum clocking. -+- max-link-speed -- (integer) indicates desired generation of link: -+ 1 => 2.5 Gbps (gen1), 2 => 5.0 Gbps (gen2), 3 => 8.0 Gbps (gen3). -+ -+Example Node: -+ -+pcie0: pcie@f0460000 { -+ reg = <0x0 0xf0460000 0x0 0x9310>; -+ interrupts = <0x0 0x0 0x4>; -+ compatible = "brcm,bcm7445-pcie"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges = <0x02000000 0x00000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x08000000 -+ 0x02000000 0x00000000 0x08000000 0x00000000 0xc8000000 0x00000000 0x08000000>; -+ #interrupt-cells = <1>; -+ interrupt-map-mask = <0 0 0 7>; -+ interrupt-map = <0 0 0 1 &intc 0 47 3 -+ 0 0 0 2 &intc 0 48 3 -+ 0 0 0 3 &intc 0 49 3 -+ 0 0 0 4 &intc 0 50 3>; -+ clocks = <&sw_pcie0>; -+ clock-names = "sw_pcie"; -+ msi-parent = <&pcie0>; /* use PCIe's internal MSI controller */ -+ msi-controller; /* use PCIe's internal MSI controller */ -+ brcm,ssc; -+ max-link-speed = <1>; -+ linux,pci-domain = <0>; -+ }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0205-vchiq-Add-36-bit-address-support.patch b/target/linux/bcm27xx/patches-5.4/950-0205-vchiq-Add-36-bit-address-support.patch new file mode 100644 index 0000000000..ca2a40488a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0205-vchiq-Add-36-bit-address-support.patch @@ -0,0 +1,196 @@ +From 2cba27bce0470a06237b3bd7883d43ade0d5c39c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 1 Nov 2018 17:31:37 +0000 +Subject: [PATCH] vchiq: Add 36-bit address support + +Conditional on a new compatible string, change the pagelist encoding +such that the top 24 bits are the pfn, leaving 8 bits for run length +(-1). + +Signed-off-by: Phil Elwell +--- + .../interface/vchiq_arm/vchiq_2835_arm.c | 90 ++++++++++++++----- + .../interface/vchiq_arm/vchiq_arm.c | 6 ++ + .../interface/vchiq_arm/vchiq_arm.h | 1 + + 3 files changed, 75 insertions(+), 22 deletions(-) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +@@ -16,6 +16,8 @@ + #include + + #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32) ++#define VC_SAFE(x) (g_use_36bit_addrs ? ((u32)(x) | 0xc0000000) : (u32)(x)) ++#define IS_VC_SAFE(x) (g_use_36bit_addrs ? !((x) & ~0x3fffffffull) : 1) + + #include "vchiq_arm.h" + #include "vchiq_connected.h" +@@ -63,6 +65,7 @@ static void __iomem *g_regs; + */ + static unsigned int g_cache_line_size = 32; + static struct dma_pool *g_dma_pool; ++static unsigned int g_use_36bit_addrs = 0; + static unsigned int g_fragments_size; + static char *g_fragments_base; + static char *g_free_fragments; +@@ -106,6 +109,8 @@ int vchiq_platform_init(struct platform_ + g_cache_line_size = drvdata->cache_line_size; + g_fragments_size = 2 * g_cache_line_size; + ++ g_use_36bit_addrs = (dev->dma_pfn_offset == 0); ++ + /* Allocate space for the channels in coherent memory */ + slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); + frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS); +@@ -117,14 +122,21 @@ int vchiq_platform_init(struct platform_ + return -ENOMEM; + } + ++ if (!IS_VC_SAFE(slot_phys)) { ++ dev_err(dev, "allocated DMA memory %pad is not VC-safe\n", ++ &slot_phys); ++ return -ENOMEM; ++ } ++ + WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0); ++ channelbase = VC_SAFE(slot_phys); + + vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size); + if (!vchiq_slot_zero) + return -EINVAL; + + vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] = +- (int)slot_phys + slot_mem_size; ++ channelbase + slot_mem_size; + vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] = + MAX_FRAGMENTS; + +@@ -158,7 +170,6 @@ int vchiq_platform_init(struct platform_ + } + + /* Send the base address of the slots to VideoCore */ +- channelbase = slot_phys; + err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT, + &channelbase, sizeof(channelbase)); + if (err || channelbase) { +@@ -244,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul + if (!pagelistinfo) + return VCHIQ_ERROR; + +- bulk->data = (void *)(unsigned long)pagelistinfo->dma_addr; ++ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr); + + /* + * Store the pagelistinfo address in remote_data, +@@ -522,25 +533,60 @@ create_pagelist(char __user *buf, size_t + + /* Combine adjacent blocks for performance */ + k = 0; +- for_each_sg(scatterlist, sg, dma_buffers, i) { +- u32 len = sg_dma_len(sg); +- u32 addr = sg_dma_address(sg); +- +- /* Note: addrs is the address + page_count - 1 +- * The firmware expects blocks after the first to be page- +- * aligned and a multiple of the page size +- */ +- WARN_ON(len == 0); +- WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); +- WARN_ON(i && (addr & ~PAGE_MASK)); +- if (k > 0 && +- ((addrs[k - 1] & PAGE_MASK) + +- (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT)) +- == (addr & PAGE_MASK)) +- addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT); +- else +- addrs[k++] = (addr & PAGE_MASK) | +- (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1); ++ if (g_use_36bit_addrs) { ++ for_each_sg(scatterlist, sg, dma_buffers, i) { ++ u32 len = sg_dma_len(sg); ++ u64 addr = sg_dma_address(sg); ++ u32 page_id = (u32)((addr >> 4) & ~0xff); ++ u32 sg_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ ++ /* Note: addrs is the address + page_count - 1 ++ * The firmware expects blocks after the first to be page- ++ * aligned and a multiple of the page size ++ */ ++ WARN_ON(len == 0); ++ WARN_ON(i && ++ (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); ++ WARN_ON(i && (addr & ~PAGE_MASK)); ++ WARN_ON(upper_32_bits(addr) > 0xf); ++ if (k > 0 && ++ ((addrs[k - 1] & ~0xff) + ++ (((addrs[k - 1] & 0xff) + 1) << 8) ++ == page_id)) { ++ u32 inc_pages = min(sg_pages, ++ 0xff - (addrs[k - 1] & 0xff)); ++ addrs[k - 1] += inc_pages; ++ page_id += inc_pages << 8; ++ sg_pages -= inc_pages; ++ } ++ while (sg_pages) { ++ u32 inc_pages = min(sg_pages, 0x100u); ++ addrs[k++] = page_id | (inc_pages - 1); ++ page_id += inc_pages << 8; ++ sg_pages -= inc_pages; ++ } ++ } ++ } else { ++ for_each_sg(scatterlist, sg, dma_buffers, i) { ++ u32 len = sg_dma_len(sg); ++ u32 addr = VC_SAFE(sg_dma_address(sg)); ++ u32 new_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ ++ /* Note: addrs is the address + page_count - 1 ++ * The firmware expects blocks after the first to be page- ++ * aligned and a multiple of the page size ++ */ ++ WARN_ON(len == 0); ++ WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); ++ WARN_ON(i && (addr & ~PAGE_MASK)); ++ if (k > 0 && ++ ((addrs[k - 1] & PAGE_MASK) + ++ (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT)) ++ == (addr & PAGE_MASK)) ++ addrs[k - 1] += new_pages; ++ else ++ addrs[k++] = (addr & PAGE_MASK) | (new_pages - 1); ++ } + } + + /* Partial cache lines (fragments) require special measures */ +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -149,6 +149,11 @@ static struct vchiq_drvdata bcm2836_drvd + .cache_line_size = 64, + }; + ++static struct vchiq_drvdata bcm2838_drvdata = { ++ .cache_line_size = 64, ++ .use_36bit_addrs = true, ++}; ++ + static const char *const ioctl_names[] = { + "CONNECT", + "SHUTDOWN", +@@ -3164,6 +3169,7 @@ void vchiq_platform_conn_state_changed(s + static const struct of_device_id vchiq_of_match[] = { + { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata }, + { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata }, ++ { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata }, + {}, + }; + MODULE_DEVICE_TABLE(of, vchiq_of_match); +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +@@ -97,6 +97,7 @@ struct vchiq_arm_state { + + struct vchiq_drvdata { + const unsigned int cache_line_size; ++ const bool use_36bit_addrs; + struct rpi_firmware *fw; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0206-arm-bcm2835-DMA-can-only-address-1GB.patch b/target/linux/bcm27xx/patches-5.4/950-0206-arm-bcm2835-DMA-can-only-address-1GB.patch deleted file mode 100644 index 86ad707b95..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0206-arm-bcm2835-DMA-can-only-address-1GB.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 67b31f71da2c251860dc6ddeffc5d15f8a74c675 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 29 May 2019 15:47:42 +0100 -Subject: [PATCH] arm: bcm2835: DMA can only address 1GB - -The legacy peripherals can only address the first gigabyte of RAM, so -ensure that DMA allocations are restricted to that region. - -Signed-off-by: Phil Elwell ---- - arch/arm/mach-bcm/board_bcm2835.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/arch/arm/mach-bcm/board_bcm2835.c -+++ b/arch/arm/mach-bcm/board_bcm2835.c -@@ -114,6 +114,9 @@ static const char * const bcm2835_compat - }; - - DT_MACHINE_START(BCM2835, "BCM2835") -+#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) -+ .dma_zone_size = SZ_1G, -+#endif - .map_io = bcm2835_map_io, - .init_machine = bcm2835_init, - .dt_compat = bcm2835_compat, diff --git a/target/linux/bcm27xx/patches-5.4/950-0206-bcm2835-pcm.c-Support-multichannel-audio.patch b/target/linux/bcm27xx/patches-5.4/950-0206-bcm2835-pcm.c-Support-multichannel-audio.patch new file mode 100644 index 0000000000..133d346afb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0206-bcm2835-pcm.c-Support-multichannel-audio.patch @@ -0,0 +1,46 @@ +From c76427651677c03c9611b20b914ab2a2ea173522 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 30 Apr 2019 19:15:30 +0100 +Subject: [PATCH] bcm2835-pcm.c: Support multichannel audio + +--- + .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c ++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c +@@ -14,9 +14,9 @@ static const struct snd_pcm_hardware snd + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_APPLPTR), + .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, +- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, +- .rate_max = 48000, ++ .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 128 * 1024, +@@ -31,15 +31,16 @@ static const struct snd_pcm_hardware snd + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_APPLPTR), + .formats = SNDRV_PCM_FMTBIT_S16_LE, +- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 | +- SNDRV_PCM_RATE_48000, ++ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .rate_min = 44100, +- .rate_max = 48000, ++ .rate_max = 192000, + .channels_min = 2, +- .channels_max = 2, +- .buffer_bytes_max = 128 * 1024, ++ .channels_max = 8, ++ .buffer_bytes_max = 512 * 1024, + .period_bytes_min = 1 * 1024, +- .period_bytes_max = 128 * 1024, ++ .period_bytes_max = 512 * 1024, + .periods_min = 1, + .periods_max = 128, + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0207-bcmgenet-constrain-max-DMA-burst-length.patch b/target/linux/bcm27xx/patches-5.4/950-0207-bcmgenet-constrain-max-DMA-burst-length.patch new file mode 100644 index 0000000000..5f683b506b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0207-bcmgenet-constrain-max-DMA-burst-length.patch @@ -0,0 +1,20 @@ +From f4d211891064eef8b133838c213485a228ad75f3 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 12 Sep 2018 14:44:53 +0100 +Subject: [PATCH] bcmgenet: constrain max DMA burst length + +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h +@@ -29,7 +29,7 @@ + #define ENET_PAD 8 + #define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \ + ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD) +-#define DMA_MAX_BURST_LENGTH 0x10 ++#define DMA_MAX_BURST_LENGTH 0x08 + + /* misc. configuration */ + #define CLEAR_ALL_HFB 0xFF diff --git a/target/linux/bcm27xx/patches-5.4/950-0207-hwrng-iproc-rng200-Add-BCM2838-support.patch b/target/linux/bcm27xx/patches-5.4/950-0207-hwrng-iproc-rng200-Add-BCM2838-support.patch deleted file mode 100644 index c9eac88066..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0207-hwrng-iproc-rng200-Add-BCM2838-support.patch +++ /dev/null @@ -1,158 +0,0 @@ -From cbf5cde9c460eae458829a7b357cea6734c4755b Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Sat, 4 May 2019 17:06:15 +0200 -Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support - -The HWRNG on the BCM2838 is compatible to iproc-rng200, so add the -support to this driver instead of bcm2835-rng. - -Signed-off-by: Stefan Wahren ---- - drivers/char/hw_random/Kconfig | 4 +- - drivers/char/hw_random/iproc-rng200.c | 81 +++++++++++++++++++++++++-- - 2 files changed, 79 insertions(+), 6 deletions(-) - ---- a/drivers/char/hw_random/Kconfig -+++ b/drivers/char/hw_random/Kconfig -@@ -90,11 +90,11 @@ config HW_RANDOM_BCM2835 - - config HW_RANDOM_IPROC_RNG200 - tristate "Broadcom iProc/STB RNG200 support" -- depends on ARCH_BCM_IPROC || ARCH_BRCMSTB -+ depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the RNG200 -- hardware found on the Broadcom iProc and STB SoCs. -+ hardware found on the Broadcom iProc, BCM2838 and STB SoCs. - - To compile this driver as a module, choose M here: the - module will be called iproc-rng200 ---- a/drivers/char/hw_random/iproc-rng200.c -+++ b/drivers/char/hw_random/iproc-rng200.c -@@ -29,6 +29,7 @@ - #define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF - #define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001 - #define RNG_CTRL_RNG_RBGEN_DISABLE 0x00000000 -+#define RNG_CTRL_RNG_DIV_CTRL_SHIFT 13 - - #define RNG_SOFT_RESET_OFFSET 0x04 - #define RNG_SOFT_RESET 0x00000001 -@@ -36,16 +37,23 @@ - #define RBG_SOFT_RESET_OFFSET 0x08 - #define RBG_SOFT_RESET 0x00000001 - -+#define RNG_TOTAL_BIT_COUNT_OFFSET 0x0C -+ -+#define RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET 0x10 -+ - #define RNG_INT_STATUS_OFFSET 0x18 - #define RNG_INT_STATUS_MASTER_FAIL_LOCKOUT_IRQ_MASK 0x80000000 - #define RNG_INT_STATUS_STARTUP_TRANSITIONS_MET_IRQ_MASK 0x00020000 - #define RNG_INT_STATUS_NIST_FAIL_IRQ_MASK 0x00000020 - #define RNG_INT_STATUS_TOTAL_BITS_COUNT_IRQ_MASK 0x00000001 - -+#define RNG_INT_ENABLE_OFFSET 0x1C -+ - #define RNG_FIFO_DATA_OFFSET 0x20 - - #define RNG_FIFO_COUNT_OFFSET 0x24 - #define RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK 0x000000FF -+#define RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT 8 - - struct iproc_rng200_dev { - struct hwrng rng; -@@ -166,6 +174,64 @@ static int iproc_rng200_init(struct hwrn - return 0; - } - -+static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max, -+ bool wait) -+{ -+ struct iproc_rng200_dev *priv = to_rng_priv(rng); -+ u32 max_words = max / sizeof(u32); -+ u32 num_words, count, val; -+ -+ /* ensure warm up period has elapsed */ -+ while (1) { -+ val = ioread32(priv->base + RNG_TOTAL_BIT_COUNT_OFFSET); -+ if (val > 16) -+ break; -+ cpu_relax(); -+ } -+ -+ /* ensure fifo is not empty */ -+ while (1) { -+ num_words = ioread32(priv->base + RNG_FIFO_COUNT_OFFSET) & -+ RNG_FIFO_COUNT_RNG_FIFO_COUNT_MASK; -+ if (num_words) -+ break; -+ if (!wait) -+ return 0; -+ cpu_relax(); -+ } -+ -+ if (num_words > max_words) -+ num_words = max_words; -+ -+ for (count = 0; count < num_words; count++) { -+ ((u32 *)buf)[count] = ioread32(priv->base + -+ RNG_FIFO_DATA_OFFSET); -+ } -+ -+ return num_words * sizeof(u32); -+} -+ -+static int bcm2838_rng200_init(struct hwrng *rng) -+{ -+ struct iproc_rng200_dev *priv = to_rng_priv(rng); -+ uint32_t val; -+ -+ if (ioread32(priv->base + RNG_CTRL_OFFSET) & RNG_CTRL_RNG_RBGEN_MASK) -+ return 0; -+ -+ /* initial numbers generated are "less random" so will be discarded */ -+ val = 0x40000; -+ iowrite32(val, priv->base + RNG_TOTAL_BIT_COUNT_THRESHOLD_OFFSET); -+ /* min fifo count to generate full interrupt */ -+ val = 2 << RNG_FIFO_COUNT_RNG_FIFO_THRESHOLD_SHIFT; -+ iowrite32(val, priv->base + RNG_FIFO_COUNT_OFFSET); -+ /* enable the rng - 1Mhz sample rate */ -+ val = (0x3 << RNG_CTRL_RNG_DIV_CTRL_SHIFT) | RNG_CTRL_RNG_RBGEN_MASK; -+ iowrite32(val, priv->base + RNG_CTRL_OFFSET); -+ -+ return 0; -+} -+ - static void iproc_rng200_cleanup(struct hwrng *rng) - { - struct iproc_rng200_dev *priv = to_rng_priv(rng); -@@ -202,10 +268,16 @@ static int iproc_rng200_probe(struct pla - return PTR_ERR(priv->base); - } - -- priv->rng.name = "iproc-rng200", -- priv->rng.read = iproc_rng200_read, -- priv->rng.init = iproc_rng200_init, -- priv->rng.cleanup = iproc_rng200_cleanup, -+ priv->rng.name = pdev->name; -+ priv->rng.cleanup = iproc_rng200_cleanup; -+ -+ if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) { -+ priv->rng.init = bcm2838_rng200_init; -+ priv->rng.read = bcm2838_rng200_read; -+ } else { -+ priv->rng.init = iproc_rng200_init; -+ priv->rng.read = iproc_rng200_read; -+ } - - /* Register driver */ - ret = devm_hwrng_register(dev, &priv->rng); -@@ -223,6 +295,7 @@ static const struct of_device_id iproc_r - { .compatible = "brcm,bcm7211-rng200", }, - { .compatible = "brcm,bcm7278-rng200", }, - { .compatible = "brcm,iproc-rng200", }, -+ { .compatible = "brcm,bcm2838-rng200"}, - {}, - }; - MODULE_DEVICE_TABLE(of, iproc_rng200_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0208-bcmgenet-Better-coalescing-parameter-defaults.patch b/target/linux/bcm27xx/patches-5.4/950-0208-bcmgenet-Better-coalescing-parameter-defaults.patch new file mode 100644 index 0000000000..3a38f64436 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0208-bcmgenet-Better-coalescing-parameter-defaults.patch @@ -0,0 +1,43 @@ +From b3344ca9ef887c4004c61be39f7d8d058a569d4d Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 27 Mar 2019 13:45:46 +0000 +Subject: [PATCH] bcmgenet: Better coalescing parameter defaults + +Set defaults for TX and RX packet coalescing to be equivalent to: + + # ethtool -C eth0 tx-frames 10 + # ethtool -C eth0 rx-usecs 50 + +This may be something we want to set via DT parameters in the +future. + +Signed-off-by: Phil Elwell +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -2149,7 +2149,7 @@ static void bcmgenet_init_tx_ring(struct + + bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); + bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX); +- bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH); ++ bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH); + /* Disable rate control for now */ + bcmgenet_tdma_ring_writel(priv, index, flow_period_val, + TDMA_FLOW_PERIOD); +@@ -3573,9 +3573,12 @@ static int bcmgenet_probe(struct platfor + netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); + + /* Set default coalescing parameters */ +- for (i = 0; i < priv->hw_params->rx_queues; i++) ++ for (i = 0; i < priv->hw_params->rx_queues; i++) { + priv->rx_rings[i].rx_max_coalesced_frames = 1; ++ priv->rx_rings[i].rx_coalesce_usecs = 50; ++ } + priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1; ++ priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50; + + /* libphy will determine the link state */ + netif_carrier_off(dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0208-vchiq-Add-36-bit-address-support.patch b/target/linux/bcm27xx/patches-5.4/950-0208-vchiq-Add-36-bit-address-support.patch deleted file mode 100644 index ca2a40488a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0208-vchiq-Add-36-bit-address-support.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 2cba27bce0470a06237b3bd7883d43ade0d5c39c Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 1 Nov 2018 17:31:37 +0000 -Subject: [PATCH] vchiq: Add 36-bit address support - -Conditional on a new compatible string, change the pagelist encoding -such that the top 24 bits are the pfn, leaving 8 bits for run length -(-1). - -Signed-off-by: Phil Elwell ---- - .../interface/vchiq_arm/vchiq_2835_arm.c | 90 ++++++++++++++----- - .../interface/vchiq_arm/vchiq_arm.c | 6 ++ - .../interface/vchiq_arm/vchiq_arm.h | 1 + - 3 files changed, 75 insertions(+), 22 deletions(-) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -@@ -16,6 +16,8 @@ - #include - - #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32) -+#define VC_SAFE(x) (g_use_36bit_addrs ? ((u32)(x) | 0xc0000000) : (u32)(x)) -+#define IS_VC_SAFE(x) (g_use_36bit_addrs ? !((x) & ~0x3fffffffull) : 1) - - #include "vchiq_arm.h" - #include "vchiq_connected.h" -@@ -63,6 +65,7 @@ static void __iomem *g_regs; - */ - static unsigned int g_cache_line_size = 32; - static struct dma_pool *g_dma_pool; -+static unsigned int g_use_36bit_addrs = 0; - static unsigned int g_fragments_size; - static char *g_fragments_base; - static char *g_free_fragments; -@@ -106,6 +109,8 @@ int vchiq_platform_init(struct platform_ - g_cache_line_size = drvdata->cache_line_size; - g_fragments_size = 2 * g_cache_line_size; - -+ g_use_36bit_addrs = (dev->dma_pfn_offset == 0); -+ - /* Allocate space for the channels in coherent memory */ - slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); - frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS); -@@ -117,14 +122,21 @@ int vchiq_platform_init(struct platform_ - return -ENOMEM; - } - -+ if (!IS_VC_SAFE(slot_phys)) { -+ dev_err(dev, "allocated DMA memory %pad is not VC-safe\n", -+ &slot_phys); -+ return -ENOMEM; -+ } -+ - WARN_ON(((unsigned long)slot_mem & (PAGE_SIZE - 1)) != 0); -+ channelbase = VC_SAFE(slot_phys); - - vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size); - if (!vchiq_slot_zero) - return -EINVAL; - - vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] = -- (int)slot_phys + slot_mem_size; -+ channelbase + slot_mem_size; - vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] = - MAX_FRAGMENTS; - -@@ -158,7 +170,6 @@ int vchiq_platform_init(struct platform_ - } - - /* Send the base address of the slots to VideoCore */ -- channelbase = slot_phys; - err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT, - &channelbase, sizeof(channelbase)); - if (err || channelbase) { -@@ -244,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul - if (!pagelistinfo) - return VCHIQ_ERROR; - -- bulk->data = (void *)(unsigned long)pagelistinfo->dma_addr; -+ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr); - - /* - * Store the pagelistinfo address in remote_data, -@@ -522,25 +533,60 @@ create_pagelist(char __user *buf, size_t - - /* Combine adjacent blocks for performance */ - k = 0; -- for_each_sg(scatterlist, sg, dma_buffers, i) { -- u32 len = sg_dma_len(sg); -- u32 addr = sg_dma_address(sg); -- -- /* Note: addrs is the address + page_count - 1 -- * The firmware expects blocks after the first to be page- -- * aligned and a multiple of the page size -- */ -- WARN_ON(len == 0); -- WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); -- WARN_ON(i && (addr & ~PAGE_MASK)); -- if (k > 0 && -- ((addrs[k - 1] & PAGE_MASK) + -- (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT)) -- == (addr & PAGE_MASK)) -- addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT); -- else -- addrs[k++] = (addr & PAGE_MASK) | -- (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1); -+ if (g_use_36bit_addrs) { -+ for_each_sg(scatterlist, sg, dma_buffers, i) { -+ u32 len = sg_dma_len(sg); -+ u64 addr = sg_dma_address(sg); -+ u32 page_id = (u32)((addr >> 4) & ~0xff); -+ u32 sg_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; -+ -+ /* Note: addrs is the address + page_count - 1 -+ * The firmware expects blocks after the first to be page- -+ * aligned and a multiple of the page size -+ */ -+ WARN_ON(len == 0); -+ WARN_ON(i && -+ (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); -+ WARN_ON(i && (addr & ~PAGE_MASK)); -+ WARN_ON(upper_32_bits(addr) > 0xf); -+ if (k > 0 && -+ ((addrs[k - 1] & ~0xff) + -+ (((addrs[k - 1] & 0xff) + 1) << 8) -+ == page_id)) { -+ u32 inc_pages = min(sg_pages, -+ 0xff - (addrs[k - 1] & 0xff)); -+ addrs[k - 1] += inc_pages; -+ page_id += inc_pages << 8; -+ sg_pages -= inc_pages; -+ } -+ while (sg_pages) { -+ u32 inc_pages = min(sg_pages, 0x100u); -+ addrs[k++] = page_id | (inc_pages - 1); -+ page_id += inc_pages << 8; -+ sg_pages -= inc_pages; -+ } -+ } -+ } else { -+ for_each_sg(scatterlist, sg, dma_buffers, i) { -+ u32 len = sg_dma_len(sg); -+ u32 addr = VC_SAFE(sg_dma_address(sg)); -+ u32 new_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; -+ -+ /* Note: addrs is the address + page_count - 1 -+ * The firmware expects blocks after the first to be page- -+ * aligned and a multiple of the page size -+ */ -+ WARN_ON(len == 0); -+ WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); -+ WARN_ON(i && (addr & ~PAGE_MASK)); -+ if (k > 0 && -+ ((addrs[k - 1] & PAGE_MASK) + -+ (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT)) -+ == (addr & PAGE_MASK)) -+ addrs[k - 1] += new_pages; -+ else -+ addrs[k++] = (addr & PAGE_MASK) | (new_pages - 1); -+ } - } - - /* Partial cache lines (fragments) require special measures */ ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -149,6 +149,11 @@ static struct vchiq_drvdata bcm2836_drvd - .cache_line_size = 64, - }; - -+static struct vchiq_drvdata bcm2838_drvdata = { -+ .cache_line_size = 64, -+ .use_36bit_addrs = true, -+}; -+ - static const char *const ioctl_names[] = { - "CONNECT", - "SHUTDOWN", -@@ -3164,6 +3169,7 @@ void vchiq_platform_conn_state_changed(s - static const struct of_device_id vchiq_of_match[] = { - { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata }, - { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata }, -+ { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata }, - {}, - }; - MODULE_DEVICE_TABLE(of, vchiq_of_match); ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h -@@ -97,6 +97,7 @@ struct vchiq_arm_state { - - struct vchiq_drvdata { - const unsigned int cache_line_size; -+ const bool use_36bit_addrs; - struct rpi_firmware *fw; - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0209-bcm2835-pcm.c-Support-multichannel-audio.patch b/target/linux/bcm27xx/patches-5.4/950-0209-bcm2835-pcm.c-Support-multichannel-audio.patch deleted file mode 100644 index 133d346afb..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0209-bcm2835-pcm.c-Support-multichannel-audio.patch +++ /dev/null @@ -1,46 +0,0 @@ -From c76427651677c03c9611b20b914ab2a2ea173522 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 30 Apr 2019 19:15:30 +0100 -Subject: [PATCH] bcm2835-pcm.c: Support multichannel audio - ---- - .../vc04_services/bcm2835-audio/bcm2835-pcm.c | 17 +++++++++-------- - 1 file changed, 9 insertions(+), 8 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c -+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c -@@ -14,9 +14,9 @@ static const struct snd_pcm_hardware snd - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_APPLPTR), - .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, -- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, -+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, - .rate_min = 8000, -- .rate_max = 48000, -+ .rate_max = 192000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = 128 * 1024, -@@ -31,15 +31,16 @@ static const struct snd_pcm_hardware snd - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_APPLPTR), - .formats = SNDRV_PCM_FMTBIT_S16_LE, -- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 | -- SNDRV_PCM_RATE_48000, -+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | -+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | -+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .rate_min = 44100, -- .rate_max = 48000, -+ .rate_max = 192000, - .channels_min = 2, -- .channels_max = 2, -- .buffer_bytes_max = 128 * 1024, -+ .channels_max = 8, -+ .buffer_bytes_max = 512 * 1024, - .period_bytes_min = 1 * 1024, -- .period_bytes_max = 128 * 1024, -+ .period_bytes_max = 512 * 1024, - .periods_min = 1, - .periods_max = 128, - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0209-net-genet-enable-link-energy-detect-powerdown-for-ex.patch b/target/linux/bcm27xx/patches-5.4/950-0209-net-genet-enable-link-energy-detect-powerdown-for-ex.patch new file mode 100644 index 0000000000..ab43dfdfe5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0209-net-genet-enable-link-energy-detect-powerdown-for-ex.patch @@ -0,0 +1,31 @@ +From cbe8b55622fc2f0a959da599447c87cf1f967a91 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 14 May 2019 17:17:59 +0100 +Subject: [PATCH] net: genet: enable link energy detect powerdown for + external PHYs + +There are several warts surrounding bcmgenet_mii_probe() as this +function is called from ndo_open, but it's calling registration-type +functions. The probe should be called at probe time and refactored +such that the PHY device data can be extracted to limit the scope +of this flag to Broadcom PHYs. + +For now, pass this flag in as it puts our attached PHY into a low-power +state when disconnected. + +Signed-off-by: Jonathan Bell +--- + drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c +@@ -316,6 +316,8 @@ int bcmgenet_mii_probe(struct net_device + /* Communicate the integrated PHY revision */ + if (priv->internal_phy) + phy_flags = priv->gphy_rev; ++ else ++ phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE; + + /* Initialize link state variables that bcmgenet_mii_setup() uses */ + priv->old_link = -1; diff --git a/target/linux/bcm27xx/patches-5.4/950-0210-bcmgenet-constrain-max-DMA-burst-length.patch b/target/linux/bcm27xx/patches-5.4/950-0210-bcmgenet-constrain-max-DMA-burst-length.patch deleted file mode 100644 index 5f683b506b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0210-bcmgenet-constrain-max-DMA-burst-length.patch +++ /dev/null @@ -1,20 +0,0 @@ -From f4d211891064eef8b133838c213485a228ad75f3 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Wed, 12 Sep 2018 14:44:53 +0100 -Subject: [PATCH] bcmgenet: constrain max DMA burst length - ---- - drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h -+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h -@@ -29,7 +29,7 @@ - #define ENET_PAD 8 - #define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \ - ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD) --#define DMA_MAX_BURST_LENGTH 0x10 -+#define DMA_MAX_BURST_LENGTH 0x08 - - /* misc. configuration */ - #define CLEAR_ALL_HFB 0xFF diff --git a/target/linux/bcm27xx/patches-5.4/950-0210-usb-xhci-Disable-the-XHCI-5-second-timeout.patch b/target/linux/bcm27xx/patches-5.4/950-0210-usb-xhci-Disable-the-XHCI-5-second-timeout.patch new file mode 100644 index 0000000000..2f5e08b7a2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0210-usb-xhci-Disable-the-XHCI-5-second-timeout.patch @@ -0,0 +1,29 @@ +From a71750c83a6f1f2f7c22864bbb4e62af5e70c214 Mon Sep 17 00:00:00 2001 +From: Tim Gover +Date: Fri, 22 Mar 2019 09:47:14 +0000 +Subject: [PATCH] usb: xhci: Disable the XHCI 5 second timeout + +If the VL805 EEPROM has not been programmed then boot will hang for five +seconds. The timeout seems to be arbitrary and is an unecessary +delay on the first boot. Remove the timeout. + +This is common code and probably can't be upstreamed unless the timeout +can be configurable somehow or perhaps the XHCI driver can be skipped +on the first boot. +--- + drivers/usb/host/xhci.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -196,8 +196,9 @@ int xhci_reset(struct xhci_hcd *xhci) + if (xhci->quirks & XHCI_INTEL_HOST) + udelay(1000); + ++ // Hack: reduce handshake timeout from 10s 0.5s due to unprogrammed vl805 + ret = xhci_handshake(&xhci->op_regs->command, +- CMD_RESET, 0, 10 * 1000 * 1000); ++ CMD_RESET, 0, 500 * 1000); + if (ret) + return ret; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0211-bcmgenet-Better-coalescing-parameter-defaults.patch b/target/linux/bcm27xx/patches-5.4/950-0211-bcmgenet-Better-coalescing-parameter-defaults.patch deleted file mode 100644 index 3a38f64436..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0211-bcmgenet-Better-coalescing-parameter-defaults.patch +++ /dev/null @@ -1,43 +0,0 @@ -From b3344ca9ef887c4004c61be39f7d8d058a569d4d Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 27 Mar 2019 13:45:46 +0000 -Subject: [PATCH] bcmgenet: Better coalescing parameter defaults - -Set defaults for TX and RX packet coalescing to be equivalent to: - - # ethtool -C eth0 tx-frames 10 - # ethtool -C eth0 rx-usecs 50 - -This may be something we want to set via DT parameters in the -future. - -Signed-off-by: Phil Elwell ---- - drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c -+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c -@@ -2149,7 +2149,7 @@ static void bcmgenet_init_tx_ring(struct - - bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); - bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX); -- bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH); -+ bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH); - /* Disable rate control for now */ - bcmgenet_tdma_ring_writel(priv, index, flow_period_val, - TDMA_FLOW_PERIOD); -@@ -3573,9 +3573,12 @@ static int bcmgenet_probe(struct platfor - netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); - - /* Set default coalescing parameters */ -- for (i = 0; i < priv->hw_params->rx_queues; i++) -+ for (i = 0; i < priv->hw_params->rx_queues; i++) { - priv->rx_rings[i].rx_max_coalesced_frames = 1; -+ priv->rx_rings[i].rx_coalesce_usecs = 50; -+ } - priv->rx_rings[DESC_INDEX].rx_max_coalesced_frames = 1; -+ priv->rx_rings[DESC_INDEX].rx_coalesce_usecs = 50; - - /* libphy will determine the link state */ - netif_carrier_off(dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0211-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch b/target/linux/bcm27xx/patches-5.4/950-0211-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch new file mode 100644 index 0000000000..b2a8279da2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0211-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch @@ -0,0 +1,23 @@ +From 605cd2341a6be51fd91da8d985a4698db7d9a623 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 23 May 2019 15:08:30 +0100 +Subject: [PATCH] usb: xhci: Show that the VIA VL805 supports LPM + +Signed-off-by: Phil Elwell +--- + drivers/usb/host/xhci-pci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -254,6 +254,10 @@ static void xhci_pci_quirks(struct devic + pdev->device == 0x3432) + xhci->quirks |= XHCI_BROKEN_STREAMS; + ++ if (pdev->vendor == PCI_VENDOR_ID_VIA && ++ pdev->device == 0x3483) ++ xhci->quirks |= XHCI_LPM_SUPPORT; ++ + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && + pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) + xhci->quirks |= XHCI_BROKEN_STREAMS; diff --git a/target/linux/bcm27xx/patches-5.4/950-0212-net-genet-enable-link-energy-detect-powerdown-for-ex.patch b/target/linux/bcm27xx/patches-5.4/950-0212-net-genet-enable-link-energy-detect-powerdown-for-ex.patch deleted file mode 100644 index ab43dfdfe5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0212-net-genet-enable-link-energy-detect-powerdown-for-ex.patch +++ /dev/null @@ -1,31 +0,0 @@ -From cbe8b55622fc2f0a959da599447c87cf1f967a91 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 14 May 2019 17:17:59 +0100 -Subject: [PATCH] net: genet: enable link energy detect powerdown for - external PHYs - -There are several warts surrounding bcmgenet_mii_probe() as this -function is called from ndo_open, but it's calling registration-type -functions. The probe should be called at probe time and refactored -such that the PHY device data can be extracted to limit the scope -of this flag to Broadcom PHYs. - -For now, pass this flag in as it puts our attached PHY into a low-power -state when disconnected. - -Signed-off-by: Jonathan Bell ---- - drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/net/ethernet/broadcom/genet/bcmmii.c -+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c -@@ -316,6 +316,8 @@ int bcmgenet_mii_probe(struct net_device - /* Communicate the integrated PHY revision */ - if (priv->internal_phy) - phy_flags = priv->gphy_rev; -+ else -+ phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE; - - /* Initialize link state variables that bcmgenet_mii_setup() uses */ - priv->old_link = -1; diff --git a/target/linux/bcm27xx/patches-5.4/950-0212-spi-bcm2835-enable-shared-interrupt-support.patch b/target/linux/bcm27xx/patches-5.4/950-0212-spi-bcm2835-enable-shared-interrupt-support.patch new file mode 100644 index 0000000000..f82ae7d9f6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0212-spi-bcm2835-enable-shared-interrupt-support.patch @@ -0,0 +1,35 @@ +From ac94635b678715af00a685ada0a1b60dfb54c771 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 13 May 2019 11:05:27 +0000 +Subject: [PATCH] spi: bcm2835: enable shared interrupt support + +Add shared interrupt support for this driver. + +Signed-off-by: Martin Sperl +--- + drivers/spi/spi-bcm2835.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -379,6 +379,10 @@ static irqreturn_t bcm2835_spi_interrupt + if (bs->tx_len && cs & BCM2835_SPI_CS_DONE) + bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); + ++ /* check if we got interrupt enabled */ ++ if (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_INTR)) ++ return IRQ_NONE; ++ + /* Read as many bytes as possible from FIFO */ + bcm2835_rd_fifo(bs); + /* Write as many bytes as possible to FIFO */ +@@ -1281,7 +1285,8 @@ static int bcm2835_spi_probe(struct plat + bcm2835_wr(bs, BCM2835_SPI_CS, + BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); + +- err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, ++ err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, ++ IRQF_SHARED, + dev_name(&pdev->dev), ctlr); + if (err) { + dev_err(&pdev->dev, "could not request IRQ: %d\n", err); diff --git a/target/linux/bcm27xx/patches-5.4/950-0213-clk-bcm2835-Don-t-wait-for-pllh-lock.patch b/target/linux/bcm27xx/patches-5.4/950-0213-clk-bcm2835-Don-t-wait-for-pllh-lock.patch new file mode 100644 index 0000000000..77625e8e23 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0213-clk-bcm2835-Don-t-wait-for-pllh-lock.patch @@ -0,0 +1,38 @@ +From 35d84e9f2944b72ccfc508dc5c540c526ab351c1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 23 Jan 2019 16:11:50 +0000 +Subject: [PATCH] clk-bcm2835: Don't wait for pllh lock + +Signed-off-by: Phil Elwell +--- + drivers/clk/bcm/clk-bcm2835.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -643,15 +643,17 @@ static int bcm2835_pll_on(struct clk_hw + spin_unlock(&cprman->regs_lock); + + /* Wait for the PLL to lock. */ +- timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); +- while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { +- if (ktime_after(ktime_get(), timeout)) { +- dev_err(cprman->dev, "%s: couldn't lock PLL\n", +- clk_hw_get_name(hw)); +- return -ETIMEDOUT; +- } ++ if (strcmp(data->name, "pllh")) { ++ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); ++ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ dev_err(cprman->dev, "%s: couldn't lock PLL\n", ++ clk_hw_get_name(hw)); ++ return -ETIMEDOUT; ++ } + +- cpu_relax(); ++ cpu_relax(); ++ } + } + + cprman_write(cprman, data->a2w_ctrl_reg, diff --git a/target/linux/bcm27xx/patches-5.4/950-0213-usb-xhci-Disable-the-XHCI-5-second-timeout.patch b/target/linux/bcm27xx/patches-5.4/950-0213-usb-xhci-Disable-the-XHCI-5-second-timeout.patch deleted file mode 100644 index 2f5e08b7a2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0213-usb-xhci-Disable-the-XHCI-5-second-timeout.patch +++ /dev/null @@ -1,29 +0,0 @@ -From a71750c83a6f1f2f7c22864bbb4e62af5e70c214 Mon Sep 17 00:00:00 2001 -From: Tim Gover -Date: Fri, 22 Mar 2019 09:47:14 +0000 -Subject: [PATCH] usb: xhci: Disable the XHCI 5 second timeout - -If the VL805 EEPROM has not been programmed then boot will hang for five -seconds. The timeout seems to be arbitrary and is an unecessary -delay on the first boot. Remove the timeout. - -This is common code and probably can't be upstreamed unless the timeout -can be configurable somehow or perhaps the XHCI driver can be skipped -on the first boot. ---- - drivers/usb/host/xhci.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/usb/host/xhci.c -+++ b/drivers/usb/host/xhci.c -@@ -196,8 +196,9 @@ int xhci_reset(struct xhci_hcd *xhci) - if (xhci->quirks & XHCI_INTEL_HOST) - udelay(1000); - -+ // Hack: reduce handshake timeout from 10s 0.5s due to unprogrammed vl805 - ret = xhci_handshake(&xhci->op_regs->command, -- CMD_RESET, 0, 10 * 1000 * 1000); -+ CMD_RESET, 0, 500 * 1000); - if (ret) - return ret; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0214-soc-bcm-bcm2835-pm-Add-support-for-2711.patch b/target/linux/bcm27xx/patches-5.4/950-0214-soc-bcm-bcm2835-pm-Add-support-for-2711.patch new file mode 100644 index 0000000000..61bf911f28 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0214-soc-bcm-bcm2835-pm-Add-support-for-2711.patch @@ -0,0 +1,102 @@ +From 0cb69292622e3530a72d3173d78c484c8f4d3eab Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 11 Jan 2019 17:31:07 -0800 +Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for 2711. + +Without the actual power management part any more, there's a lot less +to set up for V3D. We just need to clear the RSTN field for the power +domain, and expose the reset controller for toggling it again. + +This is definitely incomplete -- the old ISP and H264 is in the old +bridge, but since we have no consumers of it I've just done the +minimum to get V3D working. + +Signed-off-by: Eric Anholt +--- + drivers/mfd/bcm2835-pm.c | 11 +++++++++++ + drivers/soc/bcm/bcm2835-power.c | 22 ++++++++++++++++++++++ + include/linux/mfd/bcm2835-pm.h | 1 + + 3 files changed, 34 insertions(+) + +--- a/drivers/mfd/bcm2835-pm.c ++++ b/drivers/mfd/bcm2835-pm.c +@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platf + if (ret) + return ret; + ++ /* Map the ARGON ASB regs if present. */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ if (res) { ++ pm->arg_asb = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pm->arg_asb)) { ++ dev_err(dev, "Failed to map ARGON ASB: %ld\n", ++ PTR_ERR(pm->arg_asb)); ++ return PTR_ERR(pm->arg_asb); ++ } ++ } ++ + /* We'll use the presence of the AXI ASB regs in the + * bcm2835-pm binding as the key for whether we can reference + * the full PM register range and support power domains. +--- a/drivers/soc/bcm/bcm2835-power.c ++++ b/drivers/soc/bcm/bcm2835-power.c +@@ -143,6 +143,8 @@ struct bcm2835_power { + /* AXI Async bridge registers. */ + void __iomem *asb; + ++ bool is_2711; ++ + struct genpd_onecell_data pd_xlate; + struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT]; + struct reset_controller_dev reset; +@@ -192,6 +194,10 @@ static int bcm2835_power_power_off(struc + { + struct bcm2835_power *power = pd->power; + ++ /* 2711 has no power domains above the reset controller. */ ++ if (power->is_2711) ++ return 0; ++ + /* Enable functional isolation */ + PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC); + +@@ -213,6 +219,10 @@ static int bcm2835_power_power_on(struct + int inrush; + bool powok; + ++ /* 2711 has no power domains above the reset controller. */ ++ if (power->is_2711) ++ return 0; ++ + /* If it was already powered on by the fw, leave it that way. */ + if (PM_READ(pm_reg) & PM_POWUP) + return 0; +@@ -627,6 +637,18 @@ static int bcm2835_power_probe(struct pl + power->base = pm->base; + power->asb = pm->asb; + ++ /* 2711 hack: the new ARGON ASB took over V3D, which is our ++ * only consumer of this driver so far. The old ASB seems to ++ * still be present with ISP and H264 bits but no V3D, but I ++ * don't know if that's real or not. The V3D is in the same ++ * place in the new ASB as the old one, so just poke the new ++ * one for now. ++ */ ++ if (pm->arg_asb) { ++ power->asb = pm->arg_asb; ++ power->is_2711 = true; ++ } ++ + id = ASB_READ(ASB_AXI_BRDG_ID); + if (id != 0x62726467 /* "BRDG" */) { + dev_err(dev, "ASB register ID returned 0x%08x\n", id); +--- a/include/linux/mfd/bcm2835-pm.h ++++ b/include/linux/mfd/bcm2835-pm.h +@@ -9,6 +9,7 @@ struct bcm2835_pm { + struct device *dev; + void __iomem *base; + void __iomem *asb; ++ void __iomem *arg_asb; + }; + + #endif /* BCM2835_MFD_PM_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0214-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch b/target/linux/bcm27xx/patches-5.4/950-0214-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch deleted file mode 100644 index b2a8279da2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0214-usb-xhci-Show-that-the-VIA-VL805-supports-LPM.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 605cd2341a6be51fd91da8d985a4698db7d9a623 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 23 May 2019 15:08:30 +0100 -Subject: [PATCH] usb: xhci: Show that the VIA VL805 supports LPM - -Signed-off-by: Phil Elwell ---- - drivers/usb/host/xhci-pci.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/usb/host/xhci-pci.c -+++ b/drivers/usb/host/xhci-pci.c -@@ -254,6 +254,10 @@ static void xhci_pci_quirks(struct devic - pdev->device == 0x3432) - xhci->quirks |= XHCI_BROKEN_STREAMS; - -+ if (pdev->vendor == PCI_VENDOR_ID_VIA && -+ pdev->device == 0x3483) -+ xhci->quirks |= XHCI_LPM_SUPPORT; -+ - if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && - pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) - xhci->quirks |= XHCI_BROKEN_STREAMS; diff --git a/target/linux/bcm27xx/patches-5.4/950-0215-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch b/target/linux/bcm27xx/patches-5.4/950-0215-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch new file mode 100644 index 0000000000..4e3805d9a7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0215-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch @@ -0,0 +1,30 @@ +From 15880303abc8b93cda3c62203fa5303726f53ca6 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 4 Sep 2018 11:50:25 +0100 +Subject: [PATCH] config: Permit LPAE and PCIE_BRCMSTB on BCM2835 + +--- + arch/arm/mach-bcm/Kconfig | 4 ++++ + drivers/pci/controller/Kconfig | 4 ++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- a/arch/arm/mach-bcm/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -161,6 +161,7 @@ config ARCH_BCM2835 + select GPIOLIB + select ARM_AMBA + select ARM_ERRATA_411920 if ARCH_MULTI_V6 ++ select ARM_GIC + select ARM_TIMER_SP804 + select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 + select TIMER_OF +@@ -170,6 +171,9 @@ config ARCH_BCM2835 + select PINCTRL_BCM2835 + select MFD_CORE + select MFD_SYSCON if ARCH_MULTI_V7 ++ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE ++ select ZONE_DMA if ARM_LPAE ++ select MFD_CORE + help + This enables support for the Broadcom BCM2835 and BCM2836 SoCs. + This SoC is used in the Raspberry Pi and Roku 2 devices. diff --git a/target/linux/bcm27xx/patches-5.4/950-0215-spi-bcm2835-enable-shared-interrupt-support.patch b/target/linux/bcm27xx/patches-5.4/950-0215-spi-bcm2835-enable-shared-interrupt-support.patch deleted file mode 100644 index 35a4e71245..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0215-spi-bcm2835-enable-shared-interrupt-support.patch +++ /dev/null @@ -1,35 +0,0 @@ -From ac94635b678715af00a685ada0a1b60dfb54c771 Mon Sep 17 00:00:00 2001 -From: Martin Sperl -Date: Mon, 13 May 2019 11:05:27 +0000 -Subject: [PATCH] spi: bcm2835: enable shared interrupt support - -Add shared interrupt support for this driver. - -Signed-off-by: Martin Sperl ---- - drivers/spi/spi-bcm2835.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - ---- a/drivers/spi/spi-bcm2835.c -+++ b/drivers/spi/spi-bcm2835.c -@@ -379,6 +379,10 @@ static irqreturn_t bcm2835_spi_interrupt - if (bs->tx_len && cs & BCM2835_SPI_CS_DONE) - bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE); - -+ /* check if we got interrupt enabled */ -+ if (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_INTR)) -+ return IRQ_NONE; -+ - /* Read as many bytes as possible from FIFO */ - bcm2835_rd_fifo(bs); - /* Write as many bytes as possible to FIFO */ -@@ -1330,7 +1334,8 @@ static int bcm2835_spi_probe(struct plat - bcm2835_wr(bs, BCM2835_SPI_CS, - BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); - -- err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, -+ err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, -+ IRQF_SHARED, - dev_name(&pdev->dev), ctlr); - if (err) { - dev_err(&pdev->dev, "could not request IRQ: %d\n", err); diff --git a/target/linux/bcm27xx/patches-5.4/950-0216-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch b/target/linux/bcm27xx/patches-5.4/950-0216-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch new file mode 100644 index 0000000000..3227f8c914 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0216-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch @@ -0,0 +1,53 @@ +From cfe0832e8306cd9955f682b7314a5a6fc3b9d514 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 May 2019 15:11:05 -0700 +Subject: [PATCH] clk: bcm2835: Add support for setting leaf clock + rates while running. + +As long as you wait for !BUSY, you can do glitch-free updates of clock +rate while the clock is running. + +Signed-off-by: Eric Anholt +--- + drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1114,15 +1114,19 @@ static int bcm2835_clock_set_rate(struct + + spin_lock(&cprman->regs_lock); + +- /* +- * Setting up frac support +- * +- * In principle it is recommended to stop/start the clock first, +- * but as we set CLK_SET_RATE_GATE during registration of the +- * clock this requirement should be take care of by the +- * clk-framework. ++ ctl = cprman_read(cprman, data->ctl_reg); ++ ++ /* If the clock is running, we have to pause clock generation while ++ * updating the control and div regs. This is glitchless (no clock ++ * signals generated faster than the rate) but each reg access is two ++ * OSC cycles so the clock will slow down for a moment. + */ +- ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC; ++ if (ctl & CM_ENABLE) { ++ cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE); ++ bcm2835_clock_wait_busy(clock); ++ } ++ ++ ctl &= ~CM_FRAC; + ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; + cprman_write(cprman, data->ctl_reg, ctl); + +@@ -1494,7 +1498,7 @@ static struct clk_hw *bcm2835_register_c + init.ops = &bcm2835_vpu_clock_clk_ops; + } else { + init.ops = &bcm2835_clock_clk_ops; +- init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; ++ init.flags |= CLK_SET_PARENT_GATE; + + /* If the clock wasn't actually enabled at boot, it's not + * critical. diff --git a/target/linux/bcm27xx/patches-5.4/950-0216-clk-bcm2835-Don-t-wait-for-pllh-lock.patch b/target/linux/bcm27xx/patches-5.4/950-0216-clk-bcm2835-Don-t-wait-for-pllh-lock.patch deleted file mode 100644 index 77625e8e23..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0216-clk-bcm2835-Don-t-wait-for-pllh-lock.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 35d84e9f2944b72ccfc508dc5c540c526ab351c1 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 23 Jan 2019 16:11:50 +0000 -Subject: [PATCH] clk-bcm2835: Don't wait for pllh lock - -Signed-off-by: Phil Elwell ---- - drivers/clk/bcm/clk-bcm2835.c | 18 ++++++++++-------- - 1 file changed, 10 insertions(+), 8 deletions(-) - ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -643,15 +643,17 @@ static int bcm2835_pll_on(struct clk_hw - spin_unlock(&cprman->regs_lock); - - /* Wait for the PLL to lock. */ -- timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); -- while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { -- if (ktime_after(ktime_get(), timeout)) { -- dev_err(cprman->dev, "%s: couldn't lock PLL\n", -- clk_hw_get_name(hw)); -- return -ETIMEDOUT; -- } -+ if (strcmp(data->name, "pllh")) { -+ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); -+ while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { -+ if (ktime_after(ktime_get(), timeout)) { -+ dev_err(cprman->dev, "%s: couldn't lock PLL\n", -+ clk_hw_get_name(hw)); -+ return -ETIMEDOUT; -+ } - -- cpu_relax(); -+ cpu_relax(); -+ } - } - - cprman_write(cprman, data->a2w_ctrl_reg, diff --git a/target/linux/bcm27xx/patches-5.4/950-0217-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch b/target/linux/bcm27xx/patches-5.4/950-0217-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch new file mode 100644 index 0000000000..bae0f84e1a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0217-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch @@ -0,0 +1,71 @@ +From 1ee90bb75979c183e241c14f7c31d72cdb4bcc9b Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 May 2019 15:24:04 -0700 +Subject: [PATCH] clk: bcm2835: Allow reparenting leaf clocks while + they're running. + +This falls under the same "we can reprogram glitch-free as long as we +pause generation" rule as updating the div/frac fields. This can be +used for runtime reclocking of V3D to manage power leakage. + +Signed-off-by: Eric Anholt +--- + drivers/clk/bcm/clk-bcm2835.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1103,8 +1103,10 @@ static int bcm2835_clock_on(struct clk_h + return 0; + } + +-static int bcm2835_clock_set_rate(struct clk_hw *hw, +- unsigned long rate, unsigned long parent_rate) ++static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long parent_rate, ++ u8 parent) + { + struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); + struct bcm2835_cprman *cprman = clock->cprman; +@@ -1126,6 +1128,11 @@ static int bcm2835_clock_set_rate(struct + bcm2835_clock_wait_busy(clock); + } + ++ if (parent != 0xff) { ++ ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT); ++ ctl |= parent << CM_SRC_SHIFT; ++ } ++ + ctl &= ~CM_FRAC; + ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; + cprman_write(cprman, data->ctl_reg, ctl); +@@ -1137,6 +1144,12 @@ static int bcm2835_clock_set_rate(struct + return 0; + } + ++static int bcm2835_clock_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff); ++} ++ + static bool + bcm2835_clk_is_pllc(struct clk_hw *hw) + { +@@ -1320,6 +1333,7 @@ static const struct clk_ops bcm2835_cloc + .unprepare = bcm2835_clock_off, + .recalc_rate = bcm2835_clock_get_rate, + .set_rate = bcm2835_clock_set_rate, ++ .set_rate_and_parent = bcm2835_clock_set_rate_and_parent, + .determine_rate = bcm2835_clock_determine_rate, + .set_parent = bcm2835_clock_set_parent, + .get_parent = bcm2835_clock_get_parent, +@@ -1498,7 +1512,6 @@ static struct clk_hw *bcm2835_register_c + init.ops = &bcm2835_vpu_clock_clk_ops; + } else { + init.ops = &bcm2835_clock_clk_ops; +- init.flags |= CLK_SET_PARENT_GATE; + + /* If the clock wasn't actually enabled at boot, it's not + * critical. diff --git a/target/linux/bcm27xx/patches-5.4/950-0217-soc-bcm-bcm2835-pm-Add-support-for-2711.patch b/target/linux/bcm27xx/patches-5.4/950-0217-soc-bcm-bcm2835-pm-Add-support-for-2711.patch deleted file mode 100644 index 61bf911f28..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0217-soc-bcm-bcm2835-pm-Add-support-for-2711.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 0cb69292622e3530a72d3173d78c484c8f4d3eab Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Fri, 11 Jan 2019 17:31:07 -0800 -Subject: [PATCH] soc: bcm: bcm2835-pm: Add support for 2711. - -Without the actual power management part any more, there's a lot less -to set up for V3D. We just need to clear the RSTN field for the power -domain, and expose the reset controller for toggling it again. - -This is definitely incomplete -- the old ISP and H264 is in the old -bridge, but since we have no consumers of it I've just done the -minimum to get V3D working. - -Signed-off-by: Eric Anholt ---- - drivers/mfd/bcm2835-pm.c | 11 +++++++++++ - drivers/soc/bcm/bcm2835-power.c | 22 ++++++++++++++++++++++ - include/linux/mfd/bcm2835-pm.h | 1 + - 3 files changed, 34 insertions(+) - ---- a/drivers/mfd/bcm2835-pm.c -+++ b/drivers/mfd/bcm2835-pm.c -@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platf - if (ret) - return ret; - -+ /* Map the ARGON ASB regs if present. */ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); -+ if (res) { -+ pm->arg_asb = devm_ioremap_resource(dev, res); -+ if (IS_ERR(pm->arg_asb)) { -+ dev_err(dev, "Failed to map ARGON ASB: %ld\n", -+ PTR_ERR(pm->arg_asb)); -+ return PTR_ERR(pm->arg_asb); -+ } -+ } -+ - /* We'll use the presence of the AXI ASB regs in the - * bcm2835-pm binding as the key for whether we can reference - * the full PM register range and support power domains. ---- a/drivers/soc/bcm/bcm2835-power.c -+++ b/drivers/soc/bcm/bcm2835-power.c -@@ -143,6 +143,8 @@ struct bcm2835_power { - /* AXI Async bridge registers. */ - void __iomem *asb; - -+ bool is_2711; -+ - struct genpd_onecell_data pd_xlate; - struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT]; - struct reset_controller_dev reset; -@@ -192,6 +194,10 @@ static int bcm2835_power_power_off(struc - { - struct bcm2835_power *power = pd->power; - -+ /* 2711 has no power domains above the reset controller. */ -+ if (power->is_2711) -+ return 0; -+ - /* Enable functional isolation */ - PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC); - -@@ -213,6 +219,10 @@ static int bcm2835_power_power_on(struct - int inrush; - bool powok; - -+ /* 2711 has no power domains above the reset controller. */ -+ if (power->is_2711) -+ return 0; -+ - /* If it was already powered on by the fw, leave it that way. */ - if (PM_READ(pm_reg) & PM_POWUP) - return 0; -@@ -627,6 +637,18 @@ static int bcm2835_power_probe(struct pl - power->base = pm->base; - power->asb = pm->asb; - -+ /* 2711 hack: the new ARGON ASB took over V3D, which is our -+ * only consumer of this driver so far. The old ASB seems to -+ * still be present with ISP and H264 bits but no V3D, but I -+ * don't know if that's real or not. The V3D is in the same -+ * place in the new ASB as the old one, so just poke the new -+ * one for now. -+ */ -+ if (pm->arg_asb) { -+ power->asb = pm->arg_asb; -+ power->is_2711 = true; -+ } -+ - id = ASB_READ(ASB_AXI_BRDG_ID); - if (id != 0x62726467 /* "BRDG" */) { - dev_err(dev, "ASB register ID returned 0x%08x\n", id); ---- a/include/linux/mfd/bcm2835-pm.h -+++ b/include/linux/mfd/bcm2835-pm.h -@@ -9,6 +9,7 @@ struct bcm2835_pm { - struct device *dev; - void __iomem *base; - void __iomem *asb; -+ void __iomem *arg_asb; - }; - - #endif /* BCM2835_MFD_PM_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0218-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch b/target/linux/bcm27xx/patches-5.4/950-0218-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch deleted file mode 100644 index 4e3805d9a7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0218-config-Permit-LPAE-and-PCIE_BRCMSTB-on-BCM2835.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 15880303abc8b93cda3c62203fa5303726f53ca6 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 4 Sep 2018 11:50:25 +0100 -Subject: [PATCH] config: Permit LPAE and PCIE_BRCMSTB on BCM2835 - ---- - arch/arm/mach-bcm/Kconfig | 4 ++++ - drivers/pci/controller/Kconfig | 4 ++-- - 2 files changed, 6 insertions(+), 2 deletions(-) - ---- a/arch/arm/mach-bcm/Kconfig -+++ b/arch/arm/mach-bcm/Kconfig -@@ -161,6 +161,7 @@ config ARCH_BCM2835 - select GPIOLIB - select ARM_AMBA - select ARM_ERRATA_411920 if ARCH_MULTI_V6 -+ select ARM_GIC - select ARM_TIMER_SP804 - select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 - select TIMER_OF -@@ -170,6 +171,9 @@ config ARCH_BCM2835 - select PINCTRL_BCM2835 - select MFD_CORE - select MFD_SYSCON if ARCH_MULTI_V7 -+ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE -+ select ZONE_DMA if ARM_LPAE -+ select MFD_CORE - help - This enables support for the Broadcom BCM2835 and BCM2836 SoCs. - This SoC is used in the Raspberry Pi and Roku 2 devices. diff --git a/target/linux/bcm27xx/patches-5.4/950-0218-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch b/target/linux/bcm27xx/patches-5.4/950-0218-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch new file mode 100644 index 0000000000..127e91cd24 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0218-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch @@ -0,0 +1,104 @@ +From 2669f337d78306667e4243fda9282fb8c07d0d3d Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 11 Jun 2019 10:55:00 +0100 +Subject: [PATCH] usb: add plumbing for updating interrupt endpoint + interval state + +xHCI caches device and endpoint data after the interface is configured, +so an explicit command needs to be issued for any device driver wanting +to alter the polling interval of an endpoint. + +Add usb_fixup_endpoint() to allow drivers to do this. The fixup must be +called after calculating endpoint bandwidth requirements but before any +URBs are submitted. + +If polling intervals are shortened, any bandwidth reservations are no +longer valid but in practice polling intervals are only ever relaxed. + +Limit the scope to interrupt transfers for now. + +Signed-off-by: Jonathan Bell +--- + drivers/usb/core/hcd.c | 10 ++++++++++ + drivers/usb/core/message.c | 15 +++++++++++++++ + include/linux/usb.h | 2 ++ + include/linux/usb/hcd.h | 7 +++++++ + 4 files changed, 34 insertions(+) + +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -1941,6 +1941,16 @@ reset: + return ret; + } + ++void usb_hcd_fixup_endpoint(struct usb_device *udev, ++ struct usb_host_endpoint *ep, int interval) ++{ ++ struct usb_hcd *hcd; ++ ++ hcd = bus_to_hcd(udev->bus); ++ if (hcd->driver->fixup_endpoint) ++ hcd->driver->fixup_endpoint(hcd, udev, ep, interval); ++} ++ + /* Disables the endpoint: synchronizes with the hcd to make sure all + * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must + * have been called previously. Use for set_configuration, set_interface, +--- a/drivers/usb/core/message.c ++++ b/drivers/usb/core/message.c +@@ -1120,6 +1120,21 @@ static void remove_intf_ep_devs(struct u + intf->ep_devs_created = 0; + } + ++void usb_fixup_endpoint(struct usb_device *dev, int epaddr, int interval) ++{ ++ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; ++ struct usb_host_endpoint *ep; ++ ++ if (usb_endpoint_out(epaddr)) ++ ep = dev->ep_out[epnum]; ++ else ++ ep = dev->ep_in[epnum]; ++ ++ if (ep && usb_endpoint_xfer_int(&ep->desc)) ++ usb_hcd_fixup_endpoint(dev, ep, interval); ++} ++EXPORT_SYMBOL_GPL(usb_fixup_endpoint); ++ + /** + * usb_disable_endpoint -- Disable an endpoint by address + * @dev: the device whose endpoint is being disabled +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -1816,6 +1816,8 @@ extern int usb_clear_halt(struct usb_dev + extern int usb_reset_configuration(struct usb_device *dev); + extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); + extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr); ++extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr, ++ int interval); + + /* this request isn't really synchronous, but it belongs with the others */ + extern int usb_driver_set_configuration(struct usb_device *udev, int config); +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -382,6 +382,11 @@ struct hc_driver { + * or bandwidth constraints. + */ + void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); ++ /* Override the endpoint-derived interval ++ * (if there is any cached hardware state). ++ */ ++ void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev, ++ struct usb_host_endpoint *ep, int interval); + /* Returns the hardware-chosen device address */ + int (*address_device)(struct usb_hcd *, struct usb_device *udev); + /* prepares the hardware to send commands to the device */ +@@ -443,6 +448,8 @@ extern void usb_hcd_unmap_urb_setup_for_ + extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *); + extern void usb_hcd_flush_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); ++extern void usb_hcd_fixup_endpoint(struct usb_device *udev, ++ struct usb_host_endpoint *ep, int interval); + extern void usb_hcd_disable_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); + extern void usb_hcd_reset_endpoint(struct usb_device *udev, diff --git a/target/linux/bcm27xx/patches-5.4/950-0219-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch b/target/linux/bcm27xx/patches-5.4/950-0219-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch deleted file mode 100644 index 3227f8c914..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0219-clk-bcm2835-Add-support-for-setting-leaf-clock-rates.patch +++ /dev/null @@ -1,53 +0,0 @@ -From cfe0832e8306cd9955f682b7314a5a6fc3b9d514 Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Thu, 2 May 2019 15:11:05 -0700 -Subject: [PATCH] clk: bcm2835: Add support for setting leaf clock - rates while running. - -As long as you wait for !BUSY, you can do glitch-free updates of clock -rate while the clock is running. - -Signed-off-by: Eric Anholt ---- - drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++--------- - 1 file changed, 13 insertions(+), 9 deletions(-) - ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -1114,15 +1114,19 @@ static int bcm2835_clock_set_rate(struct - - spin_lock(&cprman->regs_lock); - -- /* -- * Setting up frac support -- * -- * In principle it is recommended to stop/start the clock first, -- * but as we set CLK_SET_RATE_GATE during registration of the -- * clock this requirement should be take care of by the -- * clk-framework. -+ ctl = cprman_read(cprman, data->ctl_reg); -+ -+ /* If the clock is running, we have to pause clock generation while -+ * updating the control and div regs. This is glitchless (no clock -+ * signals generated faster than the rate) but each reg access is two -+ * OSC cycles so the clock will slow down for a moment. - */ -- ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC; -+ if (ctl & CM_ENABLE) { -+ cprman_write(cprman, data->ctl_reg, ctl & ~CM_ENABLE); -+ bcm2835_clock_wait_busy(clock); -+ } -+ -+ ctl &= ~CM_FRAC; - ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; - cprman_write(cprman, data->ctl_reg, ctl); - -@@ -1494,7 +1498,7 @@ static struct clk_hw *bcm2835_register_c - init.ops = &bcm2835_vpu_clock_clk_ops; - } else { - init.ops = &bcm2835_clock_clk_ops; -- init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; -+ init.flags |= CLK_SET_PARENT_GATE; - - /* If the clock wasn't actually enabled at boot, it's not - * critical. diff --git a/target/linux/bcm27xx/patches-5.4/950-0219-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch b/target/linux/bcm27xx/patches-5.4/950-0219-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch new file mode 100644 index 0000000000..5c241536dd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0219-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch @@ -0,0 +1,129 @@ +From 00e1a43b64abc8950b471678b7ed4415f3513f3e Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 11 Jun 2019 11:33:39 +0100 +Subject: [PATCH] xhci: implement xhci_fixup_endpoint for interval + adjustments + +Must be called in a non-atomic context, after the endpoint +has been registered with the hardware via xhci_add_endpoint +and before the first URB is submitted for the endpoint. + +Signed-off-by: Jonathan Bell +--- + drivers/usb/host/xhci.c | 98 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 98 insertions(+) + +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -1456,6 +1456,103 @@ command_cleanup: + } + + /* ++ * RPI: Fixup endpoint intervals when requested ++ * - Check interval versus the (cached) endpoint context ++ * - set the endpoint interval to the new value ++ * - force an endpoint configure command ++ * XXX: bandwidth is not recalculated. We should probably do that. ++ */ ++static void xhci_fixup_endpoint(struct usb_hcd *hcd, struct usb_device *udev, ++ struct usb_host_endpoint *ep, int interval) ++{ ++ struct xhci_hcd *xhci; ++ struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in; ++ struct xhci_command *command; ++ struct xhci_input_control_ctx *ctrl_ctx; ++ struct xhci_virt_device *vdev; ++ int xhci_interval; ++ int ret; ++ int ep_index; ++ unsigned long flags; ++ u32 ep_info_tmp; ++ ++ xhci = hcd_to_xhci(hcd); ++ ep_index = xhci_get_endpoint_index(&ep->desc); ++ ++ /* FS/LS interval translations */ ++ if ((udev->speed == USB_SPEED_FULL || ++ udev->speed == USB_SPEED_LOW)) ++ interval *= 8; ++ ++ mutex_lock(&xhci->mutex); ++ ++ spin_lock_irqsave(&xhci->lock, flags); ++ ++ vdev = xhci->devs[udev->slot_id]; ++ /* Get context-derived endpoint interval */ ++ ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index); ++ ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index); ++ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info)); ++ ++ if (interval == xhci_interval) { ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ mutex_unlock(&xhci->mutex); ++ return; ++ } ++ ++ xhci_dbg(xhci, "Fixup interval=%d xhci_interval=%d\n", ++ interval, xhci_interval); ++ command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC); ++ if (!command) { ++ /* Failure here is benign, poll at the original rate */ ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ mutex_unlock(&xhci->mutex); ++ return; ++ } ++ ++ /* xHCI uses exponents for intervals... */ ++ xhci_interval = fls(interval) - 1; ++ xhci_interval = clamp_val(xhci_interval, 3, 10); ++ ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info); ++ ep_info_tmp &= ~EP_INTERVAL(255); ++ ep_info_tmp |= EP_INTERVAL(xhci_interval); ++ ++ /* Keep the endpoint context up-to-date while issuing the command. */ ++ xhci_endpoint_copy(xhci, vdev->in_ctx, ++ vdev->out_ctx, ep_index); ++ ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp); ++ ++ /* ++ * We need to drop the lock, so take an explicit copy ++ * of the ep context. ++ */ ++ xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index); ++ ++ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); ++ if (!ctrl_ctx) { ++ xhci_warn(xhci, ++ "%s: Could not get input context, bad type.\n", ++ __func__); ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ xhci_free_command(xhci, command); ++ mutex_unlock(&xhci->mutex); ++ return; ++ } ++ ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index); ++ ctrl_ctx->drop_flags = 0; ++ ++ spin_unlock_irqrestore(&xhci->lock, flags); ++ ++ ret = xhci_configure_endpoint(xhci, udev, command, ++ false, false); ++ if (ret) ++ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n", ++ __func__, ret); ++ xhci_free_command(xhci, command); ++ mutex_unlock(&xhci->mutex); ++} ++ ++/* + * non-error returns are a promise to giveback() the urb later + * we drop ownership so next owner (or urb unlink) can get it + */ +@@ -5337,6 +5434,7 @@ static const struct hc_driver xhci_hc_dr + .endpoint_reset = xhci_endpoint_reset, + .check_bandwidth = xhci_check_bandwidth, + .reset_bandwidth = xhci_reset_bandwidth, ++ .fixup_endpoint = xhci_fixup_endpoint, + .address_device = xhci_address_device, + .enable_device = xhci_enable_device, + .update_hub_device = xhci_update_hub_device, diff --git a/target/linux/bcm27xx/patches-5.4/950-0220-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch b/target/linux/bcm27xx/patches-5.4/950-0220-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch deleted file mode 100644 index bae0f84e1a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0220-clk-bcm2835-Allow-reparenting-leaf-clocks-while-they.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 1ee90bb75979c183e241c14f7c31d72cdb4bcc9b Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Thu, 2 May 2019 15:24:04 -0700 -Subject: [PATCH] clk: bcm2835: Allow reparenting leaf clocks while - they're running. - -This falls under the same "we can reprogram glitch-free as long as we -pause generation" rule as updating the div/frac fields. This can be -used for runtime reclocking of V3D to manage power leakage. - -Signed-off-by: Eric Anholt ---- - drivers/clk/bcm/clk-bcm2835.c | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -1103,8 +1103,10 @@ static int bcm2835_clock_on(struct clk_h - return 0; - } - --static int bcm2835_clock_set_rate(struct clk_hw *hw, -- unsigned long rate, unsigned long parent_rate) -+static int bcm2835_clock_set_rate_and_parent(struct clk_hw *hw, -+ unsigned long rate, -+ unsigned long parent_rate, -+ u8 parent) - { - struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); - struct bcm2835_cprman *cprman = clock->cprman; -@@ -1126,6 +1128,11 @@ static int bcm2835_clock_set_rate(struct - bcm2835_clock_wait_busy(clock); - } - -+ if (parent != 0xff) { -+ ctl &= ~(CM_SRC_MASK << CM_SRC_SHIFT); -+ ctl |= parent << CM_SRC_SHIFT; -+ } -+ - ctl &= ~CM_FRAC; - ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; - cprman_write(cprman, data->ctl_reg, ctl); -@@ -1137,6 +1144,12 @@ static int bcm2835_clock_set_rate(struct - return 0; - } - -+static int bcm2835_clock_set_rate(struct clk_hw *hw, -+ unsigned long rate, unsigned long parent_rate) -+{ -+ return bcm2835_clock_set_rate_and_parent(hw, rate, parent_rate, 0xff); -+} -+ - static bool - bcm2835_clk_is_pllc(struct clk_hw *hw) - { -@@ -1320,6 +1333,7 @@ static const struct clk_ops bcm2835_cloc - .unprepare = bcm2835_clock_off, - .recalc_rate = bcm2835_clock_get_rate, - .set_rate = bcm2835_clock_set_rate, -+ .set_rate_and_parent = bcm2835_clock_set_rate_and_parent, - .determine_rate = bcm2835_clock_determine_rate, - .set_parent = bcm2835_clock_set_parent, - .get_parent = bcm2835_clock_get_parent, -@@ -1498,7 +1512,6 @@ static struct clk_hw *bcm2835_register_c - init.ops = &bcm2835_vpu_clock_clk_ops; - } else { - init.ops = &bcm2835_clock_clk_ops; -- init.flags |= CLK_SET_PARENT_GATE; - - /* If the clock wasn't actually enabled at boot, it's not - * critical. diff --git a/target/linux/bcm27xx/patches-5.4/950-0220-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch b/target/linux/bcm27xx/patches-5.4/950-0220-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch new file mode 100644 index 0000000000..bf88c40780 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0220-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch @@ -0,0 +1,23 @@ +From df28fdf0b853c0951bab5c9cbb5aa82819f7b34b Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 11 Jun 2019 11:42:03 +0100 +Subject: [PATCH] usbhid: call usb_fixup_endpoint after mangling + intervals + +Lets the mousepoll override mechanism work with xhci. + +Signed-off-by: Jonathan Bell +--- + drivers/hid/usbhid/hid-core.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1128,6 +1128,7 @@ static int usbhid_start(struct hid_devic + interval = hid_kbpoll_interval; + break; + } ++ usb_fixup_endpoint(dev, endpoint->bEndpointAddress, interval); + + ret = -ENOMEM; + if (usb_endpoint_dir_in(endpoint)) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0221-arm-bcm2835-Add-bcm2838-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0221-arm-bcm2835-Add-bcm2838-compatible-string.patch new file mode 100644 index 0000000000..f11ccb44e9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0221-arm-bcm2835-Add-bcm2838-compatible-string.patch @@ -0,0 +1,20 @@ +From 8af54831d1d377b6a4ab087c409f1684e1e985a7 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 11 Jun 2019 17:38:28 +0100 +Subject: [PATCH] arm: bcm2835: Add bcm2838 compatible string. + +Signed-off-by: Phil Elwell +--- + arch/arm/mach-bcm/board_bcm2835.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/mach-bcm/board_bcm2835.c ++++ b/arch/arm/mach-bcm/board_bcm2835.c +@@ -109,6 +109,7 @@ static const char * const bcm2835_compat + #ifdef CONFIG_ARCH_MULTI_V7 + "brcm,bcm2836", + "brcm,bcm2837", ++ "brcm,bcm2838", + #endif + NULL + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0221-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch b/target/linux/bcm27xx/patches-5.4/950-0221-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch deleted file mode 100644 index 127e91cd24..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0221-usb-add-plumbing-for-updating-interrupt-endpoint-int.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 2669f337d78306667e4243fda9282fb8c07d0d3d Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 11 Jun 2019 10:55:00 +0100 -Subject: [PATCH] usb: add plumbing for updating interrupt endpoint - interval state - -xHCI caches device and endpoint data after the interface is configured, -so an explicit command needs to be issued for any device driver wanting -to alter the polling interval of an endpoint. - -Add usb_fixup_endpoint() to allow drivers to do this. The fixup must be -called after calculating endpoint bandwidth requirements but before any -URBs are submitted. - -If polling intervals are shortened, any bandwidth reservations are no -longer valid but in practice polling intervals are only ever relaxed. - -Limit the scope to interrupt transfers for now. - -Signed-off-by: Jonathan Bell ---- - drivers/usb/core/hcd.c | 10 ++++++++++ - drivers/usb/core/message.c | 15 +++++++++++++++ - include/linux/usb.h | 2 ++ - include/linux/usb/hcd.h | 7 +++++++ - 4 files changed, 34 insertions(+) - ---- a/drivers/usb/core/hcd.c -+++ b/drivers/usb/core/hcd.c -@@ -1941,6 +1941,16 @@ reset: - return ret; - } - -+void usb_hcd_fixup_endpoint(struct usb_device *udev, -+ struct usb_host_endpoint *ep, int interval) -+{ -+ struct usb_hcd *hcd; -+ -+ hcd = bus_to_hcd(udev->bus); -+ if (hcd->driver->fixup_endpoint) -+ hcd->driver->fixup_endpoint(hcd, udev, ep, interval); -+} -+ - /* Disables the endpoint: synchronizes with the hcd to make sure all - * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must - * have been called previously. Use for set_configuration, set_interface, ---- a/drivers/usb/core/message.c -+++ b/drivers/usb/core/message.c -@@ -1120,6 +1120,21 @@ static void remove_intf_ep_devs(struct u - intf->ep_devs_created = 0; - } - -+void usb_fixup_endpoint(struct usb_device *dev, int epaddr, int interval) -+{ -+ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; -+ struct usb_host_endpoint *ep; -+ -+ if (usb_endpoint_out(epaddr)) -+ ep = dev->ep_out[epnum]; -+ else -+ ep = dev->ep_in[epnum]; -+ -+ if (ep && usb_endpoint_xfer_int(&ep->desc)) -+ usb_hcd_fixup_endpoint(dev, ep, interval); -+} -+EXPORT_SYMBOL_GPL(usb_fixup_endpoint); -+ - /** - * usb_disable_endpoint -- Disable an endpoint by address - * @dev: the device whose endpoint is being disabled ---- a/include/linux/usb.h -+++ b/include/linux/usb.h -@@ -1816,6 +1816,8 @@ extern int usb_clear_halt(struct usb_dev - extern int usb_reset_configuration(struct usb_device *dev); - extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); - extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr); -+extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr, -+ int interval); - - /* this request isn't really synchronous, but it belongs with the others */ - extern int usb_driver_set_configuration(struct usb_device *udev, int config); ---- a/include/linux/usb/hcd.h -+++ b/include/linux/usb/hcd.h -@@ -382,6 +382,11 @@ struct hc_driver { - * or bandwidth constraints. - */ - void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); -+ /* Override the endpoint-derived interval -+ * (if there is any cached hardware state). -+ */ -+ void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev, -+ struct usb_host_endpoint *ep, int interval); - /* Returns the hardware-chosen device address */ - int (*address_device)(struct usb_hcd *, struct usb_device *udev); - /* prepares the hardware to send commands to the device */ -@@ -443,6 +448,8 @@ extern void usb_hcd_unmap_urb_setup_for_ - extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *); - extern void usb_hcd_flush_endpoint(struct usb_device *udev, - struct usb_host_endpoint *ep); -+extern void usb_hcd_fixup_endpoint(struct usb_device *udev, -+ struct usb_host_endpoint *ep, int interval); - extern void usb_hcd_disable_endpoint(struct usb_device *udev, - struct usb_host_endpoint *ep); - extern void usb_hcd_reset_endpoint(struct usb_device *udev, diff --git a/target/linux/bcm27xx/patches-5.4/950-0222-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch b/target/linux/bcm27xx/patches-5.4/950-0222-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch new file mode 100644 index 0000000000..f95c8778a6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0222-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch @@ -0,0 +1,22 @@ +From 50f3c90e2400a0391a7461e5e2fea86ffb3f8f60 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 4 Mar 2019 11:59:34 -0800 +Subject: [PATCH] drm/vc4: Fix oops at boot with firmwarekms on 4.19. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_kms.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -116,6 +116,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru + struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state); + struct drm_color_ctm *ctm = ctm_state->ctm; + ++ if (vc4->firmware_kms) ++ return; ++ + if (ctm_state->fifo) { + HVS_WRITE(SCALER_OLEDCOEF2, + VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]), diff --git a/target/linux/bcm27xx/patches-5.4/950-0222-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch b/target/linux/bcm27xx/patches-5.4/950-0222-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch deleted file mode 100644 index 5c241536dd..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0222-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 00e1a43b64abc8950b471678b7ed4415f3513f3e Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 11 Jun 2019 11:33:39 +0100 -Subject: [PATCH] xhci: implement xhci_fixup_endpoint for interval - adjustments - -Must be called in a non-atomic context, after the endpoint -has been registered with the hardware via xhci_add_endpoint -and before the first URB is submitted for the endpoint. - -Signed-off-by: Jonathan Bell ---- - drivers/usb/host/xhci.c | 98 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 98 insertions(+) - ---- a/drivers/usb/host/xhci.c -+++ b/drivers/usb/host/xhci.c -@@ -1456,6 +1456,103 @@ command_cleanup: - } - - /* -+ * RPI: Fixup endpoint intervals when requested -+ * - Check interval versus the (cached) endpoint context -+ * - set the endpoint interval to the new value -+ * - force an endpoint configure command -+ * XXX: bandwidth is not recalculated. We should probably do that. -+ */ -+static void xhci_fixup_endpoint(struct usb_hcd *hcd, struct usb_device *udev, -+ struct usb_host_endpoint *ep, int interval) -+{ -+ struct xhci_hcd *xhci; -+ struct xhci_ep_ctx *ep_ctx_out, *ep_ctx_in; -+ struct xhci_command *command; -+ struct xhci_input_control_ctx *ctrl_ctx; -+ struct xhci_virt_device *vdev; -+ int xhci_interval; -+ int ret; -+ int ep_index; -+ unsigned long flags; -+ u32 ep_info_tmp; -+ -+ xhci = hcd_to_xhci(hcd); -+ ep_index = xhci_get_endpoint_index(&ep->desc); -+ -+ /* FS/LS interval translations */ -+ if ((udev->speed == USB_SPEED_FULL || -+ udev->speed == USB_SPEED_LOW)) -+ interval *= 8; -+ -+ mutex_lock(&xhci->mutex); -+ -+ spin_lock_irqsave(&xhci->lock, flags); -+ -+ vdev = xhci->devs[udev->slot_id]; -+ /* Get context-derived endpoint interval */ -+ ep_ctx_out = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index); -+ ep_ctx_in = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index); -+ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx_out->ep_info)); -+ -+ if (interval == xhci_interval) { -+ spin_unlock_irqrestore(&xhci->lock, flags); -+ mutex_unlock(&xhci->mutex); -+ return; -+ } -+ -+ xhci_dbg(xhci, "Fixup interval=%d xhci_interval=%d\n", -+ interval, xhci_interval); -+ command = xhci_alloc_command_with_ctx(xhci, true, GFP_ATOMIC); -+ if (!command) { -+ /* Failure here is benign, poll at the original rate */ -+ spin_unlock_irqrestore(&xhci->lock, flags); -+ mutex_unlock(&xhci->mutex); -+ return; -+ } -+ -+ /* xHCI uses exponents for intervals... */ -+ xhci_interval = fls(interval) - 1; -+ xhci_interval = clamp_val(xhci_interval, 3, 10); -+ ep_info_tmp = le32_to_cpu(ep_ctx_out->ep_info); -+ ep_info_tmp &= ~EP_INTERVAL(255); -+ ep_info_tmp |= EP_INTERVAL(xhci_interval); -+ -+ /* Keep the endpoint context up-to-date while issuing the command. */ -+ xhci_endpoint_copy(xhci, vdev->in_ctx, -+ vdev->out_ctx, ep_index); -+ ep_ctx_in->ep_info = cpu_to_le32(ep_info_tmp); -+ -+ /* -+ * We need to drop the lock, so take an explicit copy -+ * of the ep context. -+ */ -+ xhci_endpoint_copy(xhci, command->in_ctx, vdev->in_ctx, ep_index); -+ -+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); -+ if (!ctrl_ctx) { -+ xhci_warn(xhci, -+ "%s: Could not get input context, bad type.\n", -+ __func__); -+ spin_unlock_irqrestore(&xhci->lock, flags); -+ xhci_free_command(xhci, command); -+ mutex_unlock(&xhci->mutex); -+ return; -+ } -+ ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index); -+ ctrl_ctx->drop_flags = 0; -+ -+ spin_unlock_irqrestore(&xhci->lock, flags); -+ -+ ret = xhci_configure_endpoint(xhci, udev, command, -+ false, false); -+ if (ret) -+ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n", -+ __func__, ret); -+ xhci_free_command(xhci, command); -+ mutex_unlock(&xhci->mutex); -+} -+ -+/* - * non-error returns are a promise to giveback() the urb later - * we drop ownership so next owner (or urb unlink) can get it - */ -@@ -5337,6 +5434,7 @@ static const struct hc_driver xhci_hc_dr - .endpoint_reset = xhci_endpoint_reset, - .check_bandwidth = xhci_check_bandwidth, - .reset_bandwidth = xhci_reset_bandwidth, -+ .fixup_endpoint = xhci_fixup_endpoint, - .address_device = xhci_address_device, - .enable_device = xhci_enable_device, - .update_hub_device = xhci_update_hub_device, diff --git a/target/linux/bcm27xx/patches-5.4/950-0223-drm-v3d-Add-support-for-2711.patch b/target/linux/bcm27xx/patches-5.4/950-0223-drm-v3d-Add-support-for-2711.patch new file mode 100644 index 0000000000..328c303083 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0223-drm-v3d-Add-support-for-2711.patch @@ -0,0 +1,20 @@ +From c023f241d93059ba6ee2ab5acdb2b54b85b12f53 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 4 Oct 2018 17:22:43 -0700 +Subject: [PATCH] drm/v3d: Add support for 2711. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/v3d/v3d_drv.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -221,6 +221,7 @@ static struct drm_driver v3d_drm_driver + static const struct of_device_id v3d_of_match[] = { + { .compatible = "brcm,7268-v3d" }, + { .compatible = "brcm,7278-v3d" }, ++ { .compatible = "brcm,2711-v3d" }, + {}, + }; + MODULE_DEVICE_TABLE(of, v3d_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0223-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch b/target/linux/bcm27xx/patches-5.4/950-0223-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch deleted file mode 100644 index bf88c40780..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0223-usbhid-call-usb_fixup_endpoint-after-mangling-interv.patch +++ /dev/null @@ -1,23 +0,0 @@ -From df28fdf0b853c0951bab5c9cbb5aa82819f7b34b Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 11 Jun 2019 11:42:03 +0100 -Subject: [PATCH] usbhid: call usb_fixup_endpoint after mangling - intervals - -Lets the mousepoll override mechanism work with xhci. - -Signed-off-by: Jonathan Bell ---- - drivers/hid/usbhid/hid-core.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/hid/usbhid/hid-core.c -+++ b/drivers/hid/usbhid/hid-core.c -@@ -1128,6 +1128,7 @@ static int usbhid_start(struct hid_devic - interval = hid_kbpoll_interval; - break; - } -+ usb_fixup_endpoint(dev, endpoint->bEndpointAddress, interval); - - ret = -ENOMEM; - if (usb_endpoint_dir_in(endpoint)) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0224-arm-bcm2835-Add-bcm2838-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0224-arm-bcm2835-Add-bcm2838-compatible-string.patch deleted file mode 100644 index f11ccb44e9..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0224-arm-bcm2835-Add-bcm2838-compatible-string.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 8af54831d1d377b6a4ab087c409f1684e1e985a7 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 11 Jun 2019 17:38:28 +0100 -Subject: [PATCH] arm: bcm2835: Add bcm2838 compatible string. - -Signed-off-by: Phil Elwell ---- - arch/arm/mach-bcm/board_bcm2835.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/arch/arm/mach-bcm/board_bcm2835.c -+++ b/arch/arm/mach-bcm/board_bcm2835.c -@@ -109,6 +109,7 @@ static const char * const bcm2835_compat - #ifdef CONFIG_ARCH_MULTI_V7 - "brcm,bcm2836", - "brcm,bcm2837", -+ "brcm,bcm2838", - #endif - NULL - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0224-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch b/target/linux/bcm27xx/patches-5.4/950-0224-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch new file mode 100644 index 0000000000..1581cc0070 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0224-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch @@ -0,0 +1,52 @@ +From f34daf3b5ae9533f88d31eef74bbf38099e96aa1 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 14 Jan 2019 12:35:43 -0800 +Subject: [PATCH] drm/v3d: Skip MMU flush if the device is currently + off. + +If it's off, we know it will be reset on poweron, so the MMU won't +have any TLB cached from before this point. Avoids failed waits for +MMU flush to reply. + +Signed-off-by: Eric Anholt +(cherry picked from commit 3ee4e2e0a9e9587eacbb69b067bbc72ab2cdc47b) +--- + drivers/gpu/drm/v3d/v3d_mmu.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/gpu/drm/v3d/v3d_mmu.c ++++ b/drivers/gpu/drm/v3d/v3d_mmu.c +@@ -18,6 +18,8 @@ + * each client. This is not yet implemented. + */ + ++#include ++ + #include "v3d_drv.h" + #include "v3d_regs.h" + +@@ -34,6 +36,14 @@ static int v3d_mmu_flush_all(struct v3d_ + { + int ret; + ++ /* Keep power on the device on until we're done with this ++ * call, but skip the flush if the device is off and will be ++ * reset when powered back on. ++ */ ++ ret = pm_runtime_get_if_in_use(v3d->dev); ++ if (ret == 0) ++ return 0; ++ + /* Make sure that another flush isn't already running when we + * start this one. + */ +@@ -61,6 +71,9 @@ static int v3d_mmu_flush_all(struct v3d_ + if (ret) + dev_err(v3d->dev, "MMUC flush wait idle failed\n"); + ++ pm_runtime_mark_last_busy(v3d->dev); ++ pm_runtime_put_autosuspend(v3d->dev); ++ + return ret; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0225-drm-v3d-Hook-up-the-runtime-PM-ops.patch b/target/linux/bcm27xx/patches-5.4/950-0225-drm-v3d-Hook-up-the-runtime-PM-ops.patch new file mode 100644 index 0000000000..438922177d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0225-drm-v3d-Hook-up-the-runtime-PM-ops.patch @@ -0,0 +1,34 @@ +From 0b1f35dfb545dab884df2b4761e1af731f41ca9e Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 14 Jan 2019 14:47:57 -0800 +Subject: [PATCH] drm/v3d: Hook up the runtime PM ops. + +In translating the runtime PM code from vc4, I missed the ".pm" +assignment to actually connect them up. Fixes missing MMU setup if +runtime PM resets V3D. + +Signed-off-by: Eric Anholt +(cherry picked from commit ca197699af29baa8236c74c53d4904ca8957ee06) +--- + drivers/gpu/drm/v3d/v3d_drv.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -69,7 +69,7 @@ static int v3d_runtime_resume(struct dev + } + #endif + +-static const struct dev_pm_ops v3d_v3d_pm_ops = { ++static const struct dev_pm_ops v3d_pm_ops = { + SET_RUNTIME_PM_OPS(v3d_runtime_suspend, v3d_runtime_resume, NULL) + }; + +@@ -362,6 +362,7 @@ static struct platform_driver v3d_platfo + .driver = { + .name = "v3d", + .of_match_table = v3d_of_match, ++ .pm = &v3d_pm_ops, + }, + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0225-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch b/target/linux/bcm27xx/patches-5.4/950-0225-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch deleted file mode 100644 index f95c8778a6..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0225-drm-vc4-Fix-oops-at-boot-with-firmwarekms-on-4.19.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 50f3c90e2400a0391a7461e5e2fea86ffb3f8f60 Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Mon, 4 Mar 2019 11:59:34 -0800 -Subject: [PATCH] drm/vc4: Fix oops at boot with firmwarekms on 4.19. - -Signed-off-by: Eric Anholt ---- - drivers/gpu/drm/vc4/vc4_kms.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -116,6 +116,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, stru - struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state); - struct drm_color_ctm *ctm = ctm_state->ctm; - -+ if (vc4->firmware_kms) -+ return; -+ - if (ctm_state->fifo) { - HVS_WRITE(SCALER_OLEDCOEF2, - VC4_SET_FIELD(vc4_ctm_s31_32_to_s0_9(ctm->matrix[0]), diff --git a/target/linux/bcm27xx/patches-5.4/950-0226-drm-v3d-Add-support-for-2711.patch b/target/linux/bcm27xx/patches-5.4/950-0226-drm-v3d-Add-support-for-2711.patch deleted file mode 100644 index 328c303083..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0226-drm-v3d-Add-support-for-2711.patch +++ /dev/null @@ -1,20 +0,0 @@ -From c023f241d93059ba6ee2ab5acdb2b54b85b12f53 Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Thu, 4 Oct 2018 17:22:43 -0700 -Subject: [PATCH] drm/v3d: Add support for 2711. - -Signed-off-by: Eric Anholt ---- - drivers/gpu/drm/v3d/v3d_drv.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -221,6 +221,7 @@ static struct drm_driver v3d_drm_driver - static const struct of_device_id v3d_of_match[] = { - { .compatible = "brcm,7268-v3d" }, - { .compatible = "brcm,7278-v3d" }, -+ { .compatible = "brcm,2711-v3d" }, - {}, - }; - MODULE_DEVICE_TABLE(of, v3d_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0226-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch b/target/linux/bcm27xx/patches-5.4/950-0226-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch new file mode 100644 index 0000000000..ccd6de065c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0226-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch @@ -0,0 +1,44 @@ +From 87df00d6b301f5de54443ac7e3765dce983e8b6a Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 28 Mar 2019 11:58:51 -0700 +Subject: [PATCH] drm/vc4: Fix synchronization firmwarekms against GL + rendering. + +We would present the framebuffer immediately without waiting for +rendering to finish first, resulting in stuttering and flickering as a +window was dragged around when the GPU was busy enough to not just win +the race. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -15,6 +15,7 @@ + */ + + #include "drm/drm_atomic_helper.h" ++#include "drm/drm_gem_framebuffer_helper.h" + #include "drm/drm_plane_helper.h" + #include "drm/drm_crtc_helper.h" + #include "drm/drm_fourcc.h" +@@ -291,7 +292,7 @@ static const struct drm_plane_funcs vc4_ + }; + + static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = { +- .prepare_fb = NULL, ++ .prepare_fb = drm_gem_fb_prepare_fb, + .cleanup_fb = NULL, + .atomic_check = vc4_plane_atomic_check, + .atomic_update = vc4_primary_plane_atomic_update, +@@ -299,7 +300,7 @@ static const struct drm_plane_helper_fun + }; + + static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = { +- .prepare_fb = NULL, ++ .prepare_fb = drm_gem_fb_prepare_fb, + .cleanup_fb = NULL, + .atomic_check = vc4_plane_atomic_check, + .atomic_update = vc4_cursor_plane_atomic_update, diff --git a/target/linux/bcm27xx/patches-5.4/950-0227-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch b/target/linux/bcm27xx/patches-5.4/950-0227-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch deleted file mode 100644 index 1581cc0070..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0227-drm-v3d-Skip-MMU-flush-if-the-device-is-currently-of.patch +++ /dev/null @@ -1,52 +0,0 @@ -From f34daf3b5ae9533f88d31eef74bbf38099e96aa1 Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Mon, 14 Jan 2019 12:35:43 -0800 -Subject: [PATCH] drm/v3d: Skip MMU flush if the device is currently - off. - -If it's off, we know it will be reset on poweron, so the MMU won't -have any TLB cached from before this point. Avoids failed waits for -MMU flush to reply. - -Signed-off-by: Eric Anholt -(cherry picked from commit 3ee4e2e0a9e9587eacbb69b067bbc72ab2cdc47b) ---- - drivers/gpu/drm/v3d/v3d_mmu.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - ---- a/drivers/gpu/drm/v3d/v3d_mmu.c -+++ b/drivers/gpu/drm/v3d/v3d_mmu.c -@@ -18,6 +18,8 @@ - * each client. This is not yet implemented. - */ - -+#include -+ - #include "v3d_drv.h" - #include "v3d_regs.h" - -@@ -34,6 +36,14 @@ static int v3d_mmu_flush_all(struct v3d_ - { - int ret; - -+ /* Keep power on the device on until we're done with this -+ * call, but skip the flush if the device is off and will be -+ * reset when powered back on. -+ */ -+ ret = pm_runtime_get_if_in_use(v3d->dev); -+ if (ret == 0) -+ return 0; -+ - /* Make sure that another flush isn't already running when we - * start this one. - */ -@@ -61,6 +71,9 @@ static int v3d_mmu_flush_all(struct v3d_ - if (ret) - dev_err(v3d->dev, "MMUC flush wait idle failed\n"); - -+ pm_runtime_mark_last_busy(v3d->dev); -+ pm_runtime_put_autosuspend(v3d->dev); -+ - return ret; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0227-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch b/target/linux/bcm27xx/patches-5.4/950-0227-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch new file mode 100644 index 0000000000..cb5b6d5aa7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0227-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch @@ -0,0 +1,80 @@ +From c27d4bbba9593a6ded8f482610a0247da66d78a9 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 18 Mar 2019 16:38:32 -0700 +Subject: [PATCH] drm/vc4: Expose the format modifiers for firmware + kms. + +This should technically not expose VC4_T_TILED on pi4. However, if we +don't expose anything, then userspace will assume that display can +handle whatever modifiers 3d can do (UIF on 2711). By exposing a +list, that will get intersected with what 3D can do so that we get T +tiling for display on 2710 and linear on 2711. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 33 +++++++++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -281,6 +281,27 @@ static void vc4_plane_destroy(struct drm + drm_plane_cleanup(plane); + } + ++static bool vc4_fkms_format_mod_supported(struct drm_plane *plane, ++ uint32_t format, ++ uint64_t modifier) ++{ ++ /* Support T_TILING for RGB formats only. */ ++ switch (format) { ++ case DRM_FORMAT_XRGB8888: ++ case DRM_FORMAT_ARGB8888: ++ switch (modifier) { ++ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: ++ case DRM_FORMAT_MOD_LINEAR: ++ case DRM_FORMAT_MOD_BROADCOM_UIF: ++ return true; ++ default: ++ return false; ++ } ++ default: ++ return false; ++ } ++} ++ + static const struct drm_plane_funcs vc4_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, +@@ -289,6 +310,7 @@ static const struct drm_plane_funcs vc4_ + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, ++ .format_mod_supported = vc4_fkms_format_mod_supported, + }; + + static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = { +@@ -316,6 +338,14 @@ static struct drm_plane *vc4_fkms_plane_ + u32 argb8888 = DRM_FORMAT_ARGB8888; + int ret = 0; + bool primary = (type == DRM_PLANE_TYPE_PRIMARY); ++ static const uint64_t modifiers[] = { ++ DRM_FORMAT_MOD_LINEAR, ++ /* VC4_T_TILED should come after linear, because we ++ * would prefer to scan out linear (less bus traffic). ++ */ ++ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, ++ DRM_FORMAT_MOD_INVALID, ++ }; + + vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), + GFP_KERNEL); +@@ -327,7 +357,8 @@ static struct drm_plane *vc4_fkms_plane_ + plane = &vc4_plane->base; + ret = drm_universal_plane_init(dev, plane, 0xff, + &vc4_plane_funcs, +- primary ? &xrgb8888 : &argb8888, 1, NULL, ++ primary ? &xrgb8888 : &argb8888, 1, ++ modifiers, + type, primary ? "primary" : "cursor"); + + if (type == DRM_PLANE_TYPE_PRIMARY) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0228-drm-v3d-Hook-up-the-runtime-PM-ops.patch b/target/linux/bcm27xx/patches-5.4/950-0228-drm-v3d-Hook-up-the-runtime-PM-ops.patch deleted file mode 100644 index 438922177d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0228-drm-v3d-Hook-up-the-runtime-PM-ops.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0b1f35dfb545dab884df2b4761e1af731f41ca9e Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Mon, 14 Jan 2019 14:47:57 -0800 -Subject: [PATCH] drm/v3d: Hook up the runtime PM ops. - -In translating the runtime PM code from vc4, I missed the ".pm" -assignment to actually connect them up. Fixes missing MMU setup if -runtime PM resets V3D. - -Signed-off-by: Eric Anholt -(cherry picked from commit ca197699af29baa8236c74c53d4904ca8957ee06) ---- - drivers/gpu/drm/v3d/v3d_drv.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -69,7 +69,7 @@ static int v3d_runtime_resume(struct dev - } - #endif - --static const struct dev_pm_ops v3d_v3d_pm_ops = { -+static const struct dev_pm_ops v3d_pm_ops = { - SET_RUNTIME_PM_OPS(v3d_runtime_suspend, v3d_runtime_resume, NULL) - }; - -@@ -362,6 +362,7 @@ static struct platform_driver v3d_platfo - .driver = { - .name = "v3d", - .of_match_table = v3d_of_match, -+ .pm = &v3d_pm_ops, - }, - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0228-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch b/target/linux/bcm27xx/patches-5.4/950-0228-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch new file mode 100644 index 0000000000..3b03c98088 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0228-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch @@ -0,0 +1,53 @@ +From c71f09dafd82a37a488029f33552a45a99d0a9a6 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 2 Apr 2019 13:29:00 -0700 +Subject: [PATCH] drm/vc4: Fix vblank timestamping for firmwarekms. + +The core doesn't expect a false return from the scanoutpos function in +normal usage, so we were doing the precise vblank timestamping path +and thus "immediate" vblank disables (even though firmwarekms can't +actually disable vblanks interrupts, sigh), and the kernel would get +confused when getting timestamp info when also turning vblanks back +on. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 3 --- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++ + 2 files changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -97,9 +97,6 @@ bool vc4_crtc_get_scanoutpos(struct drm_ + int vblank_lines; + bool ret = false; + +- if (vc4->firmware_kms) +- return 0; +- + /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ + + /* Get optional system timestamp before query. */ +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -20,6 +20,7 @@ + #include "drm/drm_crtc_helper.h" + #include "drm/drm_fourcc.h" + #include "drm/drm_probe_helper.h" ++#include "drm/drm_drv.h" + #include "linux/clk.h" + #include "linux/debugfs.h" + #include "drm/drm_fb_cma_helper.h" +@@ -673,6 +674,12 @@ static int vc4_fkms_bind(struct device * + + vc4->firmware_kms = true; + ++ /* firmware kms doesn't have precise a scanoutpos implementation, so ++ * we can't do the precise vblank timestamp mode. ++ */ ++ drm->driver->get_scanout_position = NULL; ++ drm->driver->get_vblank_timestamp = NULL; ++ + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); + if (!vc4_crtc) + return -ENOMEM; diff --git a/target/linux/bcm27xx/patches-5.4/950-0229-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch b/target/linux/bcm27xx/patches-5.4/950-0229-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch deleted file mode 100644 index ccd6de065c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0229-drm-vc4-Fix-synchronization-firmwarekms-against-GL-r.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 87df00d6b301f5de54443ac7e3765dce983e8b6a Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Thu, 28 Mar 2019 11:58:51 -0700 -Subject: [PATCH] drm/vc4: Fix synchronization firmwarekms against GL - rendering. - -We would present the framebuffer immediately without waiting for -rendering to finish first, resulting in stuttering and flickering as a -window was dragged around when the GPU was busy enough to not just win -the race. - -Signed-off-by: Eric Anholt ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -15,6 +15,7 @@ - */ - - #include "drm/drm_atomic_helper.h" -+#include "drm/drm_gem_framebuffer_helper.h" - #include "drm/drm_plane_helper.h" - #include "drm/drm_crtc_helper.h" - #include "drm/drm_fourcc.h" -@@ -291,7 +292,7 @@ static const struct drm_plane_funcs vc4_ - }; - - static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = { -- .prepare_fb = NULL, -+ .prepare_fb = drm_gem_fb_prepare_fb, - .cleanup_fb = NULL, - .atomic_check = vc4_plane_atomic_check, - .atomic_update = vc4_primary_plane_atomic_update, -@@ -299,7 +300,7 @@ static const struct drm_plane_helper_fun - }; - - static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = { -- .prepare_fb = NULL, -+ .prepare_fb = drm_gem_fb_prepare_fb, - .cleanup_fb = NULL, - .atomic_check = vc4_plane_atomic_check, - .atomic_update = vc4_cursor_plane_atomic_update, diff --git a/target/linux/bcm27xx/patches-5.4/950-0229-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch b/target/linux/bcm27xx/patches-5.4/950-0229-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch new file mode 100644 index 0000000000..fc84f535de --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0229-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch @@ -0,0 +1,179 @@ +From b721bcc62759ae7a2d9730d1121974702be96d7c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 26 Mar 2019 14:43:06 +0000 +Subject: [PATCH] gpu: vc4-fkms: Switch to the newer mailbox frame + buffer API. + +The old mailbox FB API was ideally deprecated but still used by +the FKMS driver. +Update to the newer API. + +NB This needs current firmware that accepts ARM allocated buffers +through the newer API. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 109 +++++++++++++------------ + 1 file changed, 57 insertions(+), 52 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -30,6 +30,25 @@ + #include "vc4_regs.h" + #include + ++struct fb_alloc_tags { ++ struct rpi_firmware_property_tag_header tag1; ++ u32 xres, yres; ++ struct rpi_firmware_property_tag_header tag2; ++ u32 xres_virtual, yres_virtual; ++ struct rpi_firmware_property_tag_header tag3; ++ u32 bpp; ++ struct rpi_firmware_property_tag_header tag4; ++ u32 xoffset, yoffset; ++ struct rpi_firmware_property_tag_header tag5; ++ u32 base, screen_size; ++ struct rpi_firmware_property_tag_header tag6; ++ u32 pitch; ++ struct rpi_firmware_property_tag_header tag7; ++ u32 alpha_mode; ++ struct rpi_firmware_property_tag_header tag8; ++ u32 layer; ++}; ++ + /* The firmware delivers a vblank interrupt to us through the SMI + * hardware, which has only this one register. + */ +@@ -123,45 +142,39 @@ static void vc4_primary_plane_atomic_upd + struct drm_plane_state *old_state) + { + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); +- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); +- volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo; ++ u32 format = fb->format->format; ++ struct fb_alloc_tags fbinfo = { ++ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT, ++ 8, 0, }, ++ .xres = state->crtc_w, ++ .yres = state->crtc_h, ++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT, ++ 8, 0, }, ++ .xres_virtual = state->crtc_w, ++ .yres_virtual = state->crtc_h, ++ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 }, ++ .bpp = 32, ++ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 }, ++ .xoffset = 0, ++ .yoffset = 0, ++ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 }, ++ .base = bo->paddr + fb->offsets[0], ++ .screen_size = state->crtc_w * state->crtc_h * 4, ++ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 }, ++ .pitch = fb->pitches[0], ++ .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 }, ++ .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2, ++ .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 }, ++ .layer = -127, ++ }; + u32 bpp = 32; + int ret; + +- fbinfo->xres = state->crtc_w; +- fbinfo->yres = state->crtc_h; +- fbinfo->xres_virtual = state->crtc_w; +- fbinfo->yres_virtual = state->crtc_h; +- fbinfo->bpp = bpp; +- fbinfo->xoffset = state->crtc_x; +- fbinfo->yoffset = state->crtc_y; +- fbinfo->base = bo->paddr + fb->offsets[0]; +- fbinfo->pitch = fb->pitches[0]; +- + if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED) +- fbinfo->bpp |= BIT(31); +- +- /* A bug in the firmware makes it so that if the fb->base is +- * set to nonzero, the configured pitch gets overwritten with +- * the previous pitch. So, to get the configured pitch +- * recomputed, we have to make it allocate itself a new buffer +- * in VC memory, first. +- */ +- if (vc4_plane->pitch != fb->pitches[0]) { +- u32 saved_base = fbinfo->base; +- fbinfo->base = 0; +- +- ret = rpi_firmware_transaction(vc4->firmware, +- RPI_FIRMWARE_CHAN_FB, +- vc4_plane->fbinfo_bus_addr); +- fbinfo->base = saved_base; +- +- vc4_plane->pitch = fbinfo->pitch; +- WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]); +- } ++ fbinfo.bpp |= BIT(31); + + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n", + plane->base.id, plane->name, +@@ -170,14 +183,13 @@ static void vc4_primary_plane_atomic_upd + bpp, + state->crtc_x, + state->crtc_y, +- &fbinfo->base, ++ &fbinfo.base, + fb->pitches[0]); + +- ret = rpi_firmware_transaction(vc4->firmware, +- RPI_FIRMWARE_CHAN_FB, +- vc4_plane->fbinfo_bus_addr); +- WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]); +- WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]); ++ ret = rpi_firmware_property_list(vc4->firmware, &fbinfo, ++ sizeof(fbinfo)); ++ WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]); ++ WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]); + + /* If the CRTC is on (or going to be on) and we're enabled, + * then unblank. Otherwise, stay blank until CRTC enable. +@@ -333,10 +345,10 @@ static const struct drm_plane_helper_fun + static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, + enum drm_plane_type type) + { ++ /* Primary and cursor planes only */ + struct drm_plane *plane = NULL; + struct vc4_fkms_plane *vc4_plane; +- u32 xrgb8888 = DRM_FORMAT_XRGB8888; +- u32 argb8888 = DRM_FORMAT_ARGB8888; ++ u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888}; + int ret = 0; + bool primary = (type == DRM_PLANE_TYPE_PRIMARY); + static const uint64_t modifiers[] = { +@@ -358,22 +370,15 @@ static struct drm_plane *vc4_fkms_plane_ + plane = &vc4_plane->base; + ret = drm_universal_plane_init(dev, plane, 0xff, + &vc4_plane_funcs, +- primary ? &xrgb8888 : &argb8888, 1, +- modifiers, ++ formats, primary ? 2 : 1, modifiers, + type, primary ? "primary" : "cursor"); + +- if (type == DRM_PLANE_TYPE_PRIMARY) { +- vc4_plane->fbinfo = +- dma_alloc_coherent(dev->dev, +- sizeof(*vc4_plane->fbinfo), +- &vc4_plane->fbinfo_bus_addr, +- GFP_KERNEL); +- memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo)); +- ++ if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs); +- } else { ++ else + drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs); +- } ++ ++ drm_plane_create_alpha_property(plane); + + return plane; + fail: diff --git a/target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch b/target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch new file mode 100644 index 0000000000..6878a0c26a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch @@ -0,0 +1,853 @@ +From 75e1dce99c260cb1365edd9af68cb5c07487831c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 27 Mar 2019 17:45:01 +0000 +Subject: [PATCH] drm: vc4: Add an overlay plane to vc4-firmware-kms + +This uses a new API that is exposed via the mailbox service +to stick an element straight on the screen using DispmanX. + +The primary and cursor planes have also been switched to using +the new plane API, and it supports layering based on the DRM +zpos parameter. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 518 ++++++++++++++------- + drivers/gpu/drm/vc4/vc4_kms.c | 1 + + drivers/gpu/drm/vc4/vc_image_types.h | 143 ++++++ + include/soc/bcm2835/raspberrypi-firmware.h | 2 + + 4 files changed, 495 insertions(+), 169 deletions(-) + create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -28,8 +28,46 @@ + #include "linux/of_device.h" + #include "vc4_drv.h" + #include "vc4_regs.h" ++#include "vc_image_types.h" + #include + ++struct set_plane { ++ u8 display; ++ u8 plane_id; ++ u8 vc_image_type; ++ s8 layer; ++ ++ u16 width; ++ u16 height; ++ ++ u16 pitch; ++ u16 vpitch; ++ ++ u32 src_x; /* 16p16 */ ++ u32 src_y; /* 16p16 */ ++ ++ u32 src_w; /* 16p16 */ ++ u32 src_h; /* 16p16 */ ++ ++ s16 dst_x; ++ s16 dst_y; ++ ++ u16 dst_w; ++ u16 dst_h; ++ ++ u8 alpha; ++ u8 num_planes; ++ u8 is_vu; ++ u8 padding; ++ ++ u32 planes[4]; /* DMA address of each plane */ ++}; ++ ++struct mailbox_set_plane { ++ struct rpi_firmware_property_tag_header tag; ++ struct set_plane plane; ++}; ++ + struct fb_alloc_tags { + struct rpi_firmware_property_tag_header tag1; + u32 xres, yres; +@@ -49,6 +87,79 @@ struct fb_alloc_tags { + u32 layer; + }; + ++static const struct vc_image_format { ++ u32 drm; /* DRM_FORMAT_* */ ++ u32 vc_image; /* VC_IMAGE_* */ ++ u32 is_vu; ++} vc_image_formats[] = { ++ { ++ .drm = DRM_FORMAT_XRGB8888, ++ .vc_image = VC_IMAGE_XRGB8888, ++ }, ++ { ++ .drm = DRM_FORMAT_ARGB8888, ++ .vc_image = VC_IMAGE_ARGB8888, ++ }, ++/* ++ * FIXME: Need to resolve which DRM format goes to which vc_image format ++ * for the remaining RGBA and RGBX formats. ++ * { ++ * .drm = DRM_FORMAT_ABGR8888, ++ * .vc_image = VC_IMAGE_RGBA8888, ++ * }, ++ * { ++ * .drm = DRM_FORMAT_XBGR8888, ++ * .vc_image = VC_IMAGE_RGBA8888, ++ * }, ++ */ ++ { ++ .drm = DRM_FORMAT_RGB565, ++ .vc_image = VC_IMAGE_RGB565, ++ }, ++ { ++ .drm = DRM_FORMAT_RGB888, ++ .vc_image = VC_IMAGE_BGR888, ++ }, ++ { ++ .drm = DRM_FORMAT_BGR888, ++ .vc_image = VC_IMAGE_RGB888, ++ }, ++ { ++ .drm = DRM_FORMAT_YUV422, ++ .vc_image = VC_IMAGE_YUV422PLANAR, ++ }, ++ { ++ .drm = DRM_FORMAT_YUV420, ++ .vc_image = VC_IMAGE_YUV420, ++ }, ++ { ++ .drm = DRM_FORMAT_YVU420, ++ .vc_image = VC_IMAGE_YUV420, ++ .is_vu = 1, ++ }, ++ { ++ .drm = DRM_FORMAT_NV12, ++ .vc_image = VC_IMAGE_YUV420SP, ++ }, ++ { ++ .drm = DRM_FORMAT_NV21, ++ .vc_image = VC_IMAGE_YUV420SP, ++ .is_vu = 1, ++ }, ++}; ++ ++static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) { ++ if (vc_image_formats[i].drm == drm_format) ++ return &vc_image_formats[i]; ++ } ++ ++ return NULL; ++} ++ + /* The firmware delivers a vblank interrupt to us through the SMI + * hardware, which has only this one register. + */ +@@ -115,6 +226,7 @@ struct vc4_fkms_plane { + struct fbinfo_s *fbinfo; + dma_addr_t fbinfo_bus_addr; + u32 pitch; ++ struct mailbox_set_plane mb; + }; + + static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane) +@@ -122,165 +234,183 @@ static inline struct vc4_fkms_plane *to_ + return (struct vc4_fkms_plane *)plane; + } + +-/* Turns the display on/off. */ +-static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank) ++static int vc4_plane_set_blank(struct drm_plane *plane, bool blank) + { + struct vc4_dev *vc4 = to_vc4_dev(plane->dev); ++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); ++ struct mailbox_set_plane blank_mb = { ++ .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 }, ++ .plane = { ++ .display = vc4_plane->mb.plane.display, ++ .plane_id = vc4_plane->mb.plane.plane_id, ++ } ++ }; ++ int ret; + +- u32 packet = blank; +- +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s", ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s", + plane->base.id, plane->name, + blank ? "blank" : "unblank"); + +- return rpi_firmware_property(vc4->firmware, +- RPI_FIRMWARE_FRAMEBUFFER_BLANK, +- &packet, sizeof(packet)); ++ if (blank) ++ ret = rpi_firmware_property_list(vc4->firmware, &blank_mb, ++ sizeof(blank_mb)); ++ else ++ ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb, ++ sizeof(vc4_plane->mb)); ++ ++ WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware", ++ __func__); ++ return ret; + } + +-static void vc4_primary_plane_atomic_update(struct drm_plane *plane, +- struct drm_plane_state *old_state) ++static void vc4_plane_atomic_update(struct drm_plane *plane, ++ struct drm_plane_state *old_state) + { +- struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); +- u32 format = fb->format->format; +- struct fb_alloc_tags fbinfo = { +- .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT, +- 8, 0, }, +- .xres = state->crtc_w, +- .yres = state->crtc_h, +- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT, +- 8, 0, }, +- .xres_virtual = state->crtc_w, +- .yres_virtual = state->crtc_h, +- .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 }, +- .bpp = 32, +- .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 }, +- .xoffset = 0, +- .yoffset = 0, +- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 }, +- .base = bo->paddr + fb->offsets[0], +- .screen_size = state->crtc_w * state->crtc_h * 4, +- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 }, +- .pitch = fb->pitches[0], +- .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 }, +- .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2, +- .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 }, +- .layer = -127, +- }; +- u32 bpp = 32; +- int ret; ++ const struct drm_format_info *drm_fmt = fb->format; ++ const struct vc_image_format *vc_fmt = ++ vc4_get_vc_image_fmt(drm_fmt->format); ++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); ++ struct mailbox_set_plane *mb = &vc4_plane->mb; ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); ++ int num_planes = fb->format->num_planes; ++ struct drm_display_mode *mode = &state->crtc->mode; + +- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED) +- fbinfo.bpp |= BIT(31); ++ mb->plane.vc_image_type = vc_fmt->vc_image; ++ mb->plane.width = fb->width; ++ mb->plane.height = fb->height; ++ mb->plane.pitch = fb->pitches[0]; ++ mb->plane.src_w = state->src_w; ++ mb->plane.src_h = state->src_h; ++ mb->plane.src_x = state->src_x; ++ mb->plane.src_y = state->src_y; ++ mb->plane.dst_w = state->crtc_w; ++ mb->plane.dst_h = state->crtc_h; ++ mb->plane.dst_x = state->crtc_x; ++ mb->plane.dst_y = state->crtc_y; ++ mb->plane.alpha = state->alpha >> 8; ++ mb->plane.layer = state->normalized_zpos ? ++ state->normalized_zpos : -127; ++ mb->plane.num_planes = num_planes; ++ mb->plane.is_vu = vc_fmt->is_vu; ++ mb->plane.planes[0] = bo->paddr + fb->offsets[0]; + +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n", ++ /* FIXME: If the dest rect goes off screen then clip the src rect so we ++ * don't have off-screen pixels. ++ */ ++ if (plane->type == DRM_PLANE_TYPE_CURSOR) { ++ /* There is no scaling on the cursor plane, therefore the calcs ++ * to alter the source crop as the cursor goes off the screen ++ * are simple. ++ */ ++ if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) { ++ mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x; ++ mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x) ++ << 16; ++ } ++ if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) { ++ mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y; ++ mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y) ++ << 16; ++ } ++ } ++ ++ if (num_planes > 1) { ++ /* Assume this must be YUV */ ++ /* Makes assumptions on the stride for the chroma planes as we ++ * can't easily plumb in non-standard pitches. ++ */ ++ mb->plane.planes[1] = bo->paddr + fb->offsets[1]; ++ if (num_planes > 2) ++ mb->plane.planes[2] = bo->paddr + fb->offsets[2]; ++ else ++ mb->plane.planes[2] = 0; ++ ++ /* Special case the YUV420 with U and V as line interleaved ++ * planes as we have special handling for that case. ++ */ ++ if (num_planes == 3 && ++ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1]) ++ mb->plane.vc_image_type = VC_IMAGE_YUV420_S; ++ } else { ++ mb->plane.planes[1] = 0; ++ mb->plane.planes[2] = 0; ++ } ++ mb->plane.planes[3] = 0; ++ ++ switch (fb->modifier) { ++ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: ++ switch (mb->plane.vc_image_type) { ++ case VC_IMAGE_RGBX32: ++ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32; ++ break; ++ case VC_IMAGE_RGBA32: ++ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32; ++ break; ++ case VC_IMAGE_RGB565: ++ mb->plane.vc_image_type = VC_IMAGE_TF_RGB565; ++ break; ++ } ++ break; ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ mb->plane.vc_image_type = VC_IMAGE_YUV_UV; ++ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier); ++ break; ++ } ++ ++ if (vc4_crtc) { ++ mb->plane.dst_x += vc4_crtc->overscan[0]; ++ mb->plane.dst_y += vc4_crtc->overscan[1]; ++ } ++ ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n", + plane->base.id, plane->name, +- state->crtc_w, +- state->crtc_h, +- bpp, ++ mb->plane.width, ++ mb->plane.height, ++ mb->plane.vc_image_type, + state->crtc_x, + state->crtc_y, +- &fbinfo.base, +- fb->pitches[0]); +- +- ret = rpi_firmware_property_list(vc4->firmware, &fbinfo, +- sizeof(fbinfo)); +- WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]); +- WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]); +- +- /* If the CRTC is on (or going to be on) and we're enabled, ++ state->crtc_w, ++ state->crtc_h, ++ mb->plane.src_x, ++ mb->plane.src_y, ++ mb->plane.src_w, ++ mb->plane.src_h, ++ mb->plane.planes[0], ++ mb->plane.planes[1], ++ mb->plane.planes[2], ++ fb->pitches[0], ++ state->alpha, ++ state->normalized_zpos); ++ ++ /* ++ * Do NOT set now, as we haven't checked if the crtc is active or not. ++ * Set from vc4_plane_set_blank instead. ++ * ++ * If the CRTC is on (or going to be on) and we're enabled, + * then unblank. Otherwise, stay blank until CRTC enable. +- */ ++ */ + if (state->crtc->state->active) +- vc4_plane_set_primary_blank(plane, false); ++ vc4_plane_set_blank(plane, false); + } + +-static void vc4_primary_plane_atomic_disable(struct drm_plane *plane, +- struct drm_plane_state *old_state) ++static void vc4_plane_atomic_disable(struct drm_plane *plane, ++ struct drm_plane_state *old_state) + { +- vc4_plane_set_primary_blank(plane, true); +-} +- +-static void vc4_cursor_plane_atomic_update(struct drm_plane *plane, +- struct drm_plane_state *old_state) +-{ +- struct vc4_dev *vc4 = to_vc4_dev(plane->dev); ++ //struct vc4_dev *vc4 = to_vc4_dev(plane->dev); + struct drm_plane_state *state = plane->state; +- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); +- struct drm_framebuffer *fb = state->fb; +- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); +- dma_addr_t addr = bo->paddr + fb->offsets[0]; +- int ret; +- u32 packet_state[] = { +- state->crtc->state->active, +- state->crtc_x, +- state->crtc_y, +- 0 +- }; +- WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4); ++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); + +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)", ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n", + plane->base.id, plane->name, + state->crtc_w, + state->crtc_h, ++ vc4_plane->mb.plane.vc_image_type, + state->crtc_x, +- state->crtc_y, +- &addr, +- fb->pitches[0]); +- +- /* add on the top/left offsets when overscan is active */ +- if (vc4_crtc) { +- packet_state[1] += vc4_crtc->overscan[0]; +- packet_state[2] += vc4_crtc->overscan[1]; +- } +- +- ret = rpi_firmware_property(vc4->firmware, +- RPI_FIRMWARE_SET_CURSOR_STATE, +- &packet_state, +- sizeof(packet_state)); +- if (ret || packet_state[0] != 0) +- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]); +- +- /* Note: When the cursor contents change, the modesetting +- * driver calls drm_mode_cursor_univeral() with +- * DRM_MODE_CURSOR_BO, which means a new fb will be allocated. +- */ +- if (!old_state || +- state->crtc_w != old_state->crtc_w || +- state->crtc_h != old_state->crtc_h || +- fb != old_state->fb) { +- u32 packet_info[] = { state->crtc_w, state->crtc_h, +- 0, /* unused */ +- addr, +- 0, 0, /* hotx, hoty */}; +- +- ret = rpi_firmware_property(vc4->firmware, +- RPI_FIRMWARE_SET_CURSOR_INFO, +- &packet_info, +- sizeof(packet_info)); +- if (ret || packet_info[0] != 0) +- DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]); +- } +-} +- +-static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane, +- struct drm_plane_state *old_state) +-{ +- struct vc4_dev *vc4 = to_vc4_dev(plane->dev); +- u32 packet_state[] = { false, 0, 0, 0 }; +- int ret; +- +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name); +- +- ret = rpi_firmware_property(vc4->firmware, +- RPI_FIRMWARE_SET_CURSOR_STATE, +- &packet_state, +- sizeof(packet_state)); +- if (ret || packet_state[0] != 0) +- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]); ++ state->crtc_y); ++ vc4_plane_set_blank(plane, true); + } + + static int vc4_plane_atomic_check(struct drm_plane *plane, +@@ -302,6 +432,7 @@ static bool vc4_fkms_format_mod_supporte + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: ++ case DRM_FORMAT_RGB565: + switch (modifier) { + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: + case DRM_FORMAT_MOD_LINEAR: +@@ -310,8 +441,22 @@ static bool vc4_fkms_format_mod_supporte + default: + return false; + } ++ case DRM_FORMAT_NV12: ++ case DRM_FORMAT_NV21: ++ switch (fourcc_mod_broadcom_mod(modifier)) { ++ case DRM_FORMAT_MOD_LINEAR: ++ case DRM_FORMAT_MOD_BROADCOM_SAND128: ++ return true; ++ default: ++ return false; ++ } ++ case DRM_FORMAT_RGB888: ++ case DRM_FORMAT_BGR888: ++ case DRM_FORMAT_YUV422: ++ case DRM_FORMAT_YUV420: ++ case DRM_FORMAT_YVU420: + default: +- return false; ++ return (modifier == DRM_FORMAT_MOD_LINEAR); + } + } + +@@ -326,31 +471,24 @@ static const struct drm_plane_funcs vc4_ + .format_mod_supported = vc4_fkms_format_mod_supported, + }; + +-static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = { +- .prepare_fb = drm_gem_fb_prepare_fb, +- .cleanup_fb = NULL, +- .atomic_check = vc4_plane_atomic_check, +- .atomic_update = vc4_primary_plane_atomic_update, +- .atomic_disable = vc4_primary_plane_atomic_disable, +-}; +- +-static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = { ++static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { + .prepare_fb = drm_gem_fb_prepare_fb, + .cleanup_fb = NULL, + .atomic_check = vc4_plane_atomic_check, +- .atomic_update = vc4_cursor_plane_atomic_update, +- .atomic_disable = vc4_cursor_plane_atomic_disable, ++ .atomic_update = vc4_plane_atomic_update, ++ .atomic_disable = vc4_plane_atomic_disable, + }; + + static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, +- enum drm_plane_type type) ++ enum drm_plane_type type, ++ u8 plane_id) + { +- /* Primary and cursor planes only */ + struct drm_plane *plane = NULL; + struct vc4_fkms_plane *vc4_plane; +- u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888}; ++ u32 formats[ARRAY_SIZE(vc_image_formats)]; ++ unsigned int default_zpos = 0; ++ u32 num_formats = 0; + int ret = 0; +- bool primary = (type == DRM_PLANE_TYPE_PRIMARY); + static const uint64_t modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + /* VC4_T_TILED should come after linear, because we +@@ -359,6 +497,7 @@ static struct drm_plane *vc4_fkms_plane_ + DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, + DRM_FORMAT_MOD_INVALID, + }; ++ int i; + + vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), + GFP_KERNEL); +@@ -367,19 +506,48 @@ static struct drm_plane *vc4_fkms_plane_ + goto fail; + } + ++ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) ++ formats[num_formats++] = vc_image_formats[i].drm; ++ + plane = &vc4_plane->base; + ret = drm_universal_plane_init(dev, plane, 0xff, + &vc4_plane_funcs, +- formats, primary ? 2 : 1, modifiers, +- type, primary ? "primary" : "cursor"); ++ formats, num_formats, modifiers, ++ type, NULL); + +- if (type == DRM_PLANE_TYPE_PRIMARY) +- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs); +- else +- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs); ++ drm_plane_helper_add(plane, &vc4_plane_helper_funcs); + + drm_plane_create_alpha_property(plane); + ++ /* ++ * Default frame buffer setup is with FB on -127, and raspistill etc ++ * tend to drop overlays on layer 2. Cursor plane was on layer +127. ++ * ++ * For F-KMS the mailbox call allows for a s8. ++ * Remap zpos 0 to -127 for the background layer, but leave all the ++ * other layers as requested by KMS. ++ */ ++ switch (type) { ++ case DRM_PLANE_TYPE_PRIMARY: ++ default_zpos = 0; ++ break; ++ case DRM_PLANE_TYPE_OVERLAY: ++ default_zpos = 1; ++ break; ++ case DRM_PLANE_TYPE_CURSOR: ++ default_zpos = 2; ++ break; ++ } ++ drm_plane_create_zpos_property(plane, default_zpos, 0, 127); ++ ++ /* Prepare the static elements of the mailbox structure */ ++ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE; ++ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane); ++ vc4_plane->mb.tag.req_resp_size = 0; ++ vc4_plane->mb.plane.display = 0; ++ vc4_plane->mb.plane.plane_id = plane_id; ++ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127; ++ + return plane; + fail: + if (plane) +@@ -401,19 +569,23 @@ static void vc4_crtc_disable(struct drm_ + * whether anything scans out at all, but the firmware doesn't + * give us a CRTC-level control for that. + */ +- vc4_cursor_plane_atomic_disable(crtc->cursor, crtc->cursor->state); +- vc4_plane_set_primary_blank(crtc->primary, true); ++ ++ vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state); ++ vc4_plane_atomic_disable(crtc->primary, crtc->primary->state); ++ ++ /* FIXME: Disable overlay planes */ + } + + static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + { + /* Unblank the planes (if they're supposed to be displayed). */ ++ + if (crtc->primary->state->fb) +- vc4_plane_set_primary_blank(crtc->primary, false); +- if (crtc->cursor->state->fb) { +- vc4_cursor_plane_atomic_update(crtc->cursor, +- crtc->cursor->state); +- } ++ vc4_plane_set_blank(crtc->primary, false); ++ if (crtc->cursor->state->fb) ++ vc4_plane_set_blank(crtc->cursor, crtc->cursor->state); ++ ++ /* FIXME: Enable overlay planes */ + } + + static int vc4_crtc_atomic_check(struct drm_crtc *crtc, +@@ -673,8 +845,10 @@ static int vc4_fkms_bind(struct device * + struct vc4_crtc *vc4_crtc; + struct vc4_fkms_encoder *vc4_encoder; + struct drm_crtc *crtc; +- struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp; ++ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane; ++ struct drm_plane *destroy_plane, *temp; + struct device_node *firmware_node; ++ u32 blank = 1; + int ret; + + vc4->firmware_kms = true; +@@ -703,20 +877,26 @@ static int vc4_fkms_bind(struct device * + if (IS_ERR(vc4_crtc->regs)) + return PTR_ERR(vc4_crtc->regs); + +- /* For now, we create just the primary and the legacy cursor +- * planes. We should be able to stack more planes on easily, +- * but to do that we would need to compute the bandwidth +- * requirement of the plane configuration, and reject ones +- * that will take too much. +- */ +- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); ++ /* Blank the firmware provided framebuffer */ ++ rpi_firmware_property(vc4->firmware, ++ RPI_FIRMWARE_FRAMEBUFFER_BLANK, ++ &blank, sizeof(blank)); ++ ++ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0); + if (IS_ERR(primary_plane)) { + dev_err(dev, "failed to construct primary plane\n"); + ret = PTR_ERR(primary_plane); + goto err; + } + +- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR); ++ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1); ++ if (IS_ERR(overlay_plane)) { ++ dev_err(dev, "failed to construct overlay plane\n"); ++ ret = PTR_ERR(overlay_plane); ++ goto err; ++ } ++ ++ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2); + if (IS_ERR(cursor_plane)) { + dev_err(dev, "failed to construct cursor plane\n"); + ret = PTR_ERR(cursor_plane); +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -542,6 +542,7 @@ int vc4_kms_load(struct drm_device *dev) + dev->mode_config.preferred_depth = 24; + dev->mode_config.async_page_flip = true; + dev->mode_config.allow_fb_modifiers = true; ++ dev->mode_config.normalize_zpos = true; + + drm_modeset_lock_init(&vc4->ctm_state_lock); + +--- /dev/null ++++ b/drivers/gpu/drm/vc4/vc_image_types.h +@@ -0,0 +1,143 @@ ++ ++/* ++ * Copyright (c) 2012, Broadcom Europe Ltd ++ * ++ * Values taken from vc_image_types.h released by Broadcom at ++ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h ++ * ++ * 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. ++ */ ++ ++enum { ++ VC_IMAGE_MIN = 0, //bounds for error checking ++ ++ VC_IMAGE_RGB565 = 1, ++ VC_IMAGE_1BPP, ++ VC_IMAGE_YUV420, ++ VC_IMAGE_48BPP, ++ VC_IMAGE_RGB888, ++ VC_IMAGE_8BPP, ++ /* 4bpp palettised image */ ++ VC_IMAGE_4BPP, ++ /* A separated format of 16 colour/light shorts followed by 16 z ++ * values ++ */ ++ VC_IMAGE_3D32, ++ /* 16 colours followed by 16 z values */ ++ VC_IMAGE_3D32B, ++ /* A separated format of 16 material/colour/light shorts followed by ++ * 16 z values ++ */ ++ VC_IMAGE_3D32MAT, ++ /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */ ++ VC_IMAGE_RGB2X9, ++ /* 32-bit format holding 18 bits of 6.6.6 RGB */ ++ VC_IMAGE_RGB666, ++ /* 4bpp palettised image with embedded palette */ ++ VC_IMAGE_PAL4_OBSOLETE, ++ /* 8bpp palettised image with embedded palette */ ++ VC_IMAGE_PAL8_OBSOLETE, ++ /* RGB888 with an alpha byte after each pixel */ ++ VC_IMAGE_RGBA32, ++ /* a line of Y (32-byte padded), a line of U (16-byte padded), and a ++ * line of V (16-byte padded) ++ */ ++ VC_IMAGE_YUV422, ++ /* RGB565 with a transparent patch */ ++ VC_IMAGE_RGBA565, ++ /* Compressed (4444) version of RGBA32 */ ++ VC_IMAGE_RGBA16, ++ /* VCIII codec format */ ++ VC_IMAGE_YUV_UV, ++ /* VCIII T-format RGBA8888 */ ++ VC_IMAGE_TF_RGBA32, ++ /* VCIII T-format RGBx8888 */ ++ VC_IMAGE_TF_RGBX32, ++ /* VCIII T-format float */ ++ VC_IMAGE_TF_FLOAT, ++ /* VCIII T-format RGBA4444 */ ++ VC_IMAGE_TF_RGBA16, ++ /* VCIII T-format RGB5551 */ ++ VC_IMAGE_TF_RGBA5551, ++ /* VCIII T-format RGB565 */ ++ VC_IMAGE_TF_RGB565, ++ /* VCIII T-format 8-bit luma and 8-bit alpha */ ++ VC_IMAGE_TF_YA88, ++ /* VCIII T-format 8 bit generic sample */ ++ VC_IMAGE_TF_BYTE, ++ /* VCIII T-format 8-bit palette */ ++ VC_IMAGE_TF_PAL8, ++ /* VCIII T-format 4-bit palette */ ++ VC_IMAGE_TF_PAL4, ++ /* VCIII T-format Ericsson Texture Compressed */ ++ VC_IMAGE_TF_ETC1, ++ /* RGB888 with R & B swapped */ ++ VC_IMAGE_BGR888, ++ /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after ++ * each row of pixels ++ */ ++ VC_IMAGE_BGR888_NP, ++ /* Bayer image, extra defines which variant is being used */ ++ VC_IMAGE_BAYER, ++ /* General wrapper for codec images e.g. JPEG from camera */ ++ VC_IMAGE_CODEC, ++ /* VCIII codec format */ ++ VC_IMAGE_YUV_UV32, ++ /* VCIII T-format 8-bit luma */ ++ VC_IMAGE_TF_Y8, ++ /* VCIII T-format 8-bit alpha */ ++ VC_IMAGE_TF_A8, ++ /* VCIII T-format 16-bit generic sample */ ++ VC_IMAGE_TF_SHORT, ++ /* VCIII T-format 1bpp black/white */ ++ VC_IMAGE_TF_1BPP, ++ VC_IMAGE_OPENGL, ++ /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */ ++ VC_IMAGE_YUV444I, ++ /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on ++ * a per line basis) ++ */ ++ VC_IMAGE_YUV422PLANAR, ++ /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */ ++ VC_IMAGE_ARGB8888, ++ /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */ ++ VC_IMAGE_XRGB8888, ++ ++ /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */ ++ VC_IMAGE_YUV422YUYV, ++ VC_IMAGE_YUV422YVYU, ++ VC_IMAGE_YUV422UYVY, ++ VC_IMAGE_YUV422VYUY, ++ ++ /* 32bpp like RGBA32 but with unused alpha */ ++ VC_IMAGE_RGBX32, ++ /* 32bpp, corresponding to RGBA with unused alpha */ ++ VC_IMAGE_RGBX8888, ++ /* 32bpp, corresponding to BGRA with unused alpha */ ++ VC_IMAGE_BGRX8888, ++ ++ /* Y as a plane, then UV byte interleaved in plane with with same pitch, ++ * half height ++ */ ++ VC_IMAGE_YUV420SP, ++ ++ /* Y, U, & V planes separately 4:4:4 */ ++ VC_IMAGE_YUV444PLANAR, ++ ++ /* T-format 8-bit U - same as TF_Y8 buf from U plane */ ++ VC_IMAGE_TF_U8, ++ /* T-format 8-bit U - same as TF_Y8 buf from V plane */ ++ VC_IMAGE_TF_V8, ++ ++ /* YUV4:2:0 planar, 16bit values */ ++ VC_IMAGE_YUV420_16, ++ /* YUV4:2:0 codec format, 16bit values */ ++ VC_IMAGE_YUV_UV_16, ++ /* YUV4:2:0 with U,V in side-by-side format */ ++ VC_IMAGE_YUV420_S, ++ ++ VC_IMAGE_MAX, /* bounds for error checking */ ++ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff, ++}; +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -147,6 +147,8 @@ enum rpi_firmware_property_tag { + + RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, + ++ RPI_FIRMWARE_SET_PLANE = 0x00048015, ++ + RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, + RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch b/target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch deleted file mode 100644 index cb5b6d5aa7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0230-drm-vc4-Expose-the-format-modifiers-for-firmware-kms.patch +++ /dev/null @@ -1,80 +0,0 @@ -From c27d4bbba9593a6ded8f482610a0247da66d78a9 Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Mon, 18 Mar 2019 16:38:32 -0700 -Subject: [PATCH] drm/vc4: Expose the format modifiers for firmware - kms. - -This should technically not expose VC4_T_TILED on pi4. However, if we -don't expose anything, then userspace will assume that display can -handle whatever modifiers 3d can do (UIF on 2711). By exposing a -list, that will get intersected with what 3D can do so that we get T -tiling for display on 2710 and linear on 2711. - -Signed-off-by: Eric Anholt ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 33 +++++++++++++++++++++++++- - 1 file changed, 32 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -281,6 +281,27 @@ static void vc4_plane_destroy(struct drm - drm_plane_cleanup(plane); - } - -+static bool vc4_fkms_format_mod_supported(struct drm_plane *plane, -+ uint32_t format, -+ uint64_t modifier) -+{ -+ /* Support T_TILING for RGB formats only. */ -+ switch (format) { -+ case DRM_FORMAT_XRGB8888: -+ case DRM_FORMAT_ARGB8888: -+ switch (modifier) { -+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: -+ case DRM_FORMAT_MOD_LINEAR: -+ case DRM_FORMAT_MOD_BROADCOM_UIF: -+ return true; -+ default: -+ return false; -+ } -+ default: -+ return false; -+ } -+} -+ - static const struct drm_plane_funcs vc4_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, -@@ -289,6 +310,7 @@ static const struct drm_plane_funcs vc4_ - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -+ .format_mod_supported = vc4_fkms_format_mod_supported, - }; - - static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = { -@@ -316,6 +338,14 @@ static struct drm_plane *vc4_fkms_plane_ - u32 argb8888 = DRM_FORMAT_ARGB8888; - int ret = 0; - bool primary = (type == DRM_PLANE_TYPE_PRIMARY); -+ static const uint64_t modifiers[] = { -+ DRM_FORMAT_MOD_LINEAR, -+ /* VC4_T_TILED should come after linear, because we -+ * would prefer to scan out linear (less bus traffic). -+ */ -+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, -+ DRM_FORMAT_MOD_INVALID, -+ }; - - vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), - GFP_KERNEL); -@@ -327,7 +357,8 @@ static struct drm_plane *vc4_fkms_plane_ - plane = &vc4_plane->base; - ret = drm_universal_plane_init(dev, plane, 0xff, - &vc4_plane_funcs, -- primary ? &xrgb8888 : &argb8888, 1, NULL, -+ primary ? &xrgb8888 : &argb8888, 1, -+ modifiers, - type, primary ? "primary" : "cursor"); - - if (type == DRM_PLANE_TYPE_PRIMARY) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0231-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch b/target/linux/bcm27xx/patches-5.4/950-0231-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch deleted file mode 100644 index 3b03c98088..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0231-drm-vc4-Fix-vblank-timestamping-for-firmwarekms.patch +++ /dev/null @@ -1,53 +0,0 @@ -From c71f09dafd82a37a488029f33552a45a99d0a9a6 Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Tue, 2 Apr 2019 13:29:00 -0700 -Subject: [PATCH] drm/vc4: Fix vblank timestamping for firmwarekms. - -The core doesn't expect a false return from the scanoutpos function in -normal usage, so we were doing the precise vblank timestamping path -and thus "immediate" vblank disables (even though firmwarekms can't -actually disable vblanks interrupts, sigh), and the kernel would get -confused when getting timestamp info when also turning vblanks back -on. - -Signed-off-by: Eric Anholt ---- - drivers/gpu/drm/vc4/vc4_crtc.c | 3 --- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++ - 2 files changed, 7 insertions(+), 3 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_crtc.c -+++ b/drivers/gpu/drm/vc4/vc4_crtc.c -@@ -97,9 +97,6 @@ bool vc4_crtc_get_scanoutpos(struct drm_ - int vblank_lines; - bool ret = false; - -- if (vc4->firmware_kms) -- return 0; -- - /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ - - /* Get optional system timestamp before query. */ ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -20,6 +20,7 @@ - #include "drm/drm_crtc_helper.h" - #include "drm/drm_fourcc.h" - #include "drm/drm_probe_helper.h" -+#include "drm/drm_drv.h" - #include "linux/clk.h" - #include "linux/debugfs.h" - #include "drm/drm_fb_cma_helper.h" -@@ -673,6 +674,12 @@ static int vc4_fkms_bind(struct device * - - vc4->firmware_kms = true; - -+ /* firmware kms doesn't have precise a scanoutpos implementation, so -+ * we can't do the precise vblank timestamp mode. -+ */ -+ drm->driver->get_scanout_position = NULL; -+ drm->driver->get_vblank_timestamp = NULL; -+ - vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); - if (!vc4_crtc) - return -ENOMEM; diff --git a/target/linux/bcm27xx/patches-5.4/950-0231-drm-vc4-Increase-max-screen-size-to-4096x4096.patch b/target/linux/bcm27xx/patches-5.4/950-0231-drm-vc4-Increase-max-screen-size-to-4096x4096.patch new file mode 100644 index 0000000000..92d3d35ead --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0231-drm-vc4-Increase-max-screen-size-to-4096x4096.patch @@ -0,0 +1,26 @@ +From a954d2d91eff32d1ab8baae12b8ac7dc856711cb Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 3 Apr 2019 15:20:05 +0100 +Subject: [PATCH] drm: vc4: Increase max screen size to 4096x4096. + +We now should support 4k screens, therefore this limit needs to +be increased. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev) + return ret; + } + +- dev->mode_config.max_width = 2048; +- dev->mode_config.max_height = 2048; ++ dev->mode_config.max_width = 4096; ++ dev->mode_config.max_height = 4096; + dev->mode_config.funcs = &vc4_mode_funcs; + dev->mode_config.preferred_depth = 24; + dev->mode_config.async_page_flip = true; diff --git a/target/linux/bcm27xx/patches-5.4/950-0232-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch b/target/linux/bcm27xx/patches-5.4/950-0232-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch new file mode 100644 index 0000000000..cbba43bf2e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0232-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch @@ -0,0 +1,282 @@ +From b7a52df8162e1eb55a8403e9e9af79c581206335 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 3 Apr 2019 17:15:45 +0100 +Subject: [PATCH] drm: vc4: Add support for multiple displays to fkms + +There is a slightly nasty hack in that all crtcs share the +same SMI interrupt from the firmware. This seems to currently +work well enough, but ought to be fixed at a later date. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 162 +++++++++++++++++-------- + 1 file changed, 113 insertions(+), 49 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -31,6 +31,8 @@ + #include "vc_image_types.h" + #include + ++#define PLANES_PER_CRTC 3 ++ + struct set_plane { + u8 display; + u8 plane_id; +@@ -177,6 +179,7 @@ struct vc4_crtc { + struct drm_pending_vblank_event *event; + u32 overscan[4]; + bool vblank_enabled; ++ u32 display_number; + }; + + static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc) +@@ -481,6 +484,7 @@ static const struct drm_plane_helper_fun + + static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, + enum drm_plane_type type, ++ u8 display_num, + u8 plane_id) + { + struct drm_plane *plane = NULL; +@@ -544,7 +548,7 @@ static struct drm_plane *vc4_fkms_plane_ + vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE; + vc4_plane->mb.tag.buf_size = sizeof(struct set_plane); + vc4_plane->mb.tag.req_resp_size = 0; +- vc4_plane->mb.plane.display = 0; ++ vc4_plane->mb.plane.display = display_num; + vc4_plane->mb.plane.plane_id = plane_id; + vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127; + +@@ -631,16 +635,20 @@ static void vc4_crtc_handle_page_flip(st + + static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) + { +- struct vc4_crtc *vc4_crtc = data; +- u32 stat = readl(vc4_crtc->regs + SMICS); ++ struct vc4_crtc **crtc_list = data; ++ int i; ++ u32 stat = readl(crtc_list[0]->regs + SMICS); + irqreturn_t ret = IRQ_NONE; + + if (stat & SMICS_INTERRUPTS) { +- writel(0, vc4_crtc->regs + SMICS); +- if (vc4_crtc->vblank_enabled) +- drm_crtc_handle_vblank(&vc4_crtc->base); +- vc4_crtc_handle_page_flip(vc4_crtc); +- ret = IRQ_HANDLED; ++ writel(0, crtc_list[0]->regs + SMICS); ++ ++ for (i = 0; crtc_list[i]; i++) { ++ if (crtc_list[i]->vblank_enabled) ++ drm_crtc_handle_vblank(&crtc_list[i]->base); ++ vc4_crtc_handle_page_flip(crtc_list[i]); ++ ret = IRQ_HANDLED; ++ } + } + + return ret; +@@ -837,66 +845,55 @@ static const struct drm_encoder_helper_f + .disable = vc4_fkms_encoder_disable, + }; + +-static int vc4_fkms_bind(struct device *dev, struct device *master, void *data) ++static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm, ++ int display_idx, int display_ref, ++ struct vc4_crtc **ret_crtc) + { +- struct platform_device *pdev = to_platform_device(dev); +- struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_crtc *vc4_crtc; + struct vc4_fkms_encoder *vc4_encoder; + struct drm_crtc *crtc; + struct drm_plane *primary_plane, *overlay_plane, *cursor_plane; + struct drm_plane *destroy_plane, *temp; +- struct device_node *firmware_node; + u32 blank = 1; + int ret; + +- vc4->firmware_kms = true; +- +- /* firmware kms doesn't have precise a scanoutpos implementation, so +- * we can't do the precise vblank timestamp mode. +- */ +- drm->driver->get_scanout_position = NULL; +- drm->driver->get_vblank_timestamp = NULL; +- + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); + if (!vc4_crtc) + return -ENOMEM; + crtc = &vc4_crtc->base; + +- firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); +- vc4->firmware = rpi_firmware_get(firmware_node); +- if (!vc4->firmware) { +- DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n"); +- return -EPROBE_DEFER; +- } +- of_node_put(firmware_node); +- +- /* Map the SMI interrupt reg */ +- vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); +- if (IS_ERR(vc4_crtc->regs)) +- return PTR_ERR(vc4_crtc->regs); ++ vc4_crtc->display_number = display_ref; + + /* Blank the firmware provided framebuffer */ + rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_FRAMEBUFFER_BLANK, + &blank, sizeof(blank)); + +- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0); ++ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, ++ display_ref, ++ 0 + (display_idx * PLANES_PER_CRTC) ++ ); + if (IS_ERR(primary_plane)) { + dev_err(dev, "failed to construct primary plane\n"); + ret = PTR_ERR(primary_plane); + goto err; + } + +- overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1); ++ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, ++ display_ref, ++ 1 + (display_idx * PLANES_PER_CRTC) ++ ); + if (IS_ERR(overlay_plane)) { + dev_err(dev, "failed to construct overlay plane\n"); + ret = PTR_ERR(overlay_plane); + goto err; + } + +- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2); ++ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, ++ display_ref, ++ 2 + (display_idx * PLANES_PER_CRTC) ++ ); + if (IS_ERR(cursor_plane)) { + dev_err(dev, "failed to construct cursor plane\n"); + ret = PTR_ERR(cursor_plane); +@@ -923,13 +920,6 @@ static int vc4_fkms_bind(struct device * + goto err_destroy_encoder; + } + +- writel(0, vc4_crtc->regs + SMICS); +- ret = devm_request_irq(dev, platform_get_irq(pdev, 0), +- vc4_crtc_irq_handler, 0, "vc4 firmware kms", +- vc4_crtc); +- if (ret) +- goto err_destroy_connector; +- + ret = rpi_firmware_property(vc4->firmware, + RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN, + &vc4_crtc->overscan, +@@ -939,7 +929,7 @@ static int vc4_fkms_bind(struct device * + memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan)); + } + +- platform_set_drvdata(pdev, vc4_crtc); ++ *ret_crtc = vc4_crtc; + + return 0; + +@@ -956,17 +946,91 @@ err: + return ret; + } + ++static int vc4_fkms_bind(struct device *dev, struct device *master, void *data) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct drm_device *drm = dev_get_drvdata(master); ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct device_node *firmware_node; ++ struct vc4_crtc **crtc_list; ++ u32 num_displays, display_num; ++ int ret; ++ const u32 display_num_lookup[] = {2, 7, 1}; ++ ++ vc4->firmware_kms = true; ++ ++ /* firmware kms doesn't have precise a scanoutpos implementation, so ++ * we can't do the precise vblank timestamp mode. ++ */ ++ drm->driver->get_scanout_position = NULL; ++ drm->driver->get_vblank_timestamp = NULL; ++ ++ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); ++ vc4->firmware = rpi_firmware_get(firmware_node); ++ if (!vc4->firmware) { ++ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n"); ++ return -EPROBE_DEFER; ++ } ++ of_node_put(firmware_node); ++ ++ ret = rpi_firmware_property(vc4->firmware, ++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, ++ &num_displays, sizeof(u32)); ++ ++ /* If we fail to get the number of displays, or it returns 0, then ++ * assume old firmware that doesn't have the mailbox call, so just ++ * set one display ++ */ ++ if (ret || num_displays == 0) { ++ num_displays = 1; ++ DRM_WARN("Unable to determine number of displays's. Assuming 1\n"); ++ ret = 0; ++ } ++ ++ /* Allocate a list, with space for a NULL on the end */ ++ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1), ++ GFP_KERNEL); ++ if (!crtc_list) ++ return -ENOMEM; ++ ++ for (display_num = 0; display_num < num_displays; display_num++) { ++ ret = vc4_fkms_create_screen(dev, drm, display_num, ++ display_num_lookup[display_num], ++ &crtc_list[display_num]); ++ if (ret) ++ DRM_ERROR("Oh dear, failed to create display %u\n", ++ display_num); ++ } ++ ++ /* Map the SMI interrupt reg */ ++ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(crtc_list[0]->regs)) ++ DRM_ERROR("Oh dear, failed to map registers\n"); ++ ++ writel(0, crtc_list[0]->regs + SMICS); ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_crtc_irq_handler, 0, "vc4 firmware kms", ++ crtc_list); ++ if (ret) ++ DRM_ERROR("Oh dear, failed to register IRQ\n"); ++ ++ platform_set_drvdata(pdev, crtc_list); ++ ++ return 0; ++} ++ + static void vc4_fkms_unbind(struct device *dev, struct device *master, + void *data) + { +- struct drm_device *drm = dev_get_drvdata(master); + struct platform_device *pdev = to_platform_device(dev); +- struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev); ++ struct vc4_crtc **crtc_list = dev_get_drvdata(dev); ++ int i; + +- vc4_fkms_connector_destroy(vc4_crtc->connector); +- vc4_fkms_encoder_destroy(vc4_crtc->encoder); +- drm_atomic_helper_shutdown(drm); +- drm_crtc_cleanup(&vc4_crtc->base); ++ for (i = 0; crtc_list[i]; i++) { ++ vc4_fkms_connector_destroy(crtc_list[i]->connector); ++ vc4_fkms_encoder_destroy(crtc_list[i]->encoder); ++ drm_crtc_cleanup(&crtc_list[i]->base); ++ } + + platform_set_drvdata(pdev, NULL); + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0232-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch b/target/linux/bcm27xx/patches-5.4/950-0232-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch deleted file mode 100644 index fc84f535de..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0232-gpu-vc4-fkms-Switch-to-the-newer-mailbox-frame-buffe.patch +++ /dev/null @@ -1,179 +0,0 @@ -From b721bcc62759ae7a2d9730d1121974702be96d7c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 26 Mar 2019 14:43:06 +0000 -Subject: [PATCH] gpu: vc4-fkms: Switch to the newer mailbox frame - buffer API. - -The old mailbox FB API was ideally deprecated but still used by -the FKMS driver. -Update to the newer API. - -NB This needs current firmware that accepts ARM allocated buffers -through the newer API. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 109 +++++++++++++------------ - 1 file changed, 57 insertions(+), 52 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -30,6 +30,25 @@ - #include "vc4_regs.h" - #include - -+struct fb_alloc_tags { -+ struct rpi_firmware_property_tag_header tag1; -+ u32 xres, yres; -+ struct rpi_firmware_property_tag_header tag2; -+ u32 xres_virtual, yres_virtual; -+ struct rpi_firmware_property_tag_header tag3; -+ u32 bpp; -+ struct rpi_firmware_property_tag_header tag4; -+ u32 xoffset, yoffset; -+ struct rpi_firmware_property_tag_header tag5; -+ u32 base, screen_size; -+ struct rpi_firmware_property_tag_header tag6; -+ u32 pitch; -+ struct rpi_firmware_property_tag_header tag7; -+ u32 alpha_mode; -+ struct rpi_firmware_property_tag_header tag8; -+ u32 layer; -+}; -+ - /* The firmware delivers a vblank interrupt to us through the SMI - * hardware, which has only this one register. - */ -@@ -123,45 +142,39 @@ static void vc4_primary_plane_atomic_upd - struct drm_plane_state *old_state) - { - struct vc4_dev *vc4 = to_vc4_dev(plane->dev); -- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); - struct drm_plane_state *state = plane->state; - struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); -- volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo; -+ u32 format = fb->format->format; -+ struct fb_alloc_tags fbinfo = { -+ .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT, -+ 8, 0, }, -+ .xres = state->crtc_w, -+ .yres = state->crtc_h, -+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT, -+ 8, 0, }, -+ .xres_virtual = state->crtc_w, -+ .yres_virtual = state->crtc_h, -+ .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 }, -+ .bpp = 32, -+ .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 }, -+ .xoffset = 0, -+ .yoffset = 0, -+ .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 }, -+ .base = bo->paddr + fb->offsets[0], -+ .screen_size = state->crtc_w * state->crtc_h * 4, -+ .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 }, -+ .pitch = fb->pitches[0], -+ .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 }, -+ .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2, -+ .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 }, -+ .layer = -127, -+ }; - u32 bpp = 32; - int ret; - -- fbinfo->xres = state->crtc_w; -- fbinfo->yres = state->crtc_h; -- fbinfo->xres_virtual = state->crtc_w; -- fbinfo->yres_virtual = state->crtc_h; -- fbinfo->bpp = bpp; -- fbinfo->xoffset = state->crtc_x; -- fbinfo->yoffset = state->crtc_y; -- fbinfo->base = bo->paddr + fb->offsets[0]; -- fbinfo->pitch = fb->pitches[0]; -- - if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED) -- fbinfo->bpp |= BIT(31); -- -- /* A bug in the firmware makes it so that if the fb->base is -- * set to nonzero, the configured pitch gets overwritten with -- * the previous pitch. So, to get the configured pitch -- * recomputed, we have to make it allocate itself a new buffer -- * in VC memory, first. -- */ -- if (vc4_plane->pitch != fb->pitches[0]) { -- u32 saved_base = fbinfo->base; -- fbinfo->base = 0; -- -- ret = rpi_firmware_transaction(vc4->firmware, -- RPI_FIRMWARE_CHAN_FB, -- vc4_plane->fbinfo_bus_addr); -- fbinfo->base = saved_base; -- -- vc4_plane->pitch = fbinfo->pitch; -- WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]); -- } -+ fbinfo.bpp |= BIT(31); - - DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n", - plane->base.id, plane->name, -@@ -170,14 +183,13 @@ static void vc4_primary_plane_atomic_upd - bpp, - state->crtc_x, - state->crtc_y, -- &fbinfo->base, -+ &fbinfo.base, - fb->pitches[0]); - -- ret = rpi_firmware_transaction(vc4->firmware, -- RPI_FIRMWARE_CHAN_FB, -- vc4_plane->fbinfo_bus_addr); -- WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]); -- WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]); -+ ret = rpi_firmware_property_list(vc4->firmware, &fbinfo, -+ sizeof(fbinfo)); -+ WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]); -+ WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]); - - /* If the CRTC is on (or going to be on) and we're enabled, - * then unblank. Otherwise, stay blank until CRTC enable. -@@ -333,10 +345,10 @@ static const struct drm_plane_helper_fun - static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, - enum drm_plane_type type) - { -+ /* Primary and cursor planes only */ - struct drm_plane *plane = NULL; - struct vc4_fkms_plane *vc4_plane; -- u32 xrgb8888 = DRM_FORMAT_XRGB8888; -- u32 argb8888 = DRM_FORMAT_ARGB8888; -+ u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888}; - int ret = 0; - bool primary = (type == DRM_PLANE_TYPE_PRIMARY); - static const uint64_t modifiers[] = { -@@ -358,22 +370,15 @@ static struct drm_plane *vc4_fkms_plane_ - plane = &vc4_plane->base; - ret = drm_universal_plane_init(dev, plane, 0xff, - &vc4_plane_funcs, -- primary ? &xrgb8888 : &argb8888, 1, -- modifiers, -+ formats, primary ? 2 : 1, modifiers, - type, primary ? "primary" : "cursor"); - -- if (type == DRM_PLANE_TYPE_PRIMARY) { -- vc4_plane->fbinfo = -- dma_alloc_coherent(dev->dev, -- sizeof(*vc4_plane->fbinfo), -- &vc4_plane->fbinfo_bus_addr, -- GFP_KERNEL); -- memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo)); -- -+ if (type == DRM_PLANE_TYPE_PRIMARY) - drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs); -- } else { -+ else - drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs); -- } -+ -+ drm_plane_create_alpha_property(plane); - - return plane; - fail: diff --git a/target/linux/bcm27xx/patches-5.4/950-0233-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch b/target/linux/bcm27xx/patches-5.4/950-0233-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch deleted file mode 100644 index 6878a0c26a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0233-drm-vc4-Add-an-overlay-plane-to-vc4-firmware-kms.patch +++ /dev/null @@ -1,853 +0,0 @@ -From 75e1dce99c260cb1365edd9af68cb5c07487831c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 27 Mar 2019 17:45:01 +0000 -Subject: [PATCH] drm: vc4: Add an overlay plane to vc4-firmware-kms - -This uses a new API that is exposed via the mailbox service -to stick an element straight on the screen using DispmanX. - -The primary and cursor planes have also been switched to using -the new plane API, and it supports layering based on the DRM -zpos parameter. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 518 ++++++++++++++------- - drivers/gpu/drm/vc4/vc4_kms.c | 1 + - drivers/gpu/drm/vc4/vc_image_types.h | 143 ++++++ - include/soc/bcm2835/raspberrypi-firmware.h | 2 + - 4 files changed, 495 insertions(+), 169 deletions(-) - create mode 100644 drivers/gpu/drm/vc4/vc_image_types.h - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -28,8 +28,46 @@ - #include "linux/of_device.h" - #include "vc4_drv.h" - #include "vc4_regs.h" -+#include "vc_image_types.h" - #include - -+struct set_plane { -+ u8 display; -+ u8 plane_id; -+ u8 vc_image_type; -+ s8 layer; -+ -+ u16 width; -+ u16 height; -+ -+ u16 pitch; -+ u16 vpitch; -+ -+ u32 src_x; /* 16p16 */ -+ u32 src_y; /* 16p16 */ -+ -+ u32 src_w; /* 16p16 */ -+ u32 src_h; /* 16p16 */ -+ -+ s16 dst_x; -+ s16 dst_y; -+ -+ u16 dst_w; -+ u16 dst_h; -+ -+ u8 alpha; -+ u8 num_planes; -+ u8 is_vu; -+ u8 padding; -+ -+ u32 planes[4]; /* DMA address of each plane */ -+}; -+ -+struct mailbox_set_plane { -+ struct rpi_firmware_property_tag_header tag; -+ struct set_plane plane; -+}; -+ - struct fb_alloc_tags { - struct rpi_firmware_property_tag_header tag1; - u32 xres, yres; -@@ -49,6 +87,79 @@ struct fb_alloc_tags { - u32 layer; - }; - -+static const struct vc_image_format { -+ u32 drm; /* DRM_FORMAT_* */ -+ u32 vc_image; /* VC_IMAGE_* */ -+ u32 is_vu; -+} vc_image_formats[] = { -+ { -+ .drm = DRM_FORMAT_XRGB8888, -+ .vc_image = VC_IMAGE_XRGB8888, -+ }, -+ { -+ .drm = DRM_FORMAT_ARGB8888, -+ .vc_image = VC_IMAGE_ARGB8888, -+ }, -+/* -+ * FIXME: Need to resolve which DRM format goes to which vc_image format -+ * for the remaining RGBA and RGBX formats. -+ * { -+ * .drm = DRM_FORMAT_ABGR8888, -+ * .vc_image = VC_IMAGE_RGBA8888, -+ * }, -+ * { -+ * .drm = DRM_FORMAT_XBGR8888, -+ * .vc_image = VC_IMAGE_RGBA8888, -+ * }, -+ */ -+ { -+ .drm = DRM_FORMAT_RGB565, -+ .vc_image = VC_IMAGE_RGB565, -+ }, -+ { -+ .drm = DRM_FORMAT_RGB888, -+ .vc_image = VC_IMAGE_BGR888, -+ }, -+ { -+ .drm = DRM_FORMAT_BGR888, -+ .vc_image = VC_IMAGE_RGB888, -+ }, -+ { -+ .drm = DRM_FORMAT_YUV422, -+ .vc_image = VC_IMAGE_YUV422PLANAR, -+ }, -+ { -+ .drm = DRM_FORMAT_YUV420, -+ .vc_image = VC_IMAGE_YUV420, -+ }, -+ { -+ .drm = DRM_FORMAT_YVU420, -+ .vc_image = VC_IMAGE_YUV420, -+ .is_vu = 1, -+ }, -+ { -+ .drm = DRM_FORMAT_NV12, -+ .vc_image = VC_IMAGE_YUV420SP, -+ }, -+ { -+ .drm = DRM_FORMAT_NV21, -+ .vc_image = VC_IMAGE_YUV420SP, -+ .is_vu = 1, -+ }, -+}; -+ -+static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) { -+ if (vc_image_formats[i].drm == drm_format) -+ return &vc_image_formats[i]; -+ } -+ -+ return NULL; -+} -+ - /* The firmware delivers a vblank interrupt to us through the SMI - * hardware, which has only this one register. - */ -@@ -115,6 +226,7 @@ struct vc4_fkms_plane { - struct fbinfo_s *fbinfo; - dma_addr_t fbinfo_bus_addr; - u32 pitch; -+ struct mailbox_set_plane mb; - }; - - static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane) -@@ -122,165 +234,183 @@ static inline struct vc4_fkms_plane *to_ - return (struct vc4_fkms_plane *)plane; - } - --/* Turns the display on/off. */ --static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank) -+static int vc4_plane_set_blank(struct drm_plane *plane, bool blank) - { - struct vc4_dev *vc4 = to_vc4_dev(plane->dev); -+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); -+ struct mailbox_set_plane blank_mb = { -+ .tag = { RPI_FIRMWARE_SET_PLANE, sizeof(struct set_plane), 0 }, -+ .plane = { -+ .display = vc4_plane->mb.plane.display, -+ .plane_id = vc4_plane->mb.plane.plane_id, -+ } -+ }; -+ int ret; - -- u32 packet = blank; -- -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s", -+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s", - plane->base.id, plane->name, - blank ? "blank" : "unblank"); - -- return rpi_firmware_property(vc4->firmware, -- RPI_FIRMWARE_FRAMEBUFFER_BLANK, -- &packet, sizeof(packet)); -+ if (blank) -+ ret = rpi_firmware_property_list(vc4->firmware, &blank_mb, -+ sizeof(blank_mb)); -+ else -+ ret = rpi_firmware_property_list(vc4->firmware, &vc4_plane->mb, -+ sizeof(vc4_plane->mb)); -+ -+ WARN_ONCE(ret, "%s: firmware call failed. Please update your firmware", -+ __func__); -+ return ret; - } - --static void vc4_primary_plane_atomic_update(struct drm_plane *plane, -- struct drm_plane_state *old_state) -+static void vc4_plane_atomic_update(struct drm_plane *plane, -+ struct drm_plane_state *old_state) - { -- struct vc4_dev *vc4 = to_vc4_dev(plane->dev); - struct drm_plane_state *state = plane->state; - struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); -- u32 format = fb->format->format; -- struct fb_alloc_tags fbinfo = { -- .tag1 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT, -- 8, 0, }, -- .xres = state->crtc_w, -- .yres = state->crtc_h, -- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT, -- 8, 0, }, -- .xres_virtual = state->crtc_w, -- .yres_virtual = state->crtc_h, -- .tag3 = { RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH, 4, 0 }, -- .bpp = 32, -- .tag4 = { RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET, 8, 0 }, -- .xoffset = 0, -- .yoffset = 0, -- .tag5 = { RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE, 8, 0 }, -- .base = bo->paddr + fb->offsets[0], -- .screen_size = state->crtc_w * state->crtc_h * 4, -- .tag6 = { RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH, 4, 0 }, -- .pitch = fb->pitches[0], -- .tag7 = { RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE, 4, 0 }, -- .alpha_mode = format == DRM_FORMAT_ARGB8888 ? 0 : 2, -- .tag8 = { RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER, 4, 0 }, -- .layer = -127, -- }; -- u32 bpp = 32; -- int ret; -+ const struct drm_format_info *drm_fmt = fb->format; -+ const struct vc_image_format *vc_fmt = -+ vc4_get_vc_image_fmt(drm_fmt->format); -+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); -+ struct mailbox_set_plane *mb = &vc4_plane->mb; -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); -+ int num_planes = fb->format->num_planes; -+ struct drm_display_mode *mode = &state->crtc->mode; - -- if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED) -- fbinfo.bpp |= BIT(31); -+ mb->plane.vc_image_type = vc_fmt->vc_image; -+ mb->plane.width = fb->width; -+ mb->plane.height = fb->height; -+ mb->plane.pitch = fb->pitches[0]; -+ mb->plane.src_w = state->src_w; -+ mb->plane.src_h = state->src_h; -+ mb->plane.src_x = state->src_x; -+ mb->plane.src_y = state->src_y; -+ mb->plane.dst_w = state->crtc_w; -+ mb->plane.dst_h = state->crtc_h; -+ mb->plane.dst_x = state->crtc_x; -+ mb->plane.dst_y = state->crtc_y; -+ mb->plane.alpha = state->alpha >> 8; -+ mb->plane.layer = state->normalized_zpos ? -+ state->normalized_zpos : -127; -+ mb->plane.num_planes = num_planes; -+ mb->plane.is_vu = vc_fmt->is_vu; -+ mb->plane.planes[0] = bo->paddr + fb->offsets[0]; - -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%pad/%d\n", -+ /* FIXME: If the dest rect goes off screen then clip the src rect so we -+ * don't have off-screen pixels. -+ */ -+ if (plane->type == DRM_PLANE_TYPE_CURSOR) { -+ /* There is no scaling on the cursor plane, therefore the calcs -+ * to alter the source crop as the cursor goes off the screen -+ * are simple. -+ */ -+ if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) { -+ mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x; -+ mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x) -+ << 16; -+ } -+ if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) { -+ mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y; -+ mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y) -+ << 16; -+ } -+ } -+ -+ if (num_planes > 1) { -+ /* Assume this must be YUV */ -+ /* Makes assumptions on the stride for the chroma planes as we -+ * can't easily plumb in non-standard pitches. -+ */ -+ mb->plane.planes[1] = bo->paddr + fb->offsets[1]; -+ if (num_planes > 2) -+ mb->plane.planes[2] = bo->paddr + fb->offsets[2]; -+ else -+ mb->plane.planes[2] = 0; -+ -+ /* Special case the YUV420 with U and V as line interleaved -+ * planes as we have special handling for that case. -+ */ -+ if (num_planes == 3 && -+ (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1]) -+ mb->plane.vc_image_type = VC_IMAGE_YUV420_S; -+ } else { -+ mb->plane.planes[1] = 0; -+ mb->plane.planes[2] = 0; -+ } -+ mb->plane.planes[3] = 0; -+ -+ switch (fb->modifier) { -+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: -+ switch (mb->plane.vc_image_type) { -+ case VC_IMAGE_RGBX32: -+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32; -+ break; -+ case VC_IMAGE_RGBA32: -+ mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32; -+ break; -+ case VC_IMAGE_RGB565: -+ mb->plane.vc_image_type = VC_IMAGE_TF_RGB565; -+ break; -+ } -+ break; -+ case DRM_FORMAT_MOD_BROADCOM_SAND128: -+ mb->plane.vc_image_type = VC_IMAGE_YUV_UV; -+ mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier); -+ break; -+ } -+ -+ if (vc4_crtc) { -+ mb->plane.dst_x += vc4_crtc->overscan[0]; -+ mb->plane.dst_y += vc4_crtc->overscan[1]; -+ } -+ -+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n", - plane->base.id, plane->name, -- state->crtc_w, -- state->crtc_h, -- bpp, -+ mb->plane.width, -+ mb->plane.height, -+ mb->plane.vc_image_type, - state->crtc_x, - state->crtc_y, -- &fbinfo.base, -- fb->pitches[0]); -- -- ret = rpi_firmware_property_list(vc4->firmware, &fbinfo, -- sizeof(fbinfo)); -- WARN_ON_ONCE(fbinfo.pitch != fb->pitches[0]); -- WARN_ON_ONCE(fbinfo.base != bo->paddr + fb->offsets[0]); -- -- /* If the CRTC is on (or going to be on) and we're enabled, -+ state->crtc_w, -+ state->crtc_h, -+ mb->plane.src_x, -+ mb->plane.src_y, -+ mb->plane.src_w, -+ mb->plane.src_h, -+ mb->plane.planes[0], -+ mb->plane.planes[1], -+ mb->plane.planes[2], -+ fb->pitches[0], -+ state->alpha, -+ state->normalized_zpos); -+ -+ /* -+ * Do NOT set now, as we haven't checked if the crtc is active or not. -+ * Set from vc4_plane_set_blank instead. -+ * -+ * If the CRTC is on (or going to be on) and we're enabled, - * then unblank. Otherwise, stay blank until CRTC enable. -- */ -+ */ - if (state->crtc->state->active) -- vc4_plane_set_primary_blank(plane, false); -+ vc4_plane_set_blank(plane, false); - } - --static void vc4_primary_plane_atomic_disable(struct drm_plane *plane, -- struct drm_plane_state *old_state) -+static void vc4_plane_atomic_disable(struct drm_plane *plane, -+ struct drm_plane_state *old_state) - { -- vc4_plane_set_primary_blank(plane, true); --} -- --static void vc4_cursor_plane_atomic_update(struct drm_plane *plane, -- struct drm_plane_state *old_state) --{ -- struct vc4_dev *vc4 = to_vc4_dev(plane->dev); -+ //struct vc4_dev *vc4 = to_vc4_dev(plane->dev); - struct drm_plane_state *state = plane->state; -- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); -- struct drm_framebuffer *fb = state->fb; -- struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); -- dma_addr_t addr = bo->paddr + fb->offsets[0]; -- int ret; -- u32 packet_state[] = { -- state->crtc->state->active, -- state->crtc_x, -- state->crtc_y, -- 0 -- }; -- WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4); -+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); - -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%pad/%d)", -+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n", - plane->base.id, plane->name, - state->crtc_w, - state->crtc_h, -+ vc4_plane->mb.plane.vc_image_type, - state->crtc_x, -- state->crtc_y, -- &addr, -- fb->pitches[0]); -- -- /* add on the top/left offsets when overscan is active */ -- if (vc4_crtc) { -- packet_state[1] += vc4_crtc->overscan[0]; -- packet_state[2] += vc4_crtc->overscan[1]; -- } -- -- ret = rpi_firmware_property(vc4->firmware, -- RPI_FIRMWARE_SET_CURSOR_STATE, -- &packet_state, -- sizeof(packet_state)); -- if (ret || packet_state[0] != 0) -- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]); -- -- /* Note: When the cursor contents change, the modesetting -- * driver calls drm_mode_cursor_univeral() with -- * DRM_MODE_CURSOR_BO, which means a new fb will be allocated. -- */ -- if (!old_state || -- state->crtc_w != old_state->crtc_w || -- state->crtc_h != old_state->crtc_h || -- fb != old_state->fb) { -- u32 packet_info[] = { state->crtc_w, state->crtc_h, -- 0, /* unused */ -- addr, -- 0, 0, /* hotx, hoty */}; -- -- ret = rpi_firmware_property(vc4->firmware, -- RPI_FIRMWARE_SET_CURSOR_INFO, -- &packet_info, -- sizeof(packet_info)); -- if (ret || packet_info[0] != 0) -- DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]); -- } --} -- --static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane, -- struct drm_plane_state *old_state) --{ -- struct vc4_dev *vc4 = to_vc4_dev(plane->dev); -- u32 packet_state[] = { false, 0, 0, 0 }; -- int ret; -- -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name); -- -- ret = rpi_firmware_property(vc4->firmware, -- RPI_FIRMWARE_SET_CURSOR_STATE, -- &packet_state, -- sizeof(packet_state)); -- if (ret || packet_state[0] != 0) -- DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]); -+ state->crtc_y); -+ vc4_plane_set_blank(plane, true); - } - - static int vc4_plane_atomic_check(struct drm_plane *plane, -@@ -302,6 +432,7 @@ static bool vc4_fkms_format_mod_supporte - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: -+ case DRM_FORMAT_RGB565: - switch (modifier) { - case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: - case DRM_FORMAT_MOD_LINEAR: -@@ -310,8 +441,22 @@ static bool vc4_fkms_format_mod_supporte - default: - return false; - } -+ case DRM_FORMAT_NV12: -+ case DRM_FORMAT_NV21: -+ switch (fourcc_mod_broadcom_mod(modifier)) { -+ case DRM_FORMAT_MOD_LINEAR: -+ case DRM_FORMAT_MOD_BROADCOM_SAND128: -+ return true; -+ default: -+ return false; -+ } -+ case DRM_FORMAT_RGB888: -+ case DRM_FORMAT_BGR888: -+ case DRM_FORMAT_YUV422: -+ case DRM_FORMAT_YUV420: -+ case DRM_FORMAT_YVU420: - default: -- return false; -+ return (modifier == DRM_FORMAT_MOD_LINEAR); - } - } - -@@ -326,31 +471,24 @@ static const struct drm_plane_funcs vc4_ - .format_mod_supported = vc4_fkms_format_mod_supported, - }; - --static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = { -- .prepare_fb = drm_gem_fb_prepare_fb, -- .cleanup_fb = NULL, -- .atomic_check = vc4_plane_atomic_check, -- .atomic_update = vc4_primary_plane_atomic_update, -- .atomic_disable = vc4_primary_plane_atomic_disable, --}; -- --static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = { -+static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { - .prepare_fb = drm_gem_fb_prepare_fb, - .cleanup_fb = NULL, - .atomic_check = vc4_plane_atomic_check, -- .atomic_update = vc4_cursor_plane_atomic_update, -- .atomic_disable = vc4_cursor_plane_atomic_disable, -+ .atomic_update = vc4_plane_atomic_update, -+ .atomic_disable = vc4_plane_atomic_disable, - }; - - static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, -- enum drm_plane_type type) -+ enum drm_plane_type type, -+ u8 plane_id) - { -- /* Primary and cursor planes only */ - struct drm_plane *plane = NULL; - struct vc4_fkms_plane *vc4_plane; -- u32 formats[] = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888}; -+ u32 formats[ARRAY_SIZE(vc_image_formats)]; -+ unsigned int default_zpos = 0; -+ u32 num_formats = 0; - int ret = 0; -- bool primary = (type == DRM_PLANE_TYPE_PRIMARY); - static const uint64_t modifiers[] = { - DRM_FORMAT_MOD_LINEAR, - /* VC4_T_TILED should come after linear, because we -@@ -359,6 +497,7 @@ static struct drm_plane *vc4_fkms_plane_ - DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, - DRM_FORMAT_MOD_INVALID, - }; -+ int i; - - vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), - GFP_KERNEL); -@@ -367,19 +506,48 @@ static struct drm_plane *vc4_fkms_plane_ - goto fail; - } - -+ for (i = 0; i < ARRAY_SIZE(vc_image_formats); i++) -+ formats[num_formats++] = vc_image_formats[i].drm; -+ - plane = &vc4_plane->base; - ret = drm_universal_plane_init(dev, plane, 0xff, - &vc4_plane_funcs, -- formats, primary ? 2 : 1, modifiers, -- type, primary ? "primary" : "cursor"); -+ formats, num_formats, modifiers, -+ type, NULL); - -- if (type == DRM_PLANE_TYPE_PRIMARY) -- drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs); -- else -- drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs); -+ drm_plane_helper_add(plane, &vc4_plane_helper_funcs); - - drm_plane_create_alpha_property(plane); - -+ /* -+ * Default frame buffer setup is with FB on -127, and raspistill etc -+ * tend to drop overlays on layer 2. Cursor plane was on layer +127. -+ * -+ * For F-KMS the mailbox call allows for a s8. -+ * Remap zpos 0 to -127 for the background layer, but leave all the -+ * other layers as requested by KMS. -+ */ -+ switch (type) { -+ case DRM_PLANE_TYPE_PRIMARY: -+ default_zpos = 0; -+ break; -+ case DRM_PLANE_TYPE_OVERLAY: -+ default_zpos = 1; -+ break; -+ case DRM_PLANE_TYPE_CURSOR: -+ default_zpos = 2; -+ break; -+ } -+ drm_plane_create_zpos_property(plane, default_zpos, 0, 127); -+ -+ /* Prepare the static elements of the mailbox structure */ -+ vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE; -+ vc4_plane->mb.tag.buf_size = sizeof(struct set_plane); -+ vc4_plane->mb.tag.req_resp_size = 0; -+ vc4_plane->mb.plane.display = 0; -+ vc4_plane->mb.plane.plane_id = plane_id; -+ vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127; -+ - return plane; - fail: - if (plane) -@@ -401,19 +569,23 @@ static void vc4_crtc_disable(struct drm_ - * whether anything scans out at all, but the firmware doesn't - * give us a CRTC-level control for that. - */ -- vc4_cursor_plane_atomic_disable(crtc->cursor, crtc->cursor->state); -- vc4_plane_set_primary_blank(crtc->primary, true); -+ -+ vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state); -+ vc4_plane_atomic_disable(crtc->primary, crtc->primary->state); -+ -+ /* FIXME: Disable overlay planes */ - } - - static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) - { - /* Unblank the planes (if they're supposed to be displayed). */ -+ - if (crtc->primary->state->fb) -- vc4_plane_set_primary_blank(crtc->primary, false); -- if (crtc->cursor->state->fb) { -- vc4_cursor_plane_atomic_update(crtc->cursor, -- crtc->cursor->state); -- } -+ vc4_plane_set_blank(crtc->primary, false); -+ if (crtc->cursor->state->fb) -+ vc4_plane_set_blank(crtc->cursor, crtc->cursor->state); -+ -+ /* FIXME: Enable overlay planes */ - } - - static int vc4_crtc_atomic_check(struct drm_crtc *crtc, -@@ -673,8 +845,10 @@ static int vc4_fkms_bind(struct device * - struct vc4_crtc *vc4_crtc; - struct vc4_fkms_encoder *vc4_encoder; - struct drm_crtc *crtc; -- struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp; -+ struct drm_plane *primary_plane, *overlay_plane, *cursor_plane; -+ struct drm_plane *destroy_plane, *temp; - struct device_node *firmware_node; -+ u32 blank = 1; - int ret; - - vc4->firmware_kms = true; -@@ -703,20 +877,26 @@ static int vc4_fkms_bind(struct device * - if (IS_ERR(vc4_crtc->regs)) - return PTR_ERR(vc4_crtc->regs); - -- /* For now, we create just the primary and the legacy cursor -- * planes. We should be able to stack more planes on easily, -- * but to do that we would need to compute the bandwidth -- * requirement of the plane configuration, and reject ones -- * that will take too much. -- */ -- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); -+ /* Blank the firmware provided framebuffer */ -+ rpi_firmware_property(vc4->firmware, -+ RPI_FIRMWARE_FRAMEBUFFER_BLANK, -+ &blank, sizeof(blank)); -+ -+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0); - if (IS_ERR(primary_plane)) { - dev_err(dev, "failed to construct primary plane\n"); - ret = PTR_ERR(primary_plane); - goto err; - } - -- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR); -+ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1); -+ if (IS_ERR(overlay_plane)) { -+ dev_err(dev, "failed to construct overlay plane\n"); -+ ret = PTR_ERR(overlay_plane); -+ goto err; -+ } -+ -+ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2); - if (IS_ERR(cursor_plane)) { - dev_err(dev, "failed to construct cursor plane\n"); - ret = PTR_ERR(cursor_plane); ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -542,6 +542,7 @@ int vc4_kms_load(struct drm_device *dev) - dev->mode_config.preferred_depth = 24; - dev->mode_config.async_page_flip = true; - dev->mode_config.allow_fb_modifiers = true; -+ dev->mode_config.normalize_zpos = true; - - drm_modeset_lock_init(&vc4->ctm_state_lock); - ---- /dev/null -+++ b/drivers/gpu/drm/vc4/vc_image_types.h -@@ -0,0 +1,143 @@ -+ -+/* -+ * Copyright (c) 2012, Broadcom Europe Ltd -+ * -+ * Values taken from vc_image_types.h released by Broadcom at -+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h -+ * -+ * 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. -+ */ -+ -+enum { -+ VC_IMAGE_MIN = 0, //bounds for error checking -+ -+ VC_IMAGE_RGB565 = 1, -+ VC_IMAGE_1BPP, -+ VC_IMAGE_YUV420, -+ VC_IMAGE_48BPP, -+ VC_IMAGE_RGB888, -+ VC_IMAGE_8BPP, -+ /* 4bpp palettised image */ -+ VC_IMAGE_4BPP, -+ /* A separated format of 16 colour/light shorts followed by 16 z -+ * values -+ */ -+ VC_IMAGE_3D32, -+ /* 16 colours followed by 16 z values */ -+ VC_IMAGE_3D32B, -+ /* A separated format of 16 material/colour/light shorts followed by -+ * 16 z values -+ */ -+ VC_IMAGE_3D32MAT, -+ /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */ -+ VC_IMAGE_RGB2X9, -+ /* 32-bit format holding 18 bits of 6.6.6 RGB */ -+ VC_IMAGE_RGB666, -+ /* 4bpp palettised image with embedded palette */ -+ VC_IMAGE_PAL4_OBSOLETE, -+ /* 8bpp palettised image with embedded palette */ -+ VC_IMAGE_PAL8_OBSOLETE, -+ /* RGB888 with an alpha byte after each pixel */ -+ VC_IMAGE_RGBA32, -+ /* a line of Y (32-byte padded), a line of U (16-byte padded), and a -+ * line of V (16-byte padded) -+ */ -+ VC_IMAGE_YUV422, -+ /* RGB565 with a transparent patch */ -+ VC_IMAGE_RGBA565, -+ /* Compressed (4444) version of RGBA32 */ -+ VC_IMAGE_RGBA16, -+ /* VCIII codec format */ -+ VC_IMAGE_YUV_UV, -+ /* VCIII T-format RGBA8888 */ -+ VC_IMAGE_TF_RGBA32, -+ /* VCIII T-format RGBx8888 */ -+ VC_IMAGE_TF_RGBX32, -+ /* VCIII T-format float */ -+ VC_IMAGE_TF_FLOAT, -+ /* VCIII T-format RGBA4444 */ -+ VC_IMAGE_TF_RGBA16, -+ /* VCIII T-format RGB5551 */ -+ VC_IMAGE_TF_RGBA5551, -+ /* VCIII T-format RGB565 */ -+ VC_IMAGE_TF_RGB565, -+ /* VCIII T-format 8-bit luma and 8-bit alpha */ -+ VC_IMAGE_TF_YA88, -+ /* VCIII T-format 8 bit generic sample */ -+ VC_IMAGE_TF_BYTE, -+ /* VCIII T-format 8-bit palette */ -+ VC_IMAGE_TF_PAL8, -+ /* VCIII T-format 4-bit palette */ -+ VC_IMAGE_TF_PAL4, -+ /* VCIII T-format Ericsson Texture Compressed */ -+ VC_IMAGE_TF_ETC1, -+ /* RGB888 with R & B swapped */ -+ VC_IMAGE_BGR888, -+ /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after -+ * each row of pixels -+ */ -+ VC_IMAGE_BGR888_NP, -+ /* Bayer image, extra defines which variant is being used */ -+ VC_IMAGE_BAYER, -+ /* General wrapper for codec images e.g. JPEG from camera */ -+ VC_IMAGE_CODEC, -+ /* VCIII codec format */ -+ VC_IMAGE_YUV_UV32, -+ /* VCIII T-format 8-bit luma */ -+ VC_IMAGE_TF_Y8, -+ /* VCIII T-format 8-bit alpha */ -+ VC_IMAGE_TF_A8, -+ /* VCIII T-format 16-bit generic sample */ -+ VC_IMAGE_TF_SHORT, -+ /* VCIII T-format 1bpp black/white */ -+ VC_IMAGE_TF_1BPP, -+ VC_IMAGE_OPENGL, -+ /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */ -+ VC_IMAGE_YUV444I, -+ /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on -+ * a per line basis) -+ */ -+ VC_IMAGE_YUV422PLANAR, -+ /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */ -+ VC_IMAGE_ARGB8888, -+ /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */ -+ VC_IMAGE_XRGB8888, -+ -+ /* interleaved 8 bit samples of Y, U, Y, V (4 flavours) */ -+ VC_IMAGE_YUV422YUYV, -+ VC_IMAGE_YUV422YVYU, -+ VC_IMAGE_YUV422UYVY, -+ VC_IMAGE_YUV422VYUY, -+ -+ /* 32bpp like RGBA32 but with unused alpha */ -+ VC_IMAGE_RGBX32, -+ /* 32bpp, corresponding to RGBA with unused alpha */ -+ VC_IMAGE_RGBX8888, -+ /* 32bpp, corresponding to BGRA with unused alpha */ -+ VC_IMAGE_BGRX8888, -+ -+ /* Y as a plane, then UV byte interleaved in plane with with same pitch, -+ * half height -+ */ -+ VC_IMAGE_YUV420SP, -+ -+ /* Y, U, & V planes separately 4:4:4 */ -+ VC_IMAGE_YUV444PLANAR, -+ -+ /* T-format 8-bit U - same as TF_Y8 buf from U plane */ -+ VC_IMAGE_TF_U8, -+ /* T-format 8-bit U - same as TF_Y8 buf from V plane */ -+ VC_IMAGE_TF_V8, -+ -+ /* YUV4:2:0 planar, 16bit values */ -+ VC_IMAGE_YUV420_16, -+ /* YUV4:2:0 codec format, 16bit values */ -+ VC_IMAGE_YUV_UV_16, -+ /* YUV4:2:0 with U,V in side-by-side format */ -+ VC_IMAGE_YUV420_S, -+ -+ VC_IMAGE_MAX, /* bounds for error checking */ -+ VC_IMAGE_FORCE_ENUM_16BIT = 0xffff, -+}; ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -147,6 +147,8 @@ enum rpi_firmware_property_tag { - - RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, - -+ RPI_FIRMWARE_SET_PLANE = 0x00048015, -+ - RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, - RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0233-drm-vc4-Fix-build-warning.patch b/target/linux/bcm27xx/patches-5.4/950-0233-drm-vc4-Fix-build-warning.patch new file mode 100644 index 0000000000..63246286a2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0233-drm-vc4-Fix-build-warning.patch @@ -0,0 +1,21 @@ +From a06b826c199e6de39d4e91e41e8347a5629bb54a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 5 Apr 2019 17:21:56 +0100 +Subject: [PATCH] drm: vc4: Fix build warning + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -933,8 +933,6 @@ static int vc4_fkms_create_screen(struct + + return 0; + +-err_destroy_connector: +- vc4_fkms_connector_destroy(vc4_crtc->connector); + err_destroy_encoder: + vc4_fkms_encoder_destroy(vc4_crtc->encoder); + list_for_each_entry_safe(destroy_plane, temp, diff --git a/target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Increase-max-screen-size-to-4096x4096.patch b/target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Increase-max-screen-size-to-4096x4096.patch deleted file mode 100644 index 92d3d35ead..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Increase-max-screen-size-to-4096x4096.patch +++ /dev/null @@ -1,26 +0,0 @@ -From a954d2d91eff32d1ab8baae12b8ac7dc856711cb Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 3 Apr 2019 15:20:05 +0100 -Subject: [PATCH] drm: vc4: Increase max screen size to 4096x4096. - -We now should support 4k screens, therefore this limit needs to -be increased. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_kms.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev) - return ret; - } - -- dev->mode_config.max_width = 2048; -- dev->mode_config.max_height = 2048; -+ dev->mode_config.max_width = 4096; -+ dev->mode_config.max_height = 4096; - dev->mode_config.funcs = &vc4_mode_funcs; - dev->mode_config.preferred_depth = 24; - dev->mode_config.async_page_flip = true; diff --git a/target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Select-display-to-blank-during-initialisatio.patch b/target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Select-display-to-blank-during-initialisatio.patch new file mode 100644 index 0000000000..693292d04f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0234-drm-vc4-Select-display-to-blank-during-initialisatio.patch @@ -0,0 +1,54 @@ +From c2666d7b749ade8ed250ab115a71d420c1403b24 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 5 Apr 2019 17:23:15 +0100 +Subject: [PATCH] drm: vc4: Select display to blank during + initialisation + +Otherwise the rainbow splash screen remained in the display list + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -89,6 +89,13 @@ struct fb_alloc_tags { + u32 layer; + }; + ++struct mailbox_blank_display { ++ struct rpi_firmware_property_tag_header tag1; ++ u32 display; ++ struct rpi_firmware_property_tag_header tag2; ++ u32 blank; ++}; ++ + static const struct vc_image_format { + u32 drm; /* DRM_FORMAT_* */ + u32 vc_image; /* VC_IMAGE_* */ +@@ -855,7 +862,12 @@ static int vc4_fkms_create_screen(struct + struct drm_crtc *crtc; + struct drm_plane *primary_plane, *overlay_plane, *cursor_plane; + struct drm_plane *destroy_plane, *temp; +- u32 blank = 1; ++ struct mailbox_blank_display blank = { ++ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, }, ++ .display = display_idx, ++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, }, ++ .blank = 1, ++ }; + int ret; + + vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); +@@ -866,9 +878,7 @@ static int vc4_fkms_create_screen(struct + vc4_crtc->display_number = display_ref; + + /* Blank the firmware provided framebuffer */ +- rpi_firmware_property(vc4->firmware, +- RPI_FIRMWARE_FRAMEBUFFER_BLANK, +- &blank, sizeof(blank)); ++ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank)); + + primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, + display_ref, diff --git a/target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch b/target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch deleted file mode 100644 index cbba43bf2e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Add-support-for-multiple-displays-to-fkms.patch +++ /dev/null @@ -1,282 +0,0 @@ -From b7a52df8162e1eb55a8403e9e9af79c581206335 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 3 Apr 2019 17:15:45 +0100 -Subject: [PATCH] drm: vc4: Add support for multiple displays to fkms - -There is a slightly nasty hack in that all crtcs share the -same SMI interrupt from the firmware. This seems to currently -work well enough, but ought to be fixed at a later date. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 162 +++++++++++++++++-------- - 1 file changed, 113 insertions(+), 49 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -31,6 +31,8 @@ - #include "vc_image_types.h" - #include - -+#define PLANES_PER_CRTC 3 -+ - struct set_plane { - u8 display; - u8 plane_id; -@@ -177,6 +179,7 @@ struct vc4_crtc { - struct drm_pending_vblank_event *event; - u32 overscan[4]; - bool vblank_enabled; -+ u32 display_number; - }; - - static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc) -@@ -481,6 +484,7 @@ static const struct drm_plane_helper_fun - - static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev, - enum drm_plane_type type, -+ u8 display_num, - u8 plane_id) - { - struct drm_plane *plane = NULL; -@@ -544,7 +548,7 @@ static struct drm_plane *vc4_fkms_plane_ - vc4_plane->mb.tag.tag = RPI_FIRMWARE_SET_PLANE; - vc4_plane->mb.tag.buf_size = sizeof(struct set_plane); - vc4_plane->mb.tag.req_resp_size = 0; -- vc4_plane->mb.plane.display = 0; -+ vc4_plane->mb.plane.display = display_num; - vc4_plane->mb.plane.plane_id = plane_id; - vc4_plane->mb.plane.layer = default_zpos ? default_zpos : -127; - -@@ -631,16 +635,20 @@ static void vc4_crtc_handle_page_flip(st - - static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) - { -- struct vc4_crtc *vc4_crtc = data; -- u32 stat = readl(vc4_crtc->regs + SMICS); -+ struct vc4_crtc **crtc_list = data; -+ int i; -+ u32 stat = readl(crtc_list[0]->regs + SMICS); - irqreturn_t ret = IRQ_NONE; - - if (stat & SMICS_INTERRUPTS) { -- writel(0, vc4_crtc->regs + SMICS); -- if (vc4_crtc->vblank_enabled) -- drm_crtc_handle_vblank(&vc4_crtc->base); -- vc4_crtc_handle_page_flip(vc4_crtc); -- ret = IRQ_HANDLED; -+ writel(0, crtc_list[0]->regs + SMICS); -+ -+ for (i = 0; crtc_list[i]; i++) { -+ if (crtc_list[i]->vblank_enabled) -+ drm_crtc_handle_vblank(&crtc_list[i]->base); -+ vc4_crtc_handle_page_flip(crtc_list[i]); -+ ret = IRQ_HANDLED; -+ } - } - - return ret; -@@ -837,66 +845,55 @@ static const struct drm_encoder_helper_f - .disable = vc4_fkms_encoder_disable, - }; - --static int vc4_fkms_bind(struct device *dev, struct device *master, void *data) -+static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm, -+ int display_idx, int display_ref, -+ struct vc4_crtc **ret_crtc) - { -- struct platform_device *pdev = to_platform_device(dev); -- struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); - struct vc4_crtc *vc4_crtc; - struct vc4_fkms_encoder *vc4_encoder; - struct drm_crtc *crtc; - struct drm_plane *primary_plane, *overlay_plane, *cursor_plane; - struct drm_plane *destroy_plane, *temp; -- struct device_node *firmware_node; - u32 blank = 1; - int ret; - -- vc4->firmware_kms = true; -- -- /* firmware kms doesn't have precise a scanoutpos implementation, so -- * we can't do the precise vblank timestamp mode. -- */ -- drm->driver->get_scanout_position = NULL; -- drm->driver->get_vblank_timestamp = NULL; -- - vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); - if (!vc4_crtc) - return -ENOMEM; - crtc = &vc4_crtc->base; - -- firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); -- vc4->firmware = rpi_firmware_get(firmware_node); -- if (!vc4->firmware) { -- DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n"); -- return -EPROBE_DEFER; -- } -- of_node_put(firmware_node); -- -- /* Map the SMI interrupt reg */ -- vc4_crtc->regs = vc4_ioremap_regs(pdev, 0); -- if (IS_ERR(vc4_crtc->regs)) -- return PTR_ERR(vc4_crtc->regs); -+ vc4_crtc->display_number = display_ref; - - /* Blank the firmware provided framebuffer */ - rpi_firmware_property(vc4->firmware, - RPI_FIRMWARE_FRAMEBUFFER_BLANK, - &blank, sizeof(blank)); - -- primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0); -+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, -+ display_ref, -+ 0 + (display_idx * PLANES_PER_CRTC) -+ ); - if (IS_ERR(primary_plane)) { - dev_err(dev, "failed to construct primary plane\n"); - ret = PTR_ERR(primary_plane); - goto err; - } - -- overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, 1); -+ overlay_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, -+ display_ref, -+ 1 + (display_idx * PLANES_PER_CRTC) -+ ); - if (IS_ERR(overlay_plane)) { - dev_err(dev, "failed to construct overlay plane\n"); - ret = PTR_ERR(overlay_plane); - goto err; - } - -- cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, 2); -+ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR, -+ display_ref, -+ 2 + (display_idx * PLANES_PER_CRTC) -+ ); - if (IS_ERR(cursor_plane)) { - dev_err(dev, "failed to construct cursor plane\n"); - ret = PTR_ERR(cursor_plane); -@@ -923,13 +920,6 @@ static int vc4_fkms_bind(struct device * - goto err_destroy_encoder; - } - -- writel(0, vc4_crtc->regs + SMICS); -- ret = devm_request_irq(dev, platform_get_irq(pdev, 0), -- vc4_crtc_irq_handler, 0, "vc4 firmware kms", -- vc4_crtc); -- if (ret) -- goto err_destroy_connector; -- - ret = rpi_firmware_property(vc4->firmware, - RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN, - &vc4_crtc->overscan, -@@ -939,7 +929,7 @@ static int vc4_fkms_bind(struct device * - memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan)); - } - -- platform_set_drvdata(pdev, vc4_crtc); -+ *ret_crtc = vc4_crtc; - - return 0; - -@@ -956,17 +946,91 @@ err: - return ret; - } - -+static int vc4_fkms_bind(struct device *dev, struct device *master, void *data) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct drm_device *drm = dev_get_drvdata(master); -+ struct vc4_dev *vc4 = to_vc4_dev(drm); -+ struct device_node *firmware_node; -+ struct vc4_crtc **crtc_list; -+ u32 num_displays, display_num; -+ int ret; -+ const u32 display_num_lookup[] = {2, 7, 1}; -+ -+ vc4->firmware_kms = true; -+ -+ /* firmware kms doesn't have precise a scanoutpos implementation, so -+ * we can't do the precise vblank timestamp mode. -+ */ -+ drm->driver->get_scanout_position = NULL; -+ drm->driver->get_vblank_timestamp = NULL; -+ -+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); -+ vc4->firmware = rpi_firmware_get(firmware_node); -+ if (!vc4->firmware) { -+ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n"); -+ return -EPROBE_DEFER; -+ } -+ of_node_put(firmware_node); -+ -+ ret = rpi_firmware_property(vc4->firmware, -+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, -+ &num_displays, sizeof(u32)); -+ -+ /* If we fail to get the number of displays, or it returns 0, then -+ * assume old firmware that doesn't have the mailbox call, so just -+ * set one display -+ */ -+ if (ret || num_displays == 0) { -+ num_displays = 1; -+ DRM_WARN("Unable to determine number of displays's. Assuming 1\n"); -+ ret = 0; -+ } -+ -+ /* Allocate a list, with space for a NULL on the end */ -+ crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1), -+ GFP_KERNEL); -+ if (!crtc_list) -+ return -ENOMEM; -+ -+ for (display_num = 0; display_num < num_displays; display_num++) { -+ ret = vc4_fkms_create_screen(dev, drm, display_num, -+ display_num_lookup[display_num], -+ &crtc_list[display_num]); -+ if (ret) -+ DRM_ERROR("Oh dear, failed to create display %u\n", -+ display_num); -+ } -+ -+ /* Map the SMI interrupt reg */ -+ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0); -+ if (IS_ERR(crtc_list[0]->regs)) -+ DRM_ERROR("Oh dear, failed to map registers\n"); -+ -+ writel(0, crtc_list[0]->regs + SMICS); -+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), -+ vc4_crtc_irq_handler, 0, "vc4 firmware kms", -+ crtc_list); -+ if (ret) -+ DRM_ERROR("Oh dear, failed to register IRQ\n"); -+ -+ platform_set_drvdata(pdev, crtc_list); -+ -+ return 0; -+} -+ - static void vc4_fkms_unbind(struct device *dev, struct device *master, - void *data) - { -- struct drm_device *drm = dev_get_drvdata(master); - struct platform_device *pdev = to_platform_device(dev); -- struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev); -+ struct vc4_crtc **crtc_list = dev_get_drvdata(dev); -+ int i; - -- vc4_fkms_connector_destroy(vc4_crtc->connector); -- vc4_fkms_encoder_destroy(vc4_crtc->encoder); -- drm_atomic_helper_shutdown(drm); -- drm_crtc_cleanup(&vc4_crtc->base); -+ for (i = 0; crtc_list[i]; i++) { -+ vc4_fkms_connector_destroy(crtc_list[i]->connector); -+ vc4_fkms_encoder_destroy(crtc_list[i]->encoder); -+ drm_crtc_cleanup(&crtc_list[i]->base); -+ } - - platform_set_drvdata(pdev, NULL); - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Remove-now-unused-structure.patch b/target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Remove-now-unused-structure.patch new file mode 100644 index 0000000000..e6e4950e9a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0235-drm-vc4-Remove-now-unused-structure.patch @@ -0,0 +1,41 @@ +From dc19d8552bc0b6e0261fe7d28be81fe808a659e8 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 5 Apr 2019 17:24:20 +0100 +Subject: [PATCH] drm: vc4: Remove now unused structure. + +Cleaning up structure that was unused after +fbb59a2 drm: vc4: Add an overlay plane to vc4-firmware-kms + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 19 ------------------- + 1 file changed, 19 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -70,25 +70,6 @@ struct mailbox_set_plane { + struct set_plane plane; + }; + +-struct fb_alloc_tags { +- struct rpi_firmware_property_tag_header tag1; +- u32 xres, yres; +- struct rpi_firmware_property_tag_header tag2; +- u32 xres_virtual, yres_virtual; +- struct rpi_firmware_property_tag_header tag3; +- u32 bpp; +- struct rpi_firmware_property_tag_header tag4; +- u32 xoffset, yoffset; +- struct rpi_firmware_property_tag_header tag5; +- u32 base, screen_size; +- struct rpi_firmware_property_tag_header tag6; +- u32 pitch; +- struct rpi_firmware_property_tag_header tag7; +- u32 alpha_mode; +- struct rpi_firmware_property_tag_header tag8; +- u32 layer; +-}; +- + struct mailbox_blank_display { + struct rpi_firmware_property_tag_header tag1; + u32 display; diff --git a/target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Fix-build-warning.patch b/target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Fix-build-warning.patch deleted file mode 100644 index 63246286a2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Fix-build-warning.patch +++ /dev/null @@ -1,21 +0,0 @@ -From a06b826c199e6de39d4e91e41e8347a5629bb54a Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 5 Apr 2019 17:21:56 +0100 -Subject: [PATCH] drm: vc4: Fix build warning - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 -- - 1 file changed, 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -933,8 +933,6 @@ static int vc4_fkms_create_screen(struct - - return 0; - --err_destroy_connector: -- vc4_fkms_connector_destroy(vc4_crtc->connector); - err_destroy_encoder: - vc4_fkms_encoder_destroy(vc4_crtc->encoder); - list_for_each_entry_safe(destroy_plane, temp, diff --git a/target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch b/target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch new file mode 100644 index 0000000000..6e463e70eb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0236-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch @@ -0,0 +1,58 @@ +From 5357e5991f09f78e945b3adcc5db0ebfa1766dc1 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 9 Apr 2019 12:37:28 +0100 +Subject: [PATCH] drm: vc4: Query the display ID for each display in + FKMS + +Replace the hard coded list of display IDs for a mailbox call +that returns the display ID for each display that has been +detected. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++--- + include/soc/bcm2835/raspberrypi-firmware.h | 1 + + 2 files changed, 14 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -944,7 +944,7 @@ static int vc4_fkms_bind(struct device * + struct vc4_crtc **crtc_list; + u32 num_displays, display_num; + int ret; +- const u32 display_num_lookup[] = {2, 7, 1}; ++ u32 display_id; + + vc4->firmware_kms = true; + +@@ -983,8 +983,18 @@ static int vc4_fkms_bind(struct device * + return -ENOMEM; + + for (display_num = 0; display_num < num_displays; display_num++) { +- ret = vc4_fkms_create_screen(dev, drm, display_num, +- display_num_lookup[display_num], ++ display_id = display_num; ++ ret = rpi_firmware_property(vc4->firmware, ++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID, ++ &display_id, sizeof(display_id)); ++ /* FIXME: Determine the correct error handling here. ++ * Should we fail to create the one "screen" but keep the ++ * others, or fail the whole thing? ++ */ ++ if (ret) ++ DRM_ERROR("Failed to get display id %u\n", display_num); ++ ++ ret = vc4_fkms_create_screen(dev, drm, display_num, display_id, + &crtc_list[display_num]); + if (ret) + DRM_ERROR("Oh dear, failed to create display %u\n", +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -114,6 +114,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f, + RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010, + RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001, ++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016, + RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013, + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013, + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014, diff --git a/target/linux/bcm27xx/patches-5.4/950-0237-drm-vc4-Select-display-to-blank-during-initialisatio.patch b/target/linux/bcm27xx/patches-5.4/950-0237-drm-vc4-Select-display-to-blank-during-initialisatio.patch deleted file mode 100644 index 693292d04f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0237-drm-vc4-Select-display-to-blank-during-initialisatio.patch +++ /dev/null @@ -1,54 +0,0 @@ -From c2666d7b749ade8ed250ab115a71d420c1403b24 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 5 Apr 2019 17:23:15 +0100 -Subject: [PATCH] drm: vc4: Select display to blank during - initialisation - -Otherwise the rainbow splash screen remained in the display list - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 ++++++++++++++---- - 1 file changed, 14 insertions(+), 4 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -89,6 +89,13 @@ struct fb_alloc_tags { - u32 layer; - }; - -+struct mailbox_blank_display { -+ struct rpi_firmware_property_tag_header tag1; -+ u32 display; -+ struct rpi_firmware_property_tag_header tag2; -+ u32 blank; -+}; -+ - static const struct vc_image_format { - u32 drm; /* DRM_FORMAT_* */ - u32 vc_image; /* VC_IMAGE_* */ -@@ -855,7 +862,12 @@ static int vc4_fkms_create_screen(struct - struct drm_crtc *crtc; - struct drm_plane *primary_plane, *overlay_plane, *cursor_plane; - struct drm_plane *destroy_plane, *temp; -- u32 blank = 1; -+ struct mailbox_blank_display blank = { -+ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, }, -+ .display = display_idx, -+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_BLANK, 4, 0, }, -+ .blank = 1, -+ }; - int ret; - - vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); -@@ -866,9 +878,7 @@ static int vc4_fkms_create_screen(struct - vc4_crtc->display_number = display_ref; - - /* Blank the firmware provided framebuffer */ -- rpi_firmware_property(vc4->firmware, -- RPI_FIRMWARE_FRAMEBUFFER_BLANK, -- &blank, sizeof(blank)); -+ rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank)); - - primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, - display_ref, diff --git a/target/linux/bcm27xx/patches-5.4/950-0237-drm-vc4-Set-the-display-number-when-querying-the-dis.patch b/target/linux/bcm27xx/patches-5.4/950-0237-drm-vc4-Set-the-display-number-when-querying-the-dis.patch new file mode 100644 index 0000000000..7b8efc7e73 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0237-drm-vc4-Set-the-display-number-when-querying-the-dis.patch @@ -0,0 +1,103 @@ +From d72d6e2388c082ef48d776105ebb285c2d470fa6 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 9 Apr 2019 14:00:07 +0100 +Subject: [PATCH] drm/vc4: Set the display number when querying the + display resolution + +Without this the two displays got set to the same resolution. +(Requires a firmware bug fix to work). + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 +++++++++++++++++++------- + 1 file changed, 27 insertions(+), 10 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -77,6 +77,13 @@ struct mailbox_blank_display { + u32 blank; + }; + ++struct mailbox_get_width_height { ++ struct rpi_firmware_property_tag_header tag1; ++ u32 display; ++ struct rpi_firmware_property_tag_header tag2; ++ u32 wh[2]; ++}; ++ + static const struct vc_image_format { + u32 drm; /* DRM_FORMAT_* */ + u32 vc_image; /* VC_IMAGE_* */ +@@ -194,6 +201,7 @@ struct vc4_fkms_connector { + * hook. + */ + struct drm_encoder *encoder; ++ u32 display_idx; + }; + + static inline struct vc4_fkms_connector * +@@ -724,21 +732,27 @@ vc4_fkms_connector_detect(struct drm_con + static int vc4_fkms_connector_get_modes(struct drm_connector *connector) + { + struct drm_device *dev = connector->dev; ++ struct vc4_fkms_connector *fkms_connector = ++ to_vc4_fkms_connector(connector); + struct vc4_dev *vc4 = to_vc4_dev(dev); +- u32 wh[2] = {0, 0}; +- int ret; + struct drm_display_mode *mode; ++ struct mailbox_get_width_height wh = { ++ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, }, ++ .display = fkms_connector->display_idx, ++ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT, ++ 8, 0, }, ++ }; ++ int ret; ++ ++ ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh)); + +- ret = rpi_firmware_property(vc4->firmware, +- RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT, +- &wh, sizeof(wh)); + if (ret) { + DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n", +- ret, wh[0], wh[1]); ++ ret, wh.wh[0], wh.wh[1]); + return 0; + } + +- mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */, ++ mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */, + 0, 0, false); + drm_mode_probed_add(connector, mode); + +@@ -773,8 +787,9 @@ static const struct drm_connector_helper + .best_encoder = vc4_fkms_connector_best_encoder, + }; + +-static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev, +- struct drm_encoder *encoder) ++static struct drm_connector * ++vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder, ++ u32 display_idx) + { + struct drm_connector *connector = NULL; + struct vc4_fkms_connector *fkms_connector; +@@ -789,6 +804,7 @@ static struct drm_connector *vc4_fkms_co + connector = &fkms_connector->base; + + fkms_connector->encoder = encoder; ++ fkms_connector->display_idx = display_idx; + + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); +@@ -905,7 +921,8 @@ static int vc4_fkms_create_screen(struct + drm_encoder_helper_add(&vc4_encoder->base, + &vc4_fkms_encoder_helper_funcs); + +- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base); ++ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base, ++ display_idx); + if (IS_ERR(vc4_crtc->connector)) { + ret = PTR_ERR(vc4_crtc->connector); + goto err_destroy_encoder; diff --git a/target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch b/target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch new file mode 100644 index 0000000000..635340c082 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch @@ -0,0 +1,54 @@ +From 236758b499086e0de280407396550125f1b6647a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 9 Apr 2019 18:14:44 +0100 +Subject: [PATCH] from + vc4_crtc_[en|dis]able + +vblank needs to be enabled and disabled by the driver to avoid the +DRM framework complaining in the kernel log. + +vc4_fkms_disable_vblank needs to signal that we don't want vblank +callbacks too. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -21,6 +21,7 @@ + #include "drm/drm_fourcc.h" + #include "drm/drm_probe_helper.h" + #include "drm/drm_drv.h" ++#include "drm/drm_vblank.h" + #include "linux/clk.h" + #include "linux/debugfs.h" + #include "drm/drm_fb_cma_helper.h" +@@ -563,6 +564,8 @@ static void vc4_crtc_mode_set_nofb(struc + + static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + { ++ drm_crtc_vblank_off(crtc); ++ + /* Always turn the planes off on CRTC disable. In DRM, planes + * are enabled/disabled through the update/disable hooks + * above, and the CRTC enable/disable independently controls +@@ -578,6 +581,7 @@ static void vc4_crtc_disable(struct drm_ + + static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + { ++ drm_crtc_vblank_on(crtc); + /* Unblank the planes (if they're supposed to be displayed). */ + + if (crtc->primary->state->fb) +@@ -674,6 +678,9 @@ static int vc4_fkms_enable_vblank(struct + + static void vc4_fkms_disable_vblank(struct drm_crtc *crtc) + { ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ ++ vc4_crtc->vblank_enabled = false; + } + + static const struct drm_crtc_funcs vc4_crtc_funcs = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Remove-now-unused-structure.patch b/target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Remove-now-unused-structure.patch deleted file mode 100644 index e6e4950e9a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0238-drm-vc4-Remove-now-unused-structure.patch +++ /dev/null @@ -1,41 +0,0 @@ -From dc19d8552bc0b6e0261fe7d28be81fe808a659e8 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 5 Apr 2019 17:24:20 +0100 -Subject: [PATCH] drm: vc4: Remove now unused structure. - -Cleaning up structure that was unused after -fbb59a2 drm: vc4: Add an overlay plane to vc4-firmware-kms - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 19 ------------------- - 1 file changed, 19 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -70,25 +70,6 @@ struct mailbox_set_plane { - struct set_plane plane; - }; - --struct fb_alloc_tags { -- struct rpi_firmware_property_tag_header tag1; -- u32 xres, yres; -- struct rpi_firmware_property_tag_header tag2; -- u32 xres_virtual, yres_virtual; -- struct rpi_firmware_property_tag_header tag3; -- u32 bpp; -- struct rpi_firmware_property_tag_header tag4; -- u32 xoffset, yoffset; -- struct rpi_firmware_property_tag_header tag5; -- u32 base, screen_size; -- struct rpi_firmware_property_tag_header tag6; -- u32 pitch; -- struct rpi_firmware_property_tag_header tag7; -- u32 alpha_mode; -- struct rpi_firmware_property_tag_header tag8; -- u32 layer; --}; -- - struct mailbox_blank_display { - struct rpi_firmware_property_tag_header tag1; - u32 display; diff --git a/target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch b/target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch new file mode 100644 index 0000000000..43a2ffab16 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch @@ -0,0 +1,86 @@ +From 495fd0373ad234c8547697e3a7de1f1724c8498d Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 9 Apr 2019 17:19:51 +0100 +Subject: [PATCH] drm: vc4: Add support for H & V flips on each plane + for FKMS + +They are near zero cost options for the HVS, therefore they +may as well be implemented, and it allows us to invert the +DSI display. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 36 ++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -64,8 +64,21 @@ struct set_plane { + u8 padding; + + u32 planes[4]; /* DMA address of each plane */ ++ ++ u32 transform; + }; + ++/* Values for the transform field */ ++#define TRANSFORM_NO_ROTATE 0 ++#define TRANSFORM_ROTATE_180 BIT(1) ++#define TRANSFORM_FLIP_HRIZ BIT(16) ++#define TRANSFORM_FLIP_VERT BIT(17) ++ ++#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \ ++ DRM_MODE_ROTATE_180 | \ ++ DRM_MODE_REFLECT_X | \ ++ DRM_MODE_REFLECT_Y) ++ + struct mailbox_set_plane { + struct rpi_firmware_property_tag_header tag; + struct set_plane plane; +@@ -277,6 +290,7 @@ static void vc4_plane_atomic_update(stru + struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); + int num_planes = fb->format->num_planes; + struct drm_display_mode *mode = &state->crtc->mode; ++ unsigned int rotation = SUPPORTED_ROTATIONS; + + mb->plane.vc_image_type = vc_fmt->vc_image; + mb->plane.width = fb->width; +@@ -297,6 +311,24 @@ static void vc4_plane_atomic_update(stru + mb->plane.is_vu = vc_fmt->is_vu; + mb->plane.planes[0] = bo->paddr + fb->offsets[0]; + ++ rotation = drm_rotation_simplify(state->rotation, rotation); ++ ++ switch (rotation) { ++ default: ++ case DRM_MODE_ROTATE_0: ++ mb->plane.transform = TRANSFORM_NO_ROTATE; ++ break; ++ case DRM_MODE_ROTATE_180: ++ mb->plane.transform = TRANSFORM_ROTATE_180; ++ break; ++ case DRM_MODE_REFLECT_X: ++ mb->plane.transform = TRANSFORM_FLIP_HRIZ; ++ break; ++ case DRM_MODE_REFLECT_Y: ++ mb->plane.transform = TRANSFORM_FLIP_VERT; ++ break; ++ } ++ + /* FIXME: If the dest rect goes off screen then clip the src rect so we + * don't have off-screen pixels. + */ +@@ -516,9 +548,13 @@ static struct drm_plane *vc4_fkms_plane_ + formats, num_formats, modifiers, + type, NULL); + ++ /* FIXME: Do we need to be checking return values from all these calls? ++ */ + drm_plane_helper_add(plane, &vc4_plane_helper_funcs); + + drm_plane_create_alpha_property(plane); ++ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, ++ SUPPORTED_ROTATIONS); + + /* + * Default frame buffer setup is with FB on -127, and raspistill etc diff --git a/target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch b/target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch deleted file mode 100644 index 6e463e70eb..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0239-drm-vc4-Query-the-display-ID-for-each-display-in-FKM.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 5357e5991f09f78e945b3adcc5db0ebfa1766dc1 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 9 Apr 2019 12:37:28 +0100 -Subject: [PATCH] drm: vc4: Query the display ID for each display in - FKMS - -Replace the hard coded list of display IDs for a mailbox call -that returns the display ID for each display that has been -detected. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++--- - include/soc/bcm2835/raspberrypi-firmware.h | 1 + - 2 files changed, 14 insertions(+), 3 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -944,7 +944,7 @@ static int vc4_fkms_bind(struct device * - struct vc4_crtc **crtc_list; - u32 num_displays, display_num; - int ret; -- const u32 display_num_lookup[] = {2, 7, 1}; -+ u32 display_id; - - vc4->firmware_kms = true; - -@@ -983,8 +983,18 @@ static int vc4_fkms_bind(struct device * - return -ENOMEM; - - for (display_num = 0; display_num < num_displays; display_num++) { -- ret = vc4_fkms_create_screen(dev, drm, display_num, -- display_num_lookup[display_num], -+ display_id = display_num; -+ ret = rpi_firmware_property(vc4->firmware, -+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID, -+ &display_id, sizeof(display_id)); -+ /* FIXME: Determine the correct error handling here. -+ * Should we fail to create the one "screen" but keep the -+ * others, or fail the whole thing? -+ */ -+ if (ret) -+ DRM_ERROR("Failed to get display id %u\n", display_num); -+ -+ ret = vc4_fkms_create_screen(dev, drm, display_num, display_id, - &crtc_list[display_num]); - if (ret) - DRM_ERROR("Oh dear, failed to create display %u\n", ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -114,6 +114,7 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f, - RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010, - RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001, -+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016, - RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013, - RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013, - RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014, diff --git a/target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch b/target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch new file mode 100644 index 0000000000..6740f7fc6e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch @@ -0,0 +1,56 @@ +From 99d029e3a379efb75725460b03465f80e0111da1 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 10 Apr 2019 17:35:05 +0100 +Subject: [PATCH] drm: vc4: Remove unused vc4_fkms_cancel_page_flip + function + +"32a3dbe drm/vc4: Nuke preclose hook" removed vc4_cancel_page_flip, +but vc4_fkms_cancel_page_flip was still be added to with the +fkms driver, even though it was never called. +Nuke it too. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 - + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 -------------------- + 2 files changed, 21 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -795,7 +795,6 @@ extern const struct dma_fence_ops vc4_fe + + /* vc4_firmware_kms.c */ + extern struct platform_driver vc4_firmware_kms_driver; +-void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); + + /* vc4_gem.c */ + void vc4_gem_init(struct drm_device *dev); +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -741,26 +741,6 @@ static const struct drm_crtc_helper_func + .atomic_flush = vc4_crtc_atomic_flush, + }; + +-/* Frees the page flip event when the DRM device is closed with the +- * event still outstanding. +- */ +-void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) +-{ +- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +- struct drm_device *dev = crtc->dev; +- unsigned long flags; +- +- spin_lock_irqsave(&dev->event_lock, flags); +- +- if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) { +- kfree(&vc4_crtc->event->base); +- drm_crtc_vblank_put(crtc); +- vc4_crtc->event = NULL; +- } +- +- spin_unlock_irqrestore(&dev->event_lock, flags); +-} +- + static const struct of_device_id vc4_firmware_kms_dt_match[] = { + { .compatible = "raspberrypi,rpi-firmware-kms" }, + {} diff --git a/target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Set-the-display-number-when-querying-the-dis.patch b/target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Set-the-display-number-when-querying-the-dis.patch deleted file mode 100644 index 7b8efc7e73..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0240-drm-vc4-Set-the-display-number-when-querying-the-dis.patch +++ /dev/null @@ -1,103 +0,0 @@ -From d72d6e2388c082ef48d776105ebb285c2d470fa6 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 9 Apr 2019 14:00:07 +0100 -Subject: [PATCH] drm/vc4: Set the display number when querying the - display resolution - -Without this the two displays got set to the same resolution. -(Requires a firmware bug fix to work). - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 +++++++++++++++++++------- - 1 file changed, 27 insertions(+), 10 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -77,6 +77,13 @@ struct mailbox_blank_display { - u32 blank; - }; - -+struct mailbox_get_width_height { -+ struct rpi_firmware_property_tag_header tag1; -+ u32 display; -+ struct rpi_firmware_property_tag_header tag2; -+ u32 wh[2]; -+}; -+ - static const struct vc_image_format { - u32 drm; /* DRM_FORMAT_* */ - u32 vc_image; /* VC_IMAGE_* */ -@@ -194,6 +201,7 @@ struct vc4_fkms_connector { - * hook. - */ - struct drm_encoder *encoder; -+ u32 display_idx; - }; - - static inline struct vc4_fkms_connector * -@@ -724,21 +732,27 @@ vc4_fkms_connector_detect(struct drm_con - static int vc4_fkms_connector_get_modes(struct drm_connector *connector) - { - struct drm_device *dev = connector->dev; -+ struct vc4_fkms_connector *fkms_connector = -+ to_vc4_fkms_connector(connector); - struct vc4_dev *vc4 = to_vc4_dev(dev); -- u32 wh[2] = {0, 0}; -- int ret; - struct drm_display_mode *mode; -+ struct mailbox_get_width_height wh = { -+ .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, }, -+ .display = fkms_connector->display_idx, -+ .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT, -+ 8, 0, }, -+ }; -+ int ret; -+ -+ ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh)); - -- ret = rpi_firmware_property(vc4->firmware, -- RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT, -- &wh, sizeof(wh)); - if (ret) { - DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n", -- ret, wh[0], wh[1]); -+ ret, wh.wh[0], wh.wh[1]); - return 0; - } - -- mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */, -+ mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */, - 0, 0, false); - drm_mode_probed_add(connector, mode); - -@@ -773,8 +787,9 @@ static const struct drm_connector_helper - .best_encoder = vc4_fkms_connector_best_encoder, - }; - --static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev, -- struct drm_encoder *encoder) -+static struct drm_connector * -+vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder, -+ u32 display_idx) - { - struct drm_connector *connector = NULL; - struct vc4_fkms_connector *fkms_connector; -@@ -789,6 +804,7 @@ static struct drm_connector *vc4_fkms_co - connector = &fkms_connector->base; - - fkms_connector->encoder = encoder; -+ fkms_connector->display_idx = display_idx; - - drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); -@@ -905,7 +921,8 @@ static int vc4_fkms_create_screen(struct - drm_encoder_helper_add(&vc4_encoder->base, - &vc4_fkms_encoder_helper_funcs); - -- vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base); -+ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base, -+ display_idx); - if (IS_ERR(vc4_crtc->connector)) { - ret = PTR_ERR(vc4_crtc->connector); - goto err_destroy_encoder; diff --git a/target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch b/target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch new file mode 100644 index 0000000000..05f50cd913 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch @@ -0,0 +1,57 @@ +From 016e6e68a119d3f4cae3c148433e2d661c7835be Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 10 Apr 2019 17:42:37 +0100 +Subject: [PATCH] drm: vc4: Iterate over all planes in + vc4_crtc_[dis|en]able + +Fixes a FIXME where the overlay plane wouldn't be restored. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -600,6 +600,8 @@ static void vc4_crtc_mode_set_nofb(struc + + static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + { ++ struct drm_plane *plane; ++ + drm_crtc_vblank_off(crtc); + + /* Always turn the planes off on CRTC disable. In DRM, planes +@@ -609,23 +611,23 @@ static void vc4_crtc_disable(struct drm_ + * give us a CRTC-level control for that. + */ + +- vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state); +- vc4_plane_atomic_disable(crtc->primary, crtc->primary->state); +- +- /* FIXME: Disable overlay planes */ ++ drm_atomic_crtc_for_each_plane(plane, crtc) ++ vc4_plane_atomic_disable(plane, plane->state); + } + + static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + { ++ struct drm_plane *plane; ++ + drm_crtc_vblank_on(crtc); ++ + /* Unblank the planes (if they're supposed to be displayed). */ ++ drm_atomic_crtc_for_each_plane(plane, crtc) ++ if (plane->state->fb) ++ vc4_plane_set_blank(plane, plane->state->visible); ++} + +- if (crtc->primary->state->fb) +- vc4_plane_set_blank(crtc->primary, false); +- if (crtc->cursor->state->fb) +- vc4_plane_set_blank(crtc->cursor, crtc->cursor->state); + +- /* FIXME: Enable overlay planes */ + } + + static int vc4_crtc_atomic_check(struct drm_crtc *crtc, diff --git a/target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch b/target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch deleted file mode 100644 index 635340c082..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0241-drm-vc4-Need-to-call-drm_crtc_vblank_-on-off-from-vc.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 236758b499086e0de280407396550125f1b6647a Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 9 Apr 2019 18:14:44 +0100 -Subject: [PATCH] from - vc4_crtc_[en|dis]able - -vblank needs to be enabled and disabled by the driver to avoid the -DRM framework complaining in the kernel log. - -vc4_fkms_disable_vblank needs to signal that we don't want vblank -callbacks too. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -21,6 +21,7 @@ - #include "drm/drm_fourcc.h" - #include "drm/drm_probe_helper.h" - #include "drm/drm_drv.h" -+#include "drm/drm_vblank.h" - #include "linux/clk.h" - #include "linux/debugfs.h" - #include "drm/drm_fb_cma_helper.h" -@@ -563,6 +564,8 @@ static void vc4_crtc_mode_set_nofb(struc - - static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) - { -+ drm_crtc_vblank_off(crtc); -+ - /* Always turn the planes off on CRTC disable. In DRM, planes - * are enabled/disabled through the update/disable hooks - * above, and the CRTC enable/disable independently controls -@@ -578,6 +581,7 @@ static void vc4_crtc_disable(struct drm_ - - static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) - { -+ drm_crtc_vblank_on(crtc); - /* Unblank the planes (if they're supposed to be displayed). */ - - if (crtc->primary->state->fb) -@@ -674,6 +678,9 @@ static int vc4_fkms_enable_vblank(struct - - static void vc4_fkms_disable_vblank(struct drm_crtc *crtc) - { -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -+ -+ vc4_crtc->vblank_enabled = false; - } - - static const struct drm_crtc_funcs vc4_crtc_funcs = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch b/target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch deleted file mode 100644 index 43a2ffab16..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Add-support-for-H-V-flips-on-each-plane-for-.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 495fd0373ad234c8547697e3a7de1f1724c8498d Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 9 Apr 2019 17:19:51 +0100 -Subject: [PATCH] drm: vc4: Add support for H & V flips on each plane - for FKMS - -They are near zero cost options for the HVS, therefore they -may as well be implemented, and it allows us to invert the -DSI display. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 36 ++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -64,8 +64,21 @@ struct set_plane { - u8 padding; - - u32 planes[4]; /* DMA address of each plane */ -+ -+ u32 transform; - }; - -+/* Values for the transform field */ -+#define TRANSFORM_NO_ROTATE 0 -+#define TRANSFORM_ROTATE_180 BIT(1) -+#define TRANSFORM_FLIP_HRIZ BIT(16) -+#define TRANSFORM_FLIP_VERT BIT(17) -+ -+#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \ -+ DRM_MODE_ROTATE_180 | \ -+ DRM_MODE_REFLECT_X | \ -+ DRM_MODE_REFLECT_Y) -+ - struct mailbox_set_plane { - struct rpi_firmware_property_tag_header tag; - struct set_plane plane; -@@ -277,6 +290,7 @@ static void vc4_plane_atomic_update(stru - struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); - int num_planes = fb->format->num_planes; - struct drm_display_mode *mode = &state->crtc->mode; -+ unsigned int rotation = SUPPORTED_ROTATIONS; - - mb->plane.vc_image_type = vc_fmt->vc_image; - mb->plane.width = fb->width; -@@ -297,6 +311,24 @@ static void vc4_plane_atomic_update(stru - mb->plane.is_vu = vc_fmt->is_vu; - mb->plane.planes[0] = bo->paddr + fb->offsets[0]; - -+ rotation = drm_rotation_simplify(state->rotation, rotation); -+ -+ switch (rotation) { -+ default: -+ case DRM_MODE_ROTATE_0: -+ mb->plane.transform = TRANSFORM_NO_ROTATE; -+ break; -+ case DRM_MODE_ROTATE_180: -+ mb->plane.transform = TRANSFORM_ROTATE_180; -+ break; -+ case DRM_MODE_REFLECT_X: -+ mb->plane.transform = TRANSFORM_FLIP_HRIZ; -+ break; -+ case DRM_MODE_REFLECT_Y: -+ mb->plane.transform = TRANSFORM_FLIP_VERT; -+ break; -+ } -+ - /* FIXME: If the dest rect goes off screen then clip the src rect so we - * don't have off-screen pixels. - */ -@@ -516,9 +548,13 @@ static struct drm_plane *vc4_fkms_plane_ - formats, num_formats, modifiers, - type, NULL); - -+ /* FIXME: Do we need to be checking return values from all these calls? -+ */ - drm_plane_helper_add(plane, &vc4_plane_helper_funcs); - - drm_plane_create_alpha_property(plane); -+ drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, -+ SUPPORTED_ROTATIONS); - - /* - * Default frame buffer setup is with FB on -127, and raspistill etc diff --git a/target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch b/target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch new file mode 100644 index 0000000000..10a655ade1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0242-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch @@ -0,0 +1,47 @@ +From 9185a16ce8804d35339402c6aec38a528cc2c7a1 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 10 Apr 2019 17:43:57 +0100 +Subject: [PATCH] drm: vc4: Bring fkms into line with kms in blocking + doublescan modes + +Implement vc4_crtc_mode_valid so that it blocks doublescan modes + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -627,7 +627,17 @@ static void vc4_crtc_enable(struct drm_c + vc4_plane_set_blank(plane, plane->state->visible); + } + ++static enum drm_mode_status ++vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) ++{ ++ /* Do not allow doublescan modes from user space */ ++ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { ++ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n", ++ crtc->base.id); ++ return MODE_NO_DBLESCAN; ++ } + ++ return MODE_OK; + } + + static int vc4_crtc_atomic_check(struct drm_crtc *crtc, +@@ -737,10 +747,11 @@ static const struct drm_crtc_funcs vc4_c + + static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { + .mode_set_nofb = vc4_crtc_mode_set_nofb, +- .atomic_disable = vc4_crtc_disable, +- .atomic_enable = vc4_crtc_enable, ++ .mode_valid = vc4_crtc_mode_valid, + .atomic_check = vc4_crtc_atomic_check, + .atomic_flush = vc4_crtc_atomic_flush, ++ .atomic_enable = vc4_crtc_enable, ++ .atomic_disable = vc4_crtc_disable, + }; + + static const struct of_device_id vc4_firmware_kms_dt_match[] = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Increase-max_width-height-to-7680.patch b/target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Increase-max_width-height-to-7680.patch new file mode 100644 index 0000000000..69d1470663 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Increase-max_width-height-to-7680.patch @@ -0,0 +1,27 @@ +From 11801b1f71144478ab6c19a4c309667d340cb9e2 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 29 Apr 2019 18:45:00 +0100 +Subject: [PATCH] drm: vc4: Increase max_width/height to 7680. + +There are some limits still being investigated that stop +us going up to 8192, but 7680 is sufficient for dual 4k +displays. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev) + return ret; + } + +- dev->mode_config.max_width = 4096; +- dev->mode_config.max_height = 4096; ++ dev->mode_config.max_width = 7680; ++ dev->mode_config.max_height = 7680; + dev->mode_config.funcs = &vc4_mode_funcs; + dev->mode_config.preferred_depth = 24; + dev->mode_config.async_page_flip = true; diff --git a/target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch b/target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch deleted file mode 100644 index 6740f7fc6e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0243-drm-vc4-Remove-unused-vc4_fkms_cancel_page_flip-func.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 99d029e3a379efb75725460b03465f80e0111da1 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 10 Apr 2019 17:35:05 +0100 -Subject: [PATCH] drm: vc4: Remove unused vc4_fkms_cancel_page_flip - function - -"32a3dbe drm/vc4: Nuke preclose hook" removed vc4_cancel_page_flip, -but vc4_fkms_cancel_page_flip was still be added to with the -fkms driver, even though it was never called. -Nuke it too. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_drv.h | 1 - - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 -------------------- - 2 files changed, 21 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_drv.h -+++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -795,7 +795,6 @@ extern const struct dma_fence_ops vc4_fe - - /* vc4_firmware_kms.c */ - extern struct platform_driver vc4_firmware_kms_driver; --void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); - - /* vc4_gem.c */ - void vc4_gem_init(struct drm_device *dev); ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -741,26 +741,6 @@ static const struct drm_crtc_helper_func - .atomic_flush = vc4_crtc_atomic_flush, - }; - --/* Frees the page flip event when the DRM device is closed with the -- * event still outstanding. -- */ --void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) --{ -- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -- struct drm_device *dev = crtc->dev; -- unsigned long flags; -- -- spin_lock_irqsave(&dev->event_lock, flags); -- -- if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) { -- kfree(&vc4_crtc->event->base); -- drm_crtc_vblank_put(crtc); -- vc4_crtc->event = NULL; -- } -- -- spin_unlock_irqrestore(&dev->event_lock, flags); --} -- - static const struct of_device_id vc4_firmware_kms_dt_match[] = { - { .compatible = "raspberrypi,rpi-firmware-kms" }, - {} diff --git a/target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch b/target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch new file mode 100644 index 0000000000..92400560ac --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch @@ -0,0 +1,557 @@ +From 52add140c76c0a211ab340ced8e7e1ea8bef9c79 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 9 Apr 2019 18:23:41 +0100 +Subject: [PATCH] drm: vc4: FKMS reads the EDID from fw, and supports + mode setting + +This extends FKMS to read the EDID from the display, and support +requesting a particular mode via KMS. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 334 ++++++++++++++++++--- + include/soc/bcm2835/raspberrypi-firmware.h | 2 + + 2 files changed, 302 insertions(+), 34 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -91,11 +91,60 @@ struct mailbox_blank_display { + u32 blank; + }; + +-struct mailbox_get_width_height { ++struct mailbox_get_edid { + struct rpi_firmware_property_tag_header tag1; +- u32 display; +- struct rpi_firmware_property_tag_header tag2; +- u32 wh[2]; ++ u32 block; ++ u32 display_number; ++ u8 edid[128]; ++}; ++ ++struct set_timings { ++ u8 display; ++ u8 padding; ++ u16 video_id_code; ++ ++ u32 clock; /* in kHz */ ++ ++ u16 hdisplay; ++ u16 hsync_start; ++ ++ u16 hsync_end; ++ u16 htotal; ++ ++ u16 hskew; ++ u16 vdisplay; ++ ++ u16 vsync_start; ++ u16 vsync_end; ++ ++ u16 vtotal; ++ u16 vscan; ++ ++ u16 vrefresh; ++ u16 padding2; ++ ++ u32 flags; ++#define TIMINGS_FLAGS_H_SYNC_POS BIT(0) ++#define TIMINGS_FLAGS_H_SYNC_NEG 0 ++#define TIMINGS_FLAGS_V_SYNC_POS BIT(1) ++#define TIMINGS_FLAGS_V_SYNC_NEG 0 ++ ++#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4) ++#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4) ++#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4) ++#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4) ++#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4) ++#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4) ++ ++/* Limited range RGB flag. Not set corresponds to full range. */ ++#define TIMINGS_FLAGS_RGB_LIMITED BIT(8) ++/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */ ++#define TIMINGS_FLAGS_DVI BIT(9) ++}; ++ ++struct mailbox_set_mode { ++ struct rpi_firmware_property_tag_header tag1; ++ struct set_timings timings; + }; + + static const struct vc_image_format { +@@ -189,6 +238,7 @@ struct vc4_crtc { + u32 overscan[4]; + bool vblank_enabled; + u32 display_number; ++ u32 display_type; + }; + + static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc) +@@ -198,6 +248,8 @@ static inline struct vc4_crtc *to_vc4_cr + + struct vc4_fkms_encoder { + struct drm_encoder base; ++ bool hdmi_monitor; ++ bool rgb_range_selectable; + }; + + static inline struct vc4_fkms_encoder * +@@ -215,7 +267,9 @@ struct vc4_fkms_connector { + * hook. + */ + struct drm_encoder *encoder; +- u32 display_idx; ++ struct vc4_dev *vc4_dev; ++ u32 display_number; ++ u32 display_type; + }; + + static inline struct vc4_fkms_connector * +@@ -224,6 +278,26 @@ to_vc4_fkms_connector(struct drm_connect + return container_of(connector, struct vc4_fkms_connector, base); + } + ++static u32 vc4_get_display_type(u32 display_number) ++{ ++ const u32 display_types[] = { ++ /* The firmware display (DispmanX) IDs map to specific types in ++ * a fixed manner. ++ */ ++ DRM_MODE_ENCODER_DSI, /* MAIN_LCD */ ++ DRM_MODE_ENCODER_DSI, /* AUX_LCD */ ++ DRM_MODE_ENCODER_TMDS, /* HDMI0 */ ++ DRM_MODE_ENCODER_TVDAC, /* VEC */ ++ DRM_MODE_ENCODER_NONE, /* FORCE_LCD */ ++ DRM_MODE_ENCODER_NONE, /* FORCE_TV */ ++ DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */ ++ DRM_MODE_ENCODER_TMDS, /* HDMI1 */ ++ DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */ ++ }; ++ return display_number > ARRAY_SIZE(display_types) - 1 ? ++ DRM_MODE_ENCODER_NONE : display_types[display_number]; ++} ++ + /* Firmware's structure for making an FB mbox call. */ + struct fbinfo_s { + u32 xres, yres, xres_virtual, yres_virtual; +@@ -258,10 +332,15 @@ static int vc4_plane_set_blank(struct dr + .plane_id = vc4_plane->mb.plane.plane_id, + } + }; ++ static const char * const plane_types[] = { ++ "overlay", ++ "primary", ++ "cursor" ++ }; + int ret; + +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s", +- plane->base.id, plane->name, ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s", ++ plane->base.id, plane->name, plane_types[plane->type], + blank ? "blank" : "unblank"); + + if (blank) +@@ -595,13 +674,102 @@ fail: + + static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) + { +- /* Everyting is handled in the planes. */ ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_display_mode *mode = &crtc->state->adjusted_mode; ++ struct vc4_fkms_encoder *vc4_encoder = ++ to_vc4_fkms_encoder(vc4_crtc->encoder); ++ struct mailbox_set_mode mb = { ++ .tag1 = { RPI_FIRMWARE_SET_TIMING, ++ sizeof(struct set_timings), 0}, ++ }; ++ union hdmi_infoframe frame; ++ int ret; ++ ++ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode); ++ if (ret < 0) { ++ DRM_ERROR("couldn't fill AVI infoframe\n"); ++ return; ++ } ++ ++ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n", ++ vc4_crtc->display_number, mode->name, mode->clock, ++ mode->hdisplay, mode->hsync_start, mode->hsync_end, ++ mode->htotal, mode->hskew, mode->vdisplay, ++ mode->vsync_start, mode->vsync_end, mode->vtotal, ++ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio); ++ mb.timings.display = vc4_crtc->display_number; ++ ++ mb.timings.video_id_code = frame.avi.video_code; ++ ++ mb.timings.clock = mode->clock; ++ mb.timings.hdisplay = mode->hdisplay; ++ mb.timings.hsync_start = mode->hsync_start; ++ mb.timings.hsync_end = mode->hsync_end; ++ mb.timings.htotal = mode->htotal; ++ mb.timings.hskew = mode->hskew; ++ mb.timings.vdisplay = mode->vdisplay; ++ mb.timings.vsync_start = mode->vsync_start; ++ mb.timings.vsync_end = mode->vsync_end; ++ mb.timings.vtotal = mode->vtotal; ++ mb.timings.vscan = mode->vscan; ++ mb.timings.vrefresh = 0; ++ mb.timings.flags = 0; ++ if (mode->flags & DRM_MODE_FLAG_PHSYNC) ++ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS; ++ if (mode->flags & DRM_MODE_FLAG_PVSYNC) ++ mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS; ++ ++ switch (frame.avi.picture_aspect) { ++ default: ++ case HDMI_PICTURE_ASPECT_NONE: ++ mode->flags |= TIMINGS_FLAGS_ASPECT_NONE; ++ break; ++ case HDMI_PICTURE_ASPECT_4_3: ++ mode->flags |= TIMINGS_FLAGS_ASPECT_4_3; ++ break; ++ case HDMI_PICTURE_ASPECT_16_9: ++ mode->flags |= TIMINGS_FLAGS_ASPECT_16_9; ++ break; ++ case HDMI_PICTURE_ASPECT_64_27: ++ mode->flags |= TIMINGS_FLAGS_ASPECT_64_27; ++ break; ++ case HDMI_PICTURE_ASPECT_256_135: ++ mode->flags |= TIMINGS_FLAGS_ASPECT_256_135; ++ break; ++ } ++ ++ if (!vc4_encoder->hdmi_monitor) ++ mb.timings.flags |= TIMINGS_FLAGS_DVI; ++ else if (drm_default_rgb_quant_range(mode) == ++ HDMI_QUANTIZATION_RANGE_LIMITED) ++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; ++ ++ /* ++ FIXME: To implement ++ switch(mode->flag & DRM_MODE_FLAG_3D_MASK) { ++ case DRM_MODE_FLAG_3D_NONE: ++ case DRM_MODE_FLAG_3D_FRAME_PACKING: ++ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: ++ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: ++ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: ++ case DRM_MODE_FLAG_3D_L_DEPTH: ++ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: ++ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: ++ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: ++ } ++ */ ++ ++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); + } + + static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + { + struct drm_plane *plane; + ++ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n", ++ crtc->base.id); + drm_crtc_vblank_off(crtc); + + /* Always turn the planes off on CRTC disable. In DRM, planes +@@ -619,6 +787,8 @@ static void vc4_crtc_enable(struct drm_c + { + struct drm_plane *plane; + ++ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n", ++ crtc->base.id); + drm_crtc_vblank_on(crtc); + + /* Unblank the planes (if they're supposed to be displayed). */ +@@ -637,12 +807,20 @@ vc4_crtc_mode_valid(struct drm_crtc *crt + return MODE_NO_DBLESCAN; + } + ++ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling ++ * working. ++ */ ++ if (mode->clock > 340000) ++ return MODE_CLOCK_HIGH; ++ + return MODE_OK; + } + + static int vc4_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) + { ++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", ++ crtc->base.id); + return 0; + } + +@@ -652,6 +830,8 @@ static void vc4_crtc_atomic_flush(struct + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + struct drm_device *dev = crtc->dev; + ++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n", ++ crtc->base.id); + if (crtc->state->event) { + unsigned long flags; + +@@ -719,6 +899,8 @@ static int vc4_fkms_enable_vblank(struct + { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + ++ DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n", ++ crtc->base.id); + vc4_crtc->vblank_enabled = true; + + return 0; +@@ -728,6 +910,8 @@ static void vc4_fkms_disable_vblank(stru + { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + ++ DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n", ++ crtc->base.id); + vc4_crtc->vblank_enabled = false; + } + +@@ -762,36 +946,92 @@ static const struct of_device_id vc4_fir + static enum drm_connector_status + vc4_fkms_connector_detect(struct drm_connector *connector, bool force) + { ++ DRM_DEBUG_KMS("connector detect.\n"); + return connector_status_connected; + } + +-static int vc4_fkms_connector_get_modes(struct drm_connector *connector) ++static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block, ++ size_t len) + { +- struct drm_device *dev = connector->dev; + struct vc4_fkms_connector *fkms_connector = +- to_vc4_fkms_connector(connector); +- struct vc4_dev *vc4 = to_vc4_dev(dev); +- struct drm_display_mode *mode; +- struct mailbox_get_width_height wh = { +- .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, }, +- .display = fkms_connector->display_idx, +- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT, +- 8, 0, }, ++ (struct vc4_fkms_connector *)data; ++ struct vc4_dev *vc4 = fkms_connector->vc4_dev; ++ struct mailbox_get_edid mb = { ++ .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY, ++ 128 + 8, 0 }, ++ .block = block, ++ .display_number = fkms_connector->display_number, + }; +- int ret; ++ int ret = 0; ++ ++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); ++ ++ if (!ret) ++ memcpy(buf, mb.edid, len); ++ ++ return ret; ++} ++ ++static int vc4_fkms_connector_get_modes(struct drm_connector *connector) ++{ ++ struct vc4_fkms_connector *fkms_connector = ++ to_vc4_fkms_connector(connector); ++ struct drm_encoder *encoder = fkms_connector->encoder; ++ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); ++ int ret = 0; ++ struct edid *edid; ++ ++ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block, ++ fkms_connector); ++ ++ /* FIXME: Can we do CEC? ++ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid); ++ * if (!edid) ++ * return -ENODEV; ++ */ ++ ++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); + +- ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh)); ++ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { ++ vc4_encoder->rgb_range_selectable = ++ drm_rgb_quant_range_selectable(edid); ++ } ++ ++ drm_connector_update_edid_property(connector, edid); ++ ret = drm_add_edid_modes(connector, edid); ++ kfree(edid); ++ ++ return ret; ++} ++ ++/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */ ++static const struct drm_display_mode lcd_mode = { ++ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, ++ 25979400 / 1000, ++ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0, ++ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0, ++ DRM_MODE_FLAG_INTERLACE) ++}; ++ ++static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector) ++{ ++ //struct vc4_fkms_connector *fkms_connector = ++ // to_vc4_fkms_connector(connector); ++ //struct drm_encoder *encoder = fkms_connector->encoder; ++ //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); ++ struct drm_display_mode *mode; ++ //int ret = 0; + +- if (ret) { +- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n", +- ret, wh.wh[0], wh.wh[1]); +- return 0; ++ mode = drm_mode_duplicate(connector->dev, ++ &lcd_mode); ++ if (!mode) { ++ DRM_ERROR("Failed to create a new display mode\n"); ++ return -ENOMEM; + } + +- mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */, +- 0, 0, false); + drm_mode_probed_add(connector, mode); + ++ /* We have one mode */ + return 1; + } + +@@ -800,11 +1040,14 @@ vc4_fkms_connector_best_encoder(struct d + { + struct vc4_fkms_connector *fkms_connector = + to_vc4_fkms_connector(connector); ++ DRM_DEBUG_KMS("best_connector.\n"); + return fkms_connector->encoder; + } + + static void vc4_fkms_connector_destroy(struct drm_connector *connector) + { ++ DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n", ++ connector->base.id); + drm_connector_unregister(connector); + drm_connector_cleanup(connector); + } +@@ -823,14 +1066,22 @@ static const struct drm_connector_helper + .best_encoder = vc4_fkms_connector_best_encoder, + }; + ++static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = { ++ .get_modes = vc4_fkms_lcd_connector_get_modes, ++ .best_encoder = vc4_fkms_connector_best_encoder, ++}; ++ + static struct drm_connector * + vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder, +- u32 display_idx) ++ u32 display_num) + { + struct drm_connector *connector = NULL; + struct vc4_fkms_connector *fkms_connector; ++ struct vc4_dev *vc4_dev = to_vc4_dev(dev); + int ret = 0; + ++ DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num); ++ + fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector), + GFP_KERNEL); + if (!fkms_connector) { +@@ -840,11 +1091,21 @@ vc4_fkms_connector_init(struct drm_devic + connector = &fkms_connector->base; + + fkms_connector->encoder = encoder; +- fkms_connector->display_idx = display_idx; +- +- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, +- DRM_MODE_CONNECTOR_HDMIA); +- drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs); ++ fkms_connector->display_number = display_num; ++ fkms_connector->display_type = vc4_get_display_type(display_num); ++ fkms_connector->vc4_dev = vc4_dev; ++ ++ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) { ++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, ++ DRM_MODE_CONNECTOR_DSI); ++ drm_connector_helper_add(connector, ++ &vc4_fkms_lcd_conn_helper_funcs); ++ } else { ++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, ++ DRM_MODE_CONNECTOR_HDMIA); ++ drm_connector_helper_add(connector, ++ &vc4_fkms_connector_helper_funcs); ++ } + + connector->polled = (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT); +@@ -865,6 +1126,7 @@ vc4_fkms_connector_init(struct drm_devic + + static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder) + { ++ DRM_DEBUG_KMS("Encoder_destroy\n"); + drm_encoder_cleanup(encoder); + } + +@@ -874,10 +1136,12 @@ static const struct drm_encoder_funcs vc + + static void vc4_fkms_encoder_enable(struct drm_encoder *encoder) + { ++ DRM_DEBUG_KMS("Encoder_enable\n"); + } + + static void vc4_fkms_encoder_disable(struct drm_encoder *encoder) + { ++ DRM_DEBUG_KMS("Encoder_disable\n"); + } + + static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = { +@@ -909,6 +1173,7 @@ static int vc4_fkms_create_screen(struct + crtc = &vc4_crtc->base; + + vc4_crtc->display_number = display_ref; ++ vc4_crtc->display_type = vc4_get_display_type(display_ref); + + /* Blank the firmware provided framebuffer */ + rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank)); +@@ -952,13 +1217,14 @@ static int vc4_fkms_create_screen(struct + return -ENOMEM; + vc4_crtc->encoder = &vc4_encoder->base; + vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ; ++ + drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs, +- DRM_MODE_ENCODER_TMDS, NULL); ++ vc4_crtc->display_type, NULL); + drm_encoder_helper_add(&vc4_encoder->base, + &vc4_fkms_encoder_helper_funcs); + + vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base, +- display_idx); ++ display_ref); + if (IS_ERR(vc4_crtc->connector)) { + ret = PTR_ERR(vc4_crtc->connector); + goto err_destroy_encoder; +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -75,6 +75,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014, + RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020, + RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021, ++ RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023, + RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, + RPI_FIRMWARE_GET_THROTTLED = 0x00030046, + RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047, +@@ -149,6 +150,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, + + RPI_FIRMWARE_SET_PLANE = 0x00048015, ++ RPI_FIRMWARE_SET_TIMING = 0x00048017, + + RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, + RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch b/target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch deleted file mode 100644 index 05f50cd913..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0244-drm-vc4-Iterate-over-all-planes-in-vc4_crtc_-dis-en-.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 016e6e68a119d3f4cae3c148433e2d661c7835be Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 10 Apr 2019 17:42:37 +0100 -Subject: [PATCH] drm: vc4: Iterate over all planes in - vc4_crtc_[dis|en]able - -Fixes a FIXME where the overlay plane wouldn't be restored. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 +++++++++++--------- - 1 file changed, 11 insertions(+), 9 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -600,6 +600,8 @@ static void vc4_crtc_mode_set_nofb(struc - - static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) - { -+ struct drm_plane *plane; -+ - drm_crtc_vblank_off(crtc); - - /* Always turn the planes off on CRTC disable. In DRM, planes -@@ -609,23 +611,23 @@ static void vc4_crtc_disable(struct drm_ - * give us a CRTC-level control for that. - */ - -- vc4_plane_atomic_disable(crtc->cursor, crtc->cursor->state); -- vc4_plane_atomic_disable(crtc->primary, crtc->primary->state); -- -- /* FIXME: Disable overlay planes */ -+ drm_atomic_crtc_for_each_plane(plane, crtc) -+ vc4_plane_atomic_disable(plane, plane->state); - } - - static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) - { -+ struct drm_plane *plane; -+ - drm_crtc_vblank_on(crtc); -+ - /* Unblank the planes (if they're supposed to be displayed). */ -+ drm_atomic_crtc_for_each_plane(plane, crtc) -+ if (plane->state->fb) -+ vc4_plane_set_blank(plane, plane->state->visible); -+} - -- if (crtc->primary->state->fb) -- vc4_plane_set_blank(crtc->primary, false); -- if (crtc->cursor->state->fb) -- vc4_plane_set_blank(crtc->cursor, crtc->cursor->state); - -- /* FIXME: Enable overlay planes */ - } - - static int vc4_crtc_atomic_check(struct drm_crtc *crtc, diff --git a/target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch b/target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch deleted file mode 100644 index 10a655ade1..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-Bring-fkms-into-line-with-kms-in-blocking-do.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 9185a16ce8804d35339402c6aec38a528cc2c7a1 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 10 Apr 2019 17:43:57 +0100 -Subject: [PATCH] drm: vc4: Bring fkms into line with kms in blocking - doublescan modes - -Implement vc4_crtc_mode_valid so that it blocks doublescan modes - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -627,7 +627,17 @@ static void vc4_crtc_enable(struct drm_c - vc4_plane_set_blank(plane, plane->state->visible); - } - -+static enum drm_mode_status -+vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) -+{ -+ /* Do not allow doublescan modes from user space */ -+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { -+ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n", -+ crtc->base.id); -+ return MODE_NO_DBLESCAN; -+ } - -+ return MODE_OK; - } - - static int vc4_crtc_atomic_check(struct drm_crtc *crtc, -@@ -737,10 +747,11 @@ static const struct drm_crtc_funcs vc4_c - - static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { - .mode_set_nofb = vc4_crtc_mode_set_nofb, -- .atomic_disable = vc4_crtc_disable, -- .atomic_enable = vc4_crtc_enable, -+ .mode_valid = vc4_crtc_mode_valid, - .atomic_check = vc4_crtc_atomic_check, - .atomic_flush = vc4_crtc_atomic_flush, -+ .atomic_enable = vc4_crtc_enable, -+ .atomic_disable = vc4_crtc_disable, - }; - - static const struct of_device_id vc4_firmware_kms_dt_match[] = { diff --git a/target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch b/target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch new file mode 100644 index 0000000000..2a365798f5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0245-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch @@ -0,0 +1,55 @@ +From 8848465a8f8934a06891823815c3176e394f5f1c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 3 May 2019 13:58:03 +0100 +Subject: [PATCH] drm: vc4-firmware-kms: Remove incorrect overscan + support. + +The overscan support was required for the old mailbox API +in order to match up the cursor and frame buffer planes. +With the newer API directly talking to dispmanx there is no +difference, therefore FKMS does not need to make any +adjustments. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 --------------- + 1 file changed, 15 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -235,7 +235,6 @@ struct vc4_crtc { + void __iomem *regs; + + struct drm_pending_vblank_event *event; +- u32 overscan[4]; + bool vblank_enabled; + u32 display_number; + u32 display_type; +@@ -471,11 +470,6 @@ static void vc4_plane_atomic_update(stru + break; + } + +- if (vc4_crtc) { +- mb->plane.dst_x += vc4_crtc->overscan[0]; +- mb->plane.dst_y += vc4_crtc->overscan[1]; +- } +- + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n", + plane->base.id, plane->name, + mb->plane.width, +@@ -1230,15 +1224,6 @@ static int vc4_fkms_create_screen(struct + goto err_destroy_encoder; + } + +- ret = rpi_firmware_property(vc4->firmware, +- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN, +- &vc4_crtc->overscan, +- sizeof(vc4_crtc->overscan)); +- if (ret) { +- DRM_ERROR("Failed to get overscan state: 0x%08x\n", vc4_crtc->overscan[0]); +- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan)); +- } +- + *ret_crtc = vc4_crtc; + + return 0; diff --git a/target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Increase-max_width-height-to-7680.patch b/target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Increase-max_width-height-to-7680.patch deleted file mode 100644 index 69d1470663..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Increase-max_width-height-to-7680.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 11801b1f71144478ab6c19a4c309667d340cb9e2 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 29 Apr 2019 18:45:00 +0100 -Subject: [PATCH] drm: vc4: Increase max_width/height to 7680. - -There are some limits still being investigated that stop -us going up to 8192, but 7680 is sufficient for dual 4k -displays. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_kms.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -536,8 +536,8 @@ int vc4_kms_load(struct drm_device *dev) - return ret; - } - -- dev->mode_config.max_width = 4096; -- dev->mode_config.max_height = 4096; -+ dev->mode_config.max_width = 7680; -+ dev->mode_config.max_height = 7680; - dev->mode_config.funcs = &vc4_mode_funcs; - dev->mode_config.preferred_depth = 24; - dev->mode_config.async_page_flip = true; diff --git a/target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Log-flags-in-fkms-mode-set.patch b/target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Log-flags-in-fkms-mode-set.patch new file mode 100644 index 0000000000..caca1c9f82 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0246-drm-vc4-Log-flags-in-fkms-mode-set.patch @@ -0,0 +1,31 @@ +From 0a93d1777bdd640a717a019ab53ab5c231dfa875 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 7 May 2019 12:13:34 +0100 +Subject: [PATCH] drm: vc4: Log flags in fkms mode set + +The flags contain info such as limited/full range RGB, aspect +ratio, and a fwe other useful things. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -687,12 +687,13 @@ static void vc4_crtc_mode_set_nofb(struc + return; + } + +- DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n", ++ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n", + vc4_crtc->display_number, mode->name, mode->clock, + mode->hdisplay, mode->hsync_start, mode->hsync_end, + mode->htotal, mode->hskew, mode->vdisplay, + mode->vsync_start, mode->vsync_end, mode->vtotal, +- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio); ++ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio, ++ mode->flags); + mb.timings.display = vc4_crtc->display_number; + + mb.timings.video_id_code = frame.avi.video_code; diff --git a/target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch b/target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch deleted file mode 100644 index 92400560ac..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-FKMS-reads-the-EDID-from-fw-and-supports-mod.patch +++ /dev/null @@ -1,557 +0,0 @@ -From 52add140c76c0a211ab340ced8e7e1ea8bef9c79 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 9 Apr 2019 18:23:41 +0100 -Subject: [PATCH] drm: vc4: FKMS reads the EDID from fw, and supports - mode setting - -This extends FKMS to read the EDID from the display, and support -requesting a particular mode via KMS. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 334 ++++++++++++++++++--- - include/soc/bcm2835/raspberrypi-firmware.h | 2 + - 2 files changed, 302 insertions(+), 34 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -91,11 +91,60 @@ struct mailbox_blank_display { - u32 blank; - }; - --struct mailbox_get_width_height { -+struct mailbox_get_edid { - struct rpi_firmware_property_tag_header tag1; -- u32 display; -- struct rpi_firmware_property_tag_header tag2; -- u32 wh[2]; -+ u32 block; -+ u32 display_number; -+ u8 edid[128]; -+}; -+ -+struct set_timings { -+ u8 display; -+ u8 padding; -+ u16 video_id_code; -+ -+ u32 clock; /* in kHz */ -+ -+ u16 hdisplay; -+ u16 hsync_start; -+ -+ u16 hsync_end; -+ u16 htotal; -+ -+ u16 hskew; -+ u16 vdisplay; -+ -+ u16 vsync_start; -+ u16 vsync_end; -+ -+ u16 vtotal; -+ u16 vscan; -+ -+ u16 vrefresh; -+ u16 padding2; -+ -+ u32 flags; -+#define TIMINGS_FLAGS_H_SYNC_POS BIT(0) -+#define TIMINGS_FLAGS_H_SYNC_NEG 0 -+#define TIMINGS_FLAGS_V_SYNC_POS BIT(1) -+#define TIMINGS_FLAGS_V_SYNC_NEG 0 -+ -+#define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4) -+#define TIMINGS_FLAGS_ASPECT_NONE (0 << 4) -+#define TIMINGS_FLAGS_ASPECT_4_3 (1 << 4) -+#define TIMINGS_FLAGS_ASPECT_16_9 (2 << 4) -+#define TIMINGS_FLAGS_ASPECT_64_27 (3 << 4) -+#define TIMINGS_FLAGS_ASPECT_256_135 (4 << 4) -+ -+/* Limited range RGB flag. Not set corresponds to full range. */ -+#define TIMINGS_FLAGS_RGB_LIMITED BIT(8) -+/* DVI monitor, therefore disable infoframes. Not set corresponds to HDMI. */ -+#define TIMINGS_FLAGS_DVI BIT(9) -+}; -+ -+struct mailbox_set_mode { -+ struct rpi_firmware_property_tag_header tag1; -+ struct set_timings timings; - }; - - static const struct vc_image_format { -@@ -189,6 +238,7 @@ struct vc4_crtc { - u32 overscan[4]; - bool vblank_enabled; - u32 display_number; -+ u32 display_type; - }; - - static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc) -@@ -198,6 +248,8 @@ static inline struct vc4_crtc *to_vc4_cr - - struct vc4_fkms_encoder { - struct drm_encoder base; -+ bool hdmi_monitor; -+ bool rgb_range_selectable; - }; - - static inline struct vc4_fkms_encoder * -@@ -215,7 +267,9 @@ struct vc4_fkms_connector { - * hook. - */ - struct drm_encoder *encoder; -- u32 display_idx; -+ struct vc4_dev *vc4_dev; -+ u32 display_number; -+ u32 display_type; - }; - - static inline struct vc4_fkms_connector * -@@ -224,6 +278,26 @@ to_vc4_fkms_connector(struct drm_connect - return container_of(connector, struct vc4_fkms_connector, base); - } - -+static u32 vc4_get_display_type(u32 display_number) -+{ -+ const u32 display_types[] = { -+ /* The firmware display (DispmanX) IDs map to specific types in -+ * a fixed manner. -+ */ -+ DRM_MODE_ENCODER_DSI, /* MAIN_LCD */ -+ DRM_MODE_ENCODER_DSI, /* AUX_LCD */ -+ DRM_MODE_ENCODER_TMDS, /* HDMI0 */ -+ DRM_MODE_ENCODER_TVDAC, /* VEC */ -+ DRM_MODE_ENCODER_NONE, /* FORCE_LCD */ -+ DRM_MODE_ENCODER_NONE, /* FORCE_TV */ -+ DRM_MODE_ENCODER_NONE, /* FORCE_OTHER */ -+ DRM_MODE_ENCODER_TMDS, /* HDMI1 */ -+ DRM_MODE_ENCODER_NONE, /* FORCE_TV2 */ -+ }; -+ return display_number > ARRAY_SIZE(display_types) - 1 ? -+ DRM_MODE_ENCODER_NONE : display_types[display_number]; -+} -+ - /* Firmware's structure for making an FB mbox call. */ - struct fbinfo_s { - u32 xres, yres, xres_virtual, yres_virtual; -@@ -258,10 +332,15 @@ static int vc4_plane_set_blank(struct dr - .plane_id = vc4_plane->mb.plane.plane_id, - } - }; -+ static const char * const plane_types[] = { -+ "overlay", -+ "primary", -+ "cursor" -+ }; - int ret; - -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] overlay plane %s", -- plane->base.id, plane->name, -+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] %s plane %s", -+ plane->base.id, plane->name, plane_types[plane->type], - blank ? "blank" : "unblank"); - - if (blank) -@@ -595,13 +674,102 @@ fail: - - static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc) - { -- /* Everyting is handled in the planes. */ -+ struct drm_device *dev = crtc->dev; -+ struct vc4_dev *vc4 = to_vc4_dev(dev); -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -+ struct drm_display_mode *mode = &crtc->state->adjusted_mode; -+ struct vc4_fkms_encoder *vc4_encoder = -+ to_vc4_fkms_encoder(vc4_crtc->encoder); -+ struct mailbox_set_mode mb = { -+ .tag1 = { RPI_FIRMWARE_SET_TIMING, -+ sizeof(struct set_timings), 0}, -+ }; -+ union hdmi_infoframe frame; -+ int ret; -+ -+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, vc4_crtc->connector, mode); -+ if (ret < 0) { -+ DRM_ERROR("couldn't fill AVI infoframe\n"); -+ return; -+ } -+ -+ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n", -+ vc4_crtc->display_number, mode->name, mode->clock, -+ mode->hdisplay, mode->hsync_start, mode->hsync_end, -+ mode->htotal, mode->hskew, mode->vdisplay, -+ mode->vsync_start, mode->vsync_end, mode->vtotal, -+ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio); -+ mb.timings.display = vc4_crtc->display_number; -+ -+ mb.timings.video_id_code = frame.avi.video_code; -+ -+ mb.timings.clock = mode->clock; -+ mb.timings.hdisplay = mode->hdisplay; -+ mb.timings.hsync_start = mode->hsync_start; -+ mb.timings.hsync_end = mode->hsync_end; -+ mb.timings.htotal = mode->htotal; -+ mb.timings.hskew = mode->hskew; -+ mb.timings.vdisplay = mode->vdisplay; -+ mb.timings.vsync_start = mode->vsync_start; -+ mb.timings.vsync_end = mode->vsync_end; -+ mb.timings.vtotal = mode->vtotal; -+ mb.timings.vscan = mode->vscan; -+ mb.timings.vrefresh = 0; -+ mb.timings.flags = 0; -+ if (mode->flags & DRM_MODE_FLAG_PHSYNC) -+ mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS; -+ if (mode->flags & DRM_MODE_FLAG_PVSYNC) -+ mb.timings.flags |= TIMINGS_FLAGS_V_SYNC_POS; -+ -+ switch (frame.avi.picture_aspect) { -+ default: -+ case HDMI_PICTURE_ASPECT_NONE: -+ mode->flags |= TIMINGS_FLAGS_ASPECT_NONE; -+ break; -+ case HDMI_PICTURE_ASPECT_4_3: -+ mode->flags |= TIMINGS_FLAGS_ASPECT_4_3; -+ break; -+ case HDMI_PICTURE_ASPECT_16_9: -+ mode->flags |= TIMINGS_FLAGS_ASPECT_16_9; -+ break; -+ case HDMI_PICTURE_ASPECT_64_27: -+ mode->flags |= TIMINGS_FLAGS_ASPECT_64_27; -+ break; -+ case HDMI_PICTURE_ASPECT_256_135: -+ mode->flags |= TIMINGS_FLAGS_ASPECT_256_135; -+ break; -+ } -+ -+ if (!vc4_encoder->hdmi_monitor) -+ mb.timings.flags |= TIMINGS_FLAGS_DVI; -+ else if (drm_default_rgb_quant_range(mode) == -+ HDMI_QUANTIZATION_RANGE_LIMITED) -+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; -+ -+ /* -+ FIXME: To implement -+ switch(mode->flag & DRM_MODE_FLAG_3D_MASK) { -+ case DRM_MODE_FLAG_3D_NONE: -+ case DRM_MODE_FLAG_3D_FRAME_PACKING: -+ case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: -+ case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: -+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: -+ case DRM_MODE_FLAG_3D_L_DEPTH: -+ case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: -+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: -+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: -+ } -+ */ -+ -+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); - } - - static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) - { - struct drm_plane *plane; - -+ DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n", -+ crtc->base.id); - drm_crtc_vblank_off(crtc); - - /* Always turn the planes off on CRTC disable. In DRM, planes -@@ -619,6 +787,8 @@ static void vc4_crtc_enable(struct drm_c - { - struct drm_plane *plane; - -+ DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n", -+ crtc->base.id); - drm_crtc_vblank_on(crtc); - - /* Unblank the planes (if they're supposed to be displayed). */ -@@ -637,12 +807,20 @@ vc4_crtc_mode_valid(struct drm_crtc *crt - return MODE_NO_DBLESCAN; - } - -+ /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling -+ * working. -+ */ -+ if (mode->clock > 340000) -+ return MODE_CLOCK_HIGH; -+ - return MODE_OK; - } - - static int vc4_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) - { -+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", -+ crtc->base.id); - return 0; - } - -@@ -652,6 +830,8 @@ static void vc4_crtc_atomic_flush(struct - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - struct drm_device *dev = crtc->dev; - -+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n", -+ crtc->base.id); - if (crtc->state->event) { - unsigned long flags; - -@@ -719,6 +899,8 @@ static int vc4_fkms_enable_vblank(struct - { - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - -+ DRM_DEBUG_KMS("[CRTC:%d] enable_vblank.\n", -+ crtc->base.id); - vc4_crtc->vblank_enabled = true; - - return 0; -@@ -728,6 +910,8 @@ static void vc4_fkms_disable_vblank(stru - { - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); - -+ DRM_DEBUG_KMS("[CRTC:%d] disable_vblank.\n", -+ crtc->base.id); - vc4_crtc->vblank_enabled = false; - } - -@@ -762,36 +946,92 @@ static const struct of_device_id vc4_fir - static enum drm_connector_status - vc4_fkms_connector_detect(struct drm_connector *connector, bool force) - { -+ DRM_DEBUG_KMS("connector detect.\n"); - return connector_status_connected; - } - --static int vc4_fkms_connector_get_modes(struct drm_connector *connector) -+static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block, -+ size_t len) - { -- struct drm_device *dev = connector->dev; - struct vc4_fkms_connector *fkms_connector = -- to_vc4_fkms_connector(connector); -- struct vc4_dev *vc4 = to_vc4_dev(dev); -- struct drm_display_mode *mode; -- struct mailbox_get_width_height wh = { -- .tag1 = {RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM, 4, 0, }, -- .display = fkms_connector->display_idx, -- .tag2 = { RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT, -- 8, 0, }, -+ (struct vc4_fkms_connector *)data; -+ struct vc4_dev *vc4 = fkms_connector->vc4_dev; -+ struct mailbox_get_edid mb = { -+ .tag1 = { RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY, -+ 128 + 8, 0 }, -+ .block = block, -+ .display_number = fkms_connector->display_number, - }; -- int ret; -+ int ret = 0; -+ -+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); -+ -+ if (!ret) -+ memcpy(buf, mb.edid, len); -+ -+ return ret; -+} -+ -+static int vc4_fkms_connector_get_modes(struct drm_connector *connector) -+{ -+ struct vc4_fkms_connector *fkms_connector = -+ to_vc4_fkms_connector(connector); -+ struct drm_encoder *encoder = fkms_connector->encoder; -+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); -+ int ret = 0; -+ struct edid *edid; -+ -+ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block, -+ fkms_connector); -+ -+ /* FIXME: Can we do CEC? -+ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid); -+ * if (!edid) -+ * return -ENODEV; -+ */ -+ -+ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); - -- ret = rpi_firmware_property_list(vc4->firmware, &wh, sizeof(wh)); -+ if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { -+ vc4_encoder->rgb_range_selectable = -+ drm_rgb_quant_range_selectable(edid); -+ } -+ -+ drm_connector_update_edid_property(connector, edid); -+ ret = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ -+ return ret; -+} -+ -+/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */ -+static const struct drm_display_mode lcd_mode = { -+ DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, -+ 25979400 / 1000, -+ 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0, -+ 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0, -+ DRM_MODE_FLAG_INTERLACE) -+}; -+ -+static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector) -+{ -+ //struct vc4_fkms_connector *fkms_connector = -+ // to_vc4_fkms_connector(connector); -+ //struct drm_encoder *encoder = fkms_connector->encoder; -+ //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); -+ struct drm_display_mode *mode; -+ //int ret = 0; - -- if (ret) { -- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n", -- ret, wh.wh[0], wh.wh[1]); -- return 0; -+ mode = drm_mode_duplicate(connector->dev, -+ &lcd_mode); -+ if (!mode) { -+ DRM_ERROR("Failed to create a new display mode\n"); -+ return -ENOMEM; - } - -- mode = drm_cvt_mode(dev, wh.wh[0], wh.wh[1], 60 /* vrefresh */, -- 0, 0, false); - drm_mode_probed_add(connector, mode); - -+ /* We have one mode */ - return 1; - } - -@@ -800,11 +1040,14 @@ vc4_fkms_connector_best_encoder(struct d - { - struct vc4_fkms_connector *fkms_connector = - to_vc4_fkms_connector(connector); -+ DRM_DEBUG_KMS("best_connector.\n"); - return fkms_connector->encoder; - } - - static void vc4_fkms_connector_destroy(struct drm_connector *connector) - { -+ DRM_DEBUG_KMS("[CONNECTOR:%d] destroy.\n", -+ connector->base.id); - drm_connector_unregister(connector); - drm_connector_cleanup(connector); - } -@@ -823,14 +1066,22 @@ static const struct drm_connector_helper - .best_encoder = vc4_fkms_connector_best_encoder, - }; - -+static const struct drm_connector_helper_funcs vc4_fkms_lcd_conn_helper_funcs = { -+ .get_modes = vc4_fkms_lcd_connector_get_modes, -+ .best_encoder = vc4_fkms_connector_best_encoder, -+}; -+ - static struct drm_connector * - vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder, -- u32 display_idx) -+ u32 display_num) - { - struct drm_connector *connector = NULL; - struct vc4_fkms_connector *fkms_connector; -+ struct vc4_dev *vc4_dev = to_vc4_dev(dev); - int ret = 0; - -+ DRM_DEBUG_KMS("connector_init, display_num %u\n", display_num); -+ - fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector), - GFP_KERNEL); - if (!fkms_connector) { -@@ -840,11 +1091,21 @@ vc4_fkms_connector_init(struct drm_devic - connector = &fkms_connector->base; - - fkms_connector->encoder = encoder; -- fkms_connector->display_idx = display_idx; -- -- drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, -- DRM_MODE_CONNECTOR_HDMIA); -- drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs); -+ fkms_connector->display_number = display_num; -+ fkms_connector->display_type = vc4_get_display_type(display_num); -+ fkms_connector->vc4_dev = vc4_dev; -+ -+ if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) { -+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, -+ DRM_MODE_CONNECTOR_DSI); -+ drm_connector_helper_add(connector, -+ &vc4_fkms_lcd_conn_helper_funcs); -+ } else { -+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, -+ DRM_MODE_CONNECTOR_HDMIA); -+ drm_connector_helper_add(connector, -+ &vc4_fkms_connector_helper_funcs); -+ } - - connector->polled = (DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT); -@@ -865,6 +1126,7 @@ vc4_fkms_connector_init(struct drm_devic - - static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder) - { -+ DRM_DEBUG_KMS("Encoder_destroy\n"); - drm_encoder_cleanup(encoder); - } - -@@ -874,10 +1136,12 @@ static const struct drm_encoder_funcs vc - - static void vc4_fkms_encoder_enable(struct drm_encoder *encoder) - { -+ DRM_DEBUG_KMS("Encoder_enable\n"); - } - - static void vc4_fkms_encoder_disable(struct drm_encoder *encoder) - { -+ DRM_DEBUG_KMS("Encoder_disable\n"); - } - - static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = { -@@ -909,6 +1173,7 @@ static int vc4_fkms_create_screen(struct - crtc = &vc4_crtc->base; - - vc4_crtc->display_number = display_ref; -+ vc4_crtc->display_type = vc4_get_display_type(display_ref); - - /* Blank the firmware provided framebuffer */ - rpi_firmware_property_list(vc4->firmware, &blank, sizeof(blank)); -@@ -952,13 +1217,14 @@ static int vc4_fkms_create_screen(struct - return -ENOMEM; - vc4_crtc->encoder = &vc4_encoder->base; - vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ; -+ - drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs, -- DRM_MODE_ENCODER_TMDS, NULL); -+ vc4_crtc->display_type, NULL); - drm_encoder_helper_add(&vc4_encoder->base, - &vc4_fkms_encoder_helper_funcs); - - vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base, -- display_idx); -+ display_ref); - if (IS_ERR(vc4_crtc->connector)) { - ret = PTR_ERR(vc4_crtc->connector); - goto err_destroy_encoder; ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -75,6 +75,7 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014, - RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020, - RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021, -+ RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023, - RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, - RPI_FIRMWARE_GET_THROTTLED = 0x00030046, - RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047, -@@ -149,6 +150,7 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, - - RPI_FIRMWARE_SET_PLANE = 0x00048015, -+ RPI_FIRMWARE_SET_TIMING = 0x00048017, - - RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, - RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-firmware-kms-Fix-DSI-display-support.patch b/target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-firmware-kms-Fix-DSI-display-support.patch new file mode 100644 index 0000000000..450c156602 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0247-drm-vc4-firmware-kms-Fix-DSI-display-support.patch @@ -0,0 +1,25 @@ +From b0f9ee06c9e611592715f9d9d31170d55d2aeded Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 16 May 2019 17:49:42 +0100 +Subject: [PATCH] drm: vc4-firmware-kms: Fix DSI display support + +The mode was incorrectly listed as interlaced, which was then +rejected. +Correct this and FKMS works with the DSI display. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -1005,7 +1005,7 @@ static const struct drm_display_mode lcd + 25979400 / 1000, + 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0, + 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0, +- DRM_MODE_FLAG_INTERLACE) ++ 0) + }; + + static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector) diff --git a/target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch b/target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch new file mode 100644 index 0000000000..a917540869 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch @@ -0,0 +1,138 @@ +From e8f126acd6da4f7d2e0df3c735fccf9971d95254 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 21 May 2019 11:50:00 +0100 +Subject: [PATCH] drm: vc4: Probe DPI/DSI timings from the firmware + +For DPI and DSI displays query the firmware as to the configuration +and add it as the only mode for DRM. + +In theory we can add plumbing for setting the DPI/DSI mode from +KMS, but this is not being added at present as the support frameworks +aren't present in the firmware. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 64 ++++++++++++++++------ + include/soc/bcm2835/raspberrypi-firmware.h | 1 + + 2 files changed, 49 insertions(+), 16 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -248,7 +248,6 @@ static inline struct vc4_crtc *to_vc4_cr + struct vc4_fkms_encoder { + struct drm_encoder base; + bool hdmi_monitor; +- bool rgb_range_selectable; + }; + + static inline struct vc4_fkms_encoder * +@@ -283,7 +282,7 @@ static u32 vc4_get_display_type(u32 disp + /* The firmware display (DispmanX) IDs map to specific types in + * a fixed manner. + */ +- DRM_MODE_ENCODER_DSI, /* MAIN_LCD */ ++ DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */ + DRM_MODE_ENCODER_DSI, /* AUX_LCD */ + DRM_MODE_ENCODER_TMDS, /* HDMI0 */ + DRM_MODE_ENCODER_TVDAC, /* VEC */ +@@ -365,7 +364,6 @@ static void vc4_plane_atomic_update(stru + vc4_get_vc_image_fmt(drm_fmt->format); + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); + struct mailbox_set_plane *mb = &vc4_plane->mb; +- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); + int num_planes = fb->format->num_planes; + struct drm_display_mode *mode = &state->crtc->mode; + unsigned int rotation = SUPPORTED_ROTATIONS; +@@ -987,11 +985,6 @@ static int vc4_fkms_connector_get_modes( + + vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); + +- if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { +- vc4_encoder->rgb_range_selectable = +- drm_rgb_quant_range_selectable(edid); +- } +- + drm_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); + kfree(edid); +@@ -999,7 +992,9 @@ static int vc4_fkms_connector_get_modes( + return ret; + } + +-/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */ ++/* This is the DSI panel resolution. Use this as a default should the firmware ++ * not respond to our request for the timings. ++ */ + static const struct drm_display_mode lcd_mode = { + DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + 25979400 / 1000, +@@ -1010,15 +1005,52 @@ static const struct drm_display_mode lcd + + static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector) + { +- //struct vc4_fkms_connector *fkms_connector = +- // to_vc4_fkms_connector(connector); +- //struct drm_encoder *encoder = fkms_connector->encoder; +- //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); ++ struct vc4_fkms_connector *fkms_connector = ++ to_vc4_fkms_connector(connector); ++ struct vc4_dev *vc4 = fkms_connector->vc4_dev; + struct drm_display_mode *mode; +- //int ret = 0; ++ struct mailbox_set_mode mb = { ++ .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING, ++ sizeof(struct set_timings), 0}, ++ .timings = { .display = fkms_connector->display_number }, ++ }; ++ struct drm_display_mode fw_mode; ++ int ret = 0; ++ ++ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); ++ if (!ret) { ++ /* Equivalent to DRM_MODE macro. */ ++ memset(&fw_mode, 0, sizeof(fw_mode)); ++ strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name)); ++ fw_mode.status = 0; ++ fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ fw_mode.clock = mb.timings.clock; ++ fw_mode.hdisplay = mb.timings.hdisplay; ++ fw_mode.hsync_start = mb.timings.hsync_start; ++ fw_mode.hsync_end = mb.timings.hsync_end; ++ fw_mode.htotal = mb.timings.htotal; ++ fw_mode.hskew = 0; ++ fw_mode.vdisplay = mb.timings.vdisplay; ++ fw_mode.vsync_start = mb.timings.vsync_start; ++ fw_mode.vsync_end = mb.timings.vsync_end; ++ fw_mode.vtotal = mb.timings.vtotal; ++ fw_mode.vscan = mb.timings.vscan; ++ if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS) ++ fw_mode.flags |= DRM_MODE_FLAG_PHSYNC; ++ else ++ fw_mode.flags |= DRM_MODE_FLAG_NHSYNC; ++ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) ++ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; ++ else ++ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; ++ ++ mode = drm_mode_duplicate(connector->dev, ++ &fw_mode); ++ } else { ++ mode = drm_mode_duplicate(connector->dev, ++ &lcd_mode); ++ } + +- mode = drm_mode_duplicate(connector->dev, +- &lcd_mode); + if (!mode) { + DRM_ERROR("Failed to create a new display mode\n"); + return -ENOMEM; +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -150,6 +150,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, + + RPI_FIRMWARE_SET_PLANE = 0x00048015, ++ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, + RPI_FIRMWARE_SET_TIMING = 0x00048017, + + RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch b/target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch deleted file mode 100644 index 2a365798f5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0248-drm-vc4-firmware-kms-Remove-incorrect-overscan-suppo.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 8848465a8f8934a06891823815c3176e394f5f1c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 3 May 2019 13:58:03 +0100 -Subject: [PATCH] drm: vc4-firmware-kms: Remove incorrect overscan - support. - -The overscan support was required for the old mailbox API -in order to match up the cursor and frame buffer planes. -With the newer API directly talking to dispmanx there is no -difference, therefore FKMS does not need to make any -adjustments. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 --------------- - 1 file changed, 15 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -235,7 +235,6 @@ struct vc4_crtc { - void __iomem *regs; - - struct drm_pending_vblank_event *event; -- u32 overscan[4]; - bool vblank_enabled; - u32 display_number; - u32 display_type; -@@ -471,11 +470,6 @@ static void vc4_plane_atomic_update(stru - break; - } - -- if (vc4_crtc) { -- mb->plane.dst_x += vc4_crtc->overscan[0]; -- mb->plane.dst_y += vc4_crtc->overscan[1]; -- } -- - DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane update %dx%d@%d +dst(%d,%d, %d,%d) +src(%d,%d, %d,%d) 0x%08x/%08x/%08x/%d, alpha %u zpos %u\n", - plane->base.id, plane->name, - mb->plane.width, -@@ -1230,15 +1224,6 @@ static int vc4_fkms_create_screen(struct - goto err_destroy_encoder; - } - -- ret = rpi_firmware_property(vc4->firmware, -- RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN, -- &vc4_crtc->overscan, -- sizeof(vc4_crtc->overscan)); -- if (ret) { -- DRM_ERROR("Failed to get overscan state: 0x%08x\n", vc4_crtc->overscan[0]); -- memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan)); -- } -- - *ret_crtc = vc4_crtc; - - return 0; diff --git a/target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-Log-flags-in-fkms-mode-set.patch b/target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-Log-flags-in-fkms-mode-set.patch deleted file mode 100644 index caca1c9f82..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-Log-flags-in-fkms-mode-set.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0a93d1777bdd640a717a019ab53ab5c231dfa875 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 7 May 2019 12:13:34 +0100 -Subject: [PATCH] drm: vc4: Log flags in fkms mode set - -The flags contain info such as limited/full range RGB, aspect -ratio, and a fwe other useful things. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -687,12 +687,13 @@ static void vc4_crtc_mode_set_nofb(struc - return; - } - -- DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u\n", -+ DRM_DEBUG_KMS("Setting mode for display num %u mode name %s, clk %d, h(disp %d, start %d, end %d, total %d, skew %d) v(disp %d, start %d, end %d, total %d, scan %d), vrefresh %d, par %u, flags 0x%04x\n", - vc4_crtc->display_number, mode->name, mode->clock, - mode->hdisplay, mode->hsync_start, mode->hsync_end, - mode->htotal, mode->hskew, mode->vdisplay, - mode->vsync_start, mode->vsync_end, mode->vtotal, -- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio); -+ mode->vscan, mode->vrefresh, mode->picture_aspect_ratio, -+ mode->flags); - mb.timings.display = vc4_crtc->display_number; - - mb.timings.video_id_code = frame.avi.video_code; diff --git a/target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-handle-the-case-where-there-are-no-available.patch b/target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-handle-the-case-where-there-are-no-available.patch new file mode 100644 index 0000000000..72b205c2e4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0249-drm-vc4-handle-the-case-where-there-are-no-available.patch @@ -0,0 +1,67 @@ +From 1fbbd377bd1c6b4e3342d03091f19089ccb7fcbe Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 28 May 2019 13:56:06 +0100 +Subject: [PATCH] drm: vc4: handle the case where there are no + available displays + +It's reasonable for the firmware to return zero as the number of +attached displays. Handle this case as otherwise drm thinks that +the DSI panel is attached, which is nonsense. + +Signed-off-by: Jonathan Bell +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++----------- + 1 file changed, 18 insertions(+), 14 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -1303,13 +1303,13 @@ static int vc4_fkms_bind(struct device * + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, + &num_displays, sizeof(u32)); + +- /* If we fail to get the number of displays, or it returns 0, then ++ /* If we fail to get the number of displays, then + * assume old firmware that doesn't have the mailbox call, so just + * set one display + */ +- if (ret || num_displays == 0) { ++ if (ret) { + num_displays = 1; +- DRM_WARN("Unable to determine number of displays's. Assuming 1\n"); ++ DRM_WARN("Unable to determine number of displays - assuming 1\n"); + ret = 0; + } + +@@ -1338,17 +1338,21 @@ static int vc4_fkms_bind(struct device * + display_num); + } + +- /* Map the SMI interrupt reg */ +- crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0); +- if (IS_ERR(crtc_list[0]->regs)) +- DRM_ERROR("Oh dear, failed to map registers\n"); +- +- writel(0, crtc_list[0]->regs + SMICS); +- ret = devm_request_irq(dev, platform_get_irq(pdev, 0), +- vc4_crtc_irq_handler, 0, "vc4 firmware kms", +- crtc_list); +- if (ret) +- DRM_ERROR("Oh dear, failed to register IRQ\n"); ++ if (num_displays > 0) { ++ /* Map the SMI interrupt reg */ ++ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0); ++ if (IS_ERR(crtc_list[0]->regs)) ++ DRM_ERROR("Oh dear, failed to map registers\n"); ++ ++ writel(0, crtc_list[0]->regs + SMICS); ++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), ++ vc4_crtc_irq_handler, 0, ++ "vc4 firmware kms", crtc_list); ++ if (ret) ++ DRM_ERROR("Oh dear, failed to register IRQ\n"); ++ } else { ++ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n"); ++ } + + platform_set_drvdata(pdev, crtc_list); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-Support-the-VEC-in-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-Support-the-VEC-in-FKMS.patch new file mode 100644 index 0000000000..87aeacd616 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-Support-the-VEC-in-FKMS.patch @@ -0,0 +1,62 @@ +From 11a567f1e76ca017f1963027655454b56ab81875 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 24 May 2019 17:59:01 +0100 +Subject: [PATCH] drm/vc4: Support the VEC in FKMS + +Extends the DPI/DSI support to also report the VEC output +which supports interlacing too. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -128,6 +128,7 @@ struct set_timings { + #define TIMINGS_FLAGS_H_SYNC_NEG 0 + #define TIMINGS_FLAGS_V_SYNC_POS BIT(1) + #define TIMINGS_FLAGS_V_SYNC_NEG 0 ++#define TIMINGS_FLAGS_INTERLACE BIT(2) + + #define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4) + #define TIMINGS_FLAGS_ASPECT_NONE (0 << 4) +@@ -1043,6 +1044,12 @@ static int vc4_fkms_lcd_connector_get_mo + fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; + else + fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; ++ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) ++ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; ++ else ++ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; ++ if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE) ++ fw_mode.flags |= DRM_MODE_FLAG_INTERLACE; + + mode = drm_mode_duplicate(connector->dev, + &fw_mode); +@@ -1127,17 +1134,24 @@ vc4_fkms_connector_init(struct drm_devic + DRM_MODE_CONNECTOR_DSI); + drm_connector_helper_add(connector, + &vc4_fkms_lcd_conn_helper_funcs); ++ connector->interlace_allowed = 0; ++ } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) { ++ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, ++ DRM_MODE_CONNECTOR_Composite); ++ drm_connector_helper_add(connector, ++ &vc4_fkms_lcd_conn_helper_funcs); ++ connector->interlace_allowed = 1; + } else { + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + drm_connector_helper_add(connector, + &vc4_fkms_connector_helper_funcs); ++ connector->interlace_allowed = 0; + } + + connector->polled = (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT); + +- connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + drm_connector_attach_encoder(connector, encoder); diff --git a/target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-firmware-kms-Fix-DSI-display-support.patch b/target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-firmware-kms-Fix-DSI-display-support.patch deleted file mode 100644 index 450c156602..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0250-drm-vc4-firmware-kms-Fix-DSI-display-support.patch +++ /dev/null @@ -1,25 +0,0 @@ -From b0f9ee06c9e611592715f9d9d31170d55d2aeded Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 16 May 2019 17:49:42 +0100 -Subject: [PATCH] drm: vc4-firmware-kms: Fix DSI display support - -The mode was incorrectly listed as interlaced, which was then -rejected. -Correct this and FKMS works with the DSI display. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -1005,7 +1005,7 @@ static const struct drm_display_mode lcd - 25979400 / 1000, - 800, 800 + 1, 800 + 1 + 2, 800 + 1 + 2 + 46, 0, - 480, 480 + 7, 480 + 7 + 2, 480 + 7 + 2 + 21, 0, -- DRM_MODE_FLAG_INTERLACE) -+ 0) - }; - - static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector) diff --git a/target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch b/target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch new file mode 100644 index 0000000000..8008619639 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch @@ -0,0 +1,39 @@ +From 06e4e4560800232b0e6628bebc605d234ef1c237 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 7 May 2019 15:00:02 +0100 +Subject: [PATCH] drm: vc4: Fixup typo when setting HDMI aspect ratio + +Assignment was to the wrong structure. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -718,19 +718,19 @@ static void vc4_crtc_mode_set_nofb(struc + switch (frame.avi.picture_aspect) { + default: + case HDMI_PICTURE_ASPECT_NONE: +- mode->flags |= TIMINGS_FLAGS_ASPECT_NONE; ++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE; + break; + case HDMI_PICTURE_ASPECT_4_3: +- mode->flags |= TIMINGS_FLAGS_ASPECT_4_3; ++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3; + break; + case HDMI_PICTURE_ASPECT_16_9: +- mode->flags |= TIMINGS_FLAGS_ASPECT_16_9; ++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9; + break; + case HDMI_PICTURE_ASPECT_64_27: +- mode->flags |= TIMINGS_FLAGS_ASPECT_64_27; ++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27; + break; + case HDMI_PICTURE_ASPECT_256_135: +- mode->flags |= TIMINGS_FLAGS_ASPECT_256_135; ++ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135; + break; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch b/target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch deleted file mode 100644 index a917540869..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0251-drm-vc4-Probe-DPI-DSI-timings-from-the-firmware.patch +++ /dev/null @@ -1,138 +0,0 @@ -From e8f126acd6da4f7d2e0df3c735fccf9971d95254 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 21 May 2019 11:50:00 +0100 -Subject: [PATCH] drm: vc4: Probe DPI/DSI timings from the firmware - -For DPI and DSI displays query the firmware as to the configuration -and add it as the only mode for DRM. - -In theory we can add plumbing for setting the DPI/DSI mode from -KMS, but this is not being added at present as the support frameworks -aren't present in the firmware. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 64 ++++++++++++++++------ - include/soc/bcm2835/raspberrypi-firmware.h | 1 + - 2 files changed, 49 insertions(+), 16 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -248,7 +248,6 @@ static inline struct vc4_crtc *to_vc4_cr - struct vc4_fkms_encoder { - struct drm_encoder base; - bool hdmi_monitor; -- bool rgb_range_selectable; - }; - - static inline struct vc4_fkms_encoder * -@@ -283,7 +282,7 @@ static u32 vc4_get_display_type(u32 disp - /* The firmware display (DispmanX) IDs map to specific types in - * a fixed manner. - */ -- DRM_MODE_ENCODER_DSI, /* MAIN_LCD */ -+ DRM_MODE_ENCODER_DSI, /* MAIN_LCD - DSI or DPI */ - DRM_MODE_ENCODER_DSI, /* AUX_LCD */ - DRM_MODE_ENCODER_TMDS, /* HDMI0 */ - DRM_MODE_ENCODER_TVDAC, /* VEC */ -@@ -365,7 +364,6 @@ static void vc4_plane_atomic_update(stru - vc4_get_vc_image_fmt(drm_fmt->format); - struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); - struct mailbox_set_plane *mb = &vc4_plane->mb; -- struct vc4_crtc *vc4_crtc = to_vc4_crtc(state->crtc); - int num_planes = fb->format->num_planes; - struct drm_display_mode *mode = &state->crtc->mode; - unsigned int rotation = SUPPORTED_ROTATIONS; -@@ -987,11 +985,6 @@ static int vc4_fkms_connector_get_modes( - - vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); - -- if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { -- vc4_encoder->rgb_range_selectable = -- drm_rgb_quant_range_selectable(edid); -- } -- - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); -@@ -999,7 +992,9 @@ static int vc4_fkms_connector_get_modes( - return ret; - } - --/* FIXME: Read LCD mode from the firmware. This is the DSI panel resolution. */ -+/* This is the DSI panel resolution. Use this as a default should the firmware -+ * not respond to our request for the timings. -+ */ - static const struct drm_display_mode lcd_mode = { - DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, - 25979400 / 1000, -@@ -1010,15 +1005,52 @@ static const struct drm_display_mode lcd - - static int vc4_fkms_lcd_connector_get_modes(struct drm_connector *connector) - { -- //struct vc4_fkms_connector *fkms_connector = -- // to_vc4_fkms_connector(connector); -- //struct drm_encoder *encoder = fkms_connector->encoder; -- //struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); -+ struct vc4_fkms_connector *fkms_connector = -+ to_vc4_fkms_connector(connector); -+ struct vc4_dev *vc4 = fkms_connector->vc4_dev; - struct drm_display_mode *mode; -- //int ret = 0; -+ struct mailbox_set_mode mb = { -+ .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING, -+ sizeof(struct set_timings), 0}, -+ .timings = { .display = fkms_connector->display_number }, -+ }; -+ struct drm_display_mode fw_mode; -+ int ret = 0; -+ -+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); -+ if (!ret) { -+ /* Equivalent to DRM_MODE macro. */ -+ memset(&fw_mode, 0, sizeof(fw_mode)); -+ strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name)); -+ fw_mode.status = 0; -+ fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -+ fw_mode.clock = mb.timings.clock; -+ fw_mode.hdisplay = mb.timings.hdisplay; -+ fw_mode.hsync_start = mb.timings.hsync_start; -+ fw_mode.hsync_end = mb.timings.hsync_end; -+ fw_mode.htotal = mb.timings.htotal; -+ fw_mode.hskew = 0; -+ fw_mode.vdisplay = mb.timings.vdisplay; -+ fw_mode.vsync_start = mb.timings.vsync_start; -+ fw_mode.vsync_end = mb.timings.vsync_end; -+ fw_mode.vtotal = mb.timings.vtotal; -+ fw_mode.vscan = mb.timings.vscan; -+ if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS) -+ fw_mode.flags |= DRM_MODE_FLAG_PHSYNC; -+ else -+ fw_mode.flags |= DRM_MODE_FLAG_NHSYNC; -+ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) -+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; -+ else -+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; -+ -+ mode = drm_mode_duplicate(connector->dev, -+ &fw_mode); -+ } else { -+ mode = drm_mode_duplicate(connector->dev, -+ &lcd_mode); -+ } - -- mode = drm_mode_duplicate(connector->dev, -- &lcd_mode); - if (!mode) { - DRM_ERROR("Failed to create a new display mode\n"); - return -ENOMEM; ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -150,6 +150,7 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, - - RPI_FIRMWARE_SET_PLANE = 0x00048015, -+ RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, - RPI_FIRMWARE_SET_TIMING = 0x00048017, - - RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-Correct-SAND-support-for-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-Correct-SAND-support-for-FKMS.patch new file mode 100644 index 0000000000..dcf57e07e7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-Correct-SAND-support-for-FKMS.patch @@ -0,0 +1,40 @@ +From 46c612d0248ba6e0c8c236cf1839b0c2ccecee01 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 29 May 2019 15:44:11 +0100 +Subject: [PATCH] drm/vc4: Correct SAND support for FKMS. + +It was accepting NV21 which doesn't map through, but +also wasn't advertising the modifier so nothing would know +to request it. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -546,7 +546,6 @@ static bool vc4_fkms_format_mod_supporte + return false; + } + case DRM_FORMAT_NV12: +- case DRM_FORMAT_NV21: + switch (fourcc_mod_broadcom_mod(modifier)) { + case DRM_FORMAT_MOD_LINEAR: + case DRM_FORMAT_MOD_BROADCOM_SAND128: +@@ -554,6 +553,7 @@ static bool vc4_fkms_format_mod_supporte + default: + return false; + } ++ case DRM_FORMAT_NV21: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + case DRM_FORMAT_YUV422: +@@ -600,6 +600,7 @@ static struct drm_plane *vc4_fkms_plane_ + * would prefer to scan out linear (less bus traffic). + */ + DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, ++ DRM_FORMAT_MOD_BROADCOM_SAND128, + DRM_FORMAT_MOD_INVALID, + }; + int i; diff --git a/target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-handle-the-case-where-there-are-no-available.patch b/target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-handle-the-case-where-there-are-no-available.patch deleted file mode 100644 index 72b205c2e4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0252-drm-vc4-handle-the-case-where-there-are-no-available.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 1fbbd377bd1c6b4e3342d03091f19089ccb7fcbe Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 28 May 2019 13:56:06 +0100 -Subject: [PATCH] drm: vc4: handle the case where there are no - available displays - -It's reasonable for the firmware to return zero as the number of -attached displays. Handle this case as otherwise drm thinks that -the DSI panel is attached, which is nonsense. - -Signed-off-by: Jonathan Bell ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++----------- - 1 file changed, 18 insertions(+), 14 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -1303,13 +1303,13 @@ static int vc4_fkms_bind(struct device * - RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, - &num_displays, sizeof(u32)); - -- /* If we fail to get the number of displays, or it returns 0, then -+ /* If we fail to get the number of displays, then - * assume old firmware that doesn't have the mailbox call, so just - * set one display - */ -- if (ret || num_displays == 0) { -+ if (ret) { - num_displays = 1; -- DRM_WARN("Unable to determine number of displays's. Assuming 1\n"); -+ DRM_WARN("Unable to determine number of displays - assuming 1\n"); - ret = 0; - } - -@@ -1338,17 +1338,21 @@ static int vc4_fkms_bind(struct device * - display_num); - } - -- /* Map the SMI interrupt reg */ -- crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0); -- if (IS_ERR(crtc_list[0]->regs)) -- DRM_ERROR("Oh dear, failed to map registers\n"); -- -- writel(0, crtc_list[0]->regs + SMICS); -- ret = devm_request_irq(dev, platform_get_irq(pdev, 0), -- vc4_crtc_irq_handler, 0, "vc4 firmware kms", -- crtc_list); -- if (ret) -- DRM_ERROR("Oh dear, failed to register IRQ\n"); -+ if (num_displays > 0) { -+ /* Map the SMI interrupt reg */ -+ crtc_list[0]->regs = vc4_ioremap_regs(pdev, 0); -+ if (IS_ERR(crtc_list[0]->regs)) -+ DRM_ERROR("Oh dear, failed to map registers\n"); -+ -+ writel(0, crtc_list[0]->regs + SMICS); -+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), -+ vc4_crtc_irq_handler, 0, -+ "vc4 firmware kms", crtc_list); -+ if (ret) -+ DRM_ERROR("Oh dear, failed to register IRQ\n"); -+ } else { -+ DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n"); -+ } - - platform_set_drvdata(pdev, crtc_list); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-Support-the-VEC-in-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-Support-the-VEC-in-FKMS.patch deleted file mode 100644 index 87aeacd616..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-Support-the-VEC-in-FKMS.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 11a567f1e76ca017f1963027655454b56ab81875 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 24 May 2019 17:59:01 +0100 -Subject: [PATCH] drm/vc4: Support the VEC in FKMS - -Extends the DPI/DSI support to also report the VEC output -which supports interlacing too. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -128,6 +128,7 @@ struct set_timings { - #define TIMINGS_FLAGS_H_SYNC_NEG 0 - #define TIMINGS_FLAGS_V_SYNC_POS BIT(1) - #define TIMINGS_FLAGS_V_SYNC_NEG 0 -+#define TIMINGS_FLAGS_INTERLACE BIT(2) - - #define TIMINGS_FLAGS_ASPECT_MASK GENMASK(7, 4) - #define TIMINGS_FLAGS_ASPECT_NONE (0 << 4) -@@ -1043,6 +1044,12 @@ static int vc4_fkms_lcd_connector_get_mo - fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; - else - fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; -+ if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) -+ fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; -+ else -+ fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; -+ if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE) -+ fw_mode.flags |= DRM_MODE_FLAG_INTERLACE; - - mode = drm_mode_duplicate(connector->dev, - &fw_mode); -@@ -1127,17 +1134,24 @@ vc4_fkms_connector_init(struct drm_devic - DRM_MODE_CONNECTOR_DSI); - drm_connector_helper_add(connector, - &vc4_fkms_lcd_conn_helper_funcs); -+ connector->interlace_allowed = 0; -+ } else if (fkms_connector->display_type == DRM_MODE_ENCODER_TVDAC) { -+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, -+ DRM_MODE_CONNECTOR_Composite); -+ drm_connector_helper_add(connector, -+ &vc4_fkms_lcd_conn_helper_funcs); -+ connector->interlace_allowed = 1; - } else { - drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA); - drm_connector_helper_add(connector, - &vc4_fkms_connector_helper_funcs); -+ connector->interlace_allowed = 0; - } - - connector->polled = (DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT); - -- connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - drm_connector_attach_encoder(connector, encoder); diff --git a/target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch b/target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch new file mode 100644 index 0000000000..186a7c891f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0253-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch @@ -0,0 +1,134 @@ +From 1a8e3d8e883b9f9b18dff052a9294d4354994992 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 30 May 2019 13:56:15 +0100 +Subject: [PATCH] drm/vc4: fkms to query the VPU for HDMI clock limits + +The VPU has configured clocks for 4k (or not) via config.txt, +and will limit the choice of video modes based on that. +Make fkms query it for these limits too to avoid selecting modes +that can not be handled by the current clock setup. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_drv.h | 1 + + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++++++ + include/soc/bcm2835/raspberrypi-firmware.h | 1 + + 3 files changed, 50 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -81,6 +81,7 @@ struct vc4_dev { + struct vc4_dsi *dsi1; + struct vc4_vec *vec; + struct vc4_txp *txp; ++ struct vc4_fkms *fkms; + + struct vc4_hang_state *hang_state; + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -32,6 +32,14 @@ + #include "vc_image_types.h" + #include + ++struct get_display_cfg { ++ u32 max_pixel_clock[2]; //Max pixel clock for each display ++}; ++ ++struct vc4_fkms { ++ struct get_display_cfg cfg; ++}; ++ + #define PLANES_PER_CRTC 3 + + struct set_plane { +@@ -795,6 +803,11 @@ static void vc4_crtc_enable(struct drm_c + static enum drm_mode_status + vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) + { ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); ++ struct vc4_fkms *fkms = vc4->fkms; ++ + /* Do not allow doublescan modes from user space */ + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { + DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n", +@@ -802,6 +815,22 @@ vc4_crtc_mode_valid(struct drm_crtc *crt + return MODE_NO_DBLESCAN; + } + ++ /* Limit the pixel clock based on the HDMI clock limits from the ++ * firmware ++ */ ++ switch (vc4_crtc->display_number) { ++ case 2: /* HDMI0 */ ++ if (fkms->cfg.max_pixel_clock[0] && ++ mode->clock > fkms->cfg.max_pixel_clock[0]) ++ return MODE_CLOCK_HIGH; ++ break; ++ case 7: /* HDMI1 */ ++ if (fkms->cfg.max_pixel_clock[1] && ++ mode->clock > fkms->cfg.max_pixel_clock[1]) ++ return MODE_CLOCK_HIGH; ++ break; ++ } ++ + /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling + * working. + */ +@@ -1295,11 +1324,16 @@ static int vc4_fkms_bind(struct device * + struct device_node *firmware_node; + struct vc4_crtc **crtc_list; + u32 num_displays, display_num; ++ struct vc4_fkms *fkms; + int ret; + u32 display_id; + + vc4->firmware_kms = true; + ++ fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL); ++ if (!fkms) ++ return -ENOMEM; ++ + /* firmware kms doesn't have precise a scanoutpos implementation, so + * we can't do the precise vblank timestamp mode. + */ +@@ -1328,6 +1362,18 @@ static int vc4_fkms_bind(struct device * + ret = 0; + } + ++ ret = rpi_firmware_property(vc4->firmware, ++ RPI_FIRMWARE_GET_DISPLAY_CFG, ++ &fkms->cfg, sizeof(fkms->cfg)); ++ ++ if (ret) ++ return -EINVAL; ++ /* The firmware works in Hz. This will be compared against kHz, so div ++ * 1000 now rather than multiple times later. ++ */ ++ fkms->cfg.max_pixel_clock[0] /= 1000; ++ fkms->cfg.max_pixel_clock[1] /= 1000; ++ + /* Allocate a list, with space for a NULL on the end */ + crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1), + GFP_KERNEL); +@@ -1369,6 +1415,8 @@ static int vc4_fkms_bind(struct device * + DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n"); + } + ++ vc4->fkms = fkms; ++ + platform_set_drvdata(pdev, crtc_list); + + return 0; +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -152,6 +152,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_SET_PLANE = 0x00048015, + RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, + RPI_FIRMWARE_SET_TIMING = 0x00048017, ++ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018, + + RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, + RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch b/target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch deleted file mode 100644 index 8008619639..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Fixup-typo-when-setting-HDMI-aspect-ratio.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 06e4e4560800232b0e6628bebc605d234ef1c237 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 7 May 2019 15:00:02 +0100 -Subject: [PATCH] drm: vc4: Fixup typo when setting HDMI aspect ratio - -Assignment was to the wrong structure. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -718,19 +718,19 @@ static void vc4_crtc_mode_set_nofb(struc - switch (frame.avi.picture_aspect) { - default: - case HDMI_PICTURE_ASPECT_NONE: -- mode->flags |= TIMINGS_FLAGS_ASPECT_NONE; -+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_NONE; - break; - case HDMI_PICTURE_ASPECT_4_3: -- mode->flags |= TIMINGS_FLAGS_ASPECT_4_3; -+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_4_3; - break; - case HDMI_PICTURE_ASPECT_16_9: -- mode->flags |= TIMINGS_FLAGS_ASPECT_16_9; -+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_16_9; - break; - case HDMI_PICTURE_ASPECT_64_27: -- mode->flags |= TIMINGS_FLAGS_ASPECT_64_27; -+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_64_27; - break; - case HDMI_PICTURE_ASPECT_256_135: -- mode->flags |= TIMINGS_FLAGS_ASPECT_256_135; -+ mb.timings.flags |= TIMINGS_FLAGS_ASPECT_256_135; - break; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch b/target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch new file mode 100644 index 0000000000..63931bf611 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0254-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch @@ -0,0 +1,46 @@ +From 2767f778820bd7392688512ec2996943a586db6e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 30 May 2019 15:55:15 +0100 +Subject: [PATCH] drm/vc4: Max resolution of 7680 is conditional on + being Pi4 + +The max resolution had been increased from 2048 to 7680 for all +platforms. This code is common with Pi0-3 which have a max render +target for GL of 2048, therefore the increased resolution has to +be conditional on the platform. +Switch based on whether the bcm2835-v3d node is found, as that is +not present on Pi4. (There is a potential configuration on Pi0-3 +with no v3d, but this is very unlikely). + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_kms.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "vc4_drv.h" + #include "vc4_regs.h" +@@ -536,8 +537,14 @@ int vc4_kms_load(struct drm_device *dev) + return ret; + } + +- dev->mode_config.max_width = 7680; +- dev->mode_config.max_height = 7680; ++ if (!drm_core_check_feature(dev, DRIVER_RENDER)) { ++ /* No V3D as part of vc4. Assume this is Pi4. */ ++ dev->mode_config.max_width = 7680; ++ dev->mode_config.max_height = 7680; ++ } else { ++ dev->mode_config.max_width = 2048; ++ dev->mode_config.max_height = 2048; ++ } + dev->mode_config.funcs = &vc4_mode_funcs; + dev->mode_config.preferred_depth = 24; + dev->mode_config.async_page_flip = true; diff --git a/target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-Correct-SAND-support-for-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-Correct-SAND-support-for-FKMS.patch deleted file mode 100644 index dcf57e07e7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-Correct-SAND-support-for-FKMS.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 46c612d0248ba6e0c8c236cf1839b0c2ccecee01 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 29 May 2019 15:44:11 +0100 -Subject: [PATCH] drm/vc4: Correct SAND support for FKMS. - -It was accepting NV21 which doesn't map through, but -also wasn't advertising the modifier so nothing would know -to request it. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -546,7 +546,6 @@ static bool vc4_fkms_format_mod_supporte - return false; - } - case DRM_FORMAT_NV12: -- case DRM_FORMAT_NV21: - switch (fourcc_mod_broadcom_mod(modifier)) { - case DRM_FORMAT_MOD_LINEAR: - case DRM_FORMAT_MOD_BROADCOM_SAND128: -@@ -554,6 +553,7 @@ static bool vc4_fkms_format_mod_supporte - default: - return false; - } -+ case DRM_FORMAT_NV21: - case DRM_FORMAT_RGB888: - case DRM_FORMAT_BGR888: - case DRM_FORMAT_YUV422: -@@ -600,6 +600,7 @@ static struct drm_plane *vc4_fkms_plane_ - * would prefer to scan out linear (less bus traffic). - */ - DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, -+ DRM_FORMAT_MOD_BROADCOM_SAND128, - DRM_FORMAT_MOD_INVALID, - }; - int i; diff --git a/target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch new file mode 100644 index 0000000000..5d6171ce40 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0255-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch @@ -0,0 +1,28 @@ +From 82551f68e9f9dea1f22d9cdfdf361bf054f6900c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 7 Jun 2019 11:31:21 +0100 +Subject: [PATCH] drm/vc4: Fix T-format modifiers in FKMS. + +The wrong vc_image formats were being checked for in the switch +statement. Correct these. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -460,10 +460,10 @@ static void vc4_plane_atomic_update(stru + switch (fb->modifier) { + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: + switch (mb->plane.vc_image_type) { +- case VC_IMAGE_RGBX32: ++ case VC_IMAGE_XRGB8888: + mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32; + break; +- case VC_IMAGE_RGBA32: ++ case VC_IMAGE_ARGB8888: + mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32; + break; + case VC_IMAGE_RGB565: diff --git a/target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch b/target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch new file mode 100644 index 0000000000..06e073b2ea --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch @@ -0,0 +1,29 @@ +From 44c7ff7864d931759efd307ef641f522c0a5bbdb Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 10 Jun 2019 16:32:51 +0100 +Subject: [PATCH] drm/vc4: Remove 340MHz clock limit from FKMS now + scrambling issues resolved + +Firmware TMDS scrambling is now being correctly configured, so +we can use it. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -831,12 +831,6 @@ vc4_crtc_mode_valid(struct drm_crtc *crt + break; + } + +- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling +- * working. +- */ +- if (mode->clock > 340000) +- return MODE_CLOCK_HIGH; +- + return MODE_OK; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch b/target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch deleted file mode 100644 index 186a7c891f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0256-drm-vc4-fkms-to-query-the-VPU-for-HDMI-clock-limits.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 1a8e3d8e883b9f9b18dff052a9294d4354994992 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 30 May 2019 13:56:15 +0100 -Subject: [PATCH] drm/vc4: fkms to query the VPU for HDMI clock limits - -The VPU has configured clocks for 4k (or not) via config.txt, -and will limit the choice of video modes based on that. -Make fkms query it for these limits too to avoid selecting modes -that can not be handled by the current clock setup. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_drv.h | 1 + - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++++++ - include/soc/bcm2835/raspberrypi-firmware.h | 1 + - 3 files changed, 50 insertions(+) - ---- a/drivers/gpu/drm/vc4/vc4_drv.h -+++ b/drivers/gpu/drm/vc4/vc4_drv.h -@@ -81,6 +81,7 @@ struct vc4_dev { - struct vc4_dsi *dsi1; - struct vc4_vec *vec; - struct vc4_txp *txp; -+ struct vc4_fkms *fkms; - - struct vc4_hang_state *hang_state; - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -32,6 +32,14 @@ - #include "vc_image_types.h" - #include - -+struct get_display_cfg { -+ u32 max_pixel_clock[2]; //Max pixel clock for each display -+}; -+ -+struct vc4_fkms { -+ struct get_display_cfg cfg; -+}; -+ - #define PLANES_PER_CRTC 3 - - struct set_plane { -@@ -795,6 +803,11 @@ static void vc4_crtc_enable(struct drm_c - static enum drm_mode_status - vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) - { -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -+ struct drm_device *dev = crtc->dev; -+ struct vc4_dev *vc4 = to_vc4_dev(dev); -+ struct vc4_fkms *fkms = vc4->fkms; -+ - /* Do not allow doublescan modes from user space */ - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { - DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n", -@@ -802,6 +815,22 @@ vc4_crtc_mode_valid(struct drm_crtc *crt - return MODE_NO_DBLESCAN; - } - -+ /* Limit the pixel clock based on the HDMI clock limits from the -+ * firmware -+ */ -+ switch (vc4_crtc->display_number) { -+ case 2: /* HDMI0 */ -+ if (fkms->cfg.max_pixel_clock[0] && -+ mode->clock > fkms->cfg.max_pixel_clock[0]) -+ return MODE_CLOCK_HIGH; -+ break; -+ case 7: /* HDMI1 */ -+ if (fkms->cfg.max_pixel_clock[1] && -+ mode->clock > fkms->cfg.max_pixel_clock[1]) -+ return MODE_CLOCK_HIGH; -+ break; -+ } -+ - /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling - * working. - */ -@@ -1295,11 +1324,16 @@ static int vc4_fkms_bind(struct device * - struct device_node *firmware_node; - struct vc4_crtc **crtc_list; - u32 num_displays, display_num; -+ struct vc4_fkms *fkms; - int ret; - u32 display_id; - - vc4->firmware_kms = true; - -+ fkms = devm_kzalloc(dev, sizeof(*fkms), GFP_KERNEL); -+ if (!fkms) -+ return -ENOMEM; -+ - /* firmware kms doesn't have precise a scanoutpos implementation, so - * we can't do the precise vblank timestamp mode. - */ -@@ -1328,6 +1362,18 @@ static int vc4_fkms_bind(struct device * - ret = 0; - } - -+ ret = rpi_firmware_property(vc4->firmware, -+ RPI_FIRMWARE_GET_DISPLAY_CFG, -+ &fkms->cfg, sizeof(fkms->cfg)); -+ -+ if (ret) -+ return -EINVAL; -+ /* The firmware works in Hz. This will be compared against kHz, so div -+ * 1000 now rather than multiple times later. -+ */ -+ fkms->cfg.max_pixel_clock[0] /= 1000; -+ fkms->cfg.max_pixel_clock[1] /= 1000; -+ - /* Allocate a list, with space for a NULL on the end */ - crtc_list = devm_kzalloc(dev, sizeof(crtc_list) * (num_displays + 1), - GFP_KERNEL); -@@ -1369,6 +1415,8 @@ static int vc4_fkms_bind(struct device * - DRM_WARN("No displays found. Consider forcing hotplug if HDMI is attached\n"); - } - -+ vc4->fkms = fkms; -+ - platform_set_drvdata(pdev, crtc_list); - - return 0; ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -152,6 +152,7 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_SET_PLANE = 0x00048015, - RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, - RPI_FIRMWARE_SET_TIMING = 0x00048017, -+ RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018, - - RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, - RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-Add-status-of-which-display-is-updated-throu.patch b/target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-Add-status-of-which-display-is-updated-throu.patch new file mode 100644 index 0000000000..8dd4caad1c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-Add-status-of-which-display-is-updated-throu.patch @@ -0,0 +1,85 @@ +From e399911ab20b650a031d883554180463804ac3f7 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 4 Jun 2019 12:14:30 +0100 +Subject: [PATCH] drm: vc4: Add status of which display is updated + through vblank + +Previously multiple displays were slaved off the same SMI +interrupt, triggered by HVS channel 1 (HDMI0). +This doesn't work if you only have a DPI or DSI screen (HVS channel +0), and gives slightly erroneous results with dual HDMI as the +events for HDMI1 are incorrect. + +Use SMIDSW0 and SMIDSW1 registers to denote which display has +triggered the vblank. +Handling should be backwards compatible with older firmware. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 41 ++++++++++++++++++++++---- + 1 file changed, 36 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -233,8 +233,13 @@ static const struct vc_image_format *vc4 + * hardware, which has only this one register. + */ + #define SMICS 0x0 ++#define SMIDSW0 0x14 ++#define SMIDSW1 0x1C + #define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11)) + ++/* Flag to denote that the firmware is giving multiple display callbacks */ ++#define SMI_NEW 0xabcd0000 ++ + #define vc4_crtc vc4_kms_crtc + #define to_vc4_crtc to_vc4_kms_crtc + struct vc4_crtc { +@@ -885,16 +890,42 @@ static irqreturn_t vc4_crtc_irq_handler( + int i; + u32 stat = readl(crtc_list[0]->regs + SMICS); + irqreturn_t ret = IRQ_NONE; ++ u32 chan; + + if (stat & SMICS_INTERRUPTS) { + writel(0, crtc_list[0]->regs + SMICS); + +- for (i = 0; crtc_list[i]; i++) { +- if (crtc_list[i]->vblank_enabled) +- drm_crtc_handle_vblank(&crtc_list[i]->base); +- vc4_crtc_handle_page_flip(crtc_list[i]); +- ret = IRQ_HANDLED; ++ chan = readl(crtc_list[0]->regs + SMIDSW0); ++ ++ if ((chan & 0xFFFF0000) != SMI_NEW) { ++ /* Older firmware. Treat the one interrupt as vblank/ ++ * complete for all crtcs. ++ */ ++ for (i = 0; crtc_list[i]; i++) { ++ if (crtc_list[i]->vblank_enabled) ++ drm_crtc_handle_vblank(&crtc_list[i]->base); ++ vc4_crtc_handle_page_flip(crtc_list[i]); ++ } ++ } else { ++ if (chan & 1) { ++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0); ++ if (crtc_list[0]->vblank_enabled) ++ drm_crtc_handle_vblank(&crtc_list[0]->base); ++ vc4_crtc_handle_page_flip(crtc_list[0]); ++ } ++ ++ /* Check for the secondary display too */ ++ chan = readl(crtc_list[0]->regs + SMIDSW1); ++ ++ if (chan & 1) { ++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1); ++ if (crtc_list[1]->vblank_enabled) ++ drm_crtc_handle_vblank(&crtc_list[1]->base); ++ vc4_crtc_handle_page_flip(crtc_list[1]); ++ } + } ++ ++ ret = IRQ_HANDLED; + } + + return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch b/target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch deleted file mode 100644 index 63931bf611..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0257-drm-vc4-Max-resolution-of-7680-is-conditional-on-bei.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2767f778820bd7392688512ec2996943a586db6e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 30 May 2019 15:55:15 +0100 -Subject: [PATCH] drm/vc4: Max resolution of 7680 is conditional on - being Pi4 - -The max resolution had been increased from 2048 to 7680 for all -platforms. This code is common with Pi0-3 which have a max render -target for GL of 2048, therefore the increased resolution has to -be conditional on the platform. -Switch based on whether the bcm2835-v3d node is found, as that is -not present on Pi4. (There is a potential configuration on Pi0-3 -with no v3d, but this is very unlikely). - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_kms.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - #include "vc4_drv.h" - #include "vc4_regs.h" -@@ -536,8 +537,14 @@ int vc4_kms_load(struct drm_device *dev) - return ret; - } - -- dev->mode_config.max_width = 7680; -- dev->mode_config.max_height = 7680; -+ if (!drm_core_check_feature(dev, DRIVER_RENDER)) { -+ /* No V3D as part of vc4. Assume this is Pi4. */ -+ dev->mode_config.max_width = 7680; -+ dev->mode_config.max_height = 7680; -+ } else { -+ dev->mode_config.max_width = 2048; -+ dev->mode_config.max_height = 2048; -+ } - dev->mode_config.funcs = &vc4_mode_funcs; - dev->mode_config.preferred_depth = 24; - dev->mode_config.async_page_flip = true; diff --git a/target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch deleted file mode 100644 index 5d6171ce40..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-Fix-T-format-modifiers-in-FKMS.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 82551f68e9f9dea1f22d9cdfdf361bf054f6900c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 7 Jun 2019 11:31:21 +0100 -Subject: [PATCH] drm/vc4: Fix T-format modifiers in FKMS. - -The wrong vc_image formats were being checked for in the switch -statement. Correct these. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -460,10 +460,10 @@ static void vc4_plane_atomic_update(stru - switch (fb->modifier) { - case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: - switch (mb->plane.vc_image_type) { -- case VC_IMAGE_RGBX32: -+ case VC_IMAGE_XRGB8888: - mb->plane.vc_image_type = VC_IMAGE_TF_RGBX32; - break; -- case VC_IMAGE_RGBA32: -+ case VC_IMAGE_ARGB8888: - mb->plane.vc_image_type = VC_IMAGE_TF_RGBA32; - break; - case VC_IMAGE_RGB565: diff --git a/target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch b/target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch new file mode 100644 index 0000000000..38b12e049f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0258-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch @@ -0,0 +1,36 @@ +From aa6061c2db8adbe0e75890cfc6f56b800b9995df Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 12 Jun 2019 17:13:21 +0100 +Subject: [PATCH] drm/vc4: In FKMS look at the modifiers correctly for + SAND + +Incorrect masking was used in the switch for the modifier, +therefore for SAND (which puts the column pitch in the +modifier) it didn't match. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -462,7 +462,7 @@ static void vc4_plane_atomic_update(stru + } + mb->plane.planes[3] = 0; + +- switch (fb->modifier) { ++ switch (fourcc_mod_broadcom_mod(fb->modifier)) { + case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: + switch (mb->plane.vc_image_type) { + case VC_IMAGE_XRGB8888: +@@ -478,6 +478,9 @@ static void vc4_plane_atomic_update(stru + break; + case DRM_FORMAT_MOD_BROADCOM_SAND128: + mb->plane.vc_image_type = VC_IMAGE_YUV_UV; ++ /* Note that the column pitch is passed across in lines, not ++ * bytes. ++ */ + mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier); + break; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Limit-fkms-to-modes-85Hz.patch b/target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Limit-fkms-to-modes-85Hz.patch new file mode 100644 index 0000000000..128ac5d54b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Limit-fkms-to-modes-85Hz.patch @@ -0,0 +1,26 @@ +From 9f9d67a11cfd6318d2bd1321090c0950242cfa25 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 18 Jun 2019 21:37:45 +0100 +Subject: [PATCH] drm/vc4: Limit fkms to modes <= 85Hz + +Selecting 1080p100 and 120 has very limited gain, but don't want +to block VGA85 and similar. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -823,6 +823,10 @@ vc4_crtc_mode_valid(struct drm_crtc *crt + return MODE_NO_DBLESCAN; + } + ++ /* Disable refresh rates > 85Hz as limited gain from them */ ++ if (drm_mode_vrefresh(mode) > 85) ++ return MODE_BAD_VVALUE; ++ + /* Limit the pixel clock based on the HDMI clock limits from the + * firmware + */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch b/target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch deleted file mode 100644 index 06e073b2ea..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0259-drm-vc4-Remove-340MHz-clock-limit-from-FKMS-now-scra.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 44c7ff7864d931759efd307ef641f522c0a5bbdb Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 10 Jun 2019 16:32:51 +0100 -Subject: [PATCH] drm/vc4: Remove 340MHz clock limit from FKMS now - scrambling issues resolved - -Firmware TMDS scrambling is now being correctly configured, so -we can use it. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ------ - 1 file changed, 6 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -831,12 +831,6 @@ vc4_crtc_mode_valid(struct drm_crtc *crt - break; - } - -- /* Limit the pixel clock until we can get dynamic HDMI 2.0 scrambling -- * working. -- */ -- if (mode->clock > 340000) -- return MODE_CLOCK_HIGH; -- - return MODE_OK; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Add-status-of-which-display-is-updated-throu.patch b/target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Add-status-of-which-display-is-updated-throu.patch deleted file mode 100644 index 8dd4caad1c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Add-status-of-which-display-is-updated-throu.patch +++ /dev/null @@ -1,85 +0,0 @@ -From e399911ab20b650a031d883554180463804ac3f7 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 4 Jun 2019 12:14:30 +0100 -Subject: [PATCH] drm: vc4: Add status of which display is updated - through vblank - -Previously multiple displays were slaved off the same SMI -interrupt, triggered by HVS channel 1 (HDMI0). -This doesn't work if you only have a DPI or DSI screen (HVS channel -0), and gives slightly erroneous results with dual HDMI as the -events for HDMI1 are incorrect. - -Use SMIDSW0 and SMIDSW1 registers to denote which display has -triggered the vblank. -Handling should be backwards compatible with older firmware. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 41 ++++++++++++++++++++++---- - 1 file changed, 36 insertions(+), 5 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -233,8 +233,13 @@ static const struct vc_image_format *vc4 - * hardware, which has only this one register. - */ - #define SMICS 0x0 -+#define SMIDSW0 0x14 -+#define SMIDSW1 0x1C - #define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11)) - -+/* Flag to denote that the firmware is giving multiple display callbacks */ -+#define SMI_NEW 0xabcd0000 -+ - #define vc4_crtc vc4_kms_crtc - #define to_vc4_crtc to_vc4_kms_crtc - struct vc4_crtc { -@@ -885,16 +890,42 @@ static irqreturn_t vc4_crtc_irq_handler( - int i; - u32 stat = readl(crtc_list[0]->regs + SMICS); - irqreturn_t ret = IRQ_NONE; -+ u32 chan; - - if (stat & SMICS_INTERRUPTS) { - writel(0, crtc_list[0]->regs + SMICS); - -- for (i = 0; crtc_list[i]; i++) { -- if (crtc_list[i]->vblank_enabled) -- drm_crtc_handle_vblank(&crtc_list[i]->base); -- vc4_crtc_handle_page_flip(crtc_list[i]); -- ret = IRQ_HANDLED; -+ chan = readl(crtc_list[0]->regs + SMIDSW0); -+ -+ if ((chan & 0xFFFF0000) != SMI_NEW) { -+ /* Older firmware. Treat the one interrupt as vblank/ -+ * complete for all crtcs. -+ */ -+ for (i = 0; crtc_list[i]; i++) { -+ if (crtc_list[i]->vblank_enabled) -+ drm_crtc_handle_vblank(&crtc_list[i]->base); -+ vc4_crtc_handle_page_flip(crtc_list[i]); -+ } -+ } else { -+ if (chan & 1) { -+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0); -+ if (crtc_list[0]->vblank_enabled) -+ drm_crtc_handle_vblank(&crtc_list[0]->base); -+ vc4_crtc_handle_page_flip(crtc_list[0]); -+ } -+ -+ /* Check for the secondary display too */ -+ chan = readl(crtc_list[0]->regs + SMIDSW1); -+ -+ if (chan & 1) { -+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1); -+ if (crtc_list[1]->vblank_enabled) -+ drm_crtc_handle_vblank(&crtc_list[1]->base); -+ vc4_crtc_handle_page_flip(crtc_list[1]); -+ } - } -+ -+ ret = IRQ_HANDLED; - } - - return ret; diff --git a/target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Ignore-HVS-unless-initialised.patch b/target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Ignore-HVS-unless-initialised.patch new file mode 100644 index 0000000000..f17f4be37d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0260-drm-vc4-Ignore-HVS-unless-initialised.patch @@ -0,0 +1,43 @@ +From cad68ea70d649cff90102022c5d161bf84e4ed16 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 19 Jul 2019 14:29:28 +0100 +Subject: [PATCH] drm/vc4: Ignore HVS unless initialised + +An upstream commit to report HVS underruns causes VC4 in firmware KMS +mode to cross into the HVS side, where it crashes due to a NULL hvs +pointer. + +Make the underrun masking conditional on the hvs pointer being +initialised. + +Fixes: 531a1b622da9 ("drm/vc4: Report HVS underrun errors") + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/vc4/vc4_crtc.c | 3 ++- + drivers/gpu/drm/vc4/vc4_kms.c | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_crtc.c ++++ b/drivers/gpu/drm/vc4/vc4_crtc.c +@@ -801,7 +801,8 @@ static void vc4_crtc_handle_page_flip(st + * the CRTC and encoder already reconfigured, leading to + * underruns. This can be seen when reconfiguring the CRTC. + */ +- vc4_hvs_unmask_underrun(dev, vc4_crtc->channel); ++ if (vc4->hvs) ++ vc4_hvs_unmask_underrun(dev, vc4_crtc->channel); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + } +--- a/drivers/gpu/drm/vc4/vc4_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_kms.c +@@ -156,7 +156,7 @@ vc4_atomic_complete_commit(struct drm_at + struct vc4_crtc *vc4_crtc; + int i; + +- for (i = 0; i < dev->mode_config.num_crtc; i++) { ++ for (i = 0; vc4->hvs && i < dev->mode_config.num_crtc; i++) { + if (!state->crtcs[i].ptr || !state->crtcs[i].commit) + continue; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch b/target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch deleted file mode 100644 index 38b12e049f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4-In-FKMS-look-at-the-modifiers-correctly-for-.patch +++ /dev/null @@ -1,36 +0,0 @@ -From aa6061c2db8adbe0e75890cfc6f56b800b9995df Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 12 Jun 2019 17:13:21 +0100 -Subject: [PATCH] drm/vc4: In FKMS look at the modifiers correctly for - SAND - -Incorrect masking was used in the switch for the modifier, -therefore for SAND (which puts the column pitch in the -modifier) it didn't match. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -462,7 +462,7 @@ static void vc4_plane_atomic_update(stru - } - mb->plane.planes[3] = 0; - -- switch (fb->modifier) { -+ switch (fourcc_mod_broadcom_mod(fb->modifier)) { - case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: - switch (mb->plane.vc_image_type) { - case VC_IMAGE_XRGB8888: -@@ -478,6 +478,9 @@ static void vc4_plane_atomic_update(stru - break; - case DRM_FORMAT_MOD_BROADCOM_SAND128: - mb->plane.vc_image_type = VC_IMAGE_YUV_UV; -+ /* Note that the column pitch is passed across in lines, not -+ * bytes. -+ */ - mb->plane.pitch = fourcc_mod_broadcom_param(fb->modifier); - break; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch b/target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch new file mode 100644 index 0000000000..9fd796850f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0261-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch @@ -0,0 +1,135 @@ +From cbda8e6de54f8a0f194e990f53e1cfad642af1be Mon Sep 17 00:00:00 2001 +From: Chris Miller +Date: Wed, 26 Jun 2019 10:40:30 +0100 +Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4 + (#3012) + +Signed-off-by: Chris G Miller +--- + drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++----------- + 1 file changed, 24 insertions(+), 11 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_dsi.c ++++ b/drivers/gpu/drm/vc4/vc4_dsi.c +@@ -1485,9 +1485,11 @@ static int vc4_dsi_bind(struct device *d + /* DSI1 has a broken AXI slave that doesn't respond to writes + * from the ARM. It does handle writes from the DMA engine, + * so set up a channel for talking to it. ++ * Where possible managed resource providers are used, but the DMA channel ++ * must - if acquired - be explicitly released prior to taking an error exit path. + */ + if (dsi->port == 1) { +- dsi->reg_dma_mem = dma_alloc_coherent(dev, 4, ++ dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4, + &dsi->reg_dma_paddr, + GFP_KERNEL); + if (!dsi->reg_dma_mem) { +@@ -1506,6 +1508,8 @@ static int vc4_dsi_bind(struct device *d + return ret; + } + ++ /* From here on, any error exits must release the dma channel */ ++ + /* Get the physical address of the device's registers. The + * struct resource for the regs gives us the bus address + * instead. +@@ -1532,7 +1536,7 @@ static int vc4_dsi_bind(struct device *d + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get interrupt: %d\n", ret); +- return ret; ++ goto rel_dma_exit; + } + + dsi->escape_clock = devm_clk_get(dev, "escape"); +@@ -1540,7 +1544,7 @@ static int vc4_dsi_bind(struct device *d + ret = PTR_ERR(dsi->escape_clock); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get escape clock: %d\n", ret); +- return ret; ++ goto rel_dma_exit; + } + + dsi->pll_phy_clock = devm_clk_get(dev, "phy"); +@@ -1548,7 +1552,7 @@ static int vc4_dsi_bind(struct device *d + ret = PTR_ERR(dsi->pll_phy_clock); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get phy clock: %d\n", ret); +- return ret; ++ goto rel_dma_exit; + } + + dsi->pixel_clock = devm_clk_get(dev, "pixel"); +@@ -1556,7 +1560,7 @@ static int vc4_dsi_bind(struct device *d + ret = PTR_ERR(dsi->pixel_clock); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get pixel clock: %d\n", ret); +- return ret; ++ goto rel_dma_exit; + } + + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, +@@ -1571,26 +1575,28 @@ static int vc4_dsi_bind(struct device *d + if (ret == -ENODEV) + return 0; + +- return ret; ++ goto rel_dma_exit; + } + + if (panel) { + dsi->bridge = devm_drm_panel_bridge_add(dev, panel, + DRM_MODE_CONNECTOR_DSI); +- if (IS_ERR(dsi->bridge)) +- return PTR_ERR(dsi->bridge); ++ if (IS_ERR(dsi->bridge)){ ++ ret = PTR_ERR(dsi->bridge); ++ goto rel_dma_exit; ++ } + } + + /* The esc clock rate is supposed to always be 100Mhz. */ + ret = clk_set_rate(dsi->escape_clock, 100 * 1000000); + if (ret) { + dev_err(dev, "Failed to set esc clock: %d\n", ret); +- return ret; ++ goto rel_dma_exit; + } + + ret = vc4_dsi_init_phy_clocks(dsi); + if (ret) +- return ret; ++ goto rel_dma_exit; + + if (dsi->port == 1) + vc4->dsi1 = dsi; +@@ -1602,7 +1608,7 @@ static int vc4_dsi_bind(struct device *d + ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL); + if (ret) { + dev_err(dev, "bridge attach failed: %d\n", ret); +- return ret; ++ goto rel_dma_exit; + } + /* Disable the atomic helper calls into the bridge. We + * manually call the bridge pre_enable / enable / etc. calls +@@ -1619,6 +1625,11 @@ static int vc4_dsi_bind(struct device *d + pm_runtime_enable(dev); + + return 0; ++ ++rel_dma_exit: ++ dma_release_channel(dsi->reg_dma_chan); ++ ++ return ret; + } + + static void vc4_dsi_unbind(struct device *dev, struct device *master, +@@ -1633,6 +1644,8 @@ static void vc4_dsi_unbind(struct device + + vc4_dsi_encoder_destroy(dsi->encoder); + ++ dma_release_channel(dsi->reg_dma_chan); ++ + if (dsi->port == 1) + vc4->dsi1 = NULL; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch b/target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch new file mode 100644 index 0000000000..619eb811cd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch @@ -0,0 +1,110 @@ +From 07f4c75cfa18cedfd192010c50cd62921b5a00ed Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 24 Jun 2019 02:29:40 +0100 +Subject: [PATCH] drm/vc4: Add support for color encoding on YUV planes + +Adds signalling for BT601/709/2020, and limited/full range +(on BT601). + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++++++++++++- + drivers/gpu/drm/vc4/vc_image_types.h | 28 ++++++++++++++++++++++ + 2 files changed, 59 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -69,7 +69,7 @@ struct set_plane { + u8 alpha; + u8 num_planes; + u8 is_vu; +- u8 padding; ++ u8 color_encoding; + + u32 planes[4]; /* DMA address of each plane */ + +@@ -456,6 +456,28 @@ static void vc4_plane_atomic_update(stru + if (num_planes == 3 && + (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1]) + mb->plane.vc_image_type = VC_IMAGE_YUV420_S; ++ ++ switch (state->color_encoding) { ++ default: ++ case DRM_COLOR_YCBCR_BT601: ++ if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) ++ mb->plane.color_encoding = ++ VC_IMAGE_YUVINFO_CSC_ITUR_BT601; ++ else ++ mb->plane.color_encoding = ++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF; ++ break; ++ case DRM_COLOR_YCBCR_BT709: ++ /* Currently no support for a full range BT709 */ ++ mb->plane.color_encoding = ++ VC_IMAGE_YUVINFO_CSC_ITUR_BT709; ++ break; ++ case DRM_COLOR_YCBCR_BT2020: ++ /* Currently no support for a full range BT2020 */ ++ mb->plane.color_encoding = ++ VC_IMAGE_YUVINFO_CSC_REC_2020; ++ break; ++ } + } else { + mb->plane.planes[1] = 0; + mb->plane.planes[2] = 0; +@@ -644,6 +666,14 @@ static struct drm_plane *vc4_fkms_plane_ + drm_plane_create_alpha_property(plane); + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, + SUPPORTED_ROTATIONS); ++ drm_plane_create_color_properties(plane, ++ BIT(DRM_COLOR_YCBCR_BT601) | ++ BIT(DRM_COLOR_YCBCR_BT709) | ++ BIT(DRM_COLOR_YCBCR_BT2020), ++ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | ++ BIT(DRM_COLOR_YCBCR_FULL_RANGE), ++ DRM_COLOR_YCBCR_BT709, ++ DRM_COLOR_YCBCR_LIMITED_RANGE); + + /* + * Default frame buffer setup is with FB on -127, and raspistill etc +--- a/drivers/gpu/drm/vc4/vc_image_types.h ++++ b/drivers/gpu/drm/vc4/vc_image_types.h +@@ -4,6 +4,8 @@ + * + * Values taken from vc_image_types.h released by Broadcom at + * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h ++ * and vc_image_structs.h at ++ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h + * + * 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 +@@ -141,3 +143,29 @@ enum { + VC_IMAGE_MAX, /* bounds for error checking */ + VC_IMAGE_FORCE_ENUM_16BIT = 0xffff, + }; ++ ++enum { ++ /* Unknown or unset - defaults to BT601 interstitial */ ++ VC_IMAGE_YUVINFO_UNSPECIFIED = 0, ++ ++ /* colour-space conversions data [4 bits] */ ++ ++ /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */ ++ VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1, ++ /* ITU-R BT.709-3 [HDTV] */ ++ VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2, ++ /* JPEG JFIF */ ++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3, ++ /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ ++ VC_IMAGE_YUVINFO_CSC_FCC = 4, ++ /* Society of Motion Picture and Television Engineers 240M (1999) */ ++ VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5, ++ /* ITU-R BT.470-2 System M */ ++ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6, ++ /* ITU-R BT.470-2 System B,G */ ++ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7, ++ /* JPEG JFIF, but with 16..255 luma */ ++ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8, ++ /* Rec 2020 */ ++ VC_IMAGE_YUVINFO_CSC_REC_2020 = 9, ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-Limit-fkms-to-modes-85Hz.patch b/target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-Limit-fkms-to-modes-85Hz.patch deleted file mode 100644 index 128ac5d54b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0262-drm-vc4-Limit-fkms-to-modes-85Hz.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 9f9d67a11cfd6318d2bd1321090c0950242cfa25 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 18 Jun 2019 21:37:45 +0100 -Subject: [PATCH] drm/vc4: Limit fkms to modes <= 85Hz - -Selecting 1080p100 and 120 has very limited gain, but don't want -to block VGA85 and similar. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -823,6 +823,10 @@ vc4_crtc_mode_valid(struct drm_crtc *crt - return MODE_NO_DBLESCAN; - } - -+ /* Disable refresh rates > 85Hz as limited gain from them */ -+ if (drm_mode_vrefresh(mode) > 85) -+ return MODE_BAD_VVALUE; -+ - /* Limit the pixel clock based on the HDMI clock limits from the - * firmware - */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0263-drm-vc4-Ignore-HVS-unless-initialised.patch b/target/linux/bcm27xx/patches-5.4/950-0263-drm-vc4-Ignore-HVS-unless-initialised.patch deleted file mode 100644 index f17f4be37d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0263-drm-vc4-Ignore-HVS-unless-initialised.patch +++ /dev/null @@ -1,43 +0,0 @@ -From cad68ea70d649cff90102022c5d161bf84e4ed16 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 19 Jul 2019 14:29:28 +0100 -Subject: [PATCH] drm/vc4: Ignore HVS unless initialised - -An upstream commit to report HVS underruns causes VC4 in firmware KMS -mode to cross into the HVS side, where it crashes due to a NULL hvs -pointer. - -Make the underrun masking conditional on the hvs pointer being -initialised. - -Fixes: 531a1b622da9 ("drm/vc4: Report HVS underrun errors") - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/vc4/vc4_crtc.c | 3 ++- - drivers/gpu/drm/vc4/vc4_kms.c | 2 +- - 2 files changed, 3 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_crtc.c -+++ b/drivers/gpu/drm/vc4/vc4_crtc.c -@@ -801,7 +801,8 @@ static void vc4_crtc_handle_page_flip(st - * the CRTC and encoder already reconfigured, leading to - * underruns. This can be seen when reconfiguring the CRTC. - */ -- vc4_hvs_unmask_underrun(dev, vc4_crtc->channel); -+ if (vc4->hvs) -+ vc4_hvs_unmask_underrun(dev, vc4_crtc->channel); - } - spin_unlock_irqrestore(&dev->event_lock, flags); - } ---- a/drivers/gpu/drm/vc4/vc4_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_kms.c -@@ -156,7 +156,7 @@ vc4_atomic_complete_commit(struct drm_at - struct vc4_crtc *vc4_crtc; - int i; - -- for (i = 0; i < dev->mode_config.num_crtc; i++) { -+ for (i = 0; vc4->hvs && i < dev->mode_config.num_crtc; i++) { - if (!state->crtcs[i].ptr || !state->crtcs[i].commit) - continue; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0263-tty-amba-pl011-Make-TX-optimisation-conditional.patch b/target/linux/bcm27xx/patches-5.4/950-0263-tty-amba-pl011-Make-TX-optimisation-conditional.patch new file mode 100644 index 0000000000..58829c9e92 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0263-tty-amba-pl011-Make-TX-optimisation-conditional.patch @@ -0,0 +1,85 @@ +From 76e24a2218069fadb28c0c2f5d813302ad5f85a3 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 11 Jul 2019 13:13:39 +0100 +Subject: [PATCH] tty: amba-pl011: Make TX optimisation conditional + +pl011_tx_chars takes a "from_irq" parameter to reduce the number of +register accesses. When from_irq is true the function assumes that the +FIFO is half empty and writes up to half a FIFO's worth of bytes +without polling the FIFO status register, the reasoning being that +the function is being called as a result of the TX interrupt being +raised. This logic would work were it not for the fact that +pl011_rx_chars, called from pl011_int before pl011_tx_chars, releases +the spinlock before calling tty_flip_buffer_push. + +A user thread writing to the UART claims the spinlock and ultimately +calls pl011_tx_chars with from_irq set to false. This reverts to the +older logic that polls the FIFO status register before sending every +byte. If this happen on an SMP system during the section of the IRQ +handler where the spinlock has been released, then by the time the TX +interrupt handler is called, the FIFO may already be full, and any +further writes are likely to be lost. + +The fix involves adding a per-port flag that is true iff running from +within the interrupt handler and the spinlock has not yet been released. +This flag is then used as the value for the from_irq parameter of +pl011_tx_chars, causing polling to be used in the unsafe case. + +Fixes: 1e84d22322ce ("serial/amba-pl011: Refactor and simplify TX FIFO handling") + +Signed-off-by: Phil Elwell +--- + drivers/tty/serial/amba-pl011.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -270,6 +270,7 @@ struct uart_amba_port { + unsigned int old_cr; /* state during shutdown */ + unsigned int fixed_baud; /* vendor-set fixed baud rate */ + char type[12]; ++ bool irq_locked; /* in irq, unreleased lock */ + #ifdef CONFIG_DMA_ENGINE + /* DMA stuff */ + bool using_tx_dma; +@@ -816,6 +817,7 @@ __acquires(&uap->port.lock) + if (!uap->using_tx_dma) + return; + ++ uap->irq_locked = 0; + dmaengine_terminate_async(uap->dmatx.chan); + + if (uap->dmatx.queued) { +@@ -942,6 +944,7 @@ static void pl011_dma_rx_chars(struct ua + fifotaken = pl011_fifo_to_tty(uap); + } + ++ uap->irq_locked = 0; + spin_unlock(&uap->port.lock); + dev_vdbg(uap->port.dev, + "Took %d chars from DMA buffer and %d chars from the FIFO\n", +@@ -1350,6 +1353,7 @@ __acquires(&uap->port.lock) + { + pl011_fifo_to_tty(uap); + ++ uap->irq_locked = 0; + spin_unlock(&uap->port.lock); + tty_flip_buffer_push(&uap->port.state->port); + /* +@@ -1485,6 +1489,7 @@ static irqreturn_t pl011_int(int irq, vo + int handled = 0; + + spin_lock_irqsave(&uap->port.lock, flags); ++ uap->irq_locked = 1; + status = pl011_read(uap, REG_RIS) & uap->im; + if (status) { + do { +@@ -1504,7 +1509,7 @@ static irqreturn_t pl011_int(int irq, vo + UART011_CTSMIS|UART011_RIMIS)) + pl011_modem_status(uap); + if (status & UART011_TXIS) +- pl011_tx_chars(uap, true); ++ pl011_tx_chars(uap, uap->irq_locked); + + if (pass_counter-- == 0) + break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0264-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch b/target/linux/bcm27xx/patches-5.4/950-0264-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch deleted file mode 100644 index 9fd796850f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0264-drm-vc4_dsi-Fix-DMA-channel-and-memory-leak-in-vc4-3.patch +++ /dev/null @@ -1,135 +0,0 @@ -From cbda8e6de54f8a0f194e990f53e1cfad642af1be Mon Sep 17 00:00:00 2001 -From: Chris Miller -Date: Wed, 26 Jun 2019 10:40:30 +0100 -Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4 - (#3012) - -Signed-off-by: Chris G Miller ---- - drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++----------- - 1 file changed, 24 insertions(+), 11 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_dsi.c -+++ b/drivers/gpu/drm/vc4/vc4_dsi.c -@@ -1485,9 +1485,11 @@ static int vc4_dsi_bind(struct device *d - /* DSI1 has a broken AXI slave that doesn't respond to writes - * from the ARM. It does handle writes from the DMA engine, - * so set up a channel for talking to it. -+ * Where possible managed resource providers are used, but the DMA channel -+ * must - if acquired - be explicitly released prior to taking an error exit path. - */ - if (dsi->port == 1) { -- dsi->reg_dma_mem = dma_alloc_coherent(dev, 4, -+ dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4, - &dsi->reg_dma_paddr, - GFP_KERNEL); - if (!dsi->reg_dma_mem) { -@@ -1506,6 +1508,8 @@ static int vc4_dsi_bind(struct device *d - return ret; - } - -+ /* From here on, any error exits must release the dma channel */ -+ - /* Get the physical address of the device's registers. The - * struct resource for the regs gives us the bus address - * instead. -@@ -1532,7 +1536,7 @@ static int vc4_dsi_bind(struct device *d - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get interrupt: %d\n", ret); -- return ret; -+ goto rel_dma_exit; - } - - dsi->escape_clock = devm_clk_get(dev, "escape"); -@@ -1540,7 +1544,7 @@ static int vc4_dsi_bind(struct device *d - ret = PTR_ERR(dsi->escape_clock); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get escape clock: %d\n", ret); -- return ret; -+ goto rel_dma_exit; - } - - dsi->pll_phy_clock = devm_clk_get(dev, "phy"); -@@ -1548,7 +1552,7 @@ static int vc4_dsi_bind(struct device *d - ret = PTR_ERR(dsi->pll_phy_clock); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get phy clock: %d\n", ret); -- return ret; -+ goto rel_dma_exit; - } - - dsi->pixel_clock = devm_clk_get(dev, "pixel"); -@@ -1556,7 +1560,7 @@ static int vc4_dsi_bind(struct device *d - ret = PTR_ERR(dsi->pixel_clock); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get pixel clock: %d\n", ret); -- return ret; -+ goto rel_dma_exit; - } - - ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, -@@ -1571,26 +1575,28 @@ static int vc4_dsi_bind(struct device *d - if (ret == -ENODEV) - return 0; - -- return ret; -+ goto rel_dma_exit; - } - - if (panel) { - dsi->bridge = devm_drm_panel_bridge_add(dev, panel, - DRM_MODE_CONNECTOR_DSI); -- if (IS_ERR(dsi->bridge)) -- return PTR_ERR(dsi->bridge); -+ if (IS_ERR(dsi->bridge)){ -+ ret = PTR_ERR(dsi->bridge); -+ goto rel_dma_exit; -+ } - } - - /* The esc clock rate is supposed to always be 100Mhz. */ - ret = clk_set_rate(dsi->escape_clock, 100 * 1000000); - if (ret) { - dev_err(dev, "Failed to set esc clock: %d\n", ret); -- return ret; -+ goto rel_dma_exit; - } - - ret = vc4_dsi_init_phy_clocks(dsi); - if (ret) -- return ret; -+ goto rel_dma_exit; - - if (dsi->port == 1) - vc4->dsi1 = dsi; -@@ -1602,7 +1608,7 @@ static int vc4_dsi_bind(struct device *d - ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL); - if (ret) { - dev_err(dev, "bridge attach failed: %d\n", ret); -- return ret; -+ goto rel_dma_exit; - } - /* Disable the atomic helper calls into the bridge. We - * manually call the bridge pre_enable / enable / etc. calls -@@ -1619,6 +1625,11 @@ static int vc4_dsi_bind(struct device *d - pm_runtime_enable(dev); - - return 0; -+ -+rel_dma_exit: -+ dma_release_channel(dsi->reg_dma_chan); -+ -+ return ret; - } - - static void vc4_dsi_unbind(struct device *dev, struct device *master, -@@ -1633,6 +1644,8 @@ static void vc4_dsi_unbind(struct device - - vc4_dsi_encoder_destroy(dsi->encoder); - -+ dma_release_channel(dsi->reg_dma_chan); -+ - if (dsi->port == 1) - vc4->dsi1 = NULL; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0264-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch b/target/linux/bcm27xx/patches-5.4/950-0264-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch new file mode 100644 index 0000000000..a125fdcb47 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0264-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch @@ -0,0 +1,90 @@ +From 7bb9b7d36fa457a9fc463108d1228fd318891da4 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Thu, 11 Jul 2019 17:55:43 +0100 +Subject: [PATCH] xhci: add quirk for host controllers that don't + update endpoint DCS + +Seen on a VLI VL805 PCIe to USB controller. For non-stream endpoints +at least, if the xHC halts on a particular TRB due to an error then +the DCS field in the Out Endpoint Context maintained by the hardware +is not updated with the current cycle state. + +Using the quirk XHCI_EP_CTX_BROKEN_DCS and instead fetch the DCS bit +from the TRB that the xHC stopped on. + +See: https://github.com/raspberrypi/linux/issues/3060 + +Signed-off-by: Jonathan Bell +--- + drivers/usb/host/xhci-pci.c | 4 +++- + drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++++++++++- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 29 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -255,8 +255,10 @@ static void xhci_pci_quirks(struct devic + xhci->quirks |= XHCI_BROKEN_STREAMS; + + if (pdev->vendor == PCI_VENDOR_ID_VIA && +- pdev->device == 0x3483) ++ pdev->device == 0x3483) { + xhci->quirks |= XHCI_LPM_SUPPORT; ++ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; ++ } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && + pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -527,7 +527,10 @@ void xhci_find_new_dequeue_state(struct + struct xhci_virt_ep *ep = &dev->eps[ep_index]; + struct xhci_ring *ep_ring; + struct xhci_segment *new_seg; ++ struct xhci_segment *halted_seg = NULL; + union xhci_trb *new_deq; ++ union xhci_trb *halted_trb; ++ int index = 0; + dma_addr_t addr; + u64 hw_dequeue; + bool cycle_found = false; +@@ -565,7 +568,28 @@ void xhci_find_new_dequeue_state(struct + hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id); + new_seg = ep_ring->deq_seg; + new_deq = ep_ring->dequeue; +- state->new_cycle_state = hw_dequeue & 0x1; ++ ++ /* ++ * Quirk: xHC write-back of the DCS field in the hardware dequeue ++ * pointer is wrong - use the cycle state of the TRB pointed to by ++ * the dequeue pointer. ++ */ ++ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS && ++ !(ep->ep_state & EP_HAS_STREAMS)) ++ halted_seg = trb_in_td(xhci, cur_td->start_seg, ++ cur_td->first_trb, cur_td->last_trb, ++ hw_dequeue & ~0xf, false); ++ if (halted_seg) { ++ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) / ++ sizeof(*halted_trb); ++ halted_trb = &halted_seg->trbs[index]; ++ state->new_cycle_state = halted_trb->generic.field[3] & 0x1; ++ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n", ++ (u8)(hw_dequeue & 0x1), index, ++ state->new_cycle_state); ++ } else { ++ state->new_cycle_state = hw_dequeue & 0x1; ++ } + state->stream_id = stream_id; + + /* +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1873,6 +1873,7 @@ struct xhci_hcd { + #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) + #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) + #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) ++#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(36) + #define XHCI_SKIP_PHY_INIT BIT_ULL(37) + #define XHCI_DISABLE_SPARSE BIT_ULL(38) + diff --git a/target/linux/bcm27xx/patches-5.4/950-0265-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch b/target/linux/bcm27xx/patches-5.4/950-0265-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch deleted file mode 100644 index 619eb811cd..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0265-drm-vc4-Add-support-for-color-encoding-on-YUV-planes.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 07f4c75cfa18cedfd192010c50cd62921b5a00ed Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 24 Jun 2019 02:29:40 +0100 -Subject: [PATCH] drm/vc4: Add support for color encoding on YUV planes - -Adds signalling for BT601/709/2020, and limited/full range -(on BT601). - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 32 +++++++++++++++++++++++++- - drivers/gpu/drm/vc4/vc_image_types.h | 28 ++++++++++++++++++++++ - 2 files changed, 59 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -69,7 +69,7 @@ struct set_plane { - u8 alpha; - u8 num_planes; - u8 is_vu; -- u8 padding; -+ u8 color_encoding; - - u32 planes[4]; /* DMA address of each plane */ - -@@ -456,6 +456,28 @@ static void vc4_plane_atomic_update(stru - if (num_planes == 3 && - (fb->offsets[2] - fb->offsets[1]) == fb->pitches[1]) - mb->plane.vc_image_type = VC_IMAGE_YUV420_S; -+ -+ switch (state->color_encoding) { -+ default: -+ case DRM_COLOR_YCBCR_BT601: -+ if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) -+ mb->plane.color_encoding = -+ VC_IMAGE_YUVINFO_CSC_ITUR_BT601; -+ else -+ mb->plane.color_encoding = -+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF; -+ break; -+ case DRM_COLOR_YCBCR_BT709: -+ /* Currently no support for a full range BT709 */ -+ mb->plane.color_encoding = -+ VC_IMAGE_YUVINFO_CSC_ITUR_BT709; -+ break; -+ case DRM_COLOR_YCBCR_BT2020: -+ /* Currently no support for a full range BT2020 */ -+ mb->plane.color_encoding = -+ VC_IMAGE_YUVINFO_CSC_REC_2020; -+ break; -+ } - } else { - mb->plane.planes[1] = 0; - mb->plane.planes[2] = 0; -@@ -644,6 +666,14 @@ static struct drm_plane *vc4_fkms_plane_ - drm_plane_create_alpha_property(plane); - drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, - SUPPORTED_ROTATIONS); -+ drm_plane_create_color_properties(plane, -+ BIT(DRM_COLOR_YCBCR_BT601) | -+ BIT(DRM_COLOR_YCBCR_BT709) | -+ BIT(DRM_COLOR_YCBCR_BT2020), -+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | -+ BIT(DRM_COLOR_YCBCR_FULL_RANGE), -+ DRM_COLOR_YCBCR_BT709, -+ DRM_COLOR_YCBCR_LIMITED_RANGE); - - /* - * Default frame buffer setup is with FB on -127, and raspistill etc ---- a/drivers/gpu/drm/vc4/vc_image_types.h -+++ b/drivers/gpu/drm/vc4/vc_image_types.h -@@ -4,6 +4,8 @@ - * - * Values taken from vc_image_types.h released by Broadcom at - * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_types.h -+ * and vc_image_structs.h at -+ * https://github.com/raspberrypi/userland/blob/master/interface/vctypes/vc_image_structs.h - * - * 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 -@@ -141,3 +143,29 @@ enum { - VC_IMAGE_MAX, /* bounds for error checking */ - VC_IMAGE_FORCE_ENUM_16BIT = 0xffff, - }; -+ -+enum { -+ /* Unknown or unset - defaults to BT601 interstitial */ -+ VC_IMAGE_YUVINFO_UNSPECIFIED = 0, -+ -+ /* colour-space conversions data [4 bits] */ -+ -+ /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */ -+ VC_IMAGE_YUVINFO_CSC_ITUR_BT601 = 1, -+ /* ITU-R BT.709-3 [HDTV] */ -+ VC_IMAGE_YUVINFO_CSC_ITUR_BT709 = 2, -+ /* JPEG JFIF */ -+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF = 3, -+ /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */ -+ VC_IMAGE_YUVINFO_CSC_FCC = 4, -+ /* Society of Motion Picture and Television Engineers 240M (1999) */ -+ VC_IMAGE_YUVINFO_CSC_SMPTE_240M = 5, -+ /* ITU-R BT.470-2 System M */ -+ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M = 6, -+ /* ITU-R BT.470-2 System B,G */ -+ VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7, -+ /* JPEG JFIF, but with 16..255 luma */ -+ VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8, -+ /* Rec 2020 */ -+ VC_IMAGE_YUVINFO_CSC_REC_2020 = 9, -+}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0265-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch b/target/linux/bcm27xx/patches-5.4/950-0265-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch new file mode 100644 index 0000000000..a3bc6c91b6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0265-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch @@ -0,0 +1,47 @@ +From 9c64858d41cc65982aaf36866ffa8e04b9792718 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 12 Jul 2019 15:38:35 +0100 +Subject: [PATCH] i2c: bcm2835: Set clock-stretch timeout to 35ms + +The BCM2835 I2C blocks have a register to set the clock-stretch +timeout - how long the device is allowed to hold SCL low - in bus +cycles. The current driver doesn't write to the register, therefore +the default value of 64 cycles is being used for all devices. + +Set the timeout to the value recommended for SMBus - 35ms. + +See: https://github.com/raspberrypi/linux/issues/3064 + +Signed-off-by: Phil Elwell +--- + drivers/i2c/busses/i2c-bcm2835.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/i2c/busses/i2c-bcm2835.c ++++ b/drivers/i2c/busses/i2c-bcm2835.c +@@ -188,6 +188,7 @@ static int clk_bcm2835_i2c_set_rate(stru + { + struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw); + u32 redl, fedl; ++ u32 clk_tout; + u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate); + + if (divider == -EINVAL) +@@ -211,6 +212,17 @@ static int clk_bcm2835_i2c_set_rate(stru + bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL, + (fedl << BCM2835_I2C_FEDL_SHIFT) | + (redl << BCM2835_I2C_REDL_SHIFT)); ++ ++ /* ++ * Set the clock stretch timeout to the SMBUs-recommended 35ms. ++ */ ++ if (rate > 0xffff*1000/35) ++ clk_tout = 0xffff; ++ else ++ clk_tout = 35*rate/1000; ++ ++ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_CLKT, clk_tout); ++ + return 0; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0266-staging-vc04_services-fix-compiling-in-separate-dire.patch b/target/linux/bcm27xx/patches-5.4/950-0266-staging-vc04_services-fix-compiling-in-separate-dire.patch new file mode 100644 index 0000000000..b3d57dc2b3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0266-staging-vc04_services-fix-compiling-in-separate-dire.patch @@ -0,0 +1,28 @@ +From 11076f57f802d2bdec3f1861ba27ce5554a710ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Sat, 3 Aug 2019 14:34:59 +0200 +Subject: [PATCH] staging: vc04_services: fix compiling in separate + directory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The vc04_services Makefiles do not respect the O=path argument +correctly: include paths in CFLAGS are given relatively to object path, +not source path. Compiling in a separate directory yields #include +errors. + +Signed-off-by: Marek Behún +--- + drivers/staging/vc04_services/bcm2835-codec/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/Makefile ++++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile +@@ -4,5 +4,5 @@ bcm2835-codec-objs := bcm2835-v4l2-codec + obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o + + ccflags-y += \ +- -Idrivers/staging/vc04_services \ ++ -I$(srctree)/drivers/staging/vc04_services \ + -D__VCCOREVER__=0x04000000 diff --git a/target/linux/bcm27xx/patches-5.4/950-0266-tty-amba-pl011-Make-TX-optimisation-conditional.patch b/target/linux/bcm27xx/patches-5.4/950-0266-tty-amba-pl011-Make-TX-optimisation-conditional.patch deleted file mode 100644 index 58829c9e92..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0266-tty-amba-pl011-Make-TX-optimisation-conditional.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 76e24a2218069fadb28c0c2f5d813302ad5f85a3 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 11 Jul 2019 13:13:39 +0100 -Subject: [PATCH] tty: amba-pl011: Make TX optimisation conditional - -pl011_tx_chars takes a "from_irq" parameter to reduce the number of -register accesses. When from_irq is true the function assumes that the -FIFO is half empty and writes up to half a FIFO's worth of bytes -without polling the FIFO status register, the reasoning being that -the function is being called as a result of the TX interrupt being -raised. This logic would work were it not for the fact that -pl011_rx_chars, called from pl011_int before pl011_tx_chars, releases -the spinlock before calling tty_flip_buffer_push. - -A user thread writing to the UART claims the spinlock and ultimately -calls pl011_tx_chars with from_irq set to false. This reverts to the -older logic that polls the FIFO status register before sending every -byte. If this happen on an SMP system during the section of the IRQ -handler where the spinlock has been released, then by the time the TX -interrupt handler is called, the FIFO may already be full, and any -further writes are likely to be lost. - -The fix involves adding a per-port flag that is true iff running from -within the interrupt handler and the spinlock has not yet been released. -This flag is then used as the value for the from_irq parameter of -pl011_tx_chars, causing polling to be used in the unsafe case. - -Fixes: 1e84d22322ce ("serial/amba-pl011: Refactor and simplify TX FIFO handling") - -Signed-off-by: Phil Elwell ---- - drivers/tty/serial/amba-pl011.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -270,6 +270,7 @@ struct uart_amba_port { - unsigned int old_cr; /* state during shutdown */ - unsigned int fixed_baud; /* vendor-set fixed baud rate */ - char type[12]; -+ bool irq_locked; /* in irq, unreleased lock */ - #ifdef CONFIG_DMA_ENGINE - /* DMA stuff */ - bool using_tx_dma; -@@ -816,6 +817,7 @@ __acquires(&uap->port.lock) - if (!uap->using_tx_dma) - return; - -+ uap->irq_locked = 0; - dmaengine_terminate_async(uap->dmatx.chan); - - if (uap->dmatx.queued) { -@@ -942,6 +944,7 @@ static void pl011_dma_rx_chars(struct ua - fifotaken = pl011_fifo_to_tty(uap); - } - -+ uap->irq_locked = 0; - spin_unlock(&uap->port.lock); - dev_vdbg(uap->port.dev, - "Took %d chars from DMA buffer and %d chars from the FIFO\n", -@@ -1350,6 +1353,7 @@ __acquires(&uap->port.lock) - { - pl011_fifo_to_tty(uap); - -+ uap->irq_locked = 0; - spin_unlock(&uap->port.lock); - tty_flip_buffer_push(&uap->port.state->port); - /* -@@ -1485,6 +1489,7 @@ static irqreturn_t pl011_int(int irq, vo - int handled = 0; - - spin_lock_irqsave(&uap->port.lock, flags); -+ uap->irq_locked = 1; - status = pl011_read(uap, REG_RIS) & uap->im; - if (status) { - do { -@@ -1504,7 +1509,7 @@ static irqreturn_t pl011_int(int irq, vo - UART011_CTSMIS|UART011_RIMIS)) - pl011_modem_status(uap); - if (status & UART011_TXIS) -- pl011_tx_chars(uap, true); -+ pl011_tx_chars(uap, uap->irq_locked); - - if (pass_counter-- == 0) - break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0267-clk-bcm2835-Avoid-null-pointer-exception.patch b/target/linux/bcm27xx/patches-5.4/950-0267-clk-bcm2835-Avoid-null-pointer-exception.patch new file mode 100644 index 0000000000..8a529af7b0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0267-clk-bcm2835-Avoid-null-pointer-exception.patch @@ -0,0 +1,29 @@ +From 7316a9e5720c2f4112a96b32c4ec78d94a44adcf Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 6 Aug 2019 15:23:14 +0100 +Subject: [PATCH] clk-bcm2835: Avoid null pointer exception + +clk_desc_array[BCM2835_PLLB] doesn't exist so we dereference null when iterating + +Signed-off-by: popcornmix +--- + drivers/clk/bcm/clk-bcm2835.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -2280,9 +2280,11 @@ static bool bcm2835_clk_is_claimed(const + int i; + + for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { +- const char *clk_name = *(const char **)(clk_desc_array[i].data); +- if (!strcmp(name, clk_name)) +- return bcm2835_clk_claimed[i]; ++ if (clk_desc_array[i].data) { ++ const char *clk_name = *(const char **)(clk_desc_array[i].data); ++ if (!strcmp(name, clk_name)) ++ return bcm2835_clk_claimed[i]; ++ } + } + + return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0267-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch b/target/linux/bcm27xx/patches-5.4/950-0267-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch deleted file mode 100644 index a125fdcb47..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0267-xhci-add-quirk-for-host-controllers-that-don-t-updat.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 7bb9b7d36fa457a9fc463108d1228fd318891da4 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Thu, 11 Jul 2019 17:55:43 +0100 -Subject: [PATCH] xhci: add quirk for host controllers that don't - update endpoint DCS - -Seen on a VLI VL805 PCIe to USB controller. For non-stream endpoints -at least, if the xHC halts on a particular TRB due to an error then -the DCS field in the Out Endpoint Context maintained by the hardware -is not updated with the current cycle state. - -Using the quirk XHCI_EP_CTX_BROKEN_DCS and instead fetch the DCS bit -from the TRB that the xHC stopped on. - -See: https://github.com/raspberrypi/linux/issues/3060 - -Signed-off-by: Jonathan Bell ---- - drivers/usb/host/xhci-pci.c | 4 +++- - drivers/usb/host/xhci-ring.c | 26 +++++++++++++++++++++++++- - drivers/usb/host/xhci.h | 1 + - 3 files changed, 29 insertions(+), 2 deletions(-) - ---- a/drivers/usb/host/xhci-pci.c -+++ b/drivers/usb/host/xhci-pci.c -@@ -255,8 +255,10 @@ static void xhci_pci_quirks(struct devic - xhci->quirks |= XHCI_BROKEN_STREAMS; - - if (pdev->vendor == PCI_VENDOR_ID_VIA && -- pdev->device == 0x3483) -+ pdev->device == 0x3483) { - xhci->quirks |= XHCI_LPM_SUPPORT; -+ xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; -+ } - - if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && - pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) ---- a/drivers/usb/host/xhci-ring.c -+++ b/drivers/usb/host/xhci-ring.c -@@ -527,7 +527,10 @@ void xhci_find_new_dequeue_state(struct - struct xhci_virt_ep *ep = &dev->eps[ep_index]; - struct xhci_ring *ep_ring; - struct xhci_segment *new_seg; -+ struct xhci_segment *halted_seg = NULL; - union xhci_trb *new_deq; -+ union xhci_trb *halted_trb; -+ int index = 0; - dma_addr_t addr; - u64 hw_dequeue; - bool cycle_found = false; -@@ -565,7 +568,28 @@ void xhci_find_new_dequeue_state(struct - hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id); - new_seg = ep_ring->deq_seg; - new_deq = ep_ring->dequeue; -- state->new_cycle_state = hw_dequeue & 0x1; -+ -+ /* -+ * Quirk: xHC write-back of the DCS field in the hardware dequeue -+ * pointer is wrong - use the cycle state of the TRB pointed to by -+ * the dequeue pointer. -+ */ -+ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS && -+ !(ep->ep_state & EP_HAS_STREAMS)) -+ halted_seg = trb_in_td(xhci, cur_td->start_seg, -+ cur_td->first_trb, cur_td->last_trb, -+ hw_dequeue & ~0xf, false); -+ if (halted_seg) { -+ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) / -+ sizeof(*halted_trb); -+ halted_trb = &halted_seg->trbs[index]; -+ state->new_cycle_state = halted_trb->generic.field[3] & 0x1; -+ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n", -+ (u8)(hw_dequeue & 0x1), index, -+ state->new_cycle_state); -+ } else { -+ state->new_cycle_state = hw_dequeue & 0x1; -+ } - state->stream_id = stream_id; - - /* ---- a/drivers/usb/host/xhci.h -+++ b/drivers/usb/host/xhci.h -@@ -1873,6 +1873,7 @@ struct xhci_hcd { - #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) - #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) - #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) -+#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(36) - #define XHCI_SKIP_PHY_INIT BIT_ULL(37) - #define XHCI_DISABLE_SPARSE BIT_ULL(38) - diff --git a/target/linux/bcm27xx/patches-5.4/950-0268-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0268-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch new file mode 100644 index 0000000000..e4f178d0a2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0268-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch @@ -0,0 +1,74 @@ +From 907dc84e0c7208b79ad57e0e2a7964dbc9155f50 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 15 Aug 2019 08:39:08 +0100 +Subject: [PATCH] drm/vc4: Prevent load tracking from breaking FKMS + +Firmware KMS uses a mixture of VC4 processing and dedicated code. The +load tracking support in VC4 assumes it is dealing with vc4_plane_state +objects when up-casting with container_of, but FKMS uses unadorned +drm_plane_state structures causing the VC4 code to read off the end +into random portions of memory. Work around the problem in a minimally- +invasive way by over-allocating the FKMS plane state structures to be +large enough to contain a vc4_plane_state, filling the remainder with +zeroes. + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 34 ++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -561,6 +561,20 @@ static int vc4_plane_atomic_check(struct + return 0; + } + ++/* Called during init to allocate the plane's atomic state. */ ++static void vc4_plane_reset(struct drm_plane *plane) ++{ ++ struct vc4_plane_state *vc4_state; ++ ++ WARN_ON(plane->state); ++ ++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); ++ if (!vc4_state) ++ return; ++ ++ __drm_atomic_helper_plane_reset(plane, &vc4_state->base); ++} ++ + static void vc4_plane_destroy(struct drm_plane *plane) + { + drm_plane_cleanup(plane); +@@ -602,13 +616,29 @@ static bool vc4_fkms_format_mod_supporte + } + } + ++static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) ++{ ++ struct vc4_plane_state *vc4_state; ++ ++ if (WARN_ON(!plane->state)) ++ return NULL; ++ ++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); ++ if (!vc4_state) ++ return NULL; ++ ++ __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); ++ ++ return &vc4_state->base; ++} ++ + static const struct drm_plane_funcs vc4_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = vc4_plane_destroy, + .set_property = NULL, +- .reset = drm_atomic_helper_plane_reset, +- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, ++ .reset = vc4_plane_reset, ++ .atomic_duplicate_state = vc4_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .format_mod_supported = vc4_fkms_format_mod_supported, + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0268-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch b/target/linux/bcm27xx/patches-5.4/950-0268-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch deleted file mode 100644 index a3bc6c91b6..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0268-i2c-bcm2835-Set-clock-stretch-timeout-to-35ms.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 9c64858d41cc65982aaf36866ffa8e04b9792718 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 12 Jul 2019 15:38:35 +0100 -Subject: [PATCH] i2c: bcm2835: Set clock-stretch timeout to 35ms - -The BCM2835 I2C blocks have a register to set the clock-stretch -timeout - how long the device is allowed to hold SCL low - in bus -cycles. The current driver doesn't write to the register, therefore -the default value of 64 cycles is being used for all devices. - -Set the timeout to the value recommended for SMBus - 35ms. - -See: https://github.com/raspberrypi/linux/issues/3064 - -Signed-off-by: Phil Elwell ---- - drivers/i2c/busses/i2c-bcm2835.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/drivers/i2c/busses/i2c-bcm2835.c -+++ b/drivers/i2c/busses/i2c-bcm2835.c -@@ -188,6 +188,7 @@ static int clk_bcm2835_i2c_set_rate(stru - { - struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw); - u32 redl, fedl; -+ u32 clk_tout; - u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate); - - if (divider == -EINVAL) -@@ -211,6 +212,17 @@ static int clk_bcm2835_i2c_set_rate(stru - bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL, - (fedl << BCM2835_I2C_FEDL_SHIFT) | - (redl << BCM2835_I2C_REDL_SHIFT)); -+ -+ /* -+ * Set the clock stretch timeout to the SMBUs-recommended 35ms. -+ */ -+ if (rate > 0xffff*1000/35) -+ clk_tout = 0xffff; -+ else -+ clk_tout = 35*rate/1000; -+ -+ bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_CLKT, clk_tout); -+ - return 0; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0269-drm-v3d-HACK-gut-runtime-pm-for-now.patch b/target/linux/bcm27xx/patches-5.4/950-0269-drm-v3d-HACK-gut-runtime-pm-for-now.patch new file mode 100644 index 0000000000..ed69f2d157 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0269-drm-v3d-HACK-gut-runtime-pm-for-now.patch @@ -0,0 +1,109 @@ +From ba05797f8e3578398a1ab6c835f6b100d4f46edb Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 14 Jan 2019 15:13:17 -0800 +Subject: [PATCH] drm/v3d: HACK: gut runtime pm for now. + +Something is still unstable -- on starting a new glxgears from an idle +X11, I get an MMU violation in high addresses. The CTS also failed +quite quickly. With this, CTS progresses for an hour before OOMing +(allocating some big buffers when my board only has 600MB available to +Linux) + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +--------------- + drivers/gpu/drm/v3d/v3d_drv.c | 9 --------- + 2 files changed, 1 insertion(+), 24 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_debugfs.c ++++ b/drivers/gpu/drm/v3d/v3d_debugfs.c +@@ -4,7 +4,6 @@ + #include + #include + #include +-#include + #include + + #include +@@ -130,11 +129,8 @@ static int v3d_v3d_debugfs_ident(struct + struct drm_device *dev = node->minor->dev; + struct v3d_dev *v3d = to_v3d_dev(dev); + u32 ident0, ident1, ident2, ident3, cores; +- int ret, core; ++ int core; + +- ret = pm_runtime_get_sync(v3d->dev); +- if (ret < 0) +- return ret; + + ident0 = V3D_READ(V3D_HUB_IDENT0); + ident1 = V3D_READ(V3D_HUB_IDENT1); +@@ -187,9 +183,6 @@ static int v3d_v3d_debugfs_ident(struct + (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); + } + +- pm_runtime_mark_last_busy(v3d->dev); +- pm_runtime_put_autosuspend(v3d->dev); +- + return 0; + } + +@@ -217,11 +210,6 @@ static int v3d_measure_clock(struct seq_ + uint32_t cycles; + int core = 0; + int measure_ms = 1000; +- int ret; +- +- ret = pm_runtime_get_sync(v3d->dev); +- if (ret < 0) +- return ret; + + if (v3d->ver >= 40) { + V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3, +@@ -245,8 +233,6 @@ static int v3d_measure_clock(struct seq_ + cycles / (measure_ms * 1000), + (cycles / (measure_ms * 100)) % 10); + +- pm_runtime_mark_last_busy(v3d->dev); +- pm_runtime_put_autosuspend(v3d->dev); + + return 0; + } +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -78,7 +78,6 @@ static int v3d_get_param_ioctl(struct dr + { + struct v3d_dev *v3d = to_v3d_dev(dev); + struct drm_v3d_get_param *args = data; +- int ret; + static const u32 reg_map[] = { + [DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_UIFCFG, + [DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_IDENT1, +@@ -104,17 +103,12 @@ static int v3d_get_param_ioctl(struct dr + if (args->value != 0) + return -EINVAL; + +- ret = pm_runtime_get_sync(v3d->dev); +- if (ret < 0) +- return ret; + if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 && + args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) { + args->value = V3D_CORE_READ(0, offset); + } else { + args->value = V3D_READ(offset); + } +- pm_runtime_mark_last_busy(v3d->dev); +- pm_runtime_put_autosuspend(v3d->dev); + return 0; + } + +@@ -302,9 +296,6 @@ static int v3d_platform_drm_probe(struct + goto dev_free; + } + +- pm_runtime_use_autosuspend(dev); +- pm_runtime_set_autosuspend_delay(dev, 50); +- pm_runtime_enable(dev); + + ret = drm_dev_init(&v3d->drm, &v3d_drm_driver, dev); + if (ret) diff --git a/target/linux/bcm27xx/patches-5.4/950-0269-staging-vc04_services-fix-compiling-in-separate-dire.patch b/target/linux/bcm27xx/patches-5.4/950-0269-staging-vc04_services-fix-compiling-in-separate-dire.patch deleted file mode 100644 index b3d57dc2b3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0269-staging-vc04_services-fix-compiling-in-separate-dire.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 11076f57f802d2bdec3f1861ba27ce5554a710ca Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marek=20Beh=C3=BAn?= -Date: Sat, 3 Aug 2019 14:34:59 +0200 -Subject: [PATCH] staging: vc04_services: fix compiling in separate - directory -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The vc04_services Makefiles do not respect the O=path argument -correctly: include paths in CFLAGS are given relatively to object path, -not source path. Compiling in a separate directory yields #include -errors. - -Signed-off-by: Marek Behún ---- - drivers/staging/vc04_services/bcm2835-codec/Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/Makefile -+++ b/drivers/staging/vc04_services/bcm2835-codec/Makefile -@@ -4,5 +4,5 @@ bcm2835-codec-objs := bcm2835-v4l2-codec - obj-$(CONFIG_VIDEO_CODEC_BCM2835) += bcm2835-codec.o - - ccflags-y += \ -- -Idrivers/staging/vc04_services \ -+ -I$(srctree)/drivers/staging/vc04_services \ - -D__VCCOREVER__=0x04000000 diff --git a/target/linux/bcm27xx/patches-5.4/950-0270-clk-bcm2835-Avoid-null-pointer-exception.patch b/target/linux/bcm27xx/patches-5.4/950-0270-clk-bcm2835-Avoid-null-pointer-exception.patch deleted file mode 100644 index 8a529af7b0..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0270-clk-bcm2835-Avoid-null-pointer-exception.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 7316a9e5720c2f4112a96b32c4ec78d94a44adcf Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 6 Aug 2019 15:23:14 +0100 -Subject: [PATCH] clk-bcm2835: Avoid null pointer exception - -clk_desc_array[BCM2835_PLLB] doesn't exist so we dereference null when iterating - -Signed-off-by: popcornmix ---- - drivers/clk/bcm/clk-bcm2835.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -2280,9 +2280,11 @@ static bool bcm2835_clk_is_claimed(const - int i; - - for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { -- const char *clk_name = *(const char **)(clk_desc_array[i].data); -- if (!strcmp(name, clk_name)) -- return bcm2835_clk_claimed[i]; -+ if (clk_desc_array[i].data) { -+ const char *clk_name = *(const char **)(clk_desc_array[i].data); -+ if (!strcmp(name, clk_name)) -+ return bcm2835_clk_claimed[i]; -+ } - } - - return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0270-drm-v3d-Clock-V3D-down-when-not-in-use.patch b/target/linux/bcm27xx/patches-5.4/950-0270-drm-v3d-Clock-V3D-down-when-not-in-use.patch new file mode 100644 index 0000000000..782cc197d5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0270-drm-v3d-Clock-V3D-down-when-not-in-use.patch @@ -0,0 +1,161 @@ +From ca8579839f0ebf0ffe73d1135284363b2155e712 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 2 May 2019 13:22:53 -0700 +Subject: [PATCH] drm/v3d: Clock V3D down when not in use. + +My various attempts at re-enabling runtime PM have failed, so just +crank the clock down when V3D is idle to reduce power consumption. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/v3d/v3d_drv.c | 18 ++++++++++++ + drivers/gpu/drm/v3d/v3d_drv.h | 6 ++++ + drivers/gpu/drm/v3d/v3d_gem.c | 53 +++++++++++++++++++++++++++++++---- + 3 files changed, 72 insertions(+), 5 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -282,6 +282,21 @@ static int v3d_platform_drm_probe(struct + } + } + ++ v3d->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(v3d->clk)) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get clock\n"); ++ goto dev_free; ++ } ++ v3d->clk_up_rate = clk_get_rate(v3d->clk); ++ /* For downclocking, drop it to the minimum frequency we can get from ++ * the CPRMAN clock generator dividing off our parent. The divider is ++ * 4 bits, but ask for just higher than that so that rounding doesn't ++ * make cprman reject our rate. ++ */ ++ v3d->clk_down_rate = ++ (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000; ++ + if (v3d->ver < 41) { + ret = map_regs(v3d, &v3d->gca_regs, "gca"); + if (ret) +@@ -316,6 +331,9 @@ static int v3d_platform_drm_probe(struct + if (ret) + goto irq_disable; + ++ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate); ++ WARN_ON_ONCE(ret != 0); ++ + return 0; + + irq_disable: +--- a/drivers/gpu/drm/v3d/v3d_drv.h ++++ b/drivers/gpu/drm/v3d/v3d_drv.h +@@ -54,6 +54,12 @@ struct v3d_dev { + void __iomem *bridge_regs; + void __iomem *gca_regs; + struct clk *clk; ++ struct delayed_work clk_down_work; ++ unsigned long clk_up_rate, clk_down_rate; ++ struct mutex clk_lock; ++ u32 clk_refcount; ++ bool clk_up; ++ + struct reset_control *reset; + + /* Virtual and DMA addresses of the single shared page table. */ +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -19,6 +20,47 @@ + #include "v3d_trace.h" + + static void ++v3d_clock_down_work(struct work_struct *work) ++{ ++ struct v3d_dev *v3d = ++ container_of(work, struct v3d_dev, clk_down_work.work); ++ int ret; ++ ++ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate); ++ v3d->clk_up = false; ++ WARN_ON_ONCE(ret != 0); ++} ++ ++static void ++v3d_clock_up_get(struct v3d_dev *v3d) ++{ ++ mutex_lock(&v3d->clk_lock); ++ if (v3d->clk_refcount++ == 0) { ++ cancel_delayed_work_sync(&v3d->clk_down_work); ++ if (!v3d->clk_up) { ++ int ret; ++ ++ ret = clk_set_rate(v3d->clk, v3d->clk_up_rate); ++ WARN_ON_ONCE(ret != 0); ++ v3d->clk_up = true; ++ } ++ } ++ mutex_unlock(&v3d->clk_lock); ++} ++ ++static void ++v3d_clock_up_put(struct v3d_dev *v3d) ++{ ++ mutex_lock(&v3d->clk_lock); ++ if (--v3d->clk_refcount == 0) { ++ schedule_delayed_work(&v3d->clk_down_work, ++ msecs_to_jiffies(100)); ++ } ++ mutex_unlock(&v3d->clk_lock); ++} ++ ++ ++static void + v3d_init_core(struct v3d_dev *v3d, int core) + { + /* Set OVRTMUOUT, which means that the texture sampler uniform +@@ -354,6 +396,7 @@ v3d_job_free(struct kref *ref) + struct v3d_job *job = container_of(ref, struct v3d_job, refcount); + unsigned long index; + struct dma_fence *fence; ++ struct v3d_dev *v3d = job->v3d; + int i; + + for (i = 0; i < job->bo_count; i++) { +@@ -367,11 +410,7 @@ v3d_job_free(struct kref *ref) + } + xa_destroy(&job->deps); + +- dma_fence_put(job->irq_fence); +- dma_fence_put(job->done_fence); +- +- pm_runtime_mark_last_busy(job->v3d->dev); +- pm_runtime_put_autosuspend(job->v3d->dev); ++ v3d_clock_up_put(v3d); + + kfree(job); + } +@@ -453,6 +492,7 @@ v3d_job_init(struct v3d_dev *v3d, struct + if (ret) + goto fail; + ++ v3d_clock_up_get(v3d); + kref_init(&job->refcount); + + return 0; +@@ -841,6 +881,9 @@ v3d_gem_init(struct drm_device *dev) + mutex_init(&v3d->sched_lock); + mutex_init(&v3d->cache_clean_lock); + ++ mutex_init(&v3d->clk_lock); ++ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work); ++ + /* Note: We don't allocate address 0. Various bits of HW + * treat 0 as special, such as the occlusion query counters + * where 0 means "disabled". diff --git a/target/linux/bcm27xx/patches-5.4/950-0271-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch b/target/linux/bcm27xx/patches-5.4/950-0271-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch new file mode 100644 index 0000000000..267725d3ef --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0271-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch @@ -0,0 +1,31 @@ +From 638f29943041f9205486a03587b7bd9e64799b2a Mon Sep 17 00:00:00 2001 +From: Hermann Lauer +Date: Thu, 8 Aug 2019 15:40:37 +0200 +Subject: [PATCH] According to 5713 pdf doc CLOCK_CTRL is a readonly + status register, and it behaves so. Remove useless setting + +--- + sound/soc/codecs/tas5713.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/sound/soc/codecs/tas5713.c ++++ b/sound/soc/codecs/tas5713.c +@@ -190,10 +190,6 @@ static int tas5713_probe(struct snd_soc_ + ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00); + if (ret < 0) return ret; + +- // Clock mode: 44/48kHz, MCLK=64xfs +- ret = snd_soc_component_write(component, TAS5713_CLOCK_CTRL, 0x60); +- if (ret < 0) return ret; +- + // I2S 24bit + ret = snd_soc_component_write(component, TAS5713_SERIAL_DATA_INTERFACE, 0x05); + if (ret < 0) return ret; +@@ -257,6 +253,7 @@ static bool tas5713_reg_volatile(struct + switch (reg) { + case TAS5713_DEVICE_ID: + case TAS5713_ERROR_STATUS: ++ case TAS5713_CLOCK_CTRL: + return true; + default: + return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0271-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch b/target/linux/bcm27xx/patches-5.4/950-0271-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch deleted file mode 100644 index e4f178d0a2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0271-drm-vc4-Prevent-load-tracking-from-breaking-FKMS.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 907dc84e0c7208b79ad57e0e2a7964dbc9155f50 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 15 Aug 2019 08:39:08 +0100 -Subject: [PATCH] drm/vc4: Prevent load tracking from breaking FKMS - -Firmware KMS uses a mixture of VC4 processing and dedicated code. The -load tracking support in VC4 assumes it is dealing with vc4_plane_state -objects when up-casting with container_of, but FKMS uses unadorned -drm_plane_state structures causing the VC4 code to read off the end -into random portions of memory. Work around the problem in a minimally- -invasive way by over-allocating the FKMS plane state structures to be -large enough to contain a vc4_plane_state, filling the remainder with -zeroes. - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 34 ++++++++++++++++++++++++-- - 1 file changed, 32 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -561,6 +561,20 @@ static int vc4_plane_atomic_check(struct - return 0; - } - -+/* Called during init to allocate the plane's atomic state. */ -+static void vc4_plane_reset(struct drm_plane *plane) -+{ -+ struct vc4_plane_state *vc4_state; -+ -+ WARN_ON(plane->state); -+ -+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); -+ if (!vc4_state) -+ return; -+ -+ __drm_atomic_helper_plane_reset(plane, &vc4_state->base); -+} -+ - static void vc4_plane_destroy(struct drm_plane *plane) - { - drm_plane_cleanup(plane); -@@ -602,13 +616,29 @@ static bool vc4_fkms_format_mod_supporte - } - } - -+static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) -+{ -+ struct vc4_plane_state *vc4_state; -+ -+ if (WARN_ON(!plane->state)) -+ return NULL; -+ -+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); -+ if (!vc4_state) -+ return NULL; -+ -+ __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); -+ -+ return &vc4_state->base; -+} -+ - static const struct drm_plane_funcs vc4_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = vc4_plane_destroy, - .set_property = NULL, -- .reset = drm_atomic_helper_plane_reset, -- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, -+ .reset = vc4_plane_reset, -+ .atomic_duplicate_state = vc4_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, - .format_mod_supported = vc4_fkms_format_mod_supported, - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0272-drm-v3d-HACK-gut-runtime-pm-for-now.patch b/target/linux/bcm27xx/patches-5.4/950-0272-drm-v3d-HACK-gut-runtime-pm-for-now.patch deleted file mode 100644 index ed69f2d157..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0272-drm-v3d-HACK-gut-runtime-pm-for-now.patch +++ /dev/null @@ -1,109 +0,0 @@ -From ba05797f8e3578398a1ab6c835f6b100d4f46edb Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Mon, 14 Jan 2019 15:13:17 -0800 -Subject: [PATCH] drm/v3d: HACK: gut runtime pm for now. - -Something is still unstable -- on starting a new glxgears from an idle -X11, I get an MMU violation in high addresses. The CTS also failed -quite quickly. With this, CTS progresses for an hour before OOMing -(allocating some big buffers when my board only has 600MB available to -Linux) - -Signed-off-by: Eric Anholt ---- - drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +--------------- - drivers/gpu/drm/v3d/v3d_drv.c | 9 --------- - 2 files changed, 1 insertion(+), 24 deletions(-) - ---- a/drivers/gpu/drm/v3d/v3d_debugfs.c -+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c -@@ -4,7 +4,6 @@ - #include - #include - #include --#include - #include - - #include -@@ -130,11 +129,8 @@ static int v3d_v3d_debugfs_ident(struct - struct drm_device *dev = node->minor->dev; - struct v3d_dev *v3d = to_v3d_dev(dev); - u32 ident0, ident1, ident2, ident3, cores; -- int ret, core; -+ int core; - -- ret = pm_runtime_get_sync(v3d->dev); -- if (ret < 0) -- return ret; - - ident0 = V3D_READ(V3D_HUB_IDENT0); - ident1 = V3D_READ(V3D_HUB_IDENT1); -@@ -187,9 +183,6 @@ static int v3d_v3d_debugfs_ident(struct - (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0); - } - -- pm_runtime_mark_last_busy(v3d->dev); -- pm_runtime_put_autosuspend(v3d->dev); -- - return 0; - } - -@@ -217,11 +210,6 @@ static int v3d_measure_clock(struct seq_ - uint32_t cycles; - int core = 0; - int measure_ms = 1000; -- int ret; -- -- ret = pm_runtime_get_sync(v3d->dev); -- if (ret < 0) -- return ret; - - if (v3d->ver >= 40) { - V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3, -@@ -245,8 +233,6 @@ static int v3d_measure_clock(struct seq_ - cycles / (measure_ms * 1000), - (cycles / (measure_ms * 100)) % 10); - -- pm_runtime_mark_last_busy(v3d->dev); -- pm_runtime_put_autosuspend(v3d->dev); - - return 0; - } ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -78,7 +78,6 @@ static int v3d_get_param_ioctl(struct dr - { - struct v3d_dev *v3d = to_v3d_dev(dev); - struct drm_v3d_get_param *args = data; -- int ret; - static const u32 reg_map[] = { - [DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_UIFCFG, - [DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_IDENT1, -@@ -104,17 +103,12 @@ static int v3d_get_param_ioctl(struct dr - if (args->value != 0) - return -EINVAL; - -- ret = pm_runtime_get_sync(v3d->dev); -- if (ret < 0) -- return ret; - if (args->param >= DRM_V3D_PARAM_V3D_CORE0_IDENT0 && - args->param <= DRM_V3D_PARAM_V3D_CORE0_IDENT2) { - args->value = V3D_CORE_READ(0, offset); - } else { - args->value = V3D_READ(offset); - } -- pm_runtime_mark_last_busy(v3d->dev); -- pm_runtime_put_autosuspend(v3d->dev); - return 0; - } - -@@ -302,9 +296,6 @@ static int v3d_platform_drm_probe(struct - goto dev_free; - } - -- pm_runtime_use_autosuspend(dev); -- pm_runtime_set_autosuspend_delay(dev, 50); -- pm_runtime_enable(dev); - - ret = drm_dev_init(&v3d->drm, &v3d_drm_driver, dev); - if (ret) diff --git a/target/linux/bcm27xx/patches-5.4/950-0272-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch b/target/linux/bcm27xx/patches-5.4/950-0272-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch new file mode 100644 index 0000000000..b5358cef29 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0272-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch @@ -0,0 +1,181 @@ +From 6402d9c21c9b144d528c3248607589db94ecbce0 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 3 Jul 2019 17:44:53 +0100 +Subject: [PATCH] drm/vc4: Query firmware for custom HDMI mode + +Allow custom HDMI modes to be specified from config.txt, +and these then override EDID parsing. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 130 ++++++++++++++----------- + 1 file changed, 75 insertions(+), 55 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -1066,6 +1066,56 @@ vc4_fkms_connector_detect(struct drm_con + return connector_status_connected; + } + ++/* Queries the firmware to populate a drm_mode structure for this display */ ++static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector, ++ struct drm_display_mode *mode) ++{ ++ struct vc4_dev *vc4 = fkms_connector->vc4_dev; ++ struct set_timings timings = { 0 }; ++ int ret; ++ ++ timings.display = fkms_connector->display_number; ++ ++ ret = rpi_firmware_property(vc4->firmware, ++ RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings, ++ sizeof(timings)); ++ if (ret || !timings.clock) ++ /* No mode returned - abort */ ++ return -1; ++ ++ /* Equivalent to DRM_MODE macro. */ ++ memset(mode, 0, sizeof(*mode)); ++ strncpy(mode->name, "FIXED_MODE", sizeof(mode->name)); ++ mode->status = 0; ++ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; ++ mode->clock = timings.clock; ++ mode->hdisplay = timings.hdisplay; ++ mode->hsync_start = timings.hsync_start; ++ mode->hsync_end = timings.hsync_end; ++ mode->htotal = timings.htotal; ++ mode->hskew = 0; ++ mode->vdisplay = timings.vdisplay; ++ mode->vsync_start = timings.vsync_start; ++ mode->vsync_end = timings.vsync_end; ++ mode->vtotal = timings.vtotal; ++ mode->vscan = timings.vscan; ++ ++ if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS) ++ mode->flags |= DRM_MODE_FLAG_PHSYNC; ++ else ++ mode->flags |= DRM_MODE_FLAG_NHSYNC; ++ ++ if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS) ++ mode->flags |= DRM_MODE_FLAG_PVSYNC; ++ else ++ mode->flags |= DRM_MODE_FLAG_NVSYNC; ++ ++ if (timings.flags & TIMINGS_FLAGS_INTERLACE) ++ mode->flags |= DRM_MODE_FLAG_INTERLACE; ++ ++ return 0; ++} ++ + static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block, + size_t len) + { +@@ -1094,25 +1144,35 @@ static int vc4_fkms_connector_get_modes( + to_vc4_fkms_connector(connector); + struct drm_encoder *encoder = fkms_connector->encoder; + struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); +- int ret = 0; ++ struct drm_display_mode fw_mode; ++ struct drm_display_mode *mode; + struct edid *edid; ++ int num_modes; + +- edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block, +- fkms_connector); ++ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) { ++ drm_mode_debug_printmodeline(&fw_mode); ++ mode = drm_mode_duplicate(connector->dev, ++ &fw_mode); ++ drm_mode_probed_add(connector, mode); ++ num_modes = 1; /* 1 mode */ ++ } else { ++ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block, ++ fkms_connector); + +- /* FIXME: Can we do CEC? +- * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid); +- * if (!edid) +- * return -ENODEV; +- */ +- +- vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); +- +- drm_connector_update_edid_property(connector, edid); +- ret = drm_add_edid_modes(connector, edid); +- kfree(edid); ++ /* FIXME: Can we do CEC? ++ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid); ++ * if (!edid) ++ * return -ENODEV; ++ */ ++ ++ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); ++ ++ drm_connector_update_edid_property(connector, edid); ++ num_modes = drm_add_edid_modes(connector, edid); ++ kfree(edid); ++ } + +- return ret; ++ return num_modes; + } + + /* This is the DSI panel resolution. Use this as a default should the firmware +@@ -1130,55 +1190,15 @@ static int vc4_fkms_lcd_connector_get_mo + { + struct vc4_fkms_connector *fkms_connector = + to_vc4_fkms_connector(connector); +- struct vc4_dev *vc4 = fkms_connector->vc4_dev; + struct drm_display_mode *mode; +- struct mailbox_set_mode mb = { +- .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING, +- sizeof(struct set_timings), 0}, +- .timings = { .display = fkms_connector->display_number }, +- }; + struct drm_display_mode fw_mode; +- int ret = 0; +- +- ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); +- if (!ret) { +- /* Equivalent to DRM_MODE macro. */ +- memset(&fw_mode, 0, sizeof(fw_mode)); +- strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name)); +- fw_mode.status = 0; +- fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; +- fw_mode.clock = mb.timings.clock; +- fw_mode.hdisplay = mb.timings.hdisplay; +- fw_mode.hsync_start = mb.timings.hsync_start; +- fw_mode.hsync_end = mb.timings.hsync_end; +- fw_mode.htotal = mb.timings.htotal; +- fw_mode.hskew = 0; +- fw_mode.vdisplay = mb.timings.vdisplay; +- fw_mode.vsync_start = mb.timings.vsync_start; +- fw_mode.vsync_end = mb.timings.vsync_end; +- fw_mode.vtotal = mb.timings.vtotal; +- fw_mode.vscan = mb.timings.vscan; +- if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS) +- fw_mode.flags |= DRM_MODE_FLAG_PHSYNC; +- else +- fw_mode.flags |= DRM_MODE_FLAG_NHSYNC; +- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) +- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; +- else +- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; +- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) +- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; +- else +- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; +- if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE) +- fw_mode.flags |= DRM_MODE_FLAG_INTERLACE; + ++ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock) + mode = drm_mode_duplicate(connector->dev, + &fw_mode); +- } else { ++ else + mode = drm_mode_duplicate(connector->dev, + &lcd_mode); +- } + + if (!mode) { + DRM_ERROR("Failed to create a new display mode\n"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0273-drm-v3d-Clock-V3D-down-when-not-in-use.patch b/target/linux/bcm27xx/patches-5.4/950-0273-drm-v3d-Clock-V3D-down-when-not-in-use.patch deleted file mode 100644 index 782cc197d5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0273-drm-v3d-Clock-V3D-down-when-not-in-use.patch +++ /dev/null @@ -1,161 +0,0 @@ -From ca8579839f0ebf0ffe73d1135284363b2155e712 Mon Sep 17 00:00:00 2001 -From: Eric Anholt -Date: Thu, 2 May 2019 13:22:53 -0700 -Subject: [PATCH] drm/v3d: Clock V3D down when not in use. - -My various attempts at re-enabling runtime PM have failed, so just -crank the clock down when V3D is idle to reduce power consumption. - -Signed-off-by: Eric Anholt ---- - drivers/gpu/drm/v3d/v3d_drv.c | 18 ++++++++++++ - drivers/gpu/drm/v3d/v3d_drv.h | 6 ++++ - drivers/gpu/drm/v3d/v3d_gem.c | 53 +++++++++++++++++++++++++++++++---- - 3 files changed, 72 insertions(+), 5 deletions(-) - ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -282,6 +282,21 @@ static int v3d_platform_drm_probe(struct - } - } - -+ v3d->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(v3d->clk)) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(dev, "Failed to get clock\n"); -+ goto dev_free; -+ } -+ v3d->clk_up_rate = clk_get_rate(v3d->clk); -+ /* For downclocking, drop it to the minimum frequency we can get from -+ * the CPRMAN clock generator dividing off our parent. The divider is -+ * 4 bits, but ask for just higher than that so that rounding doesn't -+ * make cprman reject our rate. -+ */ -+ v3d->clk_down_rate = -+ (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000; -+ - if (v3d->ver < 41) { - ret = map_regs(v3d, &v3d->gca_regs, "gca"); - if (ret) -@@ -316,6 +331,9 @@ static int v3d_platform_drm_probe(struct - if (ret) - goto irq_disable; - -+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate); -+ WARN_ON_ONCE(ret != 0); -+ - return 0; - - irq_disable: ---- a/drivers/gpu/drm/v3d/v3d_drv.h -+++ b/drivers/gpu/drm/v3d/v3d_drv.h -@@ -54,6 +54,12 @@ struct v3d_dev { - void __iomem *bridge_regs; - void __iomem *gca_regs; - struct clk *clk; -+ struct delayed_work clk_down_work; -+ unsigned long clk_up_rate, clk_down_rate; -+ struct mutex clk_lock; -+ u32 clk_refcount; -+ bool clk_up; -+ - struct reset_control *reset; - - /* Virtual and DMA addresses of the single shared page table. */ ---- a/drivers/gpu/drm/v3d/v3d_gem.c -+++ b/drivers/gpu/drm/v3d/v3d_gem.c -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -19,6 +20,47 @@ - #include "v3d_trace.h" - - static void -+v3d_clock_down_work(struct work_struct *work) -+{ -+ struct v3d_dev *v3d = -+ container_of(work, struct v3d_dev, clk_down_work.work); -+ int ret; -+ -+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate); -+ v3d->clk_up = false; -+ WARN_ON_ONCE(ret != 0); -+} -+ -+static void -+v3d_clock_up_get(struct v3d_dev *v3d) -+{ -+ mutex_lock(&v3d->clk_lock); -+ if (v3d->clk_refcount++ == 0) { -+ cancel_delayed_work_sync(&v3d->clk_down_work); -+ if (!v3d->clk_up) { -+ int ret; -+ -+ ret = clk_set_rate(v3d->clk, v3d->clk_up_rate); -+ WARN_ON_ONCE(ret != 0); -+ v3d->clk_up = true; -+ } -+ } -+ mutex_unlock(&v3d->clk_lock); -+} -+ -+static void -+v3d_clock_up_put(struct v3d_dev *v3d) -+{ -+ mutex_lock(&v3d->clk_lock); -+ if (--v3d->clk_refcount == 0) { -+ schedule_delayed_work(&v3d->clk_down_work, -+ msecs_to_jiffies(100)); -+ } -+ mutex_unlock(&v3d->clk_lock); -+} -+ -+ -+static void - v3d_init_core(struct v3d_dev *v3d, int core) - { - /* Set OVRTMUOUT, which means that the texture sampler uniform -@@ -354,6 +396,7 @@ v3d_job_free(struct kref *ref) - struct v3d_job *job = container_of(ref, struct v3d_job, refcount); - unsigned long index; - struct dma_fence *fence; -+ struct v3d_dev *v3d = job->v3d; - int i; - - for (i = 0; i < job->bo_count; i++) { -@@ -367,11 +410,7 @@ v3d_job_free(struct kref *ref) - } - xa_destroy(&job->deps); - -- dma_fence_put(job->irq_fence); -- dma_fence_put(job->done_fence); -- -- pm_runtime_mark_last_busy(job->v3d->dev); -- pm_runtime_put_autosuspend(job->v3d->dev); -+ v3d_clock_up_put(v3d); - - kfree(job); - } -@@ -453,6 +492,7 @@ v3d_job_init(struct v3d_dev *v3d, struct - if (ret) - goto fail; - -+ v3d_clock_up_get(v3d); - kref_init(&job->refcount); - - return 0; -@@ -841,6 +881,9 @@ v3d_gem_init(struct drm_device *dev) - mutex_init(&v3d->sched_lock); - mutex_init(&v3d->cache_clean_lock); - -+ mutex_init(&v3d->clk_lock); -+ INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work); -+ - /* Note: We don't allocate address 0. Various bits of HW - * treat 0 as special, such as the occlusion query counters - * where 0 means "disabled". diff --git a/target/linux/bcm27xx/patches-5.4/950-0273-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch b/target/linux/bcm27xx/patches-5.4/950-0273-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch new file mode 100644 index 0000000000..ce73e34541 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0273-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch @@ -0,0 +1,37 @@ +From f146d9a60f197fbf868be7eece68ff5cc58af4ff Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 11 Jul 2019 15:12:05 +0100 +Subject: [PATCH] drm/vc4: Pass the drm vrefresh to the firmware on + mode set + +More for completeness than need, but use drm_mode_vrefresh +to compute the vrefresh value, and pass that down to the +firmware on mode set. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -768,8 +768,8 @@ static void vc4_crtc_mode_set_nofb(struc + mode->hdisplay, mode->hsync_start, mode->hsync_end, + mode->htotal, mode->hskew, mode->vdisplay, + mode->vsync_start, mode->vsync_end, mode->vtotal, +- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio, +- mode->flags); ++ mode->vscan, drm_mode_vrefresh(mode), ++ mode->picture_aspect_ratio, mode->flags); + mb.timings.display = vc4_crtc->display_number; + + mb.timings.video_id_code = frame.avi.video_code; +@@ -785,7 +785,7 @@ static void vc4_crtc_mode_set_nofb(struc + mb.timings.vsync_end = mode->vsync_end; + mb.timings.vtotal = mode->vtotal; + mb.timings.vscan = mode->vscan; +- mb.timings.vrefresh = 0; ++ mb.timings.vrefresh = drm_mode_vrefresh(mode); + mb.timings.flags = 0; + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS; diff --git a/target/linux/bcm27xx/patches-5.4/950-0274-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch b/target/linux/bcm27xx/patches-5.4/950-0274-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch deleted file mode 100644 index 267725d3ef..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0274-According-to-5713-pdf-doc-CLOCK_CTRL-is-a-readonly-s.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 638f29943041f9205486a03587b7bd9e64799b2a Mon Sep 17 00:00:00 2001 -From: Hermann Lauer -Date: Thu, 8 Aug 2019 15:40:37 +0200 -Subject: [PATCH] According to 5713 pdf doc CLOCK_CTRL is a readonly - status register, and it behaves so. Remove useless setting - ---- - sound/soc/codecs/tas5713.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - ---- a/sound/soc/codecs/tas5713.c -+++ b/sound/soc/codecs/tas5713.c -@@ -190,10 +190,6 @@ static int tas5713_probe(struct snd_soc_ - ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00); - if (ret < 0) return ret; - -- // Clock mode: 44/48kHz, MCLK=64xfs -- ret = snd_soc_component_write(component, TAS5713_CLOCK_CTRL, 0x60); -- if (ret < 0) return ret; -- - // I2S 24bit - ret = snd_soc_component_write(component, TAS5713_SERIAL_DATA_INTERFACE, 0x05); - if (ret < 0) return ret; -@@ -257,6 +253,7 @@ static bool tas5713_reg_volatile(struct - switch (reg) { - case TAS5713_DEVICE_ID: - case TAS5713_ERROR_STATUS: -+ case TAS5713_CLOCK_CTRL: - return true; - default: - return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0274-drm-vc4-Add-support-for-margins-to-fkms.patch b/target/linux/bcm27xx/patches-5.4/950-0274-drm-vc4-Add-support-for-margins-to-fkms.patch new file mode 100644 index 0000000000..968eb3ff55 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0274-drm-vc4-Add-support-for-margins-to-fkms.patch @@ -0,0 +1,328 @@ +From 8a7170d2ad05ae00733e0535b281ce2e682c6f65 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 19 Jul 2019 15:35:13 +0100 +Subject: [PATCH] drm/vc4: Add support for margins to fkms + +Allows for overscan to be configured under FKMS. +NB This is rescaling the planes, not reducing the size of the +display mode. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 241 +++++++++++++++++++------ + 1 file changed, 190 insertions(+), 51 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -259,6 +259,23 @@ static inline struct vc4_crtc *to_vc4_cr + return container_of(crtc, struct vc4_crtc, base); + } + ++struct vc4_crtc_state { ++ struct drm_crtc_state base; ++ ++ struct { ++ unsigned int left; ++ unsigned int right; ++ unsigned int top; ++ unsigned int bottom; ++ } margins; ++}; ++ ++static inline struct vc4_crtc_state * ++to_vc4_crtc_state(struct drm_crtc_state *crtc_state) ++{ ++ return (struct vc4_crtc_state *)crtc_state; ++} ++ + struct vc4_fkms_encoder { + struct drm_encoder base; + bool hdmi_monitor; +@@ -367,17 +384,127 @@ static int vc4_plane_set_blank(struct dr + return ret; + } + ++static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state, ++ unsigned int *left, unsigned int *right, ++ unsigned int *top, unsigned int *bottom) ++{ ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); ++ struct drm_connector_state *conn_state; ++ struct drm_connector *conn; ++ int i; ++ ++ *left = vc4_state->margins.left; ++ *right = vc4_state->margins.right; ++ *top = vc4_state->margins.top; ++ *bottom = vc4_state->margins.bottom; ++ ++ /* We have to interate over all new connector states because ++ * vc4_fkms_crtc_get_margins() might be called before ++ * vc4_fkms_crtc_atomic_check() which means margins info in ++ * vc4_crtc_state might be outdated. ++ */ ++ for_each_new_connector_in_state(state->state, conn, conn_state, i) { ++ if (conn_state->crtc != state->crtc) ++ continue; ++ ++ *left = conn_state->tv.margins.left; ++ *right = conn_state->tv.margins.right; ++ *top = conn_state->tv.margins.top; ++ *bottom = conn_state->tv.margins.bottom; ++ break; ++ } ++} ++ ++static int vc4_fkms_margins_adj(struct drm_plane_state *pstate, ++ struct set_plane *plane) ++{ ++ unsigned int left, right, top, bottom; ++ int adjhdisplay, adjvdisplay; ++ struct drm_crtc_state *crtc_state; ++ ++ crtc_state = drm_atomic_get_new_crtc_state(pstate->state, ++ pstate->crtc); ++ ++ vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom); ++ ++ if (!left && !right && !top && !bottom) ++ return 0; ++ ++ if (left + right >= crtc_state->mode.hdisplay || ++ top + bottom >= crtc_state->mode.vdisplay) ++ return -EINVAL; ++ ++ adjhdisplay = crtc_state->mode.hdisplay - (left + right); ++ plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay, ++ (int)crtc_state->mode.hdisplay); ++ plane->dst_x += left; ++ if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left)) ++ plane->dst_x = crtc_state->mode.hdisplay - left; ++ ++ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom); ++ plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay, ++ (int)crtc_state->mode.vdisplay); ++ plane->dst_y += top; ++ if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top)) ++ plane->dst_y = crtc_state->mode.vdisplay - top; ++ ++ plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay, ++ crtc_state->mode.hdisplay); ++ plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay, ++ crtc_state->mode.vdisplay); ++ ++ if (!plane->dst_w || !plane->dst_h) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static void vc4_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) + { + struct drm_plane_state *state = plane->state; ++ ++ /* ++ * Do NOT set now, as we haven't checked if the crtc is active or not. ++ * Set from vc4_plane_set_blank instead. ++ * ++ * If the CRTC is on (or going to be on) and we're enabled, ++ * then unblank. Otherwise, stay blank until CRTC enable. ++ */ ++ if (state->crtc->state->active) ++ vc4_plane_set_blank(plane, false); ++} ++ ++static void vc4_plane_atomic_disable(struct drm_plane *plane, ++ struct drm_plane_state *old_state) ++{ ++ struct drm_plane_state *state = plane->state; ++ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); ++ ++ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n", ++ plane->base.id, plane->name, ++ state->crtc_w, ++ state->crtc_h, ++ vc4_plane->mb.plane.vc_image_type, ++ state->crtc_x, ++ state->crtc_y); ++ vc4_plane_set_blank(plane, true); ++} ++ ++static bool plane_enabled(struct drm_plane_state *state) ++{ ++ return state->fb && state->crtc; ++} ++ ++static int vc4_plane_to_mb(struct drm_plane *plane, ++ struct mailbox_set_plane *mb, ++ struct drm_plane_state *state) ++{ + struct drm_framebuffer *fb = state->fb; + struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); + const struct drm_format_info *drm_fmt = fb->format; + const struct vc_image_format *vc_fmt = + vc4_get_vc_image_fmt(drm_fmt->format); +- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); +- struct mailbox_set_plane *mb = &vc4_plane->mb; + int num_planes = fb->format->num_planes; + struct drm_display_mode *mode = &state->crtc->mode; + unsigned int rotation = SUPPORTED_ROTATIONS; +@@ -419,25 +546,7 @@ static void vc4_plane_atomic_update(stru + break; + } + +- /* FIXME: If the dest rect goes off screen then clip the src rect so we +- * don't have off-screen pixels. +- */ +- if (plane->type == DRM_PLANE_TYPE_CURSOR) { +- /* There is no scaling on the cursor plane, therefore the calcs +- * to alter the source crop as the cursor goes off the screen +- * are simple. +- */ +- if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) { +- mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x; +- mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x) +- << 16; +- } +- if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) { +- mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y; +- mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y) +- << 16; +- } +- } ++ vc4_fkms_margins_adj(state, &mb->plane); + + if (num_planes > 1) { + /* Assume this must be YUV */ +@@ -527,38 +636,19 @@ static void vc4_plane_atomic_update(stru + state->alpha, + state->normalized_zpos); + +- /* +- * Do NOT set now, as we haven't checked if the crtc is active or not. +- * Set from vc4_plane_set_blank instead. +- * +- * If the CRTC is on (or going to be on) and we're enabled, +- * then unblank. Otherwise, stay blank until CRTC enable. +- */ +- if (state->crtc->state->active) +- vc4_plane_set_blank(plane, false); ++ return 0; + } + +-static void vc4_plane_atomic_disable(struct drm_plane *plane, +- struct drm_plane_state *old_state) ++static int vc4_plane_atomic_check(struct drm_plane *plane, ++ struct drm_plane_state *state) + { +- //struct vc4_dev *vc4 = to_vc4_dev(plane->dev); +- struct drm_plane_state *state = plane->state; + struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); + +- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n", +- plane->base.id, plane->name, +- state->crtc_w, +- state->crtc_h, +- vc4_plane->mb.plane.vc_image_type, +- state->crtc_x, +- state->crtc_y); +- vc4_plane_set_blank(plane, true); +-} ++ if (!plane_enabled(state)) ++ return 0; ++ ++ return vc4_plane_to_mb(plane, &vc4_plane->mb, state); + +-static int vc4_plane_atomic_check(struct drm_plane *plane, +- struct drm_plane_state *state) +-{ +- return 0; + } + + /* Called during init to allocate the plane's atomic state. */ +@@ -909,8 +999,23 @@ vc4_crtc_mode_valid(struct drm_crtc *crt + static int vc4_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) + { +- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", +- crtc->base.id); ++ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); ++ struct drm_connector *conn; ++ struct drm_connector_state *conn_state; ++ int i; ++ ++ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id); ++ ++ for_each_new_connector_in_state(state->state, conn, conn_state, i) { ++ if (conn_state->crtc != crtc) ++ continue; ++ ++ vc4_state->margins.left = conn_state->tv.margins.left; ++ vc4_state->margins.right = conn_state->tv.margins.right; ++ vc4_state->margins.top = conn_state->tv.margins.top; ++ vc4_state->margins.bottom = conn_state->tv.margins.bottom; ++ break; ++ } + return 0; + } + +@@ -1011,6 +1116,33 @@ static int vc4_page_flip(struct drm_crtc + return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx); + } + ++static struct drm_crtc_state * ++vc4_crtc_duplicate_state(struct drm_crtc *crtc) ++{ ++ struct vc4_crtc_state *vc4_state, *old_vc4_state; ++ ++ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); ++ if (!vc4_state) ++ return NULL; ++ ++ old_vc4_state = to_vc4_crtc_state(crtc->state); ++ vc4_state->margins = old_vc4_state->margins; ++ ++ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base); ++ return &vc4_state->base; ++} ++ ++static void ++vc4_crtc_reset(struct drm_crtc *crtc) ++{ ++ if (crtc->state) ++ __drm_atomic_helper_crtc_destroy_state(crtc->state); ++ ++ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); ++ if (crtc->state) ++ crtc->state->crtc = crtc; ++} ++ + static int vc4_fkms_enable_vblank(struct drm_crtc *crtc) + { + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +@@ -1038,8 +1170,8 @@ static const struct drm_crtc_funcs vc4_c + .set_property = NULL, + .cursor_set = NULL, /* handled by drm_mode_cursor_universal */ + .cursor_move = NULL, /* handled by drm_mode_cursor_universal */ +- .reset = drm_atomic_helper_crtc_reset, +- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, ++ .reset = vc4_crtc_reset, ++ .atomic_duplicate_state = vc4_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = vc4_fkms_enable_vblank, + .disable_vblank = vc4_fkms_disable_vblank, +@@ -1291,6 +1423,13 @@ vc4_fkms_connector_init(struct drm_devic + connector->interlace_allowed = 0; + } + ++ /* Create and attach TV margin props to this connector. */ ++ ret = drm_mode_create_tv_margin_properties(dev); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ drm_connector_attach_tv_margin_properties(connector); ++ + connector->polled = (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0275-drm-vc4-Ensure-zpos-is-always-initialised.patch b/target/linux/bcm27xx/patches-5.4/950-0275-drm-vc4-Ensure-zpos-is-always-initialised.patch new file mode 100644 index 0000000000..32a13d9c86 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0275-drm-vc4-Ensure-zpos-is-always-initialised.patch @@ -0,0 +1,26 @@ +From 9ab46d940789f74980d18715f5715992559ea857 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 19 Jul 2019 17:49:00 +0100 +Subject: [PATCH] drm/vc4: Ensure zpos is always initialised + +The compiler is warning that default_zpos can be used +uninitialised as there is no default case to catch all plane +types. +No other plane types should ever be presented to vc4_fkms_plane_init, +but add a default case regardless. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -804,6 +804,7 @@ static struct drm_plane *vc4_fkms_plane_ + * other layers as requested by KMS. + */ + switch (type) { ++ default: + case DRM_PLANE_TYPE_PRIMARY: + default_zpos = 0; + break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0275-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch b/target/linux/bcm27xx/patches-5.4/950-0275-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch deleted file mode 100644 index b5358cef29..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0275-drm-vc4-Query-firmware-for-custom-HDMI-mode.patch +++ /dev/null @@ -1,181 +0,0 @@ -From 6402d9c21c9b144d528c3248607589db94ecbce0 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 3 Jul 2019 17:44:53 +0100 -Subject: [PATCH] drm/vc4: Query firmware for custom HDMI mode - -Allow custom HDMI modes to be specified from config.txt, -and these then override EDID parsing. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 130 ++++++++++++++----------- - 1 file changed, 75 insertions(+), 55 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -1066,6 +1066,56 @@ vc4_fkms_connector_detect(struct drm_con - return connector_status_connected; - } - -+/* Queries the firmware to populate a drm_mode structure for this display */ -+static int vc4_fkms_get_fw_mode(struct vc4_fkms_connector *fkms_connector, -+ struct drm_display_mode *mode) -+{ -+ struct vc4_dev *vc4 = fkms_connector->vc4_dev; -+ struct set_timings timings = { 0 }; -+ int ret; -+ -+ timings.display = fkms_connector->display_number; -+ -+ ret = rpi_firmware_property(vc4->firmware, -+ RPI_FIRMWARE_GET_DISPLAY_TIMING, &timings, -+ sizeof(timings)); -+ if (ret || !timings.clock) -+ /* No mode returned - abort */ -+ return -1; -+ -+ /* Equivalent to DRM_MODE macro. */ -+ memset(mode, 0, sizeof(*mode)); -+ strncpy(mode->name, "FIXED_MODE", sizeof(mode->name)); -+ mode->status = 0; -+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -+ mode->clock = timings.clock; -+ mode->hdisplay = timings.hdisplay; -+ mode->hsync_start = timings.hsync_start; -+ mode->hsync_end = timings.hsync_end; -+ mode->htotal = timings.htotal; -+ mode->hskew = 0; -+ mode->vdisplay = timings.vdisplay; -+ mode->vsync_start = timings.vsync_start; -+ mode->vsync_end = timings.vsync_end; -+ mode->vtotal = timings.vtotal; -+ mode->vscan = timings.vscan; -+ -+ if (timings.flags & TIMINGS_FLAGS_H_SYNC_POS) -+ mode->flags |= DRM_MODE_FLAG_PHSYNC; -+ else -+ mode->flags |= DRM_MODE_FLAG_NHSYNC; -+ -+ if (timings.flags & TIMINGS_FLAGS_V_SYNC_POS) -+ mode->flags |= DRM_MODE_FLAG_PVSYNC; -+ else -+ mode->flags |= DRM_MODE_FLAG_NVSYNC; -+ -+ if (timings.flags & TIMINGS_FLAGS_INTERLACE) -+ mode->flags |= DRM_MODE_FLAG_INTERLACE; -+ -+ return 0; -+} -+ - static int vc4_fkms_get_edid_block(void *data, u8 *buf, unsigned int block, - size_t len) - { -@@ -1094,25 +1144,35 @@ static int vc4_fkms_connector_get_modes( - to_vc4_fkms_connector(connector); - struct drm_encoder *encoder = fkms_connector->encoder; - struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); -- int ret = 0; -+ struct drm_display_mode fw_mode; -+ struct drm_display_mode *mode; - struct edid *edid; -+ int num_modes; - -- edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block, -- fkms_connector); -+ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode)) { -+ drm_mode_debug_printmodeline(&fw_mode); -+ mode = drm_mode_duplicate(connector->dev, -+ &fw_mode); -+ drm_mode_probed_add(connector, mode); -+ num_modes = 1; /* 1 mode */ -+ } else { -+ edid = drm_do_get_edid(connector, vc4_fkms_get_edid_block, -+ fkms_connector); - -- /* FIXME: Can we do CEC? -- * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid); -- * if (!edid) -- * return -ENODEV; -- */ -- -- vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); -- -- drm_connector_update_edid_property(connector, edid); -- ret = drm_add_edid_modes(connector, edid); -- kfree(edid); -+ /* FIXME: Can we do CEC? -+ * cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid); -+ * if (!edid) -+ * return -ENODEV; -+ */ -+ -+ vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); -+ -+ drm_connector_update_edid_property(connector, edid); -+ num_modes = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ } - -- return ret; -+ return num_modes; - } - - /* This is the DSI panel resolution. Use this as a default should the firmware -@@ -1130,55 +1190,15 @@ static int vc4_fkms_lcd_connector_get_mo - { - struct vc4_fkms_connector *fkms_connector = - to_vc4_fkms_connector(connector); -- struct vc4_dev *vc4 = fkms_connector->vc4_dev; - struct drm_display_mode *mode; -- struct mailbox_set_mode mb = { -- .tag1 = { RPI_FIRMWARE_GET_DISPLAY_TIMING, -- sizeof(struct set_timings), 0}, -- .timings = { .display = fkms_connector->display_number }, -- }; - struct drm_display_mode fw_mode; -- int ret = 0; -- -- ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb)); -- if (!ret) { -- /* Equivalent to DRM_MODE macro. */ -- memset(&fw_mode, 0, sizeof(fw_mode)); -- strncpy(fw_mode.name, "LCD_MODE", sizeof(fw_mode.name)); -- fw_mode.status = 0; -- fw_mode.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; -- fw_mode.clock = mb.timings.clock; -- fw_mode.hdisplay = mb.timings.hdisplay; -- fw_mode.hsync_start = mb.timings.hsync_start; -- fw_mode.hsync_end = mb.timings.hsync_end; -- fw_mode.htotal = mb.timings.htotal; -- fw_mode.hskew = 0; -- fw_mode.vdisplay = mb.timings.vdisplay; -- fw_mode.vsync_start = mb.timings.vsync_start; -- fw_mode.vsync_end = mb.timings.vsync_end; -- fw_mode.vtotal = mb.timings.vtotal; -- fw_mode.vscan = mb.timings.vscan; -- if (mb.timings.flags & TIMINGS_FLAGS_H_SYNC_POS) -- fw_mode.flags |= DRM_MODE_FLAG_PHSYNC; -- else -- fw_mode.flags |= DRM_MODE_FLAG_NHSYNC; -- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) -- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; -- else -- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; -- if (mb.timings.flags & TIMINGS_FLAGS_V_SYNC_POS) -- fw_mode.flags |= DRM_MODE_FLAG_PVSYNC; -- else -- fw_mode.flags |= DRM_MODE_FLAG_NVSYNC; -- if (mb.timings.flags & TIMINGS_FLAGS_INTERLACE) -- fw_mode.flags |= DRM_MODE_FLAG_INTERLACE; - -+ if (!vc4_fkms_get_fw_mode(fkms_connector, &fw_mode) && fw_mode.clock) - mode = drm_mode_duplicate(connector->dev, - &fw_mode); -- } else { -+ else - mode = drm_mode_duplicate(connector->dev, - &lcd_mode); -- } - - if (!mode) { - DRM_ERROR("Failed to create a new display mode\n"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0276-adds-the-Hifiberry-DAC-ADC-PRO-version.patch b/target/linux/bcm27xx/patches-5.4/950-0276-adds-the-Hifiberry-DAC-ADC-PRO-version.patch new file mode 100644 index 0000000000..ed6d6db813 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0276-adds-the-Hifiberry-DAC-ADC-PRO-version.patch @@ -0,0 +1,598 @@ +From 41c059c841d40bebc358e1c9e7f30c62b2fe3b37 Mon Sep 17 00:00:00 2001 +From: Joerg Schambacher +Date: Tue, 23 Jul 2019 16:57:35 +0200 +Subject: [PATCH] adds the Hifiberry DAC+ADC PRO version + +This adds the driver for the DAC+ADC PRO version of the Hifiberry soundcard with software controlled PCM1863 ADC +Signed-off-by: Joerg Schambacher joerg@i2audio.com +--- + sound/soc/bcm/Kconfig | 9 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/hifiberry_dacplusadcpro.c | 538 ++++++++++++++++++++++++ + 3 files changed, 549 insertions(+) + create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -38,6 +38,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + tristate "Support for HifiBerry DAC+" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x ++ select COMMON_CLK_HIFIBERRY_DACPRO + help + Say Y or M if you want to add support for HifiBerry DAC+. + +@@ -50,6 +51,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + help + Say Y or M if you want to add support for HifiBerry DAC+ADC. + ++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO ++ tristate "Support for HifiBerry DAC+ADC PRO" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_PCM512x_I2C ++ select SND_SOC_PCM186X_I2C ++ help ++ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO. ++ + config SND_BCM2708_SOC_HIFIBERRY_DIGI + tristate "Support for HifiBerry Digi" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -15,6 +15,7 @@ snd-soc-googlevoicehat-codec-objs := goo + # BCM2708 Machine Support + snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o + snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o ++snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o + snd-soc-justboom-dac-objs := justboom-dac.o + snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-proto-objs := rpi-proto.o +@@ -39,6 +40,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi + obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c +@@ -0,0 +1,538 @@ ++/* ++ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control) ++ * ++ * Author: Daniel Matuschek, Stuart MacLean ++ * Copyright 2014-2015 ++ * based on code by Florian Meier ++ * ADC added by Joerg Schambacher ++ * Copyright 2018-19 ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/pcm512x.h" ++#include "../codecs/pcm186x.h" ++ ++#define HIFIBERRY_DACPRO_NOCLOCK 0 ++#define HIFIBERRY_DACPRO_CLK44EN 1 ++#define HIFIBERRY_DACPRO_CLK48EN 2 ++ ++struct pcm512x_priv { ++ struct regmap *regmap; ++ struct clk *sclk; ++}; ++ ++/* Clock rate of CLK44EN attached to GPIO6 pin */ ++#define CLK_44EN_RATE 22579200UL ++/* Clock rate of CLK48EN attached to GPIO3 pin */ ++#define CLK_48EN_RATE 24576000UL ++ ++static bool slave; ++static bool snd_rpi_hifiberry_is_dacpro; ++static bool digital_gain_0db_limit = true; ++ ++static const unsigned int pcm186x_adc_input_channel_sel_value[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x10 ++}; ++ ++static const char * const pcm186x_adcl_input_channel_sel_text[] = { ++ "No Select", ++ "VINL1[SE]", /* Default for ADCL */ ++ "VINL2[SE]", ++ "VINL2[SE] + VINL1[SE]", ++ "{VIN1P, VIN1M}[DIFF]" ++}; ++ ++static const char * const pcm186x_adcr_input_channel_sel_text[] = { ++ "No Select", ++ "VINR1[SE]", /* Default for ADCR */ ++ "VINR2[SE]", ++ "VINR2[SE] + VINR1[SE]", ++ "{VIN2P, VIN2M}[DIFF]" ++}; ++ ++static const struct soc_enum pcm186x_adc_input_channel_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0, ++ PCM186X_ADC_INPUT_SEL_MASK, ++ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), ++ pcm186x_adcl_input_channel_sel_text, ++ pcm186x_adc_input_channel_sel_value), ++ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0, ++ PCM186X_ADC_INPUT_SEL_MASK, ++ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), ++ pcm186x_adcr_input_channel_sel_text, ++ pcm186x_adc_input_channel_sel_value), ++}; ++ ++static const unsigned int pcm186x_mic_bias_sel_value[] = { ++ 0x00, 0x01, 0x11 ++}; ++ ++static const char * const pcm186x_mic_bias_sel_text[] = { ++ "Mic Bias off", ++ "Mic Bias on", ++ "Mic Bias with Bypass Resistor" ++}; ++ ++static const struct soc_enum pcm186x_mic_bias_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0, ++ GENMASK(4, 0), ++ ARRAY_SIZE(pcm186x_mic_bias_sel_text), ++ pcm186x_mic_bias_sel_text, ++ pcm186x_mic_bias_sel_value), ++}; ++ ++static const unsigned int pcm186x_gain_sel_value[] = { ++ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, ++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, ++ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ++ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, ++ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, ++ 0x50 ++}; ++ ++static const char * const pcm186x_gain_sel_text[] = { ++ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB", ++ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB", ++ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB", ++ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB", ++ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB", ++ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB", ++ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB", ++ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB", ++ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB", ++ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB", ++ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB", ++ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB", ++ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB", ++ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB", ++ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB", ++ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB", ++ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB", ++ "39.0dB", "39.5dB", "40.0dB"}; ++ ++static const struct soc_enum pcm186x_gain_sel[] = { ++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0, ++ 0xff, ++ ARRAY_SIZE(pcm186x_gain_sel_text), ++ pcm186x_gain_sel_text, ++ pcm186x_gain_sel_value), ++ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0, ++ 0xff, ++ ARRAY_SIZE(pcm186x_gain_sel_text), ++ pcm186x_gain_sel_text, ++ pcm186x_gain_sel_value), ++}; ++ ++static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = { ++ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]), ++ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]), ++ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel), ++ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]), ++ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]), ++}; ++ ++static int pcm1863_add_controls(struct snd_soc_component *component) ++{ ++ snd_soc_add_component_controls(component, ++ pcm1863_snd_controls_card, ++ ARRAY_SIZE(pcm1863_snd_controls_card)); ++ return 0; ++} ++ ++static void snd_rpi_hifiberry_dacplusadcpro_select_clk( ++ struct snd_soc_component *component, int clk_id) ++{ ++ switch (clk_id) { ++ case HIFIBERRY_DACPRO_NOCLOCK: ++ snd_soc_component_update_bits(component, ++ PCM512x_GPIO_CONTROL_1, 0x24, 0x00); ++ break; ++ case HIFIBERRY_DACPRO_CLK44EN: ++ snd_soc_component_update_bits(component, ++ PCM512x_GPIO_CONTROL_1, 0x24, 0x20); ++ break; ++ case HIFIBERRY_DACPRO_CLK48EN: ++ snd_soc_component_update_bits(component, ++ PCM512x_GPIO_CONTROL_1, 0x24, 0x04); ++ break; ++ } ++} ++ ++static void snd_rpi_hifiberry_dacplusadcpro_clk_gpio(struct snd_soc_component *component) ++{ ++ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24); ++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02); ++ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02); ++} ++ ++static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk(struct snd_soc_component *component) ++{ ++ unsigned int sck; ++ ++ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck); ++ return (!(sck & 0x40)); ++} ++ ++static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep( ++ struct snd_soc_component *component) ++{ ++ msleep(2); ++ return snd_rpi_hifiberry_dacplusadcpro_is_sclk(component); ++} ++ ++static bool snd_rpi_hifiberry_dacplusadcpro_is_pro_card(struct snd_soc_component *component) ++{ ++ bool isClk44EN, isClk48En, isNoClk; ++ ++ snd_rpi_hifiberry_dacplusadcpro_clk_gpio(component); ++ ++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK44EN); ++ isClk44EN = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component); ++ ++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK); ++ isNoClk = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component); ++ ++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK48EN); ++ isClk48En = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component); ++ ++ return (isClk44EN && isClk48En && !isNoClk); ++} ++ ++static int snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(int sample_rate) ++{ ++ int type; ++ ++ switch (sample_rate) { ++ case 11025: ++ case 22050: ++ case 44100: ++ case 88200: ++ case 176400: ++ case 352800: ++ type = HIFIBERRY_DACPRO_CLK44EN; ++ break; ++ default: ++ type = HIFIBERRY_DACPRO_CLK48EN; ++ break; ++ } ++ return type; ++} ++ ++static void snd_rpi_hifiberry_dacplusadcpro_set_sclk(struct snd_soc_component *component, ++ int sample_rate) ++{ ++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); ++ ++ if (!IS_ERR(pcm512x->sclk)) { ++ int ctype; ++ ++ ctype = snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(sample_rate); ++ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN) ++ ? CLK_44EN_RATE : CLK_48EN_RATE); ++ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, ctype); ++ } ++} ++ ++static int snd_rpi_hifiberry_dacplusadcpro_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_component *dac = rtd->codec_dais[0]->component; ++ struct snd_soc_component *adc = rtd->codec_dais[1]->component; ++ struct snd_soc_dai_driver *adc_driver = rtd->codec_dais[1]->driver; ++ struct pcm512x_priv *priv; ++ int ret; ++ ++ if (slave) ++ snd_rpi_hifiberry_is_dacpro = false; ++ else ++ snd_rpi_hifiberry_is_dacpro = ++ snd_rpi_hifiberry_dacplusadcpro_is_pro_card(dac); ++ ++ if (snd_rpi_hifiberry_is_dacpro) { ++ struct snd_soc_dai_link *dai = rtd->dai_link; ++ ++ dai->name = "HiFiBerry DAC+ADC Pro"; ++ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi"; ++ ++ // set DAC DAI configuration ++ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0], ++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM); ++ if (ret < 0) ++ return ret; ++ ++ // set ADC DAI configuration ++ ret = snd_soc_dai_set_fmt(rtd->codec_dais[1], ++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBS_CFS); ++ if (ret < 0) ++ return ret; ++ ++ // set CPU DAI configuration ++ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, ++ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); ++ if (ret < 0) ++ return ret; ++ ++ snd_soc_component_update_bits(dac, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11); ++ snd_soc_component_update_bits(dac, PCM512x_MASTER_MODE, 0x03, 0x03); ++ snd_soc_component_update_bits(dac, PCM512x_MASTER_CLKDIV_2, 0x7f, 63); ++ } else { ++ priv = snd_soc_component_get_drvdata(dac); ++ priv->sclk = ERR_PTR(-ENOENT); ++ } ++ ++ /* disable 24bit mode as long as I2S module does not have sign extension fixed */ ++ adc_driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE; ++ ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08); ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ ++ ret = pcm1863_add_controls(adc); ++ if (ret < 0) ++ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n", ++ ret); ++ ++ /* set GPIO2 to output, GPIO3 input */ ++ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00); ++ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04); ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); ++ ++ if (digital_gain_0db_limit) { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ ++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_dacplusadcpro_update_rate_den( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *component = rtd->codec_dais[0]->component; /* only use DAC */ ++ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); ++ struct snd_ratnum *rats_no_pll; ++ unsigned int num = 0, den = 0; ++ int err; ++ ++ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL); ++ if (!rats_no_pll) ++ return -ENOMEM; ++ ++ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64; ++ rats_no_pll->den_min = 1; ++ rats_no_pll->den_max = 128; ++ rats_no_pll->den_step = 1; ++ ++ err = snd_interval_ratnum(hw_param_interval(params, ++ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den); ++ if (err >= 0 && den) { ++ params->rate_num = num; ++ params->rate_den = den; ++ } ++ ++ devm_kfree(rtd->dev, rats_no_pll); ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_dacplusadcpro_hw_params( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ int ret = 0; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ int channels = params_channels(params); ++ int width = 32; ++ struct snd_soc_component *dac = rtd->codec_dais[0]->component; ++ ++ if (snd_rpi_hifiberry_is_dacpro) { ++ ++ width = snd_pcm_format_physical_width(params_format(params)); ++ ++ snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac, ++ params_rate(params)); ++ ++ ret = snd_rpi_hifiberry_dacplusadcpro_update_rate_den( ++ substream, params); ++ if (ret) ++ return ret; ++ } ++ ++ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03, ++ channels, width); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x03, 0x03, ++ channels, width); ++ if (ret) ++ return ret; ++ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x03, 0x03, ++ channels, width); ++ return ret; ++} ++ ++static int snd_rpi_hifiberry_dacplusadcpro_startup( ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *dac = rtd->codec_dais[0]->component; ++ struct snd_soc_component *adc = rtd->codec_dais[1]->component; ++ ++ /* switch on respective LED */ ++ if (!substream->stream) ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ else ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); ++ return 0; ++} ++ ++static void snd_rpi_hifiberry_dacplusadcpro_shutdown( ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *dac = rtd->codec_dais[0]->component; ++ struct snd_soc_component *adc = rtd->codec_dais[1]->component; ++ ++ /* switch off respective LED */ ++ if (!substream->stream) ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); ++ else ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00); ++} ++ ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_hifiberry_dacplusadcpro_ops = { ++ .hw_params = snd_rpi_hifiberry_dacplusadcpro_hw_params, ++ .startup = snd_rpi_hifiberry_dacplusadcpro_startup, ++ .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown, ++}; ++ ++static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = { ++ { ++ .name = "pcm512x.1-004d", ++ .dai_name = "pcm512x-hifi", ++ }, ++ { ++ .name = "pcm186x.1-004a", ++ .dai_name = "pcm1863-aif", ++ }, ++}; ++ ++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = { ++{ ++ .name = "HiFiBerry DAC+ADC PRO", ++ .stream_name = "HiFiBerry DAC+ADC PRO HiFi", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .platform_name = "bcm2708-i2s.0", ++ .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs, ++ .num_codecs = 2, ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_hifiberry_dacplusadcpro_ops, ++ .init = snd_rpi_hifiberry_dacplusadcpro_init, ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_hifiberry_dacplusadcpro = { ++ .name = "snd_rpi_hifiberry_dacplusadcpro", ++ .driver_name = "HifiberryDacpAdcPro", ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_hifiberry_dacplusadcpro_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadcpro_dai), ++}; ++ ++static int snd_rpi_hifiberry_dacplusadcpro_probe(struct platform_device *pdev) ++{ ++ int ret = 0, i = 0; ++ struct snd_soc_card *card = &snd_rpi_hifiberry_dacplusadcpro; ++ ++ snd_rpi_hifiberry_dacplusadcpro.dev = &pdev->dev; ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai; ++ ++ dai = &snd_rpi_hifiberry_dacplusadcpro_dai[0]; ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ if (i2s_node) { ++ for (i = 0; i < card->num_links; i++) { ++ dai->cpu_dai_name = NULL; ++ dai->cpu_of_node = i2s_node; ++ dai->platform_name = NULL; ++ dai->platform_of_node = i2s_node; ++ } ++ } ++ } ++ digital_gain_0db_limit = !of_property_read_bool( ++ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain"); ++ slave = of_property_read_bool(pdev->dev.of_node, ++ "hifiberry-dacplusadcpro,slave"); ++ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro); ++ if (ret && ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static const struct of_device_id snd_rpi_hifiberry_dacplusadcpro_of_match[] = { ++ { .compatible = "hifiberry,hifiberry-dacplusadcpro", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadcpro_of_match); ++ ++static struct platform_driver snd_rpi_hifiberry_dacplusadcpro_driver = { ++ .driver = { ++ .name = "snd-rpi-hifiberry-dacplusadcpro", ++ .owner = THIS_MODULE, ++ .of_match_table = snd_rpi_hifiberry_dacplusadcpro_of_match, ++ }, ++ .probe = snd_rpi_hifiberry_dacplusadcpro_probe, ++}; ++ ++module_platform_driver(snd_rpi_hifiberry_dacplusadcpro_driver); ++ ++MODULE_AUTHOR("Joerg Schambacher "); ++MODULE_AUTHOR("Daniel Matuschek "); ++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0276-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch b/target/linux/bcm27xx/patches-5.4/950-0276-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch deleted file mode 100644 index ce73e34541..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0276-drm-vc4-Pass-the-drm-vrefresh-to-the-firmware-on-mod.patch +++ /dev/null @@ -1,37 +0,0 @@ -From f146d9a60f197fbf868be7eece68ff5cc58af4ff Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 11 Jul 2019 15:12:05 +0100 -Subject: [PATCH] drm/vc4: Pass the drm vrefresh to the firmware on - mode set - -More for completeness than need, but use drm_mode_vrefresh -to compute the vrefresh value, and pass that down to the -firmware on mode set. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -768,8 +768,8 @@ static void vc4_crtc_mode_set_nofb(struc - mode->hdisplay, mode->hsync_start, mode->hsync_end, - mode->htotal, mode->hskew, mode->vdisplay, - mode->vsync_start, mode->vsync_end, mode->vtotal, -- mode->vscan, mode->vrefresh, mode->picture_aspect_ratio, -- mode->flags); -+ mode->vscan, drm_mode_vrefresh(mode), -+ mode->picture_aspect_ratio, mode->flags); - mb.timings.display = vc4_crtc->display_number; - - mb.timings.video_id_code = frame.avi.video_code; -@@ -785,7 +785,7 @@ static void vc4_crtc_mode_set_nofb(struc - mb.timings.vsync_end = mode->vsync_end; - mb.timings.vtotal = mode->vtotal; - mb.timings.vscan = mode->vscan; -- mb.timings.vrefresh = 0; -+ mb.timings.vrefresh = drm_mode_vrefresh(mode); - mb.timings.flags = 0; - if (mode->flags & DRM_MODE_FLAG_PHSYNC) - mb.timings.flags |= TIMINGS_FLAGS_H_SYNC_POS; diff --git a/target/linux/bcm27xx/patches-5.4/950-0277-drm-vc4-A-present-but-empty-dmas-disables-audio.patch b/target/linux/bcm27xx/patches-5.4/950-0277-drm-vc4-A-present-but-empty-dmas-disables-audio.patch new file mode 100644 index 0000000000..b0c5b969f2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0277-drm-vc4-A-present-but-empty-dmas-disables-audio.patch @@ -0,0 +1,33 @@ +From 88d5709082671ff2abeddc2a9b4acacbb85b9194 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 31 Jul 2019 17:36:34 +0100 +Subject: [PATCH] drm/vc4: A present but empty dmas disables audio + +Overlays are unable to remove properties in the base DTB, but they +can overwrite them. Allow a present but empty 'dmas' property +to also disable the HDMI audio interface. + +See: https://github.com/raspberrypi/linux/issues/2489 + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -1066,10 +1066,12 @@ static int vc4_hdmi_audio_init(struct vc + struct device *dev = &hdmi->pdev->dev; + const __be32 *addr; + int ret; ++ int len; + +- if (!of_find_property(dev->of_node, "dmas", NULL)) { ++ if (!of_find_property(dev->of_node, "dmas", &len) || ++ len == 0) { + dev_warn(dev, +- "'dmas' DT property is missing, no HDMI audio\n"); ++ "'dmas' DT property is missing or empty, no HDMI audio\n"); + return 0; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0277-drm-vc4-Add-support-for-margins-to-fkms.patch b/target/linux/bcm27xx/patches-5.4/950-0277-drm-vc4-Add-support-for-margins-to-fkms.patch deleted file mode 100644 index 968eb3ff55..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0277-drm-vc4-Add-support-for-margins-to-fkms.patch +++ /dev/null @@ -1,328 +0,0 @@ -From 8a7170d2ad05ae00733e0535b281ce2e682c6f65 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 19 Jul 2019 15:35:13 +0100 -Subject: [PATCH] drm/vc4: Add support for margins to fkms - -Allows for overscan to be configured under FKMS. -NB This is rescaling the planes, not reducing the size of the -display mode. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 241 +++++++++++++++++++------ - 1 file changed, 190 insertions(+), 51 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -259,6 +259,23 @@ static inline struct vc4_crtc *to_vc4_cr - return container_of(crtc, struct vc4_crtc, base); - } - -+struct vc4_crtc_state { -+ struct drm_crtc_state base; -+ -+ struct { -+ unsigned int left; -+ unsigned int right; -+ unsigned int top; -+ unsigned int bottom; -+ } margins; -+}; -+ -+static inline struct vc4_crtc_state * -+to_vc4_crtc_state(struct drm_crtc_state *crtc_state) -+{ -+ return (struct vc4_crtc_state *)crtc_state; -+} -+ - struct vc4_fkms_encoder { - struct drm_encoder base; - bool hdmi_monitor; -@@ -367,17 +384,127 @@ static int vc4_plane_set_blank(struct dr - return ret; - } - -+static void vc4_fkms_crtc_get_margins(struct drm_crtc_state *state, -+ unsigned int *left, unsigned int *right, -+ unsigned int *top, unsigned int *bottom) -+{ -+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); -+ struct drm_connector_state *conn_state; -+ struct drm_connector *conn; -+ int i; -+ -+ *left = vc4_state->margins.left; -+ *right = vc4_state->margins.right; -+ *top = vc4_state->margins.top; -+ *bottom = vc4_state->margins.bottom; -+ -+ /* We have to interate over all new connector states because -+ * vc4_fkms_crtc_get_margins() might be called before -+ * vc4_fkms_crtc_atomic_check() which means margins info in -+ * vc4_crtc_state might be outdated. -+ */ -+ for_each_new_connector_in_state(state->state, conn, conn_state, i) { -+ if (conn_state->crtc != state->crtc) -+ continue; -+ -+ *left = conn_state->tv.margins.left; -+ *right = conn_state->tv.margins.right; -+ *top = conn_state->tv.margins.top; -+ *bottom = conn_state->tv.margins.bottom; -+ break; -+ } -+} -+ -+static int vc4_fkms_margins_adj(struct drm_plane_state *pstate, -+ struct set_plane *plane) -+{ -+ unsigned int left, right, top, bottom; -+ int adjhdisplay, adjvdisplay; -+ struct drm_crtc_state *crtc_state; -+ -+ crtc_state = drm_atomic_get_new_crtc_state(pstate->state, -+ pstate->crtc); -+ -+ vc4_fkms_crtc_get_margins(crtc_state, &left, &right, &top, &bottom); -+ -+ if (!left && !right && !top && !bottom) -+ return 0; -+ -+ if (left + right >= crtc_state->mode.hdisplay || -+ top + bottom >= crtc_state->mode.vdisplay) -+ return -EINVAL; -+ -+ adjhdisplay = crtc_state->mode.hdisplay - (left + right); -+ plane->dst_x = DIV_ROUND_CLOSEST(plane->dst_x * adjhdisplay, -+ (int)crtc_state->mode.hdisplay); -+ plane->dst_x += left; -+ if (plane->dst_x > (int)(crtc_state->mode.hdisplay - left)) -+ plane->dst_x = crtc_state->mode.hdisplay - left; -+ -+ adjvdisplay = crtc_state->mode.vdisplay - (top + bottom); -+ plane->dst_y = DIV_ROUND_CLOSEST(plane->dst_y * adjvdisplay, -+ (int)crtc_state->mode.vdisplay); -+ plane->dst_y += top; -+ if (plane->dst_y > (int)(crtc_state->mode.vdisplay - top)) -+ plane->dst_y = crtc_state->mode.vdisplay - top; -+ -+ plane->dst_w = DIV_ROUND_CLOSEST(plane->dst_w * adjhdisplay, -+ crtc_state->mode.hdisplay); -+ plane->dst_h = DIV_ROUND_CLOSEST(plane->dst_h * adjvdisplay, -+ crtc_state->mode.vdisplay); -+ -+ if (!plane->dst_w || !plane->dst_h) -+ return -EINVAL; -+ -+ return 0; -+} -+ - static void vc4_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *old_state) - { - struct drm_plane_state *state = plane->state; -+ -+ /* -+ * Do NOT set now, as we haven't checked if the crtc is active or not. -+ * Set from vc4_plane_set_blank instead. -+ * -+ * If the CRTC is on (or going to be on) and we're enabled, -+ * then unblank. Otherwise, stay blank until CRTC enable. -+ */ -+ if (state->crtc->state->active) -+ vc4_plane_set_blank(plane, false); -+} -+ -+static void vc4_plane_atomic_disable(struct drm_plane *plane, -+ struct drm_plane_state *old_state) -+{ -+ struct drm_plane_state *state = plane->state; -+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); -+ -+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n", -+ plane->base.id, plane->name, -+ state->crtc_w, -+ state->crtc_h, -+ vc4_plane->mb.plane.vc_image_type, -+ state->crtc_x, -+ state->crtc_y); -+ vc4_plane_set_blank(plane, true); -+} -+ -+static bool plane_enabled(struct drm_plane_state *state) -+{ -+ return state->fb && state->crtc; -+} -+ -+static int vc4_plane_to_mb(struct drm_plane *plane, -+ struct mailbox_set_plane *mb, -+ struct drm_plane_state *state) -+{ - struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); - const struct drm_format_info *drm_fmt = fb->format; - const struct vc_image_format *vc_fmt = - vc4_get_vc_image_fmt(drm_fmt->format); -- struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); -- struct mailbox_set_plane *mb = &vc4_plane->mb; - int num_planes = fb->format->num_planes; - struct drm_display_mode *mode = &state->crtc->mode; - unsigned int rotation = SUPPORTED_ROTATIONS; -@@ -419,25 +546,7 @@ static void vc4_plane_atomic_update(stru - break; - } - -- /* FIXME: If the dest rect goes off screen then clip the src rect so we -- * don't have off-screen pixels. -- */ -- if (plane->type == DRM_PLANE_TYPE_CURSOR) { -- /* There is no scaling on the cursor plane, therefore the calcs -- * to alter the source crop as the cursor goes off the screen -- * are simple. -- */ -- if (mb->plane.dst_x + mb->plane.dst_w > mode->hdisplay) { -- mb->plane.dst_w = mode->hdisplay - mb->plane.dst_x; -- mb->plane.src_w = (mode->hdisplay - mb->plane.dst_x) -- << 16; -- } -- if (mb->plane.dst_y + mb->plane.dst_h > mode->vdisplay) { -- mb->plane.dst_h = mode->vdisplay - mb->plane.dst_y; -- mb->plane.src_h = (mode->vdisplay - mb->plane.dst_y) -- << 16; -- } -- } -+ vc4_fkms_margins_adj(state, &mb->plane); - - if (num_planes > 1) { - /* Assume this must be YUV */ -@@ -527,38 +636,19 @@ static void vc4_plane_atomic_update(stru - state->alpha, - state->normalized_zpos); - -- /* -- * Do NOT set now, as we haven't checked if the crtc is active or not. -- * Set from vc4_plane_set_blank instead. -- * -- * If the CRTC is on (or going to be on) and we're enabled, -- * then unblank. Otherwise, stay blank until CRTC enable. -- */ -- if (state->crtc->state->active) -- vc4_plane_set_blank(plane, false); -+ return 0; - } - --static void vc4_plane_atomic_disable(struct drm_plane *plane, -- struct drm_plane_state *old_state) -+static int vc4_plane_atomic_check(struct drm_plane *plane, -+ struct drm_plane_state *state) - { -- //struct vc4_dev *vc4 = to_vc4_dev(plane->dev); -- struct drm_plane_state *state = plane->state; - struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane); - -- DRM_DEBUG_ATOMIC("[PLANE:%d:%s] plane disable %dx%d@%d +%d,%d\n", -- plane->base.id, plane->name, -- state->crtc_w, -- state->crtc_h, -- vc4_plane->mb.plane.vc_image_type, -- state->crtc_x, -- state->crtc_y); -- vc4_plane_set_blank(plane, true); --} -+ if (!plane_enabled(state)) -+ return 0; -+ -+ return vc4_plane_to_mb(plane, &vc4_plane->mb, state); - --static int vc4_plane_atomic_check(struct drm_plane *plane, -- struct drm_plane_state *state) --{ -- return 0; - } - - /* Called during init to allocate the plane's atomic state. */ -@@ -909,8 +999,23 @@ vc4_crtc_mode_valid(struct drm_crtc *crt - static int vc4_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) - { -- DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", -- crtc->base.id); -+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state); -+ struct drm_connector *conn; -+ struct drm_connector_state *conn_state; -+ int i; -+ -+ DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_check.\n", crtc->base.id); -+ -+ for_each_new_connector_in_state(state->state, conn, conn_state, i) { -+ if (conn_state->crtc != crtc) -+ continue; -+ -+ vc4_state->margins.left = conn_state->tv.margins.left; -+ vc4_state->margins.right = conn_state->tv.margins.right; -+ vc4_state->margins.top = conn_state->tv.margins.top; -+ vc4_state->margins.bottom = conn_state->tv.margins.bottom; -+ break; -+ } - return 0; - } - -@@ -1011,6 +1116,33 @@ static int vc4_page_flip(struct drm_crtc - return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx); - } - -+static struct drm_crtc_state * -+vc4_crtc_duplicate_state(struct drm_crtc *crtc) -+{ -+ struct vc4_crtc_state *vc4_state, *old_vc4_state; -+ -+ vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); -+ if (!vc4_state) -+ return NULL; -+ -+ old_vc4_state = to_vc4_crtc_state(crtc->state); -+ vc4_state->margins = old_vc4_state->margins; -+ -+ __drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base); -+ return &vc4_state->base; -+} -+ -+static void -+vc4_crtc_reset(struct drm_crtc *crtc) -+{ -+ if (crtc->state) -+ __drm_atomic_helper_crtc_destroy_state(crtc->state); -+ -+ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); -+ if (crtc->state) -+ crtc->state->crtc = crtc; -+} -+ - static int vc4_fkms_enable_vblank(struct drm_crtc *crtc) - { - struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -@@ -1038,8 +1170,8 @@ static const struct drm_crtc_funcs vc4_c - .set_property = NULL, - .cursor_set = NULL, /* handled by drm_mode_cursor_universal */ - .cursor_move = NULL, /* handled by drm_mode_cursor_universal */ -- .reset = drm_atomic_helper_crtc_reset, -- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, -+ .reset = vc4_crtc_reset, -+ .atomic_duplicate_state = vc4_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, - .enable_vblank = vc4_fkms_enable_vblank, - .disable_vblank = vc4_fkms_disable_vblank, -@@ -1291,6 +1423,13 @@ vc4_fkms_connector_init(struct drm_devic - connector->interlace_allowed = 0; - } - -+ /* Create and attach TV margin props to this connector. */ -+ ret = drm_mode_create_tv_margin_properties(dev); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ drm_connector_attach_tv_margin_properties(connector); -+ - connector->polled = (DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0278-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch b/target/linux/bcm27xx/patches-5.4/950-0278-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch new file mode 100644 index 0000000000..60c9c9b03f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0278-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch @@ -0,0 +1,39 @@ +From d6baa1bd90e7e68ac69d5378d70174ea67bf35dc Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Mon, 29 Jul 2019 12:02:59 +0100 +Subject: [PATCH] Fixup FKMS interrupt handing for non-existent display + +If an errant interrupt flag was received from a non-existent display, +a NULL pointer access was made. Protect against this by checking if a +second display is present prior to checking the interrupt flags. +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -1087,14 +1087,17 @@ static irqreturn_t vc4_crtc_irq_handler( + vc4_crtc_handle_page_flip(crtc_list[0]); + } + +- /* Check for the secondary display too */ +- chan = readl(crtc_list[0]->regs + SMIDSW1); ++ if (crtc_list[1]) { ++ /* Check for the secondary display too */ ++ chan = readl(crtc_list[0]->regs + SMIDSW1); + +- if (chan & 1) { +- writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1); +- if (crtc_list[1]->vblank_enabled) +- drm_crtc_handle_vblank(&crtc_list[1]->base); +- vc4_crtc_handle_page_flip(crtc_list[1]); ++ if (chan & 1) { ++ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1); ++ ++ if (crtc_list[1]->vblank_enabled) ++ drm_crtc_handle_vblank(&crtc_list[1]->base); ++ vc4_crtc_handle_page_flip(crtc_list[1]); ++ } + } + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0278-drm-vc4-Ensure-zpos-is-always-initialised.patch b/target/linux/bcm27xx/patches-5.4/950-0278-drm-vc4-Ensure-zpos-is-always-initialised.patch deleted file mode 100644 index 32a13d9c86..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0278-drm-vc4-Ensure-zpos-is-always-initialised.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 9ab46d940789f74980d18715f5715992559ea857 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 19 Jul 2019 17:49:00 +0100 -Subject: [PATCH] drm/vc4: Ensure zpos is always initialised - -The compiler is warning that default_zpos can be used -uninitialised as there is no default case to catch all plane -types. -No other plane types should ever be presented to vc4_fkms_plane_init, -but add a default case regardless. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -804,6 +804,7 @@ static struct drm_plane *vc4_fkms_plane_ - * other layers as requested by KMS. - */ - switch (type) { -+ default: - case DRM_PLANE_TYPE_PRIMARY: - default_zpos = 0; - break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0279-adds-the-Hifiberry-DAC-ADC-PRO-version.patch b/target/linux/bcm27xx/patches-5.4/950-0279-adds-the-Hifiberry-DAC-ADC-PRO-version.patch deleted file mode 100644 index ed6d6db813..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0279-adds-the-Hifiberry-DAC-ADC-PRO-version.patch +++ /dev/null @@ -1,598 +0,0 @@ -From 41c059c841d40bebc358e1c9e7f30c62b2fe3b37 Mon Sep 17 00:00:00 2001 -From: Joerg Schambacher -Date: Tue, 23 Jul 2019 16:57:35 +0200 -Subject: [PATCH] adds the Hifiberry DAC+ADC PRO version - -This adds the driver for the DAC+ADC PRO version of the Hifiberry soundcard with software controlled PCM1863 ADC -Signed-off-by: Joerg Schambacher joerg@i2audio.com ---- - sound/soc/bcm/Kconfig | 9 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/hifiberry_dacplusadcpro.c | 538 ++++++++++++++++++++++++ - 3 files changed, 549 insertions(+) - create mode 100644 sound/soc/bcm/hifiberry_dacplusadcpro.c - ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -38,6 +38,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - tristate "Support for HifiBerry DAC+" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S - select SND_SOC_PCM512x -+ select COMMON_CLK_HIFIBERRY_DACPRO - help - Say Y or M if you want to add support for HifiBerry DAC+. - -@@ -50,6 +51,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - help - Say Y or M if you want to add support for HifiBerry DAC+ADC. - -+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO -+ tristate "Support for HifiBerry DAC+ADC PRO" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_PCM512x_I2C -+ select SND_SOC_PCM186X_I2C -+ help -+ Say Y or M if you want to add support for HifiBerry DAC+ADC PRO. -+ - config SND_BCM2708_SOC_HIFIBERRY_DIGI - tristate "Support for HifiBerry Digi" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -15,6 +15,7 @@ snd-soc-googlevoicehat-codec-objs := goo - # BCM2708 Machine Support - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o -+snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o - snd-soc-justboom-dac-objs := justboom-dac.o - snd-soc-rpi-cirrus-objs := rpi-cirrus.o - snd-soc-rpi-proto-objs := rpi-proto.o -@@ -39,6 +40,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi - obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o - obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o ---- /dev/null -+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c -@@ -0,0 +1,538 @@ -+/* -+ * ASoC Driver for HiFiBerry DAC+ / DAC Pro with ADC PRO Version (SW control) -+ * -+ * Author: Daniel Matuschek, Stuart MacLean -+ * Copyright 2014-2015 -+ * based on code by Florian Meier -+ * ADC added by Joerg Schambacher -+ * Copyright 2018-19 -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../codecs/pcm512x.h" -+#include "../codecs/pcm186x.h" -+ -+#define HIFIBERRY_DACPRO_NOCLOCK 0 -+#define HIFIBERRY_DACPRO_CLK44EN 1 -+#define HIFIBERRY_DACPRO_CLK48EN 2 -+ -+struct pcm512x_priv { -+ struct regmap *regmap; -+ struct clk *sclk; -+}; -+ -+/* Clock rate of CLK44EN attached to GPIO6 pin */ -+#define CLK_44EN_RATE 22579200UL -+/* Clock rate of CLK48EN attached to GPIO3 pin */ -+#define CLK_48EN_RATE 24576000UL -+ -+static bool slave; -+static bool snd_rpi_hifiberry_is_dacpro; -+static bool digital_gain_0db_limit = true; -+ -+static const unsigned int pcm186x_adc_input_channel_sel_value[] = { -+ 0x00, 0x01, 0x02, 0x03, 0x10 -+}; -+ -+static const char * const pcm186x_adcl_input_channel_sel_text[] = { -+ "No Select", -+ "VINL1[SE]", /* Default for ADCL */ -+ "VINL2[SE]", -+ "VINL2[SE] + VINL1[SE]", -+ "{VIN1P, VIN1M}[DIFF]" -+}; -+ -+static const char * const pcm186x_adcr_input_channel_sel_text[] = { -+ "No Select", -+ "VINR1[SE]", /* Default for ADCR */ -+ "VINR2[SE]", -+ "VINR2[SE] + VINR1[SE]", -+ "{VIN2P, VIN2M}[DIFF]" -+}; -+ -+static const struct soc_enum pcm186x_adc_input_channel_sel[] = { -+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0, -+ PCM186X_ADC_INPUT_SEL_MASK, -+ ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text), -+ pcm186x_adcl_input_channel_sel_text, -+ pcm186x_adc_input_channel_sel_value), -+ SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0, -+ PCM186X_ADC_INPUT_SEL_MASK, -+ ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text), -+ pcm186x_adcr_input_channel_sel_text, -+ pcm186x_adc_input_channel_sel_value), -+}; -+ -+static const unsigned int pcm186x_mic_bias_sel_value[] = { -+ 0x00, 0x01, 0x11 -+}; -+ -+static const char * const pcm186x_mic_bias_sel_text[] = { -+ "Mic Bias off", -+ "Mic Bias on", -+ "Mic Bias with Bypass Resistor" -+}; -+ -+static const struct soc_enum pcm186x_mic_bias_sel[] = { -+ SOC_VALUE_ENUM_SINGLE(PCM186X_MIC_BIAS_CTRL, 0, -+ GENMASK(4, 0), -+ ARRAY_SIZE(pcm186x_mic_bias_sel_text), -+ pcm186x_mic_bias_sel_text, -+ pcm186x_mic_bias_sel_value), -+}; -+ -+static const unsigned int pcm186x_gain_sel_value[] = { -+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, -+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, -+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, -+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, -+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, -+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, -+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, -+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, -+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, -+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, -+ 0x50 -+}; -+ -+static const char * const pcm186x_gain_sel_text[] = { -+ "-12.0dB", "-11.5dB", "-11.0dB", "-10.5dB", "-10.0dB", "-9.5dB", -+ "-9.0dB", "-8.5dB", "-8.0dB", "-7.5dB", "-7.0dB", "-6.5dB", -+ "-6.0dB", "-5.5dB", "-5.0dB", "-4.5dB", "-4.0dB", "-3.5dB", -+ "-3.0dB", "-2.5dB", "-2.0dB", "-1.5dB", "-1.0dB", "-0.5dB", -+ "0.0dB", "0.5dB", "1.0dB", "1.5dB", "2.0dB", "2.5dB", -+ "3.0dB", "3.5dB", "4.0dB", "4.5dB", "5.0dB", "5.5dB", -+ "6.0dB", "6.5dB", "7.0dB", "7.5dB", "8.0dB", "8.5dB", -+ "9.0dB", "9.5dB", "10.0dB", "10.5dB", "11.0dB", "11.5dB", -+ "12.0dB", "12.5dB", "13.0dB", "13.5dB", "14.0dB", "14.5dB", -+ "15.0dB", "15.5dB", "16.0dB", "16.5dB", "17.0dB", "17.5dB", -+ "18.0dB", "18.5dB", "19.0dB", "19.5dB", "20.0dB", "20.5dB", -+ "21.0dB", "21.5dB", "22.0dB", "22.5dB", "23.0dB", "23.5dB", -+ "24.0dB", "24.5dB", "25.0dB", "25.5dB", "26.0dB", "26.5dB", -+ "27.0dB", "27.5dB", "28.0dB", "28.5dB", "29.0dB", "29.5dB", -+ "30.0dB", "30.5dB", "31.0dB", "31.5dB", "32.0dB", "32.5dB", -+ "33.0dB", "33.5dB", "34.0dB", "34.5dB", "35.0dB", "35.5dB", -+ "36.0dB", "36.5dB", "37.0dB", "37.5dB", "38.0dB", "38.5dB", -+ "39.0dB", "39.5dB", "40.0dB"}; -+ -+static const struct soc_enum pcm186x_gain_sel[] = { -+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_L, 0, -+ 0xff, -+ ARRAY_SIZE(pcm186x_gain_sel_text), -+ pcm186x_gain_sel_text, -+ pcm186x_gain_sel_value), -+ SOC_VALUE_ENUM_SINGLE(PCM186X_PGA_VAL_CH1_R, 0, -+ 0xff, -+ ARRAY_SIZE(pcm186x_gain_sel_text), -+ pcm186x_gain_sel_text, -+ pcm186x_gain_sel_value), -+}; -+ -+static const struct snd_kcontrol_new pcm1863_snd_controls_card[] = { -+ SOC_ENUM("ADC Left Input", pcm186x_adc_input_channel_sel[0]), -+ SOC_ENUM("ADC Right Input", pcm186x_adc_input_channel_sel[1]), -+ SOC_ENUM("ADC Mic Bias", pcm186x_mic_bias_sel), -+ SOC_ENUM("PGA Gain Left", pcm186x_gain_sel[0]), -+ SOC_ENUM("PGA Gain Right", pcm186x_gain_sel[1]), -+}; -+ -+static int pcm1863_add_controls(struct snd_soc_component *component) -+{ -+ snd_soc_add_component_controls(component, -+ pcm1863_snd_controls_card, -+ ARRAY_SIZE(pcm1863_snd_controls_card)); -+ return 0; -+} -+ -+static void snd_rpi_hifiberry_dacplusadcpro_select_clk( -+ struct snd_soc_component *component, int clk_id) -+{ -+ switch (clk_id) { -+ case HIFIBERRY_DACPRO_NOCLOCK: -+ snd_soc_component_update_bits(component, -+ PCM512x_GPIO_CONTROL_1, 0x24, 0x00); -+ break; -+ case HIFIBERRY_DACPRO_CLK44EN: -+ snd_soc_component_update_bits(component, -+ PCM512x_GPIO_CONTROL_1, 0x24, 0x20); -+ break; -+ case HIFIBERRY_DACPRO_CLK48EN: -+ snd_soc_component_update_bits(component, -+ PCM512x_GPIO_CONTROL_1, 0x24, 0x04); -+ break; -+ } -+} -+ -+static void snd_rpi_hifiberry_dacplusadcpro_clk_gpio(struct snd_soc_component *component) -+{ -+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24); -+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02); -+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02); -+} -+ -+static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk(struct snd_soc_component *component) -+{ -+ unsigned int sck; -+ -+ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck); -+ return (!(sck & 0x40)); -+} -+ -+static bool snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep( -+ struct snd_soc_component *component) -+{ -+ msleep(2); -+ return snd_rpi_hifiberry_dacplusadcpro_is_sclk(component); -+} -+ -+static bool snd_rpi_hifiberry_dacplusadcpro_is_pro_card(struct snd_soc_component *component) -+{ -+ bool isClk44EN, isClk48En, isNoClk; -+ -+ snd_rpi_hifiberry_dacplusadcpro_clk_gpio(component); -+ -+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK44EN); -+ isClk44EN = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component); -+ -+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK); -+ isNoClk = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component); -+ -+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, HIFIBERRY_DACPRO_CLK48EN); -+ isClk48En = snd_rpi_hifiberry_dacplusadcpro_is_sclk_sleep(component); -+ -+ return (isClk44EN && isClk48En && !isNoClk); -+} -+ -+static int snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(int sample_rate) -+{ -+ int type; -+ -+ switch (sample_rate) { -+ case 11025: -+ case 22050: -+ case 44100: -+ case 88200: -+ case 176400: -+ case 352800: -+ type = HIFIBERRY_DACPRO_CLK44EN; -+ break; -+ default: -+ type = HIFIBERRY_DACPRO_CLK48EN; -+ break; -+ } -+ return type; -+} -+ -+static void snd_rpi_hifiberry_dacplusadcpro_set_sclk(struct snd_soc_component *component, -+ int sample_rate) -+{ -+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); -+ -+ if (!IS_ERR(pcm512x->sclk)) { -+ int ctype; -+ -+ ctype = snd_rpi_hifiberry_dacplusadcpro_clk_for_rate(sample_rate); -+ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN) -+ ? CLK_44EN_RATE : CLK_48EN_RATE); -+ snd_rpi_hifiberry_dacplusadcpro_select_clk(component, ctype); -+ } -+} -+ -+static int snd_rpi_hifiberry_dacplusadcpro_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_component *dac = rtd->codec_dais[0]->component; -+ struct snd_soc_component *adc = rtd->codec_dais[1]->component; -+ struct snd_soc_dai_driver *adc_driver = rtd->codec_dais[1]->driver; -+ struct pcm512x_priv *priv; -+ int ret; -+ -+ if (slave) -+ snd_rpi_hifiberry_is_dacpro = false; -+ else -+ snd_rpi_hifiberry_is_dacpro = -+ snd_rpi_hifiberry_dacplusadcpro_is_pro_card(dac); -+ -+ if (snd_rpi_hifiberry_is_dacpro) { -+ struct snd_soc_dai_link *dai = rtd->dai_link; -+ -+ dai->name = "HiFiBerry DAC+ADC Pro"; -+ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi"; -+ -+ // set DAC DAI configuration -+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0], -+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM); -+ if (ret < 0) -+ return ret; -+ -+ // set ADC DAI configuration -+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[1], -+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBS_CFS); -+ if (ret < 0) -+ return ret; -+ -+ // set CPU DAI configuration -+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, -+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); -+ if (ret < 0) -+ return ret; -+ -+ snd_soc_component_update_bits(dac, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11); -+ snd_soc_component_update_bits(dac, PCM512x_MASTER_MODE, 0x03, 0x03); -+ snd_soc_component_update_bits(dac, PCM512x_MASTER_CLKDIV_2, 0x7f, 63); -+ } else { -+ priv = snd_soc_component_get_drvdata(dac); -+ priv->sclk = ERR_PTR(-ENOENT); -+ } -+ -+ /* disable 24bit mode as long as I2S module does not have sign extension fixed */ -+ adc_driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE; -+ -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08); -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ -+ ret = pcm1863_add_controls(adc); -+ if (ret < 0) -+ dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n", -+ ret); -+ -+ /* set GPIO2 to output, GPIO3 input */ -+ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00); -+ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04); -+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); -+ -+ if (digital_gain_0db_limit) { -+ int ret; -+ struct snd_soc_card *card = rtd->card; -+ -+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207); -+ if (ret < 0) -+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); -+ } -+ -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_dacplusadcpro_update_rate_den( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *component = rtd->codec_dais[0]->component; /* only use DAC */ -+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); -+ struct snd_ratnum *rats_no_pll; -+ unsigned int num = 0, den = 0; -+ int err; -+ -+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL); -+ if (!rats_no_pll) -+ return -ENOMEM; -+ -+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64; -+ rats_no_pll->den_min = 1; -+ rats_no_pll->den_max = 128; -+ rats_no_pll->den_step = 1; -+ -+ err = snd_interval_ratnum(hw_param_interval(params, -+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den); -+ if (err >= 0 && den) { -+ params->rate_num = num; -+ params->rate_den = den; -+ } -+ -+ devm_kfree(rtd->dev, rats_no_pll); -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_dacplusadcpro_hw_params( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) -+{ -+ int ret = 0; -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ int channels = params_channels(params); -+ int width = 32; -+ struct snd_soc_component *dac = rtd->codec_dais[0]->component; -+ -+ if (snd_rpi_hifiberry_is_dacpro) { -+ -+ width = snd_pcm_format_physical_width(params_format(params)); -+ -+ snd_rpi_hifiberry_dacplusadcpro_set_sclk(dac, -+ params_rate(params)); -+ -+ ret = snd_rpi_hifiberry_dacplusadcpro_update_rate_den( -+ substream, params); -+ if (ret) -+ return ret; -+ } -+ -+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x03, 0x03, -+ channels, width); -+ if (ret) -+ return ret; -+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x03, 0x03, -+ channels, width); -+ if (ret) -+ return ret; -+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x03, 0x03, -+ channels, width); -+ return ret; -+} -+ -+static int snd_rpi_hifiberry_dacplusadcpro_startup( -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *dac = rtd->codec_dais[0]->component; -+ struct snd_soc_component *adc = rtd->codec_dais[1]->component; -+ -+ /* switch on respective LED */ -+ if (!substream->stream) -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ else -+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); -+ return 0; -+} -+ -+static void snd_rpi_hifiberry_dacplusadcpro_shutdown( -+ struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *dac = rtd->codec_dais[0]->component; -+ struct snd_soc_component *adc = rtd->codec_dais[1]->component; -+ -+ /* switch off respective LED */ -+ if (!substream->stream) -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); -+ else -+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00); -+} -+ -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_hifiberry_dacplusadcpro_ops = { -+ .hw_params = snd_rpi_hifiberry_dacplusadcpro_hw_params, -+ .startup = snd_rpi_hifiberry_dacplusadcpro_startup, -+ .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown, -+}; -+ -+static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = { -+ { -+ .name = "pcm512x.1-004d", -+ .dai_name = "pcm512x-hifi", -+ }, -+ { -+ .name = "pcm186x.1-004a", -+ .dai_name = "pcm1863-aif", -+ }, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = { -+{ -+ .name = "HiFiBerry DAC+ADC PRO", -+ .stream_name = "HiFiBerry DAC+ADC PRO HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .platform_name = "bcm2708-i2s.0", -+ .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs, -+ .num_codecs = 2, -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_hifiberry_dacplusadcpro_ops, -+ .init = snd_rpi_hifiberry_dacplusadcpro_init, -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_hifiberry_dacplusadcpro = { -+ .name = "snd_rpi_hifiberry_dacplusadcpro", -+ .driver_name = "HifiberryDacpAdcPro", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_hifiberry_dacplusadcpro_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplusadcpro_dai), -+}; -+ -+static int snd_rpi_hifiberry_dacplusadcpro_probe(struct platform_device *pdev) -+{ -+ int ret = 0, i = 0; -+ struct snd_soc_card *card = &snd_rpi_hifiberry_dacplusadcpro; -+ -+ snd_rpi_hifiberry_dacplusadcpro.dev = &pdev->dev; -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai; -+ -+ dai = &snd_rpi_hifiberry_dacplusadcpro_dai[0]; -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ if (i2s_node) { -+ for (i = 0; i < card->num_links; i++) { -+ dai->cpu_dai_name = NULL; -+ dai->cpu_of_node = i2s_node; -+ dai->platform_name = NULL; -+ dai->platform_of_node = i2s_node; -+ } -+ } -+ } -+ digital_gain_0db_limit = !of_property_read_bool( -+ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain"); -+ slave = of_property_read_bool(pdev->dev.of_node, -+ "hifiberry-dacplusadcpro,slave"); -+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro); -+ if (ret && ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ -+ return ret; -+} -+ -+static const struct of_device_id snd_rpi_hifiberry_dacplusadcpro_of_match[] = { -+ { .compatible = "hifiberry,hifiberry-dacplusadcpro", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplusadcpro_of_match); -+ -+static struct platform_driver snd_rpi_hifiberry_dacplusadcpro_driver = { -+ .driver = { -+ .name = "snd-rpi-hifiberry-dacplusadcpro", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_hifiberry_dacplusadcpro_of_match, -+ }, -+ .probe = snd_rpi_hifiberry_dacplusadcpro_probe, -+}; -+ -+module_platform_driver(snd_rpi_hifiberry_dacplusadcpro_driver); -+ -+MODULE_AUTHOR("Joerg Schambacher "); -+MODULE_AUTHOR("Daniel Matuschek "); -+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ADC"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0279-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch b/target/linux/bcm27xx/patches-5.4/950-0279-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch new file mode 100644 index 0000000000..3f3c5ea148 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0279-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch @@ -0,0 +1,387 @@ +From dcf515d36ce574edd773c9c6321b6bbf9724e209 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Thu, 9 May 2019 14:30:37 +0100 +Subject: [PATCH] drivers: char: add chardev for mmap'ing the RPiVid + control registers + +Based on the gpiomem driver, allow mapping of the decoder register +spaces such that userspace can access control/status registers. +This driver is intended for use with a custom ffmpeg backend accelerator +prior to a v4l2 driver being written. + +Signed-off-by: Jonathan Bell +--- + drivers/char/broadcom/Kconfig | 8 + + drivers/char/broadcom/Makefile | 1 + + drivers/char/broadcom/rpivid-mem.c | 286 +++++++++++++++++++++++++++++ + drivers/mfd/bcm2835-pm.c | 12 +- + drivers/soc/bcm/bcm2835-power.c | 6 +- + include/linux/mfd/bcm2835-pm.h | 2 +- + 6 files changed, 305 insertions(+), 10 deletions(-) + create mode 100644 drivers/char/broadcom/rpivid-mem.c + +--- a/drivers/char/broadcom/Kconfig ++++ b/drivers/char/broadcom/Kconfig +@@ -49,3 +49,11 @@ config BCM2835_SMI_DEV + This driver provides a character device interface (ioctl + read/write) to + Broadcom's Secondary Memory interface. The low-level functionality is provided + by the SMI driver itself. ++ ++config RPIVID_MEM ++ tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware" ++ default n ++ help ++ This driver provides a character device interface for memory-map operations ++ so userspace tools can access the control and status registers of the ++ Raspberry Pi RPiVid video decoder hardware. +--- a/drivers/char/broadcom/Makefile ++++ b/drivers/char/broadcom/Makefile +@@ -4,3 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm + + obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o + obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o ++obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o +--- /dev/null ++++ b/drivers/char/broadcom/rpivid-mem.c +@@ -0,0 +1,286 @@ ++/** ++ * rpivid-mem.c - character device access to the RPiVid decoder registers ++ * ++ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder ++ * register blocks such that ffmpeg plugins can access the hardware. ++ * ++ * Jonathan Bell ++ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2, as published by the Free ++ * Software Foundation. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "rpivid-mem" ++#define DEVICE_MINOR 0 ++ ++struct rpivid_mem_priv { ++ dev_t devid; ++ struct class *class; ++ struct cdev rpivid_mem_cdev; ++ unsigned long regs_phys; ++ unsigned long mem_window_len; ++ struct device *dev; ++ const char *name; ++}; ++ ++static int rpivid_mem_open(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ struct rpivid_mem_priv *priv; ++ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1) ++ ret = -ENXIO; ++ ++ priv = container_of(inode->i_cdev, struct rpivid_mem_priv, ++ rpivid_mem_cdev); ++ if (!priv) ++ return -EINVAL; ++ file->private_data = priv; ++ return ret; ++} ++ ++static int rpivid_mem_release(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1) ++ ret = -ENXIO; ++ ++ return ret; ++} ++ ++static const struct vm_operations_struct rpivid_mem_vm_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++ ++static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct rpivid_mem_priv *priv; ++ unsigned long pages; ++ ++ priv = file->private_data; ++ pages = priv->regs_phys >> PAGE_SHIFT; ++ /* ++ * The address decode is far larger than the actual number of registers. ++ * Just map the whole lot in. ++ */ ++ vma->vm_page_prot = phys_mem_access_prot(file, pages, ++ priv->mem_window_len, ++ vma->vm_page_prot); ++ vma->vm_ops = &rpivid_mem_vm_ops; ++ if (remap_pfn_range(vma, vma->vm_start, ++ pages, ++ priv->mem_window_len, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ return 0; ++} ++ ++static const struct file_operations ++rpivid_mem_fops = { ++ .owner = THIS_MODULE, ++ .open = rpivid_mem_open, ++ .release = rpivid_mem_release, ++ .mmap = rpivid_mem_mmap, ++}; ++ ++static const struct of_device_id rpivid_mem_of_match[]; ++static int rpivid_mem_probe(struct platform_device *pdev) ++{ ++ int err; ++ void *ptr_err; ++ const struct of_device_id *id; ++ struct device *dev = &pdev->dev; ++ struct device *rpivid_mem_dev; ++ struct resource *ioresource; ++ struct rpivid_mem_priv *priv; ++ ++ ++ /* Allocate buffers and instance data */ ++ ++ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL); ++ ++ if (!priv) { ++ err = -ENOMEM; ++ goto failed_inst_alloc; ++ } ++ platform_set_drvdata(pdev, priv); ++ ++ priv->dev = dev; ++ id = of_match_device(rpivid_mem_of_match, dev); ++ if (!id) ++ return -EINVAL; ++ priv->name = id->data; ++ ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (ioresource) { ++ priv->regs_phys = ioresource->start; ++ priv->mem_window_len = ioresource->end - ioresource->start; ++ } else { ++ dev_err(priv->dev, "failed to get IO resource"); ++ err = -ENOENT; ++ goto failed_get_resource; ++ } ++ ++ /* Create character device entries */ ++ ++ err = alloc_chrdev_region(&priv->devid, ++ DEVICE_MINOR, 2, priv->name); ++ if (err != 0) { ++ dev_err(priv->dev, "unable to allocate device number"); ++ goto failed_alloc_chrdev; ++ } ++ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops); ++ priv->rpivid_mem_cdev.owner = THIS_MODULE; ++ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2); ++ if (err != 0) { ++ dev_err(priv->dev, "unable to register device"); ++ goto failed_cdev_add; ++ } ++ ++ /* Create sysfs entries */ ++ ++ priv->class = class_create(THIS_MODULE, priv->name); ++ ptr_err = priv->class; ++ if (IS_ERR(ptr_err)) ++ goto failed_class_create; ++ ++ rpivid_mem_dev = device_create(priv->class, NULL, ++ priv->devid, NULL, ++ priv->name); ++ ptr_err = rpivid_mem_dev; ++ if (IS_ERR(ptr_err)) ++ goto failed_device_create; ++ ++ /* Legacy alias */ ++ { ++ char *oldname = kstrdup(priv->name, GFP_KERNEL); ++ ++ oldname[1] = 'a'; ++ oldname[2] = 'r'; ++ oldname[3] = 'g'; ++ oldname[4] = 'o'; ++ oldname[5] = 'n'; ++ (void)device_create(priv->class, NULL, priv->devid + 1, NULL, ++ oldname + 1); ++ kfree(oldname); ++ } ++ ++ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx", ++ priv->name, priv->regs_phys, priv->mem_window_len); ++ ++ return 0; ++ ++failed_device_create: ++ class_destroy(priv->class); ++failed_class_create: ++ cdev_del(&priv->rpivid_mem_cdev); ++ err = PTR_ERR(ptr_err); ++failed_cdev_add: ++ unregister_chrdev_region(priv->devid, 1); ++failed_alloc_chrdev: ++failed_get_resource: ++ kfree(priv); ++failed_inst_alloc: ++ dev_err(priv->dev, "could not load rpivid_mem"); ++ return err; ++} ++ ++static int rpivid_mem_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev); ++ ++ device_destroy(priv->class, priv->devid); ++ class_destroy(priv->class); ++ cdev_del(&priv->rpivid_mem_cdev); ++ unregister_chrdev_region(priv->devid, 1); ++ kfree(priv); ++ ++ dev_info(dev, "%s driver removed - OK", priv->name); ++ return 0; ++} ++ ++static const struct of_device_id rpivid_mem_of_match[] = { ++ { ++ .compatible = "raspberrypi,rpivid-hevc-decoder", ++ .data = "rpivid-hevcmem", ++ }, ++ { ++ .compatible = "raspberrypi,rpivid-h264-decoder", ++ .data = "rpivid-h264mem", ++ }, ++ { ++ .compatible = "raspberrypi,rpivid-vp9-decoder", ++ .data = "rpivid-vp9mem", ++ }, ++ /* The "intc" is included as this block of hardware contains the ++ * "frame done" status flags. ++ */ ++ { ++ .compatible = "raspberrypi,rpivid-local-intc", ++ .data = "rpivid-intcmem", ++ }, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rpivid_mem_of_match); ++ ++static struct platform_driver rpivid_mem_driver = { ++ .probe = rpivid_mem_probe, ++ .remove = rpivid_mem_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rpivid_mem_of_match, ++ }, ++}; ++ ++module_platform_driver(rpivid_mem_driver); ++ ++MODULE_ALIAS("platform:rpivid-mem"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace"); ++MODULE_AUTHOR("Jonathan Bell "); +--- a/drivers/mfd/bcm2835-pm.c ++++ b/drivers/mfd/bcm2835-pm.c +@@ -50,14 +50,14 @@ static int bcm2835_pm_probe(struct platf + if (ret) + return ret; + +- /* Map the ARGON ASB regs if present. */ ++ /* Map the RPiVid ASB regs if present. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (res) { +- pm->arg_asb = devm_ioremap_resource(dev, res); +- if (IS_ERR(pm->arg_asb)) { +- dev_err(dev, "Failed to map ARGON ASB: %ld\n", +- PTR_ERR(pm->arg_asb)); +- return PTR_ERR(pm->arg_asb); ++ pm->rpivid_asb = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pm->rpivid_asb)) { ++ dev_err(dev, "Failed to map RPiVid ASB: %ld\n", ++ PTR_ERR(pm->rpivid_asb)); ++ return PTR_ERR(pm->rpivid_asb); + } + } + +--- a/drivers/soc/bcm/bcm2835-power.c ++++ b/drivers/soc/bcm/bcm2835-power.c +@@ -637,15 +637,15 @@ static int bcm2835_power_probe(struct pl + power->base = pm->base; + power->asb = pm->asb; + +- /* 2711 hack: the new ARGON ASB took over V3D, which is our ++ /* 2711 hack: the new RPiVid ASB took over V3D, which is our + * only consumer of this driver so far. The old ASB seems to + * still be present with ISP and H264 bits but no V3D, but I + * don't know if that's real or not. The V3D is in the same + * place in the new ASB as the old one, so just poke the new + * one for now. + */ +- if (pm->arg_asb) { +- power->asb = pm->arg_asb; ++ if (pm->rpivid_asb) { ++ power->asb = pm->rpivid_asb; + power->is_2711 = true; + } + +--- a/include/linux/mfd/bcm2835-pm.h ++++ b/include/linux/mfd/bcm2835-pm.h +@@ -9,7 +9,7 @@ struct bcm2835_pm { + struct device *dev; + void __iomem *base; + void __iomem *asb; +- void __iomem *arg_asb; ++ void __iomem *rpivid_asb; + }; + + #endif /* BCM2835_MFD_PM_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0280-drm-vc4-A-present-but-empty-dmas-disables-audio.patch b/target/linux/bcm27xx/patches-5.4/950-0280-drm-vc4-A-present-but-empty-dmas-disables-audio.patch deleted file mode 100644 index b0c5b969f2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0280-drm-vc4-A-present-but-empty-dmas-disables-audio.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 88d5709082671ff2abeddc2a9b4acacbb85b9194 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 31 Jul 2019 17:36:34 +0100 -Subject: [PATCH] drm/vc4: A present but empty dmas disables audio - -Overlays are unable to remove properties in the base DTB, but they -can overwrite them. Allow a present but empty 'dmas' property -to also disable the HDMI audio interface. - -See: https://github.com/raspberrypi/linux/issues/2489 - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/vc4/vc4_hdmi.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_hdmi.c -+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c -@@ -1066,10 +1066,12 @@ static int vc4_hdmi_audio_init(struct vc - struct device *dev = &hdmi->pdev->dev; - const __be32 *addr; - int ret; -+ int len; - -- if (!of_find_property(dev->of_node, "dmas", NULL)) { -+ if (!of_find_property(dev->of_node, "dmas", &len) || -+ len == 0) { - dev_warn(dev, -- "'dmas' DT property is missing, no HDMI audio\n"); -+ "'dmas' DT property is missing or empty, no HDMI audio\n"); - return 0; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0280-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch b/target/linux/bcm27xx/patches-5.4/950-0280-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch new file mode 100644 index 0000000000..ee886e31a5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0280-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch @@ -0,0 +1,63 @@ +From 8f4720ca2ed61fbaf2a3039b510e276d06d6a2fb Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Thu, 1 Aug 2019 16:41:20 +0100 +Subject: [PATCH] hid: usb: Add device quirks for Freeway Airmouse T3 + and MX3 + +These wireless mouse/keyboard combo remote control devices specify +multiple "wheel" events in their report descriptors. The wheel events +are incorrectly defined and apparently map to accelerometer data, leading +to spurious mouse scroll events being generated at an extreme rate when +the device is moved. + +As a workaround, use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE to mask +feeding the extra wheel events to the input subsystem. + +See: https://github.com/raspberrypi/firmware/issues/1189 + +Signed-off-by: Jonathan Bell +--- + drivers/hid/hid-ids.h | 6 ++++++ + drivers/hid/hid-quirks.c | 2 ++ + 2 files changed, 8 insertions(+) + +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -223,6 +223,9 @@ + #define USB_VENDOR_ID_BAANTO 0x2453 + #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100 + ++#define USB_VENDOR_ID_BEKEN 0x25a7 ++#define USB_DEVICE_ID_AIRMOUSE_T3 0x2402 ++ + #define USB_VENDOR_ID_BELKIN 0x050d + #define USB_DEVICE_ID_FLIP_KVM 0x3201 + +@@ -1254,6 +1257,9 @@ + #define USB_VENDOR_ID_XAT 0x2505 + #define USB_DEVICE_ID_XAT_CSR 0x0220 + ++#define USB_VENDOR_ID_XENTA 0x1d57 ++#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03 ++ + #define USB_VENDOR_ID_XIN_MO 0x16c0 + #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1 + #define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -41,6 +41,7 @@ static const struct hid_device_id hid_qu + { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL }, +@@ -189,6 +190,7 @@ static const struct hid_device_id hid_qu + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO), HID_QUIRK_NOGET }, + + { 0 } diff --git a/target/linux/bcm27xx/patches-5.4/950-0281-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch b/target/linux/bcm27xx/patches-5.4/950-0281-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch deleted file mode 100644 index 60c9c9b03f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0281-Fixup-FKMS-interrupt-handing-for-non-existent-displa.patch +++ /dev/null @@ -1,39 +0,0 @@ -From d6baa1bd90e7e68ac69d5378d70174ea67bf35dc Mon Sep 17 00:00:00 2001 -From: James Hughes -Date: Mon, 29 Jul 2019 12:02:59 +0100 -Subject: [PATCH] Fixup FKMS interrupt handing for non-existent display - -If an errant interrupt flag was received from a non-existent display, -a NULL pointer access was made. Protect against this by checking if a -second display is present prior to checking the interrupt flags. ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 17 ++++++++++------- - 1 file changed, 10 insertions(+), 7 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -1087,14 +1087,17 @@ static irqreturn_t vc4_crtc_irq_handler( - vc4_crtc_handle_page_flip(crtc_list[0]); - } - -- /* Check for the secondary display too */ -- chan = readl(crtc_list[0]->regs + SMIDSW1); -+ if (crtc_list[1]) { -+ /* Check for the secondary display too */ -+ chan = readl(crtc_list[0]->regs + SMIDSW1); - -- if (chan & 1) { -- writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1); -- if (crtc_list[1]->vblank_enabled) -- drm_crtc_handle_vblank(&crtc_list[1]->base); -- vc4_crtc_handle_page_flip(crtc_list[1]); -+ if (chan & 1) { -+ writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1); -+ -+ if (crtc_list[1]->vblank_enabled) -+ drm_crtc_handle_vblank(&crtc_list[1]->base); -+ vc4_crtc_handle_page_flip(crtc_list[1]); -+ } - } - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0281-drm-vc4-Add-Broadcast-RGB-connector-property.patch b/target/linux/bcm27xx/patches-5.4/950-0281-drm-vc4-Add-Broadcast-RGB-connector-property.patch new file mode 100644 index 0000000000..e221e41189 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0281-drm-vc4-Add-Broadcast-RGB-connector-property.patch @@ -0,0 +1,302 @@ +From 661cefed28f420f7ca6e52882d83a7a321d60256 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 14 Jun 2019 10:12:07 +0100 +Subject: [PATCH] drm/vc4: Add "Broadcast RGB" connector property + +Some HDMI monitors do not abide by the full or limited +(16-235) range RGB flags in the AVI infoframe. This can +result in images looking washed out (if given limited and +interpreting as full), or detail disappearing at the extremes +(given full and interpreting as limited). + +Copy the Intel i915 driver's approach of adding an override +property ("Broadcast RGB") to force one mode or the other. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 190 +++++++++++++++++++++++-- + 1 file changed, 177 insertions(+), 13 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -287,6 +287,13 @@ to_vc4_fkms_encoder(struct drm_encoder * + return container_of(encoder, struct vc4_fkms_encoder, base); + } + ++/* "Broadcast RGB" property. ++ * Allows overriding of HDMI full or limited range RGB ++ */ ++#define VC4_BROADCAST_RGB_AUTO 0 ++#define VC4_BROADCAST_RGB_FULL 1 ++#define VC4_BROADCAST_RGB_LIMITED 2 ++ + /* VC4 FKMS connector KMS struct */ + struct vc4_fkms_connector { + struct drm_connector base; +@@ -299,6 +306,8 @@ struct vc4_fkms_connector { + struct vc4_dev *vc4_dev; + u32 display_number; + u32 display_type; ++ ++ struct drm_property *broadcast_rgb_property; + }; + + static inline struct vc4_fkms_connector * +@@ -307,6 +316,16 @@ to_vc4_fkms_connector(struct drm_connect + return container_of(connector, struct vc4_fkms_connector, base); + } + ++/* VC4 FKMS connector state */ ++struct vc4_fkms_connector_state { ++ struct drm_connector_state base; ++ ++ int broadcast_rgb; ++}; ++ ++#define to_vc4_fkms_connector_state(x) \ ++ container_of(x, struct vc4_fkms_connector_state, base) ++ + static u32 vc4_get_display_type(u32 display_number) + { + const u32 display_types[] = { +@@ -863,8 +882,6 @@ static void vc4_crtc_mode_set_nofb(struc + mode->picture_aspect_ratio, mode->flags); + mb.timings.display = vc4_crtc->display_number; + +- mb.timings.video_id_code = frame.avi.video_code; +- + mb.timings.clock = mode->clock; + mb.timings.hdisplay = mode->hdisplay; + mb.timings.hsync_start = mode->hsync_start; +@@ -902,11 +919,30 @@ static void vc4_crtc_mode_set_nofb(struc + break; + } + +- if (!vc4_encoder->hdmi_monitor) ++ if (!vc4_encoder->hdmi_monitor) { + mb.timings.flags |= TIMINGS_FLAGS_DVI; +- else if (drm_default_rgb_quant_range(mode) == ++ mb.timings.video_id_code = frame.avi.video_code; ++ } else { ++ struct vc4_fkms_connector_state *conn_state = ++ to_vc4_fkms_connector_state(vc4_crtc->connector->state); ++ ++ /* Do not provide a VIC as the HDMI spec requires that we do not ++ * signal the opposite of the defined range in the AVI ++ * infoframe. ++ */ ++ mb.timings.video_id_code = 0; ++ ++ if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) { ++ /* See CEA-861-E - 5.1 Default Encoding Parameters */ ++ if (drm_default_rgb_quant_range(mode) == + HDMI_QUANTIZATION_RANGE_LIMITED) +- mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; ++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; ++ } else { ++ if (conn_state->broadcast_rgb == ++ VC4_BROADCAST_RGB_LIMITED) ++ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; ++ } ++ } + + /* + FIXME: To implement +@@ -1364,13 +1400,95 @@ static void vc4_fkms_connector_destroy(s + drm_connector_cleanup(connector); + } + ++/** ++ * vc4_connector_duplicate_state - duplicate connector state ++ * @connector: digital connector ++ * ++ * Allocates and returns a copy of the connector state (both common and ++ * digital connector specific) for the specified connector. ++ * ++ * Returns: The newly allocated connector state, or NULL on failure. ++ */ ++struct drm_connector_state * ++vc4_connector_duplicate_state(struct drm_connector *connector) ++{ ++ struct vc4_fkms_connector_state *state; ++ ++ state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL); ++ if (!state) ++ return NULL; ++ ++ __drm_atomic_helper_connector_duplicate_state(connector, &state->base); ++ return &state->base; ++} ++ ++/** ++ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property. ++ * @connector: Connector to get the property for. ++ * @state: Connector state to retrieve the property from. ++ * @property: Property to retrieve. ++ * @val: Return value for the property. ++ * ++ * Returns the atomic property value for a digital connector. ++ */ ++int vc4_connector_atomic_get_property(struct drm_connector *connector, ++ const struct drm_connector_state *state, ++ struct drm_property *property, ++ uint64_t *val) ++{ ++ struct vc4_fkms_connector *fkms_connector = ++ to_vc4_fkms_connector(connector); ++ struct vc4_fkms_connector_state *vc4_conn_state = ++ to_vc4_fkms_connector_state(state); ++ ++ if (property == fkms_connector->broadcast_rgb_property) { ++ *val = vc4_conn_state->broadcast_rgb; ++ } else { ++ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", ++ property->base.id, property->name); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property. ++ * @connector: Connector to set the property for. ++ * @state: Connector state to set the property on. ++ * @property: Property to set. ++ * @val: New value for the property. ++ * ++ * Sets the atomic property value for a digital connector. ++ */ ++int vc4_connector_atomic_set_property(struct drm_connector *connector, ++ struct drm_connector_state *state, ++ struct drm_property *property, ++ uint64_t val) ++{ ++ struct vc4_fkms_connector *fkms_connector = ++ to_vc4_fkms_connector(connector); ++ struct vc4_fkms_connector_state *vc4_conn_state = ++ to_vc4_fkms_connector_state(state); ++ ++ if (property == fkms_connector->broadcast_rgb_property) { ++ vc4_conn_state->broadcast_rgb = val; ++ return 0; ++ } ++ ++ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", ++ property->base.id, property->name); ++ return -EINVAL; ++} ++ + static const struct drm_connector_funcs vc4_fkms_connector_funcs = { + .detect = vc4_fkms_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = vc4_fkms_connector_destroy, +- .reset = drm_atomic_helper_connector_reset, +- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, ++ .atomic_duplicate_state = vc4_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, ++ .atomic_get_property = vc4_connector_atomic_get_property, ++ .atomic_set_property = vc4_connector_atomic_set_property, + }; + + static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = { +@@ -1383,12 +1501,40 @@ static const struct drm_connector_helper + .best_encoder = vc4_fkms_connector_best_encoder, + }; + ++static const struct drm_prop_enum_list broadcast_rgb_names[] = { ++ { VC4_BROADCAST_RGB_AUTO, "Automatic" }, ++ { VC4_BROADCAST_RGB_FULL, "Full" }, ++ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" }, ++}; ++ ++static void ++vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector) ++{ ++ struct drm_device *dev = fkms_connector->base.dev; ++ struct drm_property *prop; ++ ++ prop = fkms_connector->broadcast_rgb_property; ++ if (!prop) { ++ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, ++ "Broadcast RGB", ++ broadcast_rgb_names, ++ ARRAY_SIZE(broadcast_rgb_names)); ++ if (!prop) ++ return; ++ ++ fkms_connector->broadcast_rgb_property = prop; ++ } ++ ++ drm_object_attach_property(&fkms_connector->base.base, prop, 0); ++} ++ + static struct drm_connector * + vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder, + u32 display_num) + { + struct drm_connector *connector = NULL; + struct vc4_fkms_connector *fkms_connector; ++ struct vc4_fkms_connector_state *conn_state = NULL; + struct vc4_dev *vc4_dev = to_vc4_dev(dev); + int ret = 0; + +@@ -1397,9 +1543,18 @@ vc4_fkms_connector_init(struct drm_devic + fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector), + GFP_KERNEL); + if (!fkms_connector) { +- ret = -ENOMEM; +- goto fail; ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* ++ * Allocate enough memory to hold vc4_fkms_connector_state, ++ */ ++ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL); ++ if (!conn_state) { ++ kfree(fkms_connector); ++ return ERR_PTR(-ENOMEM); + } ++ + connector = &fkms_connector->base; + + fkms_connector->encoder = encoder; +@@ -1407,6 +1562,9 @@ vc4_fkms_connector_init(struct drm_devic + fkms_connector->display_type = vc4_get_display_type(display_num); + fkms_connector->vc4_dev = vc4_dev; + ++ __drm_atomic_helper_connector_reset(connector, ++ &conn_state->base); ++ + if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) { + drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, + DRM_MODE_CONNECTOR_DSI); +@@ -1427,10 +1585,14 @@ vc4_fkms_connector_init(struct drm_devic + connector->interlace_allowed = 0; + } + +- /* Create and attach TV margin props to this connector. */ +- ret = drm_mode_create_tv_margin_properties(dev); +- if (ret) +- return ERR_PTR(ret); ++ /* Create and attach TV margin props to this connector. ++ * Already done for SDTV outputs. ++ */ ++ if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) { ++ ret = drm_mode_create_tv_margin_properties(dev); ++ if (ret) ++ goto fail; ++ } + + drm_connector_attach_tv_margin_properties(connector); + +@@ -1439,6 +1601,8 @@ vc4_fkms_connector_init(struct drm_devic + + connector->doublescan_allowed = 0; + ++ vc4_attach_broadcast_rgb_property(fkms_connector); ++ + drm_connector_attach_encoder(connector, encoder); + + return connector; diff --git a/target/linux/bcm27xx/patches-5.4/950-0282-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch b/target/linux/bcm27xx/patches-5.4/950-0282-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch deleted file mode 100644 index 3f3c5ea148..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0282-drivers-char-add-chardev-for-mmap-ing-the-RPiVid-con.patch +++ /dev/null @@ -1,387 +0,0 @@ -From dcf515d36ce574edd773c9c6321b6bbf9724e209 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Thu, 9 May 2019 14:30:37 +0100 -Subject: [PATCH] drivers: char: add chardev for mmap'ing the RPiVid - control registers - -Based on the gpiomem driver, allow mapping of the decoder register -spaces such that userspace can access control/status registers. -This driver is intended for use with a custom ffmpeg backend accelerator -prior to a v4l2 driver being written. - -Signed-off-by: Jonathan Bell ---- - drivers/char/broadcom/Kconfig | 8 + - drivers/char/broadcom/Makefile | 1 + - drivers/char/broadcom/rpivid-mem.c | 286 +++++++++++++++++++++++++++++ - drivers/mfd/bcm2835-pm.c | 12 +- - drivers/soc/bcm/bcm2835-power.c | 6 +- - include/linux/mfd/bcm2835-pm.h | 2 +- - 6 files changed, 305 insertions(+), 10 deletions(-) - create mode 100644 drivers/char/broadcom/rpivid-mem.c - ---- a/drivers/char/broadcom/Kconfig -+++ b/drivers/char/broadcom/Kconfig -@@ -49,3 +49,11 @@ config BCM2835_SMI_DEV - This driver provides a character device interface (ioctl + read/write) to - Broadcom's Secondary Memory interface. The low-level functionality is provided - by the SMI driver itself. -+ -+config RPIVID_MEM -+ tristate "Character device driver for the Raspberry Pi RPIVid video decoder hardware" -+ default n -+ help -+ This driver provides a character device interface for memory-map operations -+ so userspace tools can access the control and status registers of the -+ Raspberry Pi RPiVid video decoder hardware. ---- a/drivers/char/broadcom/Makefile -+++ b/drivers/char/broadcom/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_BCM_VC_SM) += vc_sm - - obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o - obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o -+obj-$(CONFIG_RPIVID_MEM) += rpivid-mem.o ---- /dev/null -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -0,0 +1,286 @@ -+/** -+ * rpivid-mem.c - character device access to the RPiVid decoder registers -+ * -+ * Based on bcm2835-gpiomem.c. Provides IO memory access to the decoder -+ * register blocks such that ffmpeg plugins can access the hardware. -+ * -+ * Jonathan Bell -+ * Copyright (c) 2019, Raspberry Pi (Trading) Ltd. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions, and the following disclaimer, -+ * without modification. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The names of the above-listed copyright holders may not be used -+ * to endorse or promote products derived from this software without -+ * specific prior written permission. -+ * -+ * ALTERNATIVELY, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") version 2, as published by the Free -+ * Software Foundation. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "rpivid-mem" -+#define DEVICE_MINOR 0 -+ -+struct rpivid_mem_priv { -+ dev_t devid; -+ struct class *class; -+ struct cdev rpivid_mem_cdev; -+ unsigned long regs_phys; -+ unsigned long mem_window_len; -+ struct device *dev; -+ const char *name; -+}; -+ -+static int rpivid_mem_open(struct inode *inode, struct file *file) -+{ -+ int dev = iminor(inode); -+ int ret = 0; -+ struct rpivid_mem_priv *priv; -+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1) -+ ret = -ENXIO; -+ -+ priv = container_of(inode->i_cdev, struct rpivid_mem_priv, -+ rpivid_mem_cdev); -+ if (!priv) -+ return -EINVAL; -+ file->private_data = priv; -+ return ret; -+} -+ -+static int rpivid_mem_release(struct inode *inode, struct file *file) -+{ -+ int dev = iminor(inode); -+ int ret = 0; -+ -+ if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1) -+ ret = -ENXIO; -+ -+ return ret; -+} -+ -+static const struct vm_operations_struct rpivid_mem_vm_ops = { -+#ifdef CONFIG_HAVE_IOREMAP_PROT -+ .access = generic_access_phys -+#endif -+}; -+ -+static int rpivid_mem_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct rpivid_mem_priv *priv; -+ unsigned long pages; -+ -+ priv = file->private_data; -+ pages = priv->regs_phys >> PAGE_SHIFT; -+ /* -+ * The address decode is far larger than the actual number of registers. -+ * Just map the whole lot in. -+ */ -+ vma->vm_page_prot = phys_mem_access_prot(file, pages, -+ priv->mem_window_len, -+ vma->vm_page_prot); -+ vma->vm_ops = &rpivid_mem_vm_ops; -+ if (remap_pfn_range(vma, vma->vm_start, -+ pages, -+ priv->mem_window_len, -+ vma->vm_page_prot)) { -+ return -EAGAIN; -+ } -+ return 0; -+} -+ -+static const struct file_operations -+rpivid_mem_fops = { -+ .owner = THIS_MODULE, -+ .open = rpivid_mem_open, -+ .release = rpivid_mem_release, -+ .mmap = rpivid_mem_mmap, -+}; -+ -+static const struct of_device_id rpivid_mem_of_match[]; -+static int rpivid_mem_probe(struct platform_device *pdev) -+{ -+ int err; -+ void *ptr_err; -+ const struct of_device_id *id; -+ struct device *dev = &pdev->dev; -+ struct device *rpivid_mem_dev; -+ struct resource *ioresource; -+ struct rpivid_mem_priv *priv; -+ -+ -+ /* Allocate buffers and instance data */ -+ -+ priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL); -+ -+ if (!priv) { -+ err = -ENOMEM; -+ goto failed_inst_alloc; -+ } -+ platform_set_drvdata(pdev, priv); -+ -+ priv->dev = dev; -+ id = of_match_device(rpivid_mem_of_match, dev); -+ if (!id) -+ return -EINVAL; -+ priv->name = id->data; -+ -+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (ioresource) { -+ priv->regs_phys = ioresource->start; -+ priv->mem_window_len = ioresource->end - ioresource->start; -+ } else { -+ dev_err(priv->dev, "failed to get IO resource"); -+ err = -ENOENT; -+ goto failed_get_resource; -+ } -+ -+ /* Create character device entries */ -+ -+ err = alloc_chrdev_region(&priv->devid, -+ DEVICE_MINOR, 2, priv->name); -+ if (err != 0) { -+ dev_err(priv->dev, "unable to allocate device number"); -+ goto failed_alloc_chrdev; -+ } -+ cdev_init(&priv->rpivid_mem_cdev, &rpivid_mem_fops); -+ priv->rpivid_mem_cdev.owner = THIS_MODULE; -+ err = cdev_add(&priv->rpivid_mem_cdev, priv->devid, 2); -+ if (err != 0) { -+ dev_err(priv->dev, "unable to register device"); -+ goto failed_cdev_add; -+ } -+ -+ /* Create sysfs entries */ -+ -+ priv->class = class_create(THIS_MODULE, priv->name); -+ ptr_err = priv->class; -+ if (IS_ERR(ptr_err)) -+ goto failed_class_create; -+ -+ rpivid_mem_dev = device_create(priv->class, NULL, -+ priv->devid, NULL, -+ priv->name); -+ ptr_err = rpivid_mem_dev; -+ if (IS_ERR(ptr_err)) -+ goto failed_device_create; -+ -+ /* Legacy alias */ -+ { -+ char *oldname = kstrdup(priv->name, GFP_KERNEL); -+ -+ oldname[1] = 'a'; -+ oldname[2] = 'r'; -+ oldname[3] = 'g'; -+ oldname[4] = 'o'; -+ oldname[5] = 'n'; -+ (void)device_create(priv->class, NULL, priv->devid + 1, NULL, -+ oldname + 1); -+ kfree(oldname); -+ } -+ -+ dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx", -+ priv->name, priv->regs_phys, priv->mem_window_len); -+ -+ return 0; -+ -+failed_device_create: -+ class_destroy(priv->class); -+failed_class_create: -+ cdev_del(&priv->rpivid_mem_cdev); -+ err = PTR_ERR(ptr_err); -+failed_cdev_add: -+ unregister_chrdev_region(priv->devid, 1); -+failed_alloc_chrdev: -+failed_get_resource: -+ kfree(priv); -+failed_inst_alloc: -+ dev_err(priv->dev, "could not load rpivid_mem"); -+ return err; -+} -+ -+static int rpivid_mem_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rpivid_mem_priv *priv = platform_get_drvdata(pdev); -+ -+ device_destroy(priv->class, priv->devid); -+ class_destroy(priv->class); -+ cdev_del(&priv->rpivid_mem_cdev); -+ unregister_chrdev_region(priv->devid, 1); -+ kfree(priv); -+ -+ dev_info(dev, "%s driver removed - OK", priv->name); -+ return 0; -+} -+ -+static const struct of_device_id rpivid_mem_of_match[] = { -+ { -+ .compatible = "raspberrypi,rpivid-hevc-decoder", -+ .data = "rpivid-hevcmem", -+ }, -+ { -+ .compatible = "raspberrypi,rpivid-h264-decoder", -+ .data = "rpivid-h264mem", -+ }, -+ { -+ .compatible = "raspberrypi,rpivid-vp9-decoder", -+ .data = "rpivid-vp9mem", -+ }, -+ /* The "intc" is included as this block of hardware contains the -+ * "frame done" status flags. -+ */ -+ { -+ .compatible = "raspberrypi,rpivid-local-intc", -+ .data = "rpivid-intcmem", -+ }, -+ { /* sentinel */ }, -+}; -+ -+MODULE_DEVICE_TABLE(of, rpivid_mem_of_match); -+ -+static struct platform_driver rpivid_mem_driver = { -+ .probe = rpivid_mem_probe, -+ .remove = rpivid_mem_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .of_match_table = rpivid_mem_of_match, -+ }, -+}; -+ -+module_platform_driver(rpivid_mem_driver); -+ -+MODULE_ALIAS("platform:rpivid-mem"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Driver for accessing RPiVid decoder registers from userspace"); -+MODULE_AUTHOR("Jonathan Bell "); ---- a/drivers/mfd/bcm2835-pm.c -+++ b/drivers/mfd/bcm2835-pm.c -@@ -50,14 +50,14 @@ static int bcm2835_pm_probe(struct platf - if (ret) - return ret; - -- /* Map the ARGON ASB regs if present. */ -+ /* Map the RPiVid ASB regs if present. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - if (res) { -- pm->arg_asb = devm_ioremap_resource(dev, res); -- if (IS_ERR(pm->arg_asb)) { -- dev_err(dev, "Failed to map ARGON ASB: %ld\n", -- PTR_ERR(pm->arg_asb)); -- return PTR_ERR(pm->arg_asb); -+ pm->rpivid_asb = devm_ioremap_resource(dev, res); -+ if (IS_ERR(pm->rpivid_asb)) { -+ dev_err(dev, "Failed to map RPiVid ASB: %ld\n", -+ PTR_ERR(pm->rpivid_asb)); -+ return PTR_ERR(pm->rpivid_asb); - } - } - ---- a/drivers/soc/bcm/bcm2835-power.c -+++ b/drivers/soc/bcm/bcm2835-power.c -@@ -637,15 +637,15 @@ static int bcm2835_power_probe(struct pl - power->base = pm->base; - power->asb = pm->asb; - -- /* 2711 hack: the new ARGON ASB took over V3D, which is our -+ /* 2711 hack: the new RPiVid ASB took over V3D, which is our - * only consumer of this driver so far. The old ASB seems to - * still be present with ISP and H264 bits but no V3D, but I - * don't know if that's real or not. The V3D is in the same - * place in the new ASB as the old one, so just poke the new - * one for now. - */ -- if (pm->arg_asb) { -- power->asb = pm->arg_asb; -+ if (pm->rpivid_asb) { -+ power->asb = pm->rpivid_asb; - power->is_2711 = true; - } - ---- a/include/linux/mfd/bcm2835-pm.h -+++ b/include/linux/mfd/bcm2835-pm.h -@@ -9,7 +9,7 @@ struct bcm2835_pm { - struct device *dev; - void __iomem *base; - void __iomem *asb; -- void __iomem *arg_asb; -+ void __iomem *rpivid_asb; - }; - - #endif /* BCM2835_MFD_PM_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0282-drm-vc4-fkms-Set-default-state-margin-at-reset.patch b/target/linux/bcm27xx/patches-5.4/950-0282-drm-vc4-fkms-Set-default-state-margin-at-reset.patch new file mode 100644 index 0000000000..51664f3f98 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0282-drm-vc4-fkms-Set-default-state-margin-at-reset.patch @@ -0,0 +1,34 @@ +From 651d4137cc20de6b64edd2302ebd82d8e88121df Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 23 Jul 2019 11:09:26 +0100 +Subject: [PATCH] drm/vc4: fkms: Set default state margin at reset + +Now that the TV margins are properly parsed and filled into +drm_cmdline_mode, we just need to initialise the first state at reset to +get those values and start using them. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -1481,10 +1481,17 @@ int vc4_connector_atomic_set_property(st + return -EINVAL; + } + ++static void vc4_hdmi_connector_reset(struct drm_connector *connector) ++{ ++ drm_atomic_helper_connector_reset(connector); ++ drm_atomic_helper_connector_tv_reset(connector); ++} ++ + static const struct drm_connector_funcs vc4_fkms_connector_funcs = { + .detect = vc4_fkms_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = vc4_fkms_connector_destroy, ++ .reset = vc4_hdmi_connector_reset, + .atomic_duplicate_state = vc4_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_get_property = vc4_connector_atomic_get_property, diff --git a/target/linux/bcm27xx/patches-5.4/950-0283-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch b/target/linux/bcm27xx/patches-5.4/950-0283-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch deleted file mode 100644 index ee886e31a5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0283-hid-usb-Add-device-quirks-for-Freeway-Airmouse-T3-an.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 8f4720ca2ed61fbaf2a3039b510e276d06d6a2fb Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Thu, 1 Aug 2019 16:41:20 +0100 -Subject: [PATCH] hid: usb: Add device quirks for Freeway Airmouse T3 - and MX3 - -These wireless mouse/keyboard combo remote control devices specify -multiple "wheel" events in their report descriptors. The wheel events -are incorrectly defined and apparently map to accelerometer data, leading -to spurious mouse scroll events being generated at an extreme rate when -the device is moved. - -As a workaround, use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE to mask -feeding the extra wheel events to the input subsystem. - -See: https://github.com/raspberrypi/firmware/issues/1189 - -Signed-off-by: Jonathan Bell ---- - drivers/hid/hid-ids.h | 6 ++++++ - drivers/hid/hid-quirks.c | 2 ++ - 2 files changed, 8 insertions(+) - ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -223,6 +223,9 @@ - #define USB_VENDOR_ID_BAANTO 0x2453 - #define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100 - -+#define USB_VENDOR_ID_BEKEN 0x25a7 -+#define USB_DEVICE_ID_AIRMOUSE_T3 0x2402 -+ - #define USB_VENDOR_ID_BELKIN 0x050d - #define USB_DEVICE_ID_FLIP_KVM 0x3201 - -@@ -1254,6 +1257,9 @@ - #define USB_VENDOR_ID_XAT 0x2505 - #define USB_DEVICE_ID_XAT_CSR 0x0220 - -+#define USB_VENDOR_ID_XENTA 0x1d57 -+#define USB_DEVICE_ID_AIRMOUSE_MX3 0xad03 -+ - #define USB_VENDOR_ID_XIN_MO 0x16c0 - #define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1 - #define USB_DEVICE_ID_THT_2P_ARCADE 0x75e1 ---- a/drivers/hid/hid-quirks.c -+++ b/drivers/hid/hid-quirks.c -@@ -41,6 +41,7 @@ static const struct hid_device_id hid_qu - { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET }, - { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET }, - { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_BEKEN, USB_DEVICE_ID_AIRMOUSE_T3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL }, -@@ -189,6 +190,7 @@ static const struct hid_device_id hid_qu - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT }, -+ { HID_USB_DEVICE(USB_VENDOR_ID_XENTA, USB_DEVICE_ID_AIRMOUSE_MX3), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_GROUP_AUDIO), HID_QUIRK_NOGET }, - - { 0 } diff --git a/target/linux/bcm27xx/patches-5.4/950-0283-staging-bcm2835-codec-switch-to-multi-planar-API.patch b/target/linux/bcm27xx/patches-5.4/950-0283-staging-bcm2835-codec-switch-to-multi-planar-API.patch new file mode 100644 index 0000000000..c4eab3a02a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0283-staging-bcm2835-codec-switch-to-multi-planar-API.patch @@ -0,0 +1,347 @@ +From 9495e07dac5cb6230838763572f73b863cd72019 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Thu, 18 Jul 2019 17:07:05 +0800 +Subject: [PATCH] staging: bcm2835-codec: switch to multi-planar API + +There are two APIs for mem2mem devices, the older single-planar API and +the newer multi-planar one. Without making things overly complex, the +driver can only support one or the other. However the userspace libv4l2 +library has a plugin that allows multi-planar API devices to service +single-planar consumers. + +Chromium supports the multi-planar API exclusively, though this is +currently limited to ChromiumOS. It would be possible to add support +for generic Linux. + +Switching to the multi-planar API would allow usage of both APIs from +userspace. + +Signed-off-by: Chen-Yu Tsai +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 141 +++++++++--------- + 1 file changed, 74 insertions(+), 67 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_fo + + for (k = 0; k < fmts->num_entries; k++) { + fmt = &fmts->list[k]; +- if (fmt->fourcc == f->fmt.pix.pixelformat) ++ if (fmt->fourcc == f->fmt.pix_mp.pixelformat) + break; + } + if (k == fmts->num_entries) +@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_ + enum v4l2_buf_type type) + { + switch (type) { +- case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return &ctx->q_data[V4L2_M2M_SRC]; +- case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return &ctx->q_data[V4L2_M2M_DST]; + default: + v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", +@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_ + return NULL; + + switch (type) { +- case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return &ctx->component->input[0]; +- case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return &ctx->component->output[0]; + default: + v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", +@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bc + format->es.video.crop.width, format->es.video.crop.height, + format->es.video.color_space); + +- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); ++ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + q_data->crop_width = format->es.video.crop.width; + q_data->crop_height = format->es.video.crop.height; + q_data->bytesperline = format->es.video.crop.width; +@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file * + strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + MEM2MEM_NAME); +- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; ++ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; + } +@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_c + + q_data = get_q_data(ctx, f->type); + +- f->fmt.pix.width = q_data->crop_width; +- f->fmt.pix.height = q_data->height; +- f->fmt.pix.field = V4L2_FIELD_NONE; +- f->fmt.pix.pixelformat = q_data->fmt->fourcc; +- f->fmt.pix.bytesperline = q_data->bytesperline; +- f->fmt.pix.sizeimage = q_data->sizeimage; +- f->fmt.pix.colorspace = ctx->colorspace; +- f->fmt.pix.xfer_func = ctx->xfer_func; +- f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; +- f->fmt.pix.quantization = ctx->quant; ++ f->fmt.pix_mp.width = q_data->crop_width; ++ f->fmt.pix_mp.height = q_data->height; ++ f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc; ++ f->fmt.pix_mp.field = V4L2_FIELD_NONE; ++ f->fmt.pix_mp.colorspace = ctx->colorspace; ++ f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage; ++ f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline; ++ f->fmt.pix_mp.num_planes = 1; ++ f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; ++ f->fmt.pix_mp.quantization = ctx->quant; ++ f->fmt.pix_mp.xfer_func = ctx->xfer_func; ++ ++ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0, ++ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved)); + + return 0; + } +@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835 + * The V4L2 specification requires the driver to correct the format + * struct if any of the dimensions is unsupported + */ +- if (f->fmt.pix.width > MAX_W) +- f->fmt.pix.width = MAX_W; +- if (f->fmt.pix.height > MAX_H) +- f->fmt.pix.height = MAX_H; ++ if (f->fmt.pix_mp.width > MAX_W) ++ f->fmt.pix_mp.width = MAX_W; ++ if (f->fmt.pix_mp.height > MAX_H) ++ f->fmt.pix_mp.height = MAX_H; + + if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { + /* Only clip min w/h on capture. Treat 0x0 as unknown. */ +- if (f->fmt.pix.width < MIN_W) +- f->fmt.pix.width = MIN_W; +- if (f->fmt.pix.height < MIN_H) +- f->fmt.pix.height = MIN_H; ++ if (f->fmt.pix_mp.width < MIN_W) ++ f->fmt.pix_mp.width = MIN_W; ++ if (f->fmt.pix_mp.height < MIN_H) ++ f->fmt.pix_mp.height = MIN_H; + + /* + * For codecs the buffer must have a vertical alignment of 16 +@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835 + * some of the pixels are active. + */ + if (ctx->dev->role != ISP) +- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); ++ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16); + } +- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, +- fmt); +- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, +- f->fmt.pix.width, +- f->fmt.pix.height, +- fmt); ++ f->fmt.pix_mp.num_planes = 1; ++ f->fmt.pix_mp.plane_fmt[0].bytesperline = ++ get_bytesperline(f->fmt.pix_mp.width, fmt); ++ f->fmt.pix_mp.plane_fmt[0].sizeimage = ++ get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline, ++ f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt); ++ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0, ++ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved)); + +- f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix_mp.field = V4L2_FIELD_NONE; + + return 0; + } +@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct + + fmt = find_format(f, ctx->dev, true); + if (!fmt) { +- f->fmt.pix.pixelformat = get_default_format(ctx->dev, +- true)->fourcc; ++ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev, ++ true)->fourcc; + fmt = find_format(f, ctx->dev, true); + } + +@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct + + fmt = find_format(f, ctx->dev, false); + if (!fmt) { +- f->fmt.pix.pixelformat = get_default_format(ctx->dev, +- false)->fourcc; ++ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev, ++ false)->fourcc; + fmt = find_format(f, ctx->dev, false); + } + +- if (!f->fmt.pix.colorspace) +- f->fmt.pix.colorspace = ctx->colorspace; ++ if (!f->fmt.pix_mp.colorspace) ++ f->fmt.pix_mp.colorspace = ctx->colorspace; + + return vidioc_try_fmt(ctx, f, fmt); + } +@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_c + bool update_capture_port = false; + int ret; + +- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", +- f->type, f->fmt.pix.width, f->fmt.pix.height, +- f->fmt.pix.pixelformat, f->fmt.pix.sizeimage); ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", ++ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height, ++ f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage); ++ + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) +@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_c + } + + q_data->fmt = find_format(f, ctx->dev, +- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); +- q_data->crop_width = f->fmt.pix.width; +- q_data->height = f->fmt.pix.height; ++ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ q_data->crop_width = f->fmt.pix_mp.width; ++ q_data->height = f->fmt.pix_mp.height; + if (!q_data->selection_set) + q_data->crop_height = requested_height; + +@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_c + * Copying the behaviour of vicodec which retains a single set of + * colorspace parameters for both input and output. + */ +- ctx->colorspace = f->fmt.pix.colorspace; +- ctx->xfer_func = f->fmt.pix.xfer_func; +- ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; +- ctx->quant = f->fmt.pix.quantization; ++ ctx->colorspace = f->fmt.pix_mp.colorspace; ++ ctx->xfer_func = f->fmt.pix_mp.xfer_func; ++ ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; ++ ctx->quant = f->fmt.pix_mp.quantization; + + /* All parameters should have been set correctly by try_fmt */ +- q_data->bytesperline = f->fmt.pix.bytesperline; +- q_data->sizeimage = f->fmt.pix.sizeimage; ++ q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline; ++ q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", + q_data->bytesperline, q_data->sizeimage); + + if (ctx->dev->role == DECODE && + q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && +- f->fmt.pix.width && f->fmt.pix.height) { ++ q_data->crop_width && q_data->height) { + /* + * On the decoder, if provided with a resolution on the input + * side, then replicate that to the output side. +@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_c + q_data_dst->height = ALIGN(q_data->crop_height, 16); + + q_data_dst->bytesperline = +- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt); ++ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt); + q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, + q_data_dst->crop_width, + q_data_dst->height, +@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_c + static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) + { +- unsigned int height = f->fmt.pix.height; ++ unsigned int height = f->fmt.pix_mp.height; + int ret; + + ret = vidioc_try_fmt_vid_cap(file, priv, f); +@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct f + static int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) + { +- unsigned int height = f->fmt.pix.height; ++ unsigned int height = f->fmt.pix_mp.height; + int ret; + + ret = vidioc_try_fmt_vid_out(file, priv, f); +@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct fil + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + struct bcm2835_codec_q_data *q_data; +- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? ++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? + true : false; + + if ((ctx->dev->role == DECODE && !capture_queue) || +@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct fil + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + struct bcm2835_codec_q_data *q_data = NULL; +- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? ++ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? + true : false; + + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n", +@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *fi + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + ctx->framerate_num = +@@ -1739,14 +1746,14 @@ static const struct v4l2_ioctl_ops bcm28 + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, +- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, +- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, +- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, ++ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, ++ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, ++ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, +- .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, +- .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, +- .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, ++ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, ++ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, ++ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, +@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming + ctx->component_enabled = true; + } + +- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* + * Create the EOS buffer. + * We only need the MMAL part, and want to NOT attach a memory +@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct + struct bcm2835_codec_ctx *ctx = priv; + int ret; + +- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); +@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct + if (ret) + return ret; + +- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); diff --git a/target/linux/bcm27xx/patches-5.4/950-0284-drm-vc4-Add-Broadcast-RGB-connector-property.patch b/target/linux/bcm27xx/patches-5.4/950-0284-drm-vc4-Add-Broadcast-RGB-connector-property.patch deleted file mode 100644 index e221e41189..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0284-drm-vc4-Add-Broadcast-RGB-connector-property.patch +++ /dev/null @@ -1,302 +0,0 @@ -From 661cefed28f420f7ca6e52882d83a7a321d60256 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 14 Jun 2019 10:12:07 +0100 -Subject: [PATCH] drm/vc4: Add "Broadcast RGB" connector property - -Some HDMI monitors do not abide by the full or limited -(16-235) range RGB flags in the AVI infoframe. This can -result in images looking washed out (if given limited and -interpreting as full), or detail disappearing at the extremes -(given full and interpreting as limited). - -Copy the Intel i915 driver's approach of adding an override -property ("Broadcast RGB") to force one mode or the other. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 190 +++++++++++++++++++++++-- - 1 file changed, 177 insertions(+), 13 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -287,6 +287,13 @@ to_vc4_fkms_encoder(struct drm_encoder * - return container_of(encoder, struct vc4_fkms_encoder, base); - } - -+/* "Broadcast RGB" property. -+ * Allows overriding of HDMI full or limited range RGB -+ */ -+#define VC4_BROADCAST_RGB_AUTO 0 -+#define VC4_BROADCAST_RGB_FULL 1 -+#define VC4_BROADCAST_RGB_LIMITED 2 -+ - /* VC4 FKMS connector KMS struct */ - struct vc4_fkms_connector { - struct drm_connector base; -@@ -299,6 +306,8 @@ struct vc4_fkms_connector { - struct vc4_dev *vc4_dev; - u32 display_number; - u32 display_type; -+ -+ struct drm_property *broadcast_rgb_property; - }; - - static inline struct vc4_fkms_connector * -@@ -307,6 +316,16 @@ to_vc4_fkms_connector(struct drm_connect - return container_of(connector, struct vc4_fkms_connector, base); - } - -+/* VC4 FKMS connector state */ -+struct vc4_fkms_connector_state { -+ struct drm_connector_state base; -+ -+ int broadcast_rgb; -+}; -+ -+#define to_vc4_fkms_connector_state(x) \ -+ container_of(x, struct vc4_fkms_connector_state, base) -+ - static u32 vc4_get_display_type(u32 display_number) - { - const u32 display_types[] = { -@@ -863,8 +882,6 @@ static void vc4_crtc_mode_set_nofb(struc - mode->picture_aspect_ratio, mode->flags); - mb.timings.display = vc4_crtc->display_number; - -- mb.timings.video_id_code = frame.avi.video_code; -- - mb.timings.clock = mode->clock; - mb.timings.hdisplay = mode->hdisplay; - mb.timings.hsync_start = mode->hsync_start; -@@ -902,11 +919,30 @@ static void vc4_crtc_mode_set_nofb(struc - break; - } - -- if (!vc4_encoder->hdmi_monitor) -+ if (!vc4_encoder->hdmi_monitor) { - mb.timings.flags |= TIMINGS_FLAGS_DVI; -- else if (drm_default_rgb_quant_range(mode) == -+ mb.timings.video_id_code = frame.avi.video_code; -+ } else { -+ struct vc4_fkms_connector_state *conn_state = -+ to_vc4_fkms_connector_state(vc4_crtc->connector->state); -+ -+ /* Do not provide a VIC as the HDMI spec requires that we do not -+ * signal the opposite of the defined range in the AVI -+ * infoframe. -+ */ -+ mb.timings.video_id_code = 0; -+ -+ if (conn_state->broadcast_rgb == VC4_BROADCAST_RGB_AUTO) { -+ /* See CEA-861-E - 5.1 Default Encoding Parameters */ -+ if (drm_default_rgb_quant_range(mode) == - HDMI_QUANTIZATION_RANGE_LIMITED) -- mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; -+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; -+ } else { -+ if (conn_state->broadcast_rgb == -+ VC4_BROADCAST_RGB_LIMITED) -+ mb.timings.flags |= TIMINGS_FLAGS_RGB_LIMITED; -+ } -+ } - - /* - FIXME: To implement -@@ -1364,13 +1400,95 @@ static void vc4_fkms_connector_destroy(s - drm_connector_cleanup(connector); - } - -+/** -+ * vc4_connector_duplicate_state - duplicate connector state -+ * @connector: digital connector -+ * -+ * Allocates and returns a copy of the connector state (both common and -+ * digital connector specific) for the specified connector. -+ * -+ * Returns: The newly allocated connector state, or NULL on failure. -+ */ -+struct drm_connector_state * -+vc4_connector_duplicate_state(struct drm_connector *connector) -+{ -+ struct vc4_fkms_connector_state *state; -+ -+ state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL); -+ if (!state) -+ return NULL; -+ -+ __drm_atomic_helper_connector_duplicate_state(connector, &state->base); -+ return &state->base; -+} -+ -+/** -+ * vc4_connector_atomic_get_property - hook for connector->atomic_get_property. -+ * @connector: Connector to get the property for. -+ * @state: Connector state to retrieve the property from. -+ * @property: Property to retrieve. -+ * @val: Return value for the property. -+ * -+ * Returns the atomic property value for a digital connector. -+ */ -+int vc4_connector_atomic_get_property(struct drm_connector *connector, -+ const struct drm_connector_state *state, -+ struct drm_property *property, -+ uint64_t *val) -+{ -+ struct vc4_fkms_connector *fkms_connector = -+ to_vc4_fkms_connector(connector); -+ struct vc4_fkms_connector_state *vc4_conn_state = -+ to_vc4_fkms_connector_state(state); -+ -+ if (property == fkms_connector->broadcast_rgb_property) { -+ *val = vc4_conn_state->broadcast_rgb; -+ } else { -+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", -+ property->base.id, property->name); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * vc4_connector_atomic_set_property - hook for connector->atomic_set_property. -+ * @connector: Connector to set the property for. -+ * @state: Connector state to set the property on. -+ * @property: Property to set. -+ * @val: New value for the property. -+ * -+ * Sets the atomic property value for a digital connector. -+ */ -+int vc4_connector_atomic_set_property(struct drm_connector *connector, -+ struct drm_connector_state *state, -+ struct drm_property *property, -+ uint64_t val) -+{ -+ struct vc4_fkms_connector *fkms_connector = -+ to_vc4_fkms_connector(connector); -+ struct vc4_fkms_connector_state *vc4_conn_state = -+ to_vc4_fkms_connector_state(state); -+ -+ if (property == fkms_connector->broadcast_rgb_property) { -+ vc4_conn_state->broadcast_rgb = val; -+ return 0; -+ } -+ -+ DRM_DEBUG_ATOMIC("Unknown property [PROP:%d:%s]\n", -+ property->base.id, property->name); -+ return -EINVAL; -+} -+ - static const struct drm_connector_funcs vc4_fkms_connector_funcs = { - .detect = vc4_fkms_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vc4_fkms_connector_destroy, -- .reset = drm_atomic_helper_connector_reset, -- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_duplicate_state = vc4_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+ .atomic_get_property = vc4_connector_atomic_get_property, -+ .atomic_set_property = vc4_connector_atomic_set_property, - }; - - static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = { -@@ -1383,12 +1501,40 @@ static const struct drm_connector_helper - .best_encoder = vc4_fkms_connector_best_encoder, - }; - -+static const struct drm_prop_enum_list broadcast_rgb_names[] = { -+ { VC4_BROADCAST_RGB_AUTO, "Automatic" }, -+ { VC4_BROADCAST_RGB_FULL, "Full" }, -+ { VC4_BROADCAST_RGB_LIMITED, "Limited 16:235" }, -+}; -+ -+static void -+vc4_attach_broadcast_rgb_property(struct vc4_fkms_connector *fkms_connector) -+{ -+ struct drm_device *dev = fkms_connector->base.dev; -+ struct drm_property *prop; -+ -+ prop = fkms_connector->broadcast_rgb_property; -+ if (!prop) { -+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, -+ "Broadcast RGB", -+ broadcast_rgb_names, -+ ARRAY_SIZE(broadcast_rgb_names)); -+ if (!prop) -+ return; -+ -+ fkms_connector->broadcast_rgb_property = prop; -+ } -+ -+ drm_object_attach_property(&fkms_connector->base.base, prop, 0); -+} -+ - static struct drm_connector * - vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder, - u32 display_num) - { - struct drm_connector *connector = NULL; - struct vc4_fkms_connector *fkms_connector; -+ struct vc4_fkms_connector_state *conn_state = NULL; - struct vc4_dev *vc4_dev = to_vc4_dev(dev); - int ret = 0; - -@@ -1397,9 +1543,18 @@ vc4_fkms_connector_init(struct drm_devic - fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector), - GFP_KERNEL); - if (!fkms_connector) { -- ret = -ENOMEM; -- goto fail; -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ /* -+ * Allocate enough memory to hold vc4_fkms_connector_state, -+ */ -+ conn_state = kzalloc(sizeof(*conn_state), GFP_KERNEL); -+ if (!conn_state) { -+ kfree(fkms_connector); -+ return ERR_PTR(-ENOMEM); - } -+ - connector = &fkms_connector->base; - - fkms_connector->encoder = encoder; -@@ -1407,6 +1562,9 @@ vc4_fkms_connector_init(struct drm_devic - fkms_connector->display_type = vc4_get_display_type(display_num); - fkms_connector->vc4_dev = vc4_dev; - -+ __drm_atomic_helper_connector_reset(connector, -+ &conn_state->base); -+ - if (fkms_connector->display_type == DRM_MODE_ENCODER_DSI) { - drm_connector_init(dev, connector, &vc4_fkms_connector_funcs, - DRM_MODE_CONNECTOR_DSI); -@@ -1427,10 +1585,14 @@ vc4_fkms_connector_init(struct drm_devic - connector->interlace_allowed = 0; - } - -- /* Create and attach TV margin props to this connector. */ -- ret = drm_mode_create_tv_margin_properties(dev); -- if (ret) -- return ERR_PTR(ret); -+ /* Create and attach TV margin props to this connector. -+ * Already done for SDTV outputs. -+ */ -+ if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) { -+ ret = drm_mode_create_tv_margin_properties(dev); -+ if (ret) -+ goto fail; -+ } - - drm_connector_attach_tv_margin_properties(connector); - -@@ -1439,6 +1601,8 @@ vc4_fkms_connector_init(struct drm_devic - - connector->doublescan_allowed = 0; - -+ vc4_attach_broadcast_rgb_property(fkms_connector); -+ - drm_connector_attach_encoder(connector, encoder); - - return connector; diff --git a/target/linux/bcm27xx/patches-5.4/950-0284-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch b/target/linux/bcm27xx/patches-5.4/950-0284-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch new file mode 100644 index 0000000000..6e4af3e38d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0284-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch @@ -0,0 +1,46 @@ +From 8ffc08d336326d576b84d59135402f08cf2cf41c Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Mon, 22 Jul 2019 22:13:30 +0800 +Subject: [PATCH] staging: bcm2835-codec: implement + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE + +The stateful decoder specification shows an optional step for retrieving +the miminum number of capture buffers required for the decoder to +proceed. While not a required parameter, having it makes some +applications happy. + +bcm2835-codec is a little different from other decoder implementations +in that there is an intermediate format conversion between the hardware +and V4L2 buffers. The number of capture buffers required is therefore +independent of the stream and DPB etc. + +There are plans to remove the conversion, but it requires a fair amount +of rework within the firmware. Until that is done, simply return a value +of 1. + +Signed-off-by: Chen-Yu Tsai +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -2357,6 +2357,18 @@ static int bcm2835_codec_open(struct fil + } + ctx->fh.ctrl_handler = hdl; + v4l2_ctrl_handler_setup(hdl); ++ } else if (dev->role == DECODE) { ++ v4l2_ctrl_handler_init(hdl, 1); ++ ++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, ++ 1, 1, 1, 1); ++ if (hdl->error) { ++ rc = hdl->error; ++ goto free_ctrl_handler; ++ } ++ ctx->fh.ctrl_handler = hdl; ++ v4l2_ctrl_handler_setup(hdl); + } + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); diff --git a/target/linux/bcm27xx/patches-5.4/950-0285-drm-vc4-fkms-Set-default-state-margin-at-reset.patch b/target/linux/bcm27xx/patches-5.4/950-0285-drm-vc4-fkms-Set-default-state-margin-at-reset.patch deleted file mode 100644 index 51664f3f98..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0285-drm-vc4-fkms-Set-default-state-margin-at-reset.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 651d4137cc20de6b64edd2302ebd82d8e88121df Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 23 Jul 2019 11:09:26 +0100 -Subject: [PATCH] drm/vc4: fkms: Set default state margin at reset - -Now that the TV margins are properly parsed and filled into -drm_cmdline_mode, we just need to initialise the first state at reset to -get those values and start using them. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -1481,10 +1481,17 @@ int vc4_connector_atomic_set_property(st - return -EINVAL; - } - -+static void vc4_hdmi_connector_reset(struct drm_connector *connector) -+{ -+ drm_atomic_helper_connector_reset(connector); -+ drm_atomic_helper_connector_tv_reset(connector); -+} -+ - static const struct drm_connector_funcs vc4_fkms_connector_funcs = { - .detect = vc4_fkms_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vc4_fkms_connector_destroy, -+ .reset = vc4_hdmi_connector_reset, - .atomic_duplicate_state = vc4_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, - .atomic_get_property = vc4_connector_atomic_get_property, diff --git a/target/linux/bcm27xx/patches-5.4/950-0285-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch b/target/linux/bcm27xx/patches-5.4/950-0285-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch new file mode 100644 index 0000000000..a194eaba14 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0285-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch @@ -0,0 +1,40 @@ +From d06677b96fc10122363028dea9ca06e5f9899865 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Mon, 22 Jul 2019 22:20:55 +0800 +Subject: [PATCH] staging: bcm2835-codec: set device_caps in struct + video_device + +Instead of filling in the struct v4l2_capability device_caps +field, fill in the struct video_device device_caps field. + +That way the V4L2 core knows what the capabilities of the +video device are. + +This is similar to a cleanup series by Hans Verkuil [1]. + +[1] https://www.spinics.net/lists/linux-media/msg153313.html + +Signed-off-by: Chen-Yu Tsai +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -945,8 +945,6 @@ static int vidioc_querycap(struct file * + strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + MEM2MEM_NAME); +- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; +- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; + } + +@@ -2600,6 +2598,7 @@ static int bcm2835_codec_create(struct p + vfd = &dev->vfd; + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; ++ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + + switch (role) { + case DECODE: diff --git a/target/linux/bcm27xx/patches-5.4/950-0286-Add-HDMI1-facility-to-the-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0286-Add-HDMI1-facility-to-the-driver.patch new file mode 100644 index 0000000000..b18d1458fd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0286-Add-HDMI1-facility-to-the-driver.patch @@ -0,0 +1,85 @@ +From fb8e73c19c2e153444b34e8d9804371095e92fe0 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Tue, 16 Jul 2019 12:18:21 +0100 +Subject: [PATCH] Add HDMI1 facility to the driver. + +For generic ALSA, all you need is the bcm2835.h change, but +have also added structures for IEC958 HDMI. Not sure how to +test those. +--- + .../vc04_services/bcm2835-audio/bcm2835.c | 29 ++++++++++++++++--- + .../vc04_services/bcm2835-audio/bcm2835.h | 4 ++- + 2 files changed, 28 insertions(+), 5 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c ++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c +@@ -79,7 +79,11 @@ static int bcm2835_audio_alsa_newpcm(str + if (err) + return err; + +- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true); ++ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true); ++ if (err) ++ return err; ++ ++ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true); + if (err) + return err; + +@@ -106,7 +110,7 @@ static struct bcm2835_audio_driver bcm28 + .newctl = snd_bcm2835_new_ctl, + }; + +-static struct bcm2835_audio_driver bcm2835_audio_hdmi = { ++static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = { + .driver = { + .name = "bcm2835_hdmi", + .owner = THIS_MODULE, +@@ -116,7 +120,20 @@ static struct bcm2835_audio_driver bcm28 + .minchannels = 1, + .newpcm = bcm2835_audio_simple_newpcm, + .newctl = snd_bcm2835_new_hdmi_ctl, +- .route = AUDIO_DEST_HDMI ++ .route = AUDIO_DEST_HDMI0 ++}; ++ ++static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = { ++ .driver = { ++ .name = "bcm2835_hdmi", ++ .owner = THIS_MODULE, ++ }, ++ .shortname = "bcm2835 HDMI 1", ++ .longname = "bcm2835 HDMI 1", ++ .minchannels = 1, ++ .newpcm = bcm2835_audio_simple_newpcm, ++ .newctl = snd_bcm2835_new_hdmi_ctl, ++ .route = AUDIO_DEST_HDMI1 + }; + + static struct bcm2835_audio_driver bcm2835_audio_headphones = { +@@ -143,7 +160,11 @@ static struct bcm2835_audio_drivers chil + .is_enabled = &enable_compat_alsa, + }, + { +- .audio_driver = &bcm2835_audio_hdmi, ++ .audio_driver = &bcm2835_audio_hdmi0, ++ .is_enabled = &enable_hdmi, ++ }, ++ { ++ .audio_driver = &bcm2835_audio_hdmi1, + .is_enabled = &enable_hdmi, + }, + { +--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h ++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h +@@ -33,7 +33,9 @@ enum { + enum snd_bcm2835_route { + AUDIO_DEST_AUTO = 0, + AUDIO_DEST_HEADPHONES = 1, +- AUDIO_DEST_HDMI = 2, ++ AUDIO_DEST_HDMI = 2, // for backwards compatibility. ++ AUDIO_DEST_HDMI0 = 2, ++ AUDIO_DEST_HDMI1 = 3, + AUDIO_DEST_MAX, + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0286-staging-bcm2835-codec-switch-to-multi-planar-API.patch b/target/linux/bcm27xx/patches-5.4/950-0286-staging-bcm2835-codec-switch-to-multi-planar-API.patch deleted file mode 100644 index c4eab3a02a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0286-staging-bcm2835-codec-switch-to-multi-planar-API.patch +++ /dev/null @@ -1,347 +0,0 @@ -From 9495e07dac5cb6230838763572f73b863cd72019 Mon Sep 17 00:00:00 2001 -From: Chen-Yu Tsai -Date: Thu, 18 Jul 2019 17:07:05 +0800 -Subject: [PATCH] staging: bcm2835-codec: switch to multi-planar API - -There are two APIs for mem2mem devices, the older single-planar API and -the newer multi-planar one. Without making things overly complex, the -driver can only support one or the other. However the userspace libv4l2 -library has a plugin that allows multi-planar API devices to service -single-planar consumers. - -Chromium supports the multi-planar API exclusively, though this is -currently limited to ChromiumOS. It would be possible to add support -for generic Linux. - -Switching to the multi-planar API would allow usage of both APIs from -userspace. - -Signed-off-by: Chen-Yu Tsai ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 141 +++++++++--------- - 1 file changed, 74 insertions(+), 67 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -504,7 +504,7 @@ static struct bcm2835_codec_fmt *find_fo - - for (k = 0; k < fmts->num_entries; k++) { - fmt = &fmts->list[k]; -- if (fmt->fourcc == f->fmt.pix.pixelformat) -+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat) - break; - } - if (k == fmts->num_entries) -@@ -522,9 +522,9 @@ static struct bcm2835_codec_q_data *get_ - enum v4l2_buf_type type) - { - switch (type) { -- case V4L2_BUF_TYPE_VIDEO_OUTPUT: -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return &ctx->q_data[V4L2_M2M_SRC]; -- case V4L2_BUF_TYPE_VIDEO_CAPTURE: -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return &ctx->q_data[V4L2_M2M_DST]; - default: - v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", -@@ -541,9 +541,9 @@ static struct vchiq_mmal_port *get_port_ - return NULL; - - switch (type) { -- case V4L2_BUF_TYPE_VIDEO_OUTPUT: -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return &ctx->component->input[0]; -- case V4L2_BUF_TYPE_VIDEO_CAPTURE: -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return &ctx->component->output[0]; - default: - v4l2_err(&ctx->dev->v4l2_dev, "%s: Invalid queue type %u\n", -@@ -752,7 +752,7 @@ static void handle_fmt_changed(struct bc - format->es.video.crop.width, format->es.video.crop.height, - format->es.video.color_space); - -- q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); -+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - q_data->crop_width = format->es.video.crop.width; - q_data->crop_height = format->es.video.crop.height; - q_data->bytesperline = format->es.video.crop.width; -@@ -945,7 +945,7 @@ static int vidioc_querycap(struct file * - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - MEM2MEM_NAME); -- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; -+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; - } -@@ -996,16 +996,20 @@ static int vidioc_g_fmt(struct bcm2835_c - - q_data = get_q_data(ctx, f->type); - -- f->fmt.pix.width = q_data->crop_width; -- f->fmt.pix.height = q_data->height; -- f->fmt.pix.field = V4L2_FIELD_NONE; -- f->fmt.pix.pixelformat = q_data->fmt->fourcc; -- f->fmt.pix.bytesperline = q_data->bytesperline; -- f->fmt.pix.sizeimage = q_data->sizeimage; -- f->fmt.pix.colorspace = ctx->colorspace; -- f->fmt.pix.xfer_func = ctx->xfer_func; -- f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; -- f->fmt.pix.quantization = ctx->quant; -+ f->fmt.pix_mp.width = q_data->crop_width; -+ f->fmt.pix_mp.height = q_data->height; -+ f->fmt.pix_mp.pixelformat = q_data->fmt->fourcc; -+ f->fmt.pix_mp.field = V4L2_FIELD_NONE; -+ f->fmt.pix_mp.colorspace = ctx->colorspace; -+ f->fmt.pix_mp.plane_fmt[0].sizeimage = q_data->sizeimage; -+ f->fmt.pix_mp.plane_fmt[0].bytesperline = q_data->bytesperline; -+ f->fmt.pix_mp.num_planes = 1; -+ f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; -+ f->fmt.pix_mp.quantization = ctx->quant; -+ f->fmt.pix_mp.xfer_func = ctx->xfer_func; -+ -+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0, -+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved)); - - return 0; - } -@@ -1029,17 +1033,17 @@ static int vidioc_try_fmt(struct bcm2835 - * The V4L2 specification requires the driver to correct the format - * struct if any of the dimensions is unsupported - */ -- if (f->fmt.pix.width > MAX_W) -- f->fmt.pix.width = MAX_W; -- if (f->fmt.pix.height > MAX_H) -- f->fmt.pix.height = MAX_H; -+ if (f->fmt.pix_mp.width > MAX_W) -+ f->fmt.pix_mp.width = MAX_W; -+ if (f->fmt.pix_mp.height > MAX_H) -+ f->fmt.pix_mp.height = MAX_H; - - if (!fmt->flags & V4L2_FMT_FLAG_COMPRESSED) { - /* Only clip min w/h on capture. Treat 0x0 as unknown. */ -- if (f->fmt.pix.width < MIN_W) -- f->fmt.pix.width = MIN_W; -- if (f->fmt.pix.height < MIN_H) -- f->fmt.pix.height = MIN_H; -+ if (f->fmt.pix_mp.width < MIN_W) -+ f->fmt.pix_mp.width = MIN_W; -+ if (f->fmt.pix_mp.height < MIN_H) -+ f->fmt.pix_mp.height = MIN_H; - - /* - * For codecs the buffer must have a vertical alignment of 16 -@@ -1048,16 +1052,18 @@ static int vidioc_try_fmt(struct bcm2835 - * some of the pixels are active. - */ - if (ctx->dev->role != ISP) -- f->fmt.pix.height = ALIGN(f->fmt.pix.height, 16); -+ f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16); - } -- f->fmt.pix.bytesperline = get_bytesperline(f->fmt.pix.width, -- fmt); -- f->fmt.pix.sizeimage = get_sizeimage(f->fmt.pix.bytesperline, -- f->fmt.pix.width, -- f->fmt.pix.height, -- fmt); -+ f->fmt.pix_mp.num_planes = 1; -+ f->fmt.pix_mp.plane_fmt[0].bytesperline = -+ get_bytesperline(f->fmt.pix_mp.width, fmt); -+ f->fmt.pix_mp.plane_fmt[0].sizeimage = -+ get_sizeimage(f->fmt.pix_mp.plane_fmt[0].bytesperline, -+ f->fmt.pix_mp.width, f->fmt.pix_mp.height, fmt); -+ memset(f->fmt.pix_mp.plane_fmt[0].reserved, 0, -+ sizeof(f->fmt.pix_mp.plane_fmt[0].reserved)); - -- f->fmt.pix.field = V4L2_FIELD_NONE; -+ f->fmt.pix_mp.field = V4L2_FIELD_NONE; - - return 0; - } -@@ -1070,8 +1076,8 @@ static int vidioc_try_fmt_vid_cap(struct - - fmt = find_format(f, ctx->dev, true); - if (!fmt) { -- f->fmt.pix.pixelformat = get_default_format(ctx->dev, -- true)->fourcc; -+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev, -+ true)->fourcc; - fmt = find_format(f, ctx->dev, true); - } - -@@ -1086,13 +1092,13 @@ static int vidioc_try_fmt_vid_out(struct - - fmt = find_format(f, ctx->dev, false); - if (!fmt) { -- f->fmt.pix.pixelformat = get_default_format(ctx->dev, -- false)->fourcc; -+ f->fmt.pix_mp.pixelformat = get_default_format(ctx->dev, -+ false)->fourcc; - fmt = find_format(f, ctx->dev, false); - } - -- if (!f->fmt.pix.colorspace) -- f->fmt.pix.colorspace = ctx->colorspace; -+ if (!f->fmt.pix_mp.colorspace) -+ f->fmt.pix_mp.colorspace = ctx->colorspace; - - return vidioc_try_fmt(ctx, f, fmt); - } -@@ -1106,9 +1112,10 @@ static int vidioc_s_fmt(struct bcm2835_c - bool update_capture_port = false; - int ret; - -- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", -- f->type, f->fmt.pix.width, f->fmt.pix.height, -- f->fmt.pix.pixelformat, f->fmt.pix.sizeimage); -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", -+ f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height, -+ f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage); -+ - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) -@@ -1124,9 +1131,9 @@ static int vidioc_s_fmt(struct bcm2835_c - } - - q_data->fmt = find_format(f, ctx->dev, -- f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); -- q_data->crop_width = f->fmt.pix.width; -- q_data->height = f->fmt.pix.height; -+ f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); -+ q_data->crop_width = f->fmt.pix_mp.width; -+ q_data->height = f->fmt.pix_mp.height; - if (!q_data->selection_set) - q_data->crop_height = requested_height; - -@@ -1134,21 +1141,21 @@ static int vidioc_s_fmt(struct bcm2835_c - * Copying the behaviour of vicodec which retains a single set of - * colorspace parameters for both input and output. - */ -- ctx->colorspace = f->fmt.pix.colorspace; -- ctx->xfer_func = f->fmt.pix.xfer_func; -- ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; -- ctx->quant = f->fmt.pix.quantization; -+ ctx->colorspace = f->fmt.pix_mp.colorspace; -+ ctx->xfer_func = f->fmt.pix_mp.xfer_func; -+ ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; -+ ctx->quant = f->fmt.pix_mp.quantization; - - /* All parameters should have been set correctly by try_fmt */ -- q_data->bytesperline = f->fmt.pix.bytesperline; -- q_data->sizeimage = f->fmt.pix.sizeimage; -+ q_data->bytesperline = f->fmt.pix_mp.plane_fmt[0].bytesperline; -+ q_data->sizeimage = f->fmt.pix_mp.plane_fmt[0].sizeimage; - - v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Calulated bpl as %u, size %u\n", - q_data->bytesperline, q_data->sizeimage); - - if (ctx->dev->role == DECODE && - q_data->fmt->flags & V4L2_FMT_FLAG_COMPRESSED && -- f->fmt.pix.width && f->fmt.pix.height) { -+ q_data->crop_width && q_data->height) { - /* - * On the decoder, if provided with a resolution on the input - * side, then replicate that to the output side. -@@ -1165,7 +1172,7 @@ static int vidioc_s_fmt(struct bcm2835_c - q_data_dst->height = ALIGN(q_data->crop_height, 16); - - q_data_dst->bytesperline = -- get_bytesperline(f->fmt.pix.width, q_data_dst->fmt); -+ get_bytesperline(f->fmt.pix_mp.width, q_data_dst->fmt); - q_data_dst->sizeimage = get_sizeimage(q_data_dst->bytesperline, - q_data_dst->crop_width, - q_data_dst->height, -@@ -1215,7 +1222,7 @@ static int vidioc_s_fmt(struct bcm2835_c - static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) - { -- unsigned int height = f->fmt.pix.height; -+ unsigned int height = f->fmt.pix_mp.height; - int ret; - - ret = vidioc_try_fmt_vid_cap(file, priv, f); -@@ -1228,7 +1235,7 @@ static int vidioc_s_fmt_vid_cap(struct f - static int vidioc_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) - { -- unsigned int height = f->fmt.pix.height; -+ unsigned int height = f->fmt.pix_mp.height; - int ret; - - ret = vidioc_try_fmt_vid_out(file, priv, f); -@@ -1244,7 +1251,7 @@ static int vidioc_g_selection(struct fil - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - struct bcm2835_codec_q_data *q_data; -- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? -+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? - true : false; - - if ((ctx->dev->role == DECODE && !capture_queue) || -@@ -1307,7 +1314,7 @@ static int vidioc_s_selection(struct fil - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - struct bcm2835_codec_q_data *q_data = NULL; -- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? -+ bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? - true : false; - - v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n", -@@ -1368,7 +1375,7 @@ static int vidioc_s_parm(struct file *fi - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return -EINVAL; - - ctx->framerate_num = -@@ -1739,14 +1746,14 @@ static const struct v4l2_ioctl_ops bcm28 - .vidioc_querycap = vidioc_querycap, - - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, -- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, -- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, -- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, -+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, -+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, -+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, - - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, -- .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, -- .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, -- .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, -+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, -+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, -+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, -@@ -2089,7 +2096,7 @@ static int bcm2835_codec_start_streaming - ctx->component_enabled = true; - } - -- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { -+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - /* - * Create the EOS buffer. - * We only need the MMAL part, and want to NOT attach a memory -@@ -2216,7 +2223,7 @@ static int queue_init(void *priv, struct - struct bcm2835_codec_ctx *ctx = priv; - int ret; - -- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; -+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); -@@ -2230,7 +2237,7 @@ static int queue_init(void *priv, struct - if (ret) - return ret; - -- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->buf_struct_size = sizeof(struct m2m_mmal_buffer); diff --git a/target/linux/bcm27xx/patches-5.4/950-0287-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch b/target/linux/bcm27xx/patches-5.4/950-0287-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch new file mode 100644 index 0000000000..e50bdee8ae --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0287-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch @@ -0,0 +1,100 @@ +From a82d716ab4c2ab5f198f3461e32614defb52c724 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 25 Jul 2019 17:27:44 +0100 +Subject: [PATCH] drm/vc4: Resolve the vblank warnings on mode + switching + +The details over when and how a driver is to service the +vblank events are sketchy, and the fkms driver was triggering +a kernel warning every time the crtc was enabled or disabled. + +Copy the event handling as used by the vc4-kms driver slightly +more closely, and we avoid the warnings. + +https://github.com/raspberrypi/linux/issues/3020 + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 15 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -964,6 +964,7 @@ static void vc4_crtc_mode_set_nofb(struc + + static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) + { ++ struct drm_device *dev = crtc->dev; + struct drm_plane *plane; + + DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n", +@@ -979,6 +980,35 @@ static void vc4_crtc_disable(struct drm_ + + drm_atomic_crtc_for_each_plane(plane, crtc) + vc4_plane_atomic_disable(plane, plane->state); ++ ++ /* ++ * Make sure we issue a vblank event after disabling the CRTC if ++ * someone was waiting it. ++ */ ++ if (crtc->state->event) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ drm_crtc_send_vblank_event(crtc, crtc->state->event); ++ crtc->state->event = NULL; ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ } ++} ++ ++static void vc4_crtc_consume_event(struct drm_crtc *crtc) ++{ ++ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ unsigned long flags; ++ ++ crtc->state->event->pipe = drm_crtc_index(crtc); ++ ++ WARN_ON(drm_crtc_vblank_get(crtc) != 0); ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ vc4_crtc->event = crtc->state->event; ++ crtc->state->event = NULL; ++ spin_unlock_irqrestore(&dev->event_lock, flags); + } + + static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) +@@ -988,6 +1018,7 @@ static void vc4_crtc_enable(struct drm_c + DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n", + crtc->base.id); + drm_crtc_vblank_on(crtc); ++ vc4_crtc_consume_event(crtc); + + /* Unblank the planes (if they're supposed to be displayed). */ + drm_atomic_crtc_for_each_plane(plane, crtc) +@@ -1059,23 +1090,10 @@ static int vc4_crtc_atomic_check(struct + static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) + { +- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); +- struct drm_device *dev = crtc->dev; +- + DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n", + crtc->base.id); +- if (crtc->state->event) { +- unsigned long flags; +- +- crtc->state->event->pipe = drm_crtc_index(crtc); +- +- WARN_ON(drm_crtc_vblank_get(crtc) != 0); +- +- spin_lock_irqsave(&dev->event_lock, flags); +- vc4_crtc->event = crtc->state->event; +- crtc->state->event = NULL; +- spin_unlock_irqrestore(&dev->event_lock, flags); +- } ++ if (crtc->state->active && old_state->active && crtc->state->event) ++ vc4_crtc_consume_event(crtc); + } + + static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) diff --git a/target/linux/bcm27xx/patches-5.4/950-0287-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch b/target/linux/bcm27xx/patches-5.4/950-0287-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch deleted file mode 100644 index 6e4af3e38d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0287-staging-bcm2835-codec-implement-V4L2_CID_MIN_BUFFERS.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 8ffc08d336326d576b84d59135402f08cf2cf41c Mon Sep 17 00:00:00 2001 -From: Chen-Yu Tsai -Date: Mon, 22 Jul 2019 22:13:30 +0800 -Subject: [PATCH] staging: bcm2835-codec: implement - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE - -The stateful decoder specification shows an optional step for retrieving -the miminum number of capture buffers required for the decoder to -proceed. While not a required parameter, having it makes some -applications happy. - -bcm2835-codec is a little different from other decoder implementations -in that there is an intermediate format conversion between the hardware -and V4L2 buffers. The number of capture buffers required is therefore -independent of the stream and DPB etc. - -There are plans to remove the conversion, but it requires a fair amount -of rework within the firmware. Until that is done, simply return a value -of 1. - -Signed-off-by: Chen-Yu Tsai ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -2357,6 +2357,18 @@ static int bcm2835_codec_open(struct fil - } - ctx->fh.ctrl_handler = hdl; - v4l2_ctrl_handler_setup(hdl); -+ } else if (dev->role == DECODE) { -+ v4l2_ctrl_handler_init(hdl, 1); -+ -+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, -+ 1, 1, 1, 1); -+ if (hdl->error) { -+ rc = hdl->error; -+ goto free_ctrl_handler; -+ } -+ ctx->fh.ctrl_handler = hdl; -+ v4l2_ctrl_handler_setup(hdl); - } - - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); diff --git a/target/linux/bcm27xx/patches-5.4/950-0288-drm-vc4-Remove-unused-mode-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0288-drm-vc4-Remove-unused-mode-variable.patch new file mode 100644 index 0000000000..e82fc421d2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0288-drm-vc4-Remove-unused-mode-variable.patch @@ -0,0 +1,27 @@ +From 71402ae2a97b18f0c03b763a2e1e2800f360d50a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 25 Jul 2019 17:34:29 +0100 +Subject: [PATCH] drm/vc4: Remove unused mode variable + +"89d1376 drm/vc4: Add support for margins to fkms" removed +the requirement for having the mode structure from vc4_plane_to_mb, +but didn't remove it as a local to the function, causing a +compiler warning. + +Remove the unused variable. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -525,7 +525,6 @@ static int vc4_plane_to_mb(struct drm_pl + const struct vc_image_format *vc_fmt = + vc4_get_vc_image_fmt(drm_fmt->format); + int num_planes = fb->format->num_planes; +- struct drm_display_mode *mode = &state->crtc->mode; + unsigned int rotation = SUPPORTED_ROTATIONS; + + mb->plane.vc_image_type = vc_fmt->vc_image; diff --git a/target/linux/bcm27xx/patches-5.4/950-0288-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch b/target/linux/bcm27xx/patches-5.4/950-0288-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch deleted file mode 100644 index a194eaba14..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0288-staging-bcm2835-codec-set-device_caps-in-struct-vide.patch +++ /dev/null @@ -1,40 +0,0 @@ -From d06677b96fc10122363028dea9ca06e5f9899865 Mon Sep 17 00:00:00 2001 -From: Chen-Yu Tsai -Date: Mon, 22 Jul 2019 22:20:55 +0800 -Subject: [PATCH] staging: bcm2835-codec: set device_caps in struct - video_device - -Instead of filling in the struct v4l2_capability device_caps -field, fill in the struct video_device device_caps field. - -That way the V4L2 core knows what the capabilities of the -video device are. - -This is similar to a cleanup series by Hans Verkuil [1]. - -[1] https://www.spinics.net/lists/linux-media/msg153313.html - -Signed-off-by: Chen-Yu Tsai ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -945,8 +945,6 @@ static int vidioc_querycap(struct file * - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - MEM2MEM_NAME); -- cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; -- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; - } - -@@ -2600,6 +2598,7 @@ static int bcm2835_codec_create(struct p - vfd = &dev->vfd; - vfd->lock = &dev->dev_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; -+ vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - - switch (role) { - case DECODE: diff --git a/target/linux/bcm27xx/patches-5.4/950-0289-Add-HDMI1-facility-to-the-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0289-Add-HDMI1-facility-to-the-driver.patch deleted file mode 100644 index b18d1458fd..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0289-Add-HDMI1-facility-to-the-driver.patch +++ /dev/null @@ -1,85 +0,0 @@ -From fb8e73c19c2e153444b34e8d9804371095e92fe0 Mon Sep 17 00:00:00 2001 -From: James Hughes -Date: Tue, 16 Jul 2019 12:18:21 +0100 -Subject: [PATCH] Add HDMI1 facility to the driver. - -For generic ALSA, all you need is the bcm2835.h change, but -have also added structures for IEC958 HDMI. Not sure how to -test those. ---- - .../vc04_services/bcm2835-audio/bcm2835.c | 29 ++++++++++++++++--- - .../vc04_services/bcm2835-audio/bcm2835.h | 4 ++- - 2 files changed, 28 insertions(+), 5 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -@@ -79,7 +79,11 @@ static int bcm2835_audio_alsa_newpcm(str - if (err) - return err; - -- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true); -+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true); -+ if (err) -+ return err; -+ -+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true); - if (err) - return err; - -@@ -106,7 +110,7 @@ static struct bcm2835_audio_driver bcm28 - .newctl = snd_bcm2835_new_ctl, - }; - --static struct bcm2835_audio_driver bcm2835_audio_hdmi = { -+static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = { - .driver = { - .name = "bcm2835_hdmi", - .owner = THIS_MODULE, -@@ -116,7 +120,20 @@ static struct bcm2835_audio_driver bcm28 - .minchannels = 1, - .newpcm = bcm2835_audio_simple_newpcm, - .newctl = snd_bcm2835_new_hdmi_ctl, -- .route = AUDIO_DEST_HDMI -+ .route = AUDIO_DEST_HDMI0 -+}; -+ -+static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = { -+ .driver = { -+ .name = "bcm2835_hdmi", -+ .owner = THIS_MODULE, -+ }, -+ .shortname = "bcm2835 HDMI 1", -+ .longname = "bcm2835 HDMI 1", -+ .minchannels = 1, -+ .newpcm = bcm2835_audio_simple_newpcm, -+ .newctl = snd_bcm2835_new_hdmi_ctl, -+ .route = AUDIO_DEST_HDMI1 - }; - - static struct bcm2835_audio_driver bcm2835_audio_headphones = { -@@ -143,7 +160,11 @@ static struct bcm2835_audio_drivers chil - .is_enabled = &enable_compat_alsa, - }, - { -- .audio_driver = &bcm2835_audio_hdmi, -+ .audio_driver = &bcm2835_audio_hdmi0, -+ .is_enabled = &enable_hdmi, -+ }, -+ { -+ .audio_driver = &bcm2835_audio_hdmi1, - .is_enabled = &enable_hdmi, - }, - { ---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h -+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h -@@ -33,7 +33,9 @@ enum { - enum snd_bcm2835_route { - AUDIO_DEST_AUTO = 0, - AUDIO_DEST_HEADPHONES = 1, -- AUDIO_DEST_HDMI = 2, -+ AUDIO_DEST_HDMI = 2, // for backwards compatibility. -+ AUDIO_DEST_HDMI0 = 2, -+ AUDIO_DEST_HDMI1 = 3, - AUDIO_DEST_MAX, - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0289-staging-bcm2835-codec-Expand-logging-on-format-setti.patch b/target/linux/bcm27xx/patches-5.4/950-0289-staging-bcm2835-codec-Expand-logging-on-format-setti.patch new file mode 100644 index 0000000000..d2ebeea7f7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0289-staging-bcm2835-codec-Expand-logging-on-format-setti.patch @@ -0,0 +1,42 @@ +From cedd3e7ee97213d0d3d0ada2a7df58ad0059372e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 11 Jul 2019 14:57:09 +0100 +Subject: [PATCH] staging:bcm2835-codec: Expand logging on format + setting + +Adds some more useful logging during format changed events and +s_fmt. + +Reported by: zillevdr +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -753,6 +753,10 @@ static void handle_fmt_changed(struct bc + format->es.video.color_space); + + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format was %ux%u, crop %ux%u\n", ++ __func__, q_data->bytesperline, q_data->height, ++ q_data->crop_width, q_data->crop_height); ++ + q_data->crop_width = format->es.video.crop.width; + q_data->crop_height = format->es.video.crop.height; + q_data->bytesperline = format->es.video.crop.width; +@@ -1110,10 +1114,10 @@ static int vidioc_s_fmt(struct bcm2835_c + bool update_capture_port = false; + int ret; + +- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", ++ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: " V4L2_FOURCC_CONV ", size %u\n", + f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height, +- f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage); +- ++ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat), ++ f->fmt.pix_mp.plane_fmt[0].sizeimage); + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) diff --git a/target/linux/bcm27xx/patches-5.4/950-0290-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch b/target/linux/bcm27xx/patches-5.4/950-0290-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch deleted file mode 100644 index e50bdee8ae..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0290-drm-vc4-Resolve-the-vblank-warnings-on-mode-switchin.patch +++ /dev/null @@ -1,100 +0,0 @@ -From a82d716ab4c2ab5f198f3461e32614defb52c724 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 25 Jul 2019 17:27:44 +0100 -Subject: [PATCH] drm/vc4: Resolve the vblank warnings on mode - switching - -The details over when and how a driver is to service the -vblank events are sketchy, and the fkms driver was triggering -a kernel warning every time the crtc was enabled or disabled. - -Copy the event handling as used by the vc4-kms driver slightly -more closely, and we avoid the warnings. - -https://github.com/raspberrypi/linux/issues/3020 - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 48 ++++++++++++++++++-------- - 1 file changed, 33 insertions(+), 15 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -964,6 +964,7 @@ static void vc4_crtc_mode_set_nofb(struc - - static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) - { -+ struct drm_device *dev = crtc->dev; - struct drm_plane *plane; - - DRM_DEBUG_KMS("[CRTC:%d] vblanks off.\n", -@@ -979,6 +980,35 @@ static void vc4_crtc_disable(struct drm_ - - drm_atomic_crtc_for_each_plane(plane, crtc) - vc4_plane_atomic_disable(plane, plane->state); -+ -+ /* -+ * Make sure we issue a vblank event after disabling the CRTC if -+ * someone was waiting it. -+ */ -+ if (crtc->state->event) { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ drm_crtc_send_vblank_event(crtc, crtc->state->event); -+ crtc->state->event = NULL; -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ } -+} -+ -+static void vc4_crtc_consume_event(struct drm_crtc *crtc) -+{ -+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -+ struct drm_device *dev = crtc->dev; -+ unsigned long flags; -+ -+ crtc->state->event->pipe = drm_crtc_index(crtc); -+ -+ WARN_ON(drm_crtc_vblank_get(crtc) != 0); -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ vc4_crtc->event = crtc->state->event; -+ crtc->state->event = NULL; -+ spin_unlock_irqrestore(&dev->event_lock, flags); - } - - static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) -@@ -988,6 +1018,7 @@ static void vc4_crtc_enable(struct drm_c - DRM_DEBUG_KMS("[CRTC:%d] vblanks on.\n", - crtc->base.id); - drm_crtc_vblank_on(crtc); -+ vc4_crtc_consume_event(crtc); - - /* Unblank the planes (if they're supposed to be displayed). */ - drm_atomic_crtc_for_each_plane(plane, crtc) -@@ -1059,23 +1090,10 @@ static int vc4_crtc_atomic_check(struct - static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) - { -- struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); -- struct drm_device *dev = crtc->dev; -- - DRM_DEBUG_KMS("[CRTC:%d] crtc_atomic_flush.\n", - crtc->base.id); -- if (crtc->state->event) { -- unsigned long flags; -- -- crtc->state->event->pipe = drm_crtc_index(crtc); -- -- WARN_ON(drm_crtc_vblank_get(crtc) != 0); -- -- spin_lock_irqsave(&dev->event_lock, flags); -- vc4_crtc->event = crtc->state->event; -- crtc->state->event = NULL; -- spin_unlock_irqrestore(&dev->event_lock, flags); -- } -+ if (crtc->state->active && old_state->active && crtc->state->event) -+ vc4_crtc_consume_event(crtc); - } - - static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) diff --git a/target/linux/bcm27xx/patches-5.4/950-0290-staging-bcm2835-codec-Correct-bytesperline-on-format.patch b/target/linux/bcm27xx/patches-5.4/950-0290-staging-bcm2835-codec-Correct-bytesperline-on-format.patch new file mode 100644 index 0000000000..eaba48466a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0290-staging-bcm2835-codec-Correct-bytesperline-on-format.patch @@ -0,0 +1,30 @@ +From eb4cbf0e6893397f00aff0f90dc9d3df75e98b52 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Thu, 11 Jul 2019 14:58:35 +0100 +Subject: [PATCH] staging: bcm2835-codec: Correct bytesperline on + format changed + +The handling of format changed events incorrectly set bytesperline +to the cropped width, which ignored padding and formats with +more than 8bpp. +Fix these. + +Reported by: zillevdr +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -759,7 +759,9 @@ static void handle_fmt_changed(struct bc + + q_data->crop_width = format->es.video.crop.width; + q_data->crop_height = format->es.video.crop.height; +- q_data->bytesperline = format->es.video.crop.width; ++ q_data->bytesperline = get_bytesperline(format->es.video.width, ++ q_data->fmt); ++ + q_data->height = format->es.video.height; + q_data->sizeimage = format->buffer_size_min; + if (format->es.video.color_space) diff --git a/target/linux/bcm27xx/patches-5.4/950-0291-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch b/target/linux/bcm27xx/patches-5.4/950-0291-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch new file mode 100644 index 0000000000..f29ba4dc5d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0291-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch @@ -0,0 +1,28 @@ +From e2e9da35d4a598490b73da41eea1db27540339fd Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 7 Aug 2019 11:31:08 +0100 +Subject: [PATCH] drm/vc4: Add missing NULL check to + vc4_crtc_consume_event + +vc4_crtc_consume_event wasn't checking crtc->state->event was +set before dereferencing it, leading to an OOPS. + +Fixes "a5b534b drm/vc4: Resolve the vblank warnings on mode switching" + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -1000,6 +1000,9 @@ static void vc4_crtc_consume_event(struc + struct drm_device *dev = crtc->dev; + unsigned long flags; + ++ if (!crtc->state->event) ++ return; ++ + crtc->state->event->pipe = drm_crtc_index(crtc); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); diff --git a/target/linux/bcm27xx/patches-5.4/950-0291-drm-vc4-Remove-unused-mode-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0291-drm-vc4-Remove-unused-mode-variable.patch deleted file mode 100644 index e82fc421d2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0291-drm-vc4-Remove-unused-mode-variable.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 71402ae2a97b18f0c03b763a2e1e2800f360d50a Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 25 Jul 2019 17:34:29 +0100 -Subject: [PATCH] drm/vc4: Remove unused mode variable - -"89d1376 drm/vc4: Add support for margins to fkms" removed -the requirement for having the mode structure from vc4_plane_to_mb, -but didn't remove it as a local to the function, causing a -compiler warning. - -Remove the unused variable. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 1 - - 1 file changed, 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -525,7 +525,6 @@ static int vc4_plane_to_mb(struct drm_pl - const struct vc_image_format *vc_fmt = - vc4_get_vc_image_fmt(drm_fmt->format); - int num_planes = fb->format->num_planes; -- struct drm_display_mode *mode = &state->crtc->mode; - unsigned int rotation = SUPPORTED_ROTATIONS; - - mb->plane.vc_image_type = vc_fmt->vc_image; diff --git a/target/linux/bcm27xx/patches-5.4/950-0292-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch b/target/linux/bcm27xx/patches-5.4/950-0292-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch new file mode 100644 index 0000000000..db1866d6e7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0292-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch @@ -0,0 +1,52 @@ +From 128e363e406841fbbd9800199cb093b4737d7cba Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 9 Aug 2019 08:51:43 +0100 +Subject: [PATCH] net: bcmgenet: Workaround #2 for Pi4 Ethernet fail + +Some combinations of Pi 4Bs and Ethernet switches don't reliably get a +DCHP-assigned IP address, leaving the unit with a self=assigned 169.254 +address. In the failure case, the Pi is left able to receive packets +but not send them, suggesting that the MAC<->PHY link is getting into +a bad state. + +It has been found empirically that skipping a reset step by the genet +driver prevents the failures. No downsides have been discovered yet, +and unlike the forced renegotiation it doesn't increase the time to +get an IP address, so the workaround is enabled by default; add + + genet.skip_umac_reset=n + +to the command line to disable it. + +See: https://github.com/raspberrypi/linux/issues/3108 + +Signed-off-by: Phil Elwell +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -72,6 +72,10 @@ + /* Forward declarations */ + static void bcmgenet_set_rx_mode(struct net_device *dev); + ++static bool skip_umac_reset = true; ++module_param(skip_umac_reset, bool, 0444); ++MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step"); ++ + static inline void bcmgenet_writel(u32 value, void __iomem *offset) + { + /* MIPS chips strapped for BE will automagically configure the +@@ -1995,6 +1999,11 @@ static void reset_umac(struct bcmgenet_p + bcmgenet_rbuf_ctrl_set(priv, 0); + udelay(10); + ++ if (skip_umac_reset) { ++ pr_warn("Skipping UMAC reset\n"); ++ return; ++ } ++ + /* disable MAC while updating its registers */ + bcmgenet_umac_writel(priv, 0, UMAC_CMD); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0292-staging-bcm2835-codec-Expand-logging-on-format-setti.patch b/target/linux/bcm27xx/patches-5.4/950-0292-staging-bcm2835-codec-Expand-logging-on-format-setti.patch deleted file mode 100644 index d2ebeea7f7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0292-staging-bcm2835-codec-Expand-logging-on-format-setti.patch +++ /dev/null @@ -1,42 +0,0 @@ -From cedd3e7ee97213d0d3d0ada2a7df58ad0059372e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 11 Jul 2019 14:57:09 +0100 -Subject: [PATCH] staging:bcm2835-codec: Expand logging on format - setting - -Adds some more useful logging during format changed events and -s_fmt. - -Reported by: zillevdr -Signed-off-by: Dave Stevenson ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -753,6 +753,10 @@ static void handle_fmt_changed(struct bc - format->es.video.color_space); - - q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: Format was %ux%u, crop %ux%u\n", -+ __func__, q_data->bytesperline, q_data->height, -+ q_data->crop_width, q_data->crop_height); -+ - q_data->crop_width = format->es.video.crop.width; - q_data->crop_height = format->es.video.crop.height; - q_data->bytesperline = format->es.video.crop.width; -@@ -1110,10 +1114,10 @@ static int vidioc_s_fmt(struct bcm2835_c - bool update_capture_port = false; - int ret; - -- v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %08x, size %u\n", -+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: " V4L2_FOURCC_CONV ", size %u\n", - f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height, -- f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.plane_fmt[0].sizeimage); -- -+ V4L2_FOURCC_CONV_ARGS(f->fmt.pix_mp.pixelformat), -+ f->fmt.pix_mp.plane_fmt[0].sizeimage); - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) diff --git a/target/linux/bcm27xx/patches-5.4/950-0293-staging-bcm2835-codec-Correct-bytesperline-on-format.patch b/target/linux/bcm27xx/patches-5.4/950-0293-staging-bcm2835-codec-Correct-bytesperline-on-format.patch deleted file mode 100644 index eaba48466a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0293-staging-bcm2835-codec-Correct-bytesperline-on-format.patch +++ /dev/null @@ -1,30 +0,0 @@ -From eb4cbf0e6893397f00aff0f90dc9d3df75e98b52 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Thu, 11 Jul 2019 14:58:35 +0100 -Subject: [PATCH] staging: bcm2835-codec: Correct bytesperline on - format changed - -The handling of format changed events incorrectly set bytesperline -to the cropped width, which ignored padding and formats with -more than 8bpp. -Fix these. - -Reported by: zillevdr -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -759,7 +759,9 @@ static void handle_fmt_changed(struct bc - - q_data->crop_width = format->es.video.crop.width; - q_data->crop_height = format->es.video.crop.height; -- q_data->bytesperline = format->es.video.crop.width; -+ q_data->bytesperline = get_bytesperline(format->es.video.width, -+ q_data->fmt); -+ - q_data->height = format->es.video.height; - q_data->sizeimage = format->buffer_size_min; - if (format->es.video.color_space) diff --git a/target/linux/bcm27xx/patches-5.4/950-0293-xhci-Use-more-event-ring-segment-table-entries.patch b/target/linux/bcm27xx/patches-5.4/950-0293-xhci-Use-more-event-ring-segment-table-entries.patch new file mode 100644 index 0000000000..4b4766f739 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0293-xhci-Use-more-event-ring-segment-table-entries.patch @@ -0,0 +1,60 @@ +From 90c56c8f52c912aa6e990e63d953b6dbccea7250 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 13 Aug 2019 15:53:29 +0100 +Subject: [PATCH] xhci: Use more event ring segment table entries + +Users have reported log spam created by "Event Ring Full" xHC event +TRBs. These are caused by interrupt latency in conjunction with a very +busy set of devices on the bus. The errors are benign, but throughput +will suffer as the xHC will pause processing of transfers until the +event ring is drained by the kernel. Expand the number of event TRB slots +available by increasing the number of event ring segments in the ERST. + +Controllers have a hardware-defined limit as to the number of ERST +entries they can process, so make the actual number in use +min(ERST_MAX_SEGS, hw_max). + +Signed-off-by: Jonathan Bell +--- + drivers/usb/host/xhci-mem.c | 8 +++++--- + drivers/usb/host/xhci.h | 4 ++-- + 2 files changed, 7 insertions(+), 5 deletions(-) + +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -2503,9 +2503,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, + * Event ring setup: Allocate a normal ring, but also setup + * the event ring segment table (ERST). Section 4.9.3. + */ ++ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2); ++ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring"); +- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, +- 0, flags); ++ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT, ++ 0, flags); + if (!xhci->event_ring) + goto fail; + if (xhci_check_trb_in_td_math(xhci) < 0) +@@ -2518,7 +2520,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, + /* set ERST count with the number of entries in the segment table */ + val = readl(&xhci->ir_set->erst_size); + val &= ERST_SIZE_MASK; +- val |= ERST_NUM_SEGS; ++ val |= val2; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Write ERST size = %i to ir_set 0 (some bits preserved)", + val); +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1649,8 +1649,8 @@ struct urb_priv { + * Each segment table entry is 4*32bits long. 1K seems like an ok size: + * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, + * meaning 64 ring segments. +- * Initial allocated size of the ERST, in number of entries */ +-#define ERST_NUM_SEGS 1 ++ * Maximum number of segments in the ERST */ ++#define ERST_MAX_SEGS 8 + /* Initial allocated size of the ERST, in number of entries */ + #define ERST_SIZE 64 + /* Initial number of event segment rings allocated */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0294-configs-arm64-bcm2711-Enable-V3D.patch b/target/linux/bcm27xx/patches-5.4/950-0294-configs-arm64-bcm2711-Enable-V3D.patch new file mode 100644 index 0000000000..f079fcf9ac --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0294-configs-arm64-bcm2711-Enable-V3D.patch @@ -0,0 +1,28 @@ +From 4896c33bf9fe61ab62d5f6f93762d7c951a64a49 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 15 Aug 2019 12:02:34 +0100 +Subject: [PATCH] configs: arm64/bcm2711: Enable V3D + +Enable the V3D driver, which depends on BCM2835_POWER. + +Originally submitted by GitHub user 'phire' in a slightly different +form. + +See: https://github.com/raspberrypi/linux/pull/3063 + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/Kconfig | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/v3d/Kconfig ++++ b/drivers/gpu/drm/v3d/Kconfig +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only + config DRM_V3D + tristate "Broadcom V3D 3.x and newer" +- depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST ++ depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST + depends on DRM + depends on COMMON_CLK + depends on MMU diff --git a/target/linux/bcm27xx/patches-5.4/950-0294-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch b/target/linux/bcm27xx/patches-5.4/950-0294-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch deleted file mode 100644 index f29ba4dc5d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0294-drm-vc4-Add-missing-NULL-check-to-vc4_crtc_consume_e.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e2e9da35d4a598490b73da41eea1db27540339fd Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 7 Aug 2019 11:31:08 +0100 -Subject: [PATCH] drm/vc4: Add missing NULL check to - vc4_crtc_consume_event - -vc4_crtc_consume_event wasn't checking crtc->state->event was -set before dereferencing it, leading to an OOPS. - -Fixes "a5b534b drm/vc4: Resolve the vblank warnings on mode switching" - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -1000,6 +1000,9 @@ static void vc4_crtc_consume_event(struc - struct drm_device *dev = crtc->dev; - unsigned long flags; - -+ if (!crtc->state->event) -+ return; -+ - crtc->state->event->pipe = drm_crtc_index(crtc); - - WARN_ON(drm_crtc_vblank_get(crtc) != 0); diff --git a/target/linux/bcm27xx/patches-5.4/950-0295-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch b/target/linux/bcm27xx/patches-5.4/950-0295-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch deleted file mode 100644 index db1866d6e7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0295-net-bcmgenet-Workaround-2-for-Pi4-Ethernet-fail.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 128e363e406841fbbd9800199cb093b4737d7cba Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 9 Aug 2019 08:51:43 +0100 -Subject: [PATCH] net: bcmgenet: Workaround #2 for Pi4 Ethernet fail - -Some combinations of Pi 4Bs and Ethernet switches don't reliably get a -DCHP-assigned IP address, leaving the unit with a self=assigned 169.254 -address. In the failure case, the Pi is left able to receive packets -but not send them, suggesting that the MAC<->PHY link is getting into -a bad state. - -It has been found empirically that skipping a reset step by the genet -driver prevents the failures. No downsides have been discovered yet, -and unlike the forced renegotiation it doesn't increase the time to -get an IP address, so the workaround is enabled by default; add - - genet.skip_umac_reset=n - -to the command line to disable it. - -See: https://github.com/raspberrypi/linux/issues/3108 - -Signed-off-by: Phil Elwell ---- - drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - ---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c -+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c -@@ -72,6 +72,10 @@ - /* Forward declarations */ - static void bcmgenet_set_rx_mode(struct net_device *dev); - -+static bool skip_umac_reset = true; -+module_param(skip_umac_reset, bool, 0444); -+MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step"); -+ - static inline void bcmgenet_writel(u32 value, void __iomem *offset) - { - /* MIPS chips strapped for BE will automagically configure the -@@ -1995,6 +1999,11 @@ static void reset_umac(struct bcmgenet_p - bcmgenet_rbuf_ctrl_set(priv, 0); - udelay(10); - -+ if (skip_umac_reset) { -+ pr_warn("Skipping UMAC reset\n"); -+ return; -+ } -+ - /* disable MAC while updating its registers */ - bcmgenet_umac_writel(priv, 0, UMAC_CMD); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0295-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch b/target/linux/bcm27xx/patches-5.4/950-0295-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch new file mode 100644 index 0000000000..42baf4c7d4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0295-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch @@ -0,0 +1,55 @@ +From f80d87ce56916edf52dce4a311f3d512443ca7f7 Mon Sep 17 00:00:00 2001 +From: Aman Gupta +Date: Thu, 22 Aug 2019 22:31:37 +0000 +Subject: [PATCH] staging: bcm2835-codec: add support for + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME + +fixes #3171 + +Signed-off-by: Aman Gupta +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1587,6 +1587,20 @@ static int bcm2835_codec_s_ctrl(struct v + ret = bcm2835_codec_set_level_profile(ctx, ctrl); + break; + ++ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: { ++ u32 mmal_bool = 1; ++ ++ if (!ctx->component) ++ break; ++ ++ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, ++ &ctx->component->output[0], ++ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, ++ &mmal_bool, ++ sizeof(mmal_bool)); ++ break; ++ } ++ + default: + v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); + return -EINVAL; +@@ -2311,7 +2325,7 @@ static int bcm2835_codec_open(struct fil + hdl = &ctx->hdl; + if (dev->role == ENCODE) { + /* Encode controls */ +- v4l2_ctrl_handler_init(hdl, 6); ++ v4l2_ctrl_handler_init(hdl, 7); + + v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, +@@ -2355,6 +2369,9 @@ static int bcm2835_codec_open(struct fil + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); ++ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, ++ V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, ++ 0, 0, 0, 0); + if (hdl->error) { + rc = hdl->error; + goto free_ctrl_handler; diff --git a/target/linux/bcm27xx/patches-5.4/950-0296-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch b/target/linux/bcm27xx/patches-5.4/950-0296-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch new file mode 100644 index 0000000000..d2a50860d2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0296-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch @@ -0,0 +1,30 @@ +From aa8519dd50cf310e8760fbc11f5fa3ff672683e1 Mon Sep 17 00:00:00 2001 +From: Aman Gupta +Date: Fri, 23 Aug 2019 16:29:07 -0700 +Subject: [PATCH] staging: bcm2835-codec: remove unnecessary padding on + encoder input + +The ISP and ENCODE roles have the same underlying hardware. Neither requires vertical alignment. + +Signed-off-by: Aman Gupta +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1050,12 +1050,12 @@ static int vidioc_try_fmt(struct bcm2835 + f->fmt.pix_mp.height = MIN_H; + + /* +- * For codecs the buffer must have a vertical alignment of 16 ++ * For decoders the buffer must have a vertical alignment of 16 + * lines. + * The selection will reflect any cropping rectangle when only + * some of the pixels are active. + */ +- if (ctx->dev->role != ISP) ++ if (ctx->dev->role == DECODE) + f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16); + } + f->fmt.pix_mp.num_planes = 1; diff --git a/target/linux/bcm27xx/patches-5.4/950-0296-xhci-Use-more-event-ring-segment-table-entries.patch b/target/linux/bcm27xx/patches-5.4/950-0296-xhci-Use-more-event-ring-segment-table-entries.patch deleted file mode 100644 index 4b4766f739..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0296-xhci-Use-more-event-ring-segment-table-entries.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 90c56c8f52c912aa6e990e63d953b6dbccea7250 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 13 Aug 2019 15:53:29 +0100 -Subject: [PATCH] xhci: Use more event ring segment table entries - -Users have reported log spam created by "Event Ring Full" xHC event -TRBs. These are caused by interrupt latency in conjunction with a very -busy set of devices on the bus. The errors are benign, but throughput -will suffer as the xHC will pause processing of transfers until the -event ring is drained by the kernel. Expand the number of event TRB slots -available by increasing the number of event ring segments in the ERST. - -Controllers have a hardware-defined limit as to the number of ERST -entries they can process, so make the actual number in use -min(ERST_MAX_SEGS, hw_max). - -Signed-off-by: Jonathan Bell ---- - drivers/usb/host/xhci-mem.c | 8 +++++--- - drivers/usb/host/xhci.h | 4 ++-- - 2 files changed, 7 insertions(+), 5 deletions(-) - ---- a/drivers/usb/host/xhci-mem.c -+++ b/drivers/usb/host/xhci-mem.c -@@ -2503,9 +2503,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, - * Event ring setup: Allocate a normal ring, but also setup - * the event ring segment table (ERST). Section 4.9.3. - */ -+ val2 = 1 << HCS_ERST_MAX(xhci->hcs_params2); -+ val2 = min_t(unsigned int, ERST_MAX_SEGS, val2); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring"); -- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, -- 0, flags); -+ xhci->event_ring = xhci_ring_alloc(xhci, val2, 1, TYPE_EVENT, -+ 0, flags); - if (!xhci->event_ring) - goto fail; - if (xhci_check_trb_in_td_math(xhci) < 0) -@@ -2518,7 +2520,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, - /* set ERST count with the number of entries in the segment table */ - val = readl(&xhci->ir_set->erst_size); - val &= ERST_SIZE_MASK; -- val |= ERST_NUM_SEGS; -+ val |= val2; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write ERST size = %i to ir_set 0 (some bits preserved)", - val); ---- a/drivers/usb/host/xhci.h -+++ b/drivers/usb/host/xhci.h -@@ -1649,8 +1649,8 @@ struct urb_priv { - * Each segment table entry is 4*32bits long. 1K seems like an ok size: - * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, - * meaning 64 ring segments. -- * Initial allocated size of the ERST, in number of entries */ --#define ERST_NUM_SEGS 1 -+ * Maximum number of segments in the ERST */ -+#define ERST_MAX_SEGS 8 - /* Initial allocated size of the ERST, in number of entries */ - #define ERST_SIZE 64 - /* Initial number of event segment rings allocated */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0297-arch-arm-Add-model-string-to-cpuinfo.patch b/target/linux/bcm27xx/patches-5.4/950-0297-arch-arm-Add-model-string-to-cpuinfo.patch new file mode 100644 index 0000000000..83c1592df9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0297-arch-arm-Add-model-string-to-cpuinfo.patch @@ -0,0 +1,36 @@ +From 4964bc1608844cb58c8ee96f315867e8142706a1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 3 Sep 2019 18:16:56 +0100 +Subject: [PATCH] arch/arm: Add model string to cpuinfo + +Signed-off-by: Phil Elwell +--- + arch/arm/kernel/setup.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/arm/kernel/setup.c ++++ b/arch/arm/kernel/setup.c +@@ -1240,6 +1240,8 @@ static int c_show(struct seq_file *m, vo + { + int i, j; + u32 cpuid; ++ struct device_node *np; ++ const char *model; + + for_each_online_cpu(i) { + /* +@@ -1299,6 +1301,14 @@ static int c_show(struct seq_file *m, vo + seq_printf(m, "Revision\t: %04x\n", system_rev); + seq_printf(m, "Serial\t\t: %s\n", system_serial); + ++ np = of_find_node_by_path("/"); ++ if (np) { ++ if (!of_property_read_string(np, "model", ++ &model)) ++ seq_printf(m, "Model\t\t: %s\n", model); ++ of_node_put(np); ++ } ++ + return 0; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0297-configs-arm64-bcm2711-Enable-V3D.patch b/target/linux/bcm27xx/patches-5.4/950-0297-configs-arm64-bcm2711-Enable-V3D.patch deleted file mode 100644 index f079fcf9ac..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0297-configs-arm64-bcm2711-Enable-V3D.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 4896c33bf9fe61ab62d5f6f93762d7c951a64a49 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 15 Aug 2019 12:02:34 +0100 -Subject: [PATCH] configs: arm64/bcm2711: Enable V3D - -Enable the V3D driver, which depends on BCM2835_POWER. - -Originally submitted by GitHub user 'phire' in a slightly different -form. - -See: https://github.com/raspberrypi/linux/pull/3063 - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/Kconfig | 2 +- - 2 files changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/v3d/Kconfig -+++ b/drivers/gpu/drm/v3d/Kconfig -@@ -1,7 +1,7 @@ - # SPDX-License-Identifier: GPL-2.0-only - config DRM_V3D - tristate "Broadcom V3D 3.x and newer" -- depends on ARCH_BCM || ARCH_BCMSTB || COMPILE_TEST -+ depends on ARCH_BCM || ARCH_BCMSTB || ARCH_BCM2835 || COMPILE_TEST - depends on DRM - depends on COMMON_CLK - depends on MMU diff --git a/target/linux/bcm27xx/patches-5.4/950-0298-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch b/target/linux/bcm27xx/patches-5.4/950-0298-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch new file mode 100644 index 0000000000..af76b81f31 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0298-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch @@ -0,0 +1,58 @@ +From 6ce4c2034f11fe1ba270637ebd5ba459c69e2b27 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 3 Sep 2019 18:17:25 +0100 +Subject: [PATCH] arch/arm64: Add Revision, Serial, Model to cpuinfo + +Signed-off-by: Phil Elwell +--- + arch/arm64/kernel/cpuinfo.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/arch/arm64/kernel/cpuinfo.c ++++ b/arch/arm64/kernel/cpuinfo.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -128,6 +129,10 @@ static int c_show(struct seq_file *m, vo + { + int i, j; + bool compat = personality(current->personality) == PER_LINUX32; ++ struct device_node *np; ++ const char *model; ++ const char *serial; ++ u32 revision; + + for_each_online_cpu(i) { + struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); +@@ -179,6 +184,26 @@ static int c_show(struct seq_file *m, vo + seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr)); + } + ++ seq_printf(m, "Hardware\t: BCM2835\n"); ++ ++ np = of_find_node_by_path("/system"); ++ if (np) { ++ if (!of_property_read_u32(np, "linux,revision", &revision)) ++ seq_printf(m, "Revision\t: %04x\n", revision); ++ of_node_put(np); ++ } ++ ++ np = of_find_node_by_path("/"); ++ if (np) { ++ if (!of_property_read_string(np, "serial-number", ++ &serial)) ++ seq_printf(m, "Serial\t\t: %s\n", serial); ++ if (!of_property_read_string(np, "model", ++ &model)) ++ seq_printf(m, "Model\t\t: %s\n", model); ++ of_node_put(np); ++ } ++ + return 0; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0298-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch b/target/linux/bcm27xx/patches-5.4/950-0298-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch deleted file mode 100644 index 42baf4c7d4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0298-staging-bcm2835-codec-add-support-for-V4L2_CID_MPEG_.patch +++ /dev/null @@ -1,55 +0,0 @@ -From f80d87ce56916edf52dce4a311f3d512443ca7f7 Mon Sep 17 00:00:00 2001 -From: Aman Gupta -Date: Thu, 22 Aug 2019 22:31:37 +0000 -Subject: [PATCH] staging: bcm2835-codec: add support for - V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME - -fixes #3171 - -Signed-off-by: Aman Gupta ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 19 ++++++++++++++++++- - 1 file changed, 18 insertions(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1587,6 +1587,20 @@ static int bcm2835_codec_s_ctrl(struct v - ret = bcm2835_codec_set_level_profile(ctx, ctrl); - break; - -+ case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: { -+ u32 mmal_bool = 1; -+ -+ if (!ctx->component) -+ break; -+ -+ ret = vchiq_mmal_port_parameter_set(ctx->dev->instance, -+ &ctx->component->output[0], -+ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, -+ &mmal_bool, -+ sizeof(mmal_bool)); -+ break; -+ } -+ - default: - v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); - return -EINVAL; -@@ -2311,7 +2325,7 @@ static int bcm2835_codec_open(struct fil - hdl = &ctx->hdl; - if (dev->role == ENCODE) { - /* Encode controls */ -- v4l2_ctrl_handler_init(hdl, 6); -+ v4l2_ctrl_handler_init(hdl, 7); - - v4l2_ctrl_new_std_menu(hdl, &bcm2835_codec_ctrl_ops, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, -@@ -2355,6 +2369,9 @@ static int bcm2835_codec_open(struct fil - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); -+ v4l2_ctrl_new_std(hdl, &bcm2835_codec_ctrl_ops, -+ V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, -+ 0, 0, 0, 0); - if (hdl->error) { - rc = hdl->error; - goto free_ctrl_handler; diff --git a/target/linux/bcm27xx/patches-5.4/950-0299-staging-bcm2835-codec-Fix-non-documentation-comment-.patch b/target/linux/bcm27xx/patches-5.4/950-0299-staging-bcm2835-codec-Fix-non-documentation-comment-.patch new file mode 100644 index 0000000000..e1ec7d9e69 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0299-staging-bcm2835-codec-Fix-non-documentation-comment-.patch @@ -0,0 +1,27 @@ +From 8c9e3687480d787750a7cc09016ac551a9009e87 Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Sun, 28 Apr 2019 12:15:35 +0200 +Subject: [PATCH] staging: bcm2835-codec: Fix non-documentation comment + block + +The job_ready comment is incorrectly using the documentation prefix +(/**) which causes a warning at build time. + +Simplify it. + +Signed-off-by: Kieran Bingham +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -557,7 +557,7 @@ static struct vchiq_mmal_port *get_port_ + * mem2mem callbacks + */ + +-/** ++/* + * job_ready() - check whether an instance is ready to be scheduled to run + */ + static int job_ready(void *priv) diff --git a/target/linux/bcm27xx/patches-5.4/950-0299-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch b/target/linux/bcm27xx/patches-5.4/950-0299-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch deleted file mode 100644 index d2a50860d2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0299-staging-bcm2835-codec-remove-unnecessary-padding-on-.patch +++ /dev/null @@ -1,30 +0,0 @@ -From aa8519dd50cf310e8760fbc11f5fa3ff672683e1 Mon Sep 17 00:00:00 2001 -From: Aman Gupta -Date: Fri, 23 Aug 2019 16:29:07 -0700 -Subject: [PATCH] staging: bcm2835-codec: remove unnecessary padding on - encoder input - -The ISP and ENCODE roles have the same underlying hardware. Neither requires vertical alignment. - -Signed-off-by: Aman Gupta ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1050,12 +1050,12 @@ static int vidioc_try_fmt(struct bcm2835 - f->fmt.pix_mp.height = MIN_H; - - /* -- * For codecs the buffer must have a vertical alignment of 16 -+ * For decoders the buffer must have a vertical alignment of 16 - * lines. - * The selection will reflect any cropping rectangle when only - * some of the pixels are active. - */ -- if (ctx->dev->role != ISP) -+ if (ctx->dev->role == DECODE) - f->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 16); - } - f->fmt.pix_mp.num_planes = 1; diff --git a/target/linux/bcm27xx/patches-5.4/950-0300-arch-arm-Add-model-string-to-cpuinfo.patch b/target/linux/bcm27xx/patches-5.4/950-0300-arch-arm-Add-model-string-to-cpuinfo.patch deleted file mode 100644 index 83c1592df9..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0300-arch-arm-Add-model-string-to-cpuinfo.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 4964bc1608844cb58c8ee96f315867e8142706a1 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 3 Sep 2019 18:16:56 +0100 -Subject: [PATCH] arch/arm: Add model string to cpuinfo - -Signed-off-by: Phil Elwell ---- - arch/arm/kernel/setup.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - ---- a/arch/arm/kernel/setup.c -+++ b/arch/arm/kernel/setup.c -@@ -1240,6 +1240,8 @@ static int c_show(struct seq_file *m, vo - { - int i, j; - u32 cpuid; -+ struct device_node *np; -+ const char *model; - - for_each_online_cpu(i) { - /* -@@ -1299,6 +1301,14 @@ static int c_show(struct seq_file *m, vo - seq_printf(m, "Revision\t: %04x\n", system_rev); - seq_printf(m, "Serial\t\t: %s\n", system_serial); - -+ np = of_find_node_by_path("/"); -+ if (np) { -+ if (!of_property_read_string(np, "model", -+ &model)) -+ seq_printf(m, "Model\t\t: %s\n", model); -+ of_node_put(np); -+ } -+ - return 0; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0300-staging-bcm2835-codec-Fix-declaration-of-roles.patch b/target/linux/bcm27xx/patches-5.4/950-0300-staging-bcm2835-codec-Fix-declaration-of-roles.patch new file mode 100644 index 0000000000..6e544199ba --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0300-staging-bcm2835-codec-Fix-declaration-of-roles.patch @@ -0,0 +1,26 @@ +From 1efb26ffda4c95103a91eb51505ef1bb30553b08 Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Wed, 20 Mar 2019 11:42:39 +0000 +Subject: [PATCH] staging: bcm2835-codec: Fix declaration of roles + +The static role text is declared incorrectly. The static should be +first, and the roles should also be constified. + +Convert from "const static char *" to "static const char * const". + +Signed-off-by: Kieran Bingham +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -77,7 +77,7 @@ enum bcm2835_codec_role { + ISP, + }; + +-const static char *roles[] = { ++static const char * const roles[] = { + "decode", + "encode", + "isp" diff --git a/target/linux/bcm27xx/patches-5.4/950-0301-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch b/target/linux/bcm27xx/patches-5.4/950-0301-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch deleted file mode 100644 index af76b81f31..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0301-arch-arm64-Add-Revision-Serial-Model-to-cpuinfo.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 6ce4c2034f11fe1ba270637ebd5ba459c69e2b27 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 3 Sep 2019 18:17:25 +0100 -Subject: [PATCH] arch/arm64: Add Revision, Serial, Model to cpuinfo - -Signed-off-by: Phil Elwell ---- - arch/arm64/kernel/cpuinfo.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - ---- a/arch/arm64/kernel/cpuinfo.c -+++ b/arch/arm64/kernel/cpuinfo.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -128,6 +129,10 @@ static int c_show(struct seq_file *m, vo - { - int i, j; - bool compat = personality(current->personality) == PER_LINUX32; -+ struct device_node *np; -+ const char *model; -+ const char *serial; -+ u32 revision; - - for_each_online_cpu(i) { - struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); -@@ -179,6 +184,26 @@ static int c_show(struct seq_file *m, vo - seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr)); - } - -+ seq_printf(m, "Hardware\t: BCM2835\n"); -+ -+ np = of_find_node_by_path("/system"); -+ if (np) { -+ if (!of_property_read_u32(np, "linux,revision", &revision)) -+ seq_printf(m, "Revision\t: %04x\n", revision); -+ of_node_put(np); -+ } -+ -+ np = of_find_node_by_path("/"); -+ if (np) { -+ if (!of_property_read_string(np, "serial-number", -+ &serial)) -+ seq_printf(m, "Serial\t\t: %s\n", serial); -+ if (!of_property_read_string(np, "model", -+ &model)) -+ seq_printf(m, "Model\t\t: %s\n", model); -+ of_node_put(np); -+ } -+ - return 0; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0301-staging-bcm2835-codec-Add-role-to-device-name.patch b/target/linux/bcm27xx/patches-5.4/950-0301-staging-bcm2835-codec-Add-role-to-device-name.patch new file mode 100644 index 0000000000..e1539f4a71 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0301-staging-bcm2835-codec-Add-role-to-device-name.patch @@ -0,0 +1,45 @@ +From 434803a4828aed99d5328dd41b4600ef7b0be0ff Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Wed, 20 Mar 2019 11:55:43 +0000 +Subject: [PATCH] staging: bcm2835-codec: Add role to device name + +Three entities are created, Decode, Encode and ISP but all of the video +nodes use the same video name string "bcm2835-codec" which makes it +difficult to identify each role. + +Append the role-name to the video name to facilitate identifying a +specific instance from userspace. + +The Card-Type is also extended with the role name to support identifying +the device context from within QUERY_CAP operations. + +Signed-off-by: Kieran Bingham +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -947,8 +947,10 @@ static void device_run(void *priv) + static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) + { ++ struct bcm2835_codec_dev *dev = video_drvdata(file); ++ + strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); +- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); ++ strncpy(cap->card, dev->vfd.name, sizeof(cap->card) - 1); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + MEM2MEM_NAME); + return 0; +@@ -2657,8 +2659,8 @@ static int bcm2835_codec_create(struct p + } + + video_set_drvdata(vfd, dev); +- snprintf(vfd->name, sizeof(vfd->name), "%s", +- bcm2835_codec_videodev.name); ++ snprintf(vfd->name, sizeof(vfd->name), "%s-%s", ++ bcm2835_codec_videodev.name, roles[role]); + v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", + vfd->num); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0302-staging-bcm2835-codec-Fix-non-documentation-comment-.patch b/target/linux/bcm27xx/patches-5.4/950-0302-staging-bcm2835-codec-Fix-non-documentation-comment-.patch deleted file mode 100644 index e1ec7d9e69..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0302-staging-bcm2835-codec-Fix-non-documentation-comment-.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 8c9e3687480d787750a7cc09016ac551a9009e87 Mon Sep 17 00:00:00 2001 -From: Kieran Bingham -Date: Sun, 28 Apr 2019 12:15:35 +0200 -Subject: [PATCH] staging: bcm2835-codec: Fix non-documentation comment - block - -The job_ready comment is incorrectly using the documentation prefix -(/**) which causes a warning at build time. - -Simplify it. - -Signed-off-by: Kieran Bingham ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -557,7 +557,7 @@ static struct vchiq_mmal_port *get_port_ - * mem2mem callbacks - */ - --/** -+/* - * job_ready() - check whether an instance is ready to be scheduled to run - */ - static int job_ready(void *priv) diff --git a/target/linux/bcm27xx/patches-5.4/950-0302-staging-bcm2835-codec-Pass-driver-context-to-create-.patch b/target/linux/bcm27xx/patches-5.4/950-0302-staging-bcm2835-codec-Pass-driver-context-to-create-.patch new file mode 100644 index 0000000000..a0b86db2d6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0302-staging-bcm2835-codec-Pass-driver-context-to-create-.patch @@ -0,0 +1,61 @@ +From aebdaf3bf7931e42b6787d1f1554de03e84422c7 Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Wed, 20 Mar 2019 11:35:26 +0000 +Subject: [PATCH] staging: bcm2835-codec: Pass driver context to create + entities + +Pass the bcm2835_codec_driver driver context directly into the +bcm2835_codec_create() so that it can be used to store driver global +state. Pass the struct platform_device *pdev by adding it to the driver +global state. + +Signed-off-by: Kieran Bingham +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -457,6 +457,8 @@ struct bcm2835_codec_ctx { + }; + + struct bcm2835_codec_driver { ++ struct platform_device *pdev; ++ + struct bcm2835_codec_dev *encode; + struct bcm2835_codec_dev *decode; + struct bcm2835_codec_dev *isp; +@@ -2587,10 +2589,11 @@ destroy_component: + return ret; + } + +-static int bcm2835_codec_create(struct platform_device *pdev, ++static int bcm2835_codec_create(struct bcm2835_codec_driver *drv, + struct bcm2835_codec_dev **new_dev, + enum bcm2835_codec_role role) + { ++ struct platform_device *pdev = drv->pdev; + struct bcm2835_codec_dev *dev; + struct video_device *vfd; + int video_nr; +@@ -2711,15 +2714,17 @@ static int bcm2835_codec_probe(struct pl + if (!drv) + return -ENOMEM; + +- ret = bcm2835_codec_create(pdev, &drv->decode, DECODE); ++ drv->pdev = pdev; ++ ++ ret = bcm2835_codec_create(drv, &drv->decode, DECODE); + if (ret) + goto out; + +- ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE); ++ ret = bcm2835_codec_create(drv, &drv->encode, ENCODE); + if (ret) + goto out; + +- ret = bcm2835_codec_create(pdev, &drv->isp, ISP); ++ ret = bcm2835_codec_create(drv, &drv->isp, ISP); + if (ret) + goto out; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0303-staging-bcm2835-codec-Fix-declaration-of-roles.patch b/target/linux/bcm27xx/patches-5.4/950-0303-staging-bcm2835-codec-Fix-declaration-of-roles.patch deleted file mode 100644 index 6e544199ba..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0303-staging-bcm2835-codec-Fix-declaration-of-roles.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 1efb26ffda4c95103a91eb51505ef1bb30553b08 Mon Sep 17 00:00:00 2001 -From: Kieran Bingham -Date: Wed, 20 Mar 2019 11:42:39 +0000 -Subject: [PATCH] staging: bcm2835-codec: Fix declaration of roles - -The static role text is declared incorrectly. The static should be -first, and the roles should also be constified. - -Convert from "const static char *" to "static const char * const". - -Signed-off-by: Kieran Bingham ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -77,7 +77,7 @@ enum bcm2835_codec_role { - ISP, - }; - --const static char *roles[] = { -+static const char * const roles[] = { - "decode", - "encode", - "isp" diff --git a/target/linux/bcm27xx/patches-5.4/950-0303-staging-bcm2835-codec-add-media-controller-support.patch b/target/linux/bcm27xx/patches-5.4/950-0303-staging-bcm2835-codec-add-media-controller-support.patch new file mode 100644 index 0000000000..f0ac32340c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0303-staging-bcm2835-codec-add-media-controller-support.patch @@ -0,0 +1,163 @@ +From 4d066da23979b8de03b5915388136be6e293600f Mon Sep 17 00:00:00 2001 +From: Kieran Bingham +Date: Wed, 20 Mar 2019 12:54:15 +0000 +Subject: [PATCH] staging: bcm2835-codec: add media controller support + +Provide a single media device to contain all of the bcm2835_codec +devices created. + +Signed-off-by: Kieran Bingham +--- + .../vc04_services/bcm2835-codec/Kconfig | 2 +- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 41 +++++++++++++++++-- + 2 files changed, 38 insertions(+), 5 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/Kconfig ++++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig +@@ -1,6 +1,6 @@ + config VIDEO_CODEC_BCM2835 + tristate "BCM2835 Video codec support" +- depends on MEDIA_SUPPORT ++ depends on MEDIA_SUPPORT && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) + select BCM2835_VCHIQ_MMAL + select VIDEOBUF2_DMA_CONTIG +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -458,6 +458,7 @@ struct bcm2835_codec_ctx { + + struct bcm2835_codec_driver { + struct platform_device *pdev; ++ struct media_device mdev; + + struct bcm2835_codec_dev *encode; + struct bcm2835_codec_dev *decode; +@@ -2596,6 +2597,7 @@ static int bcm2835_codec_create(struct b + struct platform_device *pdev = drv->pdev; + struct bcm2835_codec_dev *dev; + struct video_device *vfd; ++ int function; + int video_nr; + int ret; + +@@ -2615,18 +2617,21 @@ static int bcm2835_codec_create(struct b + if (ret) + goto vchiq_finalise; + +- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); +- if (ret) +- goto vchiq_finalise; +- + atomic_set(&dev->num_inst, 0); + mutex_init(&dev->dev_mutex); + ++ /* Initialise the video device */ + dev->vfd = bcm2835_codec_videodev; ++ + vfd = &dev->vfd; + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; ++ vfd->v4l2_dev->mdev = &drv->mdev; ++ ++ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); ++ if (ret) ++ goto vchiq_finalise; + + switch (role) { + case DECODE: +@@ -2634,11 +2639,13 @@ static int bcm2835_codec_create(struct b + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); ++ function = MEDIA_ENT_F_PROC_VIDEO_DECODER; + video_nr = decode_video_nr; + break; + case ENCODE: + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); ++ function = MEDIA_ENT_F_PROC_VIDEO_ENCODER; + video_nr = encode_video_nr; + break; + case ISP: +@@ -2648,6 +2655,7 @@ static int bcm2835_codec_create(struct b + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); ++ function = MEDIA_ENT_F_PROC_VIDEO_SCALER; + video_nr = isp_video_nr; + break; + default: +@@ -2676,6 +2684,10 @@ static int bcm2835_codec_create(struct b + goto err_m2m; + } + ++ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, function); ++ if (ret) ++ goto err_m2m; ++ + v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", + roles[role]); + return 0; +@@ -2697,6 +2709,7 @@ static int bcm2835_codec_destroy(struct + + v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n", + roles[dev->role]); ++ v4l2_m2m_unregister_media_controller(dev->m2m_dev); + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(&dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); +@@ -2708,6 +2721,7 @@ static int bcm2835_codec_destroy(struct + static int bcm2835_codec_probe(struct platform_device *pdev) + { + struct bcm2835_codec_driver *drv; ++ struct media_device *mdev; + int ret = 0; + + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); +@@ -2715,6 +2729,17 @@ static int bcm2835_codec_probe(struct pl + return -ENOMEM; + + drv->pdev = pdev; ++ mdev = &drv->mdev; ++ mdev->dev = &pdev->dev; ++ ++ strscpy(mdev->model, bcm2835_codec_videodev.name, sizeof(mdev->model)); ++ strscpy(mdev->serial, "0000", sizeof(mdev->serial)); ++ snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", ++ pdev->name); ++ ++ /* This should return the vgencmd version information or such .. */ ++ mdev->hw_revision = 1; ++ media_device_init(mdev); + + ret = bcm2835_codec_create(drv, &drv->decode, DECODE); + if (ret) +@@ -2728,6 +2753,10 @@ static int bcm2835_codec_probe(struct pl + if (ret) + goto out; + ++ /* Register the media device node */ ++ if (media_device_register(mdev) < 0) ++ goto out; ++ + platform_set_drvdata(pdev, drv); + + return 0; +@@ -2748,12 +2777,16 @@ static int bcm2835_codec_remove(struct p + { + struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev); + ++ media_device_unregister(&drv->mdev); ++ + bcm2835_codec_destroy(drv->isp); + + bcm2835_codec_destroy(drv->encode); + + bcm2835_codec_destroy(drv->decode); + ++ media_device_cleanup(&drv->mdev); ++ + return 0; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0304-staging-bcm2835-codec-Add-role-to-device-name.patch b/target/linux/bcm27xx/patches-5.4/950-0304-staging-bcm2835-codec-Add-role-to-device-name.patch deleted file mode 100644 index e1539f4a71..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0304-staging-bcm2835-codec-Add-role-to-device-name.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 434803a4828aed99d5328dd41b4600ef7b0be0ff Mon Sep 17 00:00:00 2001 -From: Kieran Bingham -Date: Wed, 20 Mar 2019 11:55:43 +0000 -Subject: [PATCH] staging: bcm2835-codec: Add role to device name - -Three entities are created, Decode, Encode and ISP but all of the video -nodes use the same video name string "bcm2835-codec" which makes it -difficult to identify each role. - -Append the role-name to the video name to facilitate identifying a -specific instance from userspace. - -The Card-Type is also extended with the role name to support identifying -the device context from within QUERY_CAP operations. - -Signed-off-by: Kieran Bingham ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -947,8 +947,10 @@ static void device_run(void *priv) - static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) - { -+ struct bcm2835_codec_dev *dev = video_drvdata(file); -+ - strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); -- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); -+ strncpy(cap->card, dev->vfd.name, sizeof(cap->card) - 1); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - MEM2MEM_NAME); - return 0; -@@ -2657,8 +2659,8 @@ static int bcm2835_codec_create(struct p - } - - video_set_drvdata(vfd, dev); -- snprintf(vfd->name, sizeof(vfd->name), "%s", -- bcm2835_codec_videodev.name); -+ snprintf(vfd->name, sizeof(vfd->name), "%s-%s", -+ bcm2835_codec_videodev.name, roles[role]); - v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", - vfd->num); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0304-v4l2-Add-a-Greyworld-AWB-mode.patch b/target/linux/bcm27xx/patches-5.4/950-0304-v4l2-Add-a-Greyworld-AWB-mode.patch new file mode 100644 index 0000000000..459646e7e7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0304-v4l2-Add-a-Greyworld-AWB-mode.patch @@ -0,0 +1,34 @@ +From 1b14387d6b699c4cfc8218867997b1508a67167a Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 6 Sep 2019 15:04:51 +0100 +Subject: [PATCH] v4l2: Add a Greyworld AWB mode. + +Adds a simple greyworld white balance preset, mainly for use +with cameras without an IR filter (eg Raspberry Pi NoIR) + +Signed-off-by: Dave Stevenson +--- + drivers/media/v4l2-core/v4l2-ctrls.c | 1 + + include/uapi/linux/v4l2-controls.h | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/media/v4l2-core/v4l2-ctrls.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls.c +@@ -271,6 +271,7 @@ const char * const *v4l2_ctrl_get_menu(u + "Flash", + "Cloudy", + "Shade", ++ "Greyworld", + NULL, + }; + static const char * const camera_iso_sensitivity_auto[] = { +--- a/include/uapi/linux/v4l2-controls.h ++++ b/include/uapi/linux/v4l2-controls.h +@@ -850,6 +850,7 @@ enum v4l2_auto_n_preset_white_balance { + V4L2_WHITE_BALANCE_FLASH = 7, + V4L2_WHITE_BALANCE_CLOUDY = 8, + V4L2_WHITE_BALANCE_SHADE = 9, ++ V4L2_WHITE_BALANCE_GREYWORLD = 10, + }; + + #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21) diff --git a/target/linux/bcm27xx/patches-5.4/950-0305-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch b/target/linux/bcm27xx/patches-5.4/950-0305-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch new file mode 100644 index 0000000000..e29c3800c4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0305-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch @@ -0,0 +1,48 @@ +From a1504ea7c24e74fe4d10b024d8105dc66115b01e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 6 Sep 2019 15:13:06 +0100 +Subject: [PATCH] staging: bcm2835-camera: Add greyworld AWB mode + +This is mainly used for the NoIR camera which has no IR +filter and can completely confuse normal AWB presets. + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/bcm2835-camera/controls.c | 8 ++++++-- + .../staging/vc04_services/vchiq-mmal/mmal-parameters.h | 1 + + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c ++++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c +@@ -477,6 +477,10 @@ static int ctrl_set_awb_mode(struct bm28 + case V4L2_WHITE_BALANCE_SHADE: + u32_value = MMAL_PARAM_AWBMODE_SHADE; + break; ++ ++ case V4L2_WHITE_BALANCE_GREYWORLD: ++ u32_value = MMAL_PARAM_AWBMODE_GREYWORLD; ++ break; + } + + return vchiq_mmal_port_parameter_set(dev->instance, control, +@@ -1014,8 +1018,8 @@ static const struct bm2835_mmal_v4l2_ctr + { + V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, + MMAL_CONTROL_TYPE_STD_MENU, +- ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0, +- NULL, ++ ~0x7ff, V4L2_WHITE_BALANCE_GREYWORLD, V4L2_WHITE_BALANCE_AUTO, ++ 0, NULL, + MMAL_PARAMETER_AWB_MODE, + ctrl_set_awb_mode, + false +--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h ++++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h +@@ -313,6 +313,7 @@ enum mmal_parameter_awbmode { + MMAL_PARAM_AWBMODE_INCANDESCENT, + MMAL_PARAM_AWBMODE_FLASH, + MMAL_PARAM_AWBMODE_HORIZON, ++ MMAL_PARAM_AWBMODE_GREYWORLD, + }; + + enum mmal_parameter_imagefx { diff --git a/target/linux/bcm27xx/patches-5.4/950-0305-staging-bcm2835-codec-Pass-driver-context-to-create-.patch b/target/linux/bcm27xx/patches-5.4/950-0305-staging-bcm2835-codec-Pass-driver-context-to-create-.patch deleted file mode 100644 index a0b86db2d6..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0305-staging-bcm2835-codec-Pass-driver-context-to-create-.patch +++ /dev/null @@ -1,61 +0,0 @@ -From aebdaf3bf7931e42b6787d1f1554de03e84422c7 Mon Sep 17 00:00:00 2001 -From: Kieran Bingham -Date: Wed, 20 Mar 2019 11:35:26 +0000 -Subject: [PATCH] staging: bcm2835-codec: Pass driver context to create - entities - -Pass the bcm2835_codec_driver driver context directly into the -bcm2835_codec_create() so that it can be used to store driver global -state. Pass the struct platform_device *pdev by adding it to the driver -global state. - -Signed-off-by: Kieran Bingham ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 13 +++++++++---- - 1 file changed, 9 insertions(+), 4 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -457,6 +457,8 @@ struct bcm2835_codec_ctx { - }; - - struct bcm2835_codec_driver { -+ struct platform_device *pdev; -+ - struct bcm2835_codec_dev *encode; - struct bcm2835_codec_dev *decode; - struct bcm2835_codec_dev *isp; -@@ -2587,10 +2589,11 @@ destroy_component: - return ret; - } - --static int bcm2835_codec_create(struct platform_device *pdev, -+static int bcm2835_codec_create(struct bcm2835_codec_driver *drv, - struct bcm2835_codec_dev **new_dev, - enum bcm2835_codec_role role) - { -+ struct platform_device *pdev = drv->pdev; - struct bcm2835_codec_dev *dev; - struct video_device *vfd; - int video_nr; -@@ -2711,15 +2714,17 @@ static int bcm2835_codec_probe(struct pl - if (!drv) - return -ENOMEM; - -- ret = bcm2835_codec_create(pdev, &drv->decode, DECODE); -+ drv->pdev = pdev; -+ -+ ret = bcm2835_codec_create(drv, &drv->decode, DECODE); - if (ret) - goto out; - -- ret = bcm2835_codec_create(pdev, &drv->encode, ENCODE); -+ ret = bcm2835_codec_create(drv, &drv->encode, ENCODE); - if (ret) - goto out; - -- ret = bcm2835_codec_create(pdev, &drv->isp, ISP); -+ ret = bcm2835_codec_create(drv, &drv->isp, ISP); - if (ret) - goto out; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0306-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch b/target/linux/bcm27xx/patches-5.4/950-0306-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch new file mode 100644 index 0000000000..f6391e0b96 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0306-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch @@ -0,0 +1,34 @@ +From ae66baa23455df9f7593b98c5c2f02818dbaf41b Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Wed, 11 Sep 2019 14:57:18 +0100 +Subject: [PATCH] drm/vc4: Fix for margins in composite/SDTV mode + (#3223) + +Margins were incorrectly assumed to be setup in SDTV mode, but were +not actually done, so this make the setup non-conditional on mode. + +Signed-off-by: James Hughes +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -1612,14 +1612,9 @@ vc4_fkms_connector_init(struct drm_devic + connector->interlace_allowed = 0; + } + +- /* Create and attach TV margin props to this connector. +- * Already done for SDTV outputs. +- */ +- if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) { +- ret = drm_mode_create_tv_margin_properties(dev); +- if (ret) +- goto fail; +- } ++ ret = drm_mode_create_tv_margin_properties(dev); ++ if (ret) ++ goto fail; + + drm_connector_attach_tv_margin_properties(connector); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0306-staging-bcm2835-codec-add-media-controller-support.patch b/target/linux/bcm27xx/patches-5.4/950-0306-staging-bcm2835-codec-add-media-controller-support.patch deleted file mode 100644 index f0ac32340c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0306-staging-bcm2835-codec-add-media-controller-support.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 4d066da23979b8de03b5915388136be6e293600f Mon Sep 17 00:00:00 2001 -From: Kieran Bingham -Date: Wed, 20 Mar 2019 12:54:15 +0000 -Subject: [PATCH] staging: bcm2835-codec: add media controller support - -Provide a single media device to contain all of the bcm2835_codec -devices created. - -Signed-off-by: Kieran Bingham ---- - .../vc04_services/bcm2835-codec/Kconfig | 2 +- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 41 +++++++++++++++++-- - 2 files changed, 38 insertions(+), 5 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/Kconfig -+++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig -@@ -1,6 +1,6 @@ - config VIDEO_CODEC_BCM2835 - tristate "BCM2835 Video codec support" -- depends on MEDIA_SUPPORT -+ depends on MEDIA_SUPPORT && MEDIA_CONTROLLER - depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) - select BCM2835_VCHIQ_MMAL - select VIDEOBUF2_DMA_CONTIG ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -458,6 +458,7 @@ struct bcm2835_codec_ctx { - - struct bcm2835_codec_driver { - struct platform_device *pdev; -+ struct media_device mdev; - - struct bcm2835_codec_dev *encode; - struct bcm2835_codec_dev *decode; -@@ -2596,6 +2597,7 @@ static int bcm2835_codec_create(struct b - struct platform_device *pdev = drv->pdev; - struct bcm2835_codec_dev *dev; - struct video_device *vfd; -+ int function; - int video_nr; - int ret; - -@@ -2615,18 +2617,21 @@ static int bcm2835_codec_create(struct b - if (ret) - goto vchiq_finalise; - -- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); -- if (ret) -- goto vchiq_finalise; -- - atomic_set(&dev->num_inst, 0); - mutex_init(&dev->dev_mutex); - -+ /* Initialise the video device */ - dev->vfd = bcm2835_codec_videodev; -+ - vfd = &dev->vfd; - vfd->lock = &dev->dev_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; -+ vfd->v4l2_dev->mdev = &drv->mdev; -+ -+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); -+ if (ret) -+ goto vchiq_finalise; - - switch (role) { - case DECODE: -@@ -2634,11 +2639,13 @@ static int bcm2835_codec_create(struct b - v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); - v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); -+ function = MEDIA_ENT_F_PROC_VIDEO_DECODER; - video_nr = decode_video_nr; - break; - case ENCODE: - v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); -+ function = MEDIA_ENT_F_PROC_VIDEO_ENCODER; - video_nr = encode_video_nr; - break; - case ISP: -@@ -2648,6 +2655,7 @@ static int bcm2835_codec_create(struct b - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); - v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); -+ function = MEDIA_ENT_F_PROC_VIDEO_SCALER; - video_nr = isp_video_nr; - break; - default: -@@ -2676,6 +2684,10 @@ static int bcm2835_codec_create(struct b - goto err_m2m; - } - -+ ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, function); -+ if (ret) -+ goto err_m2m; -+ - v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n", - roles[role]); - return 0; -@@ -2697,6 +2709,7 @@ static int bcm2835_codec_destroy(struct - - v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n", - roles[dev->role]); -+ v4l2_m2m_unregister_media_controller(dev->m2m_dev); - v4l2_m2m_release(dev->m2m_dev); - video_unregister_device(&dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); -@@ -2708,6 +2721,7 @@ static int bcm2835_codec_destroy(struct - static int bcm2835_codec_probe(struct platform_device *pdev) - { - struct bcm2835_codec_driver *drv; -+ struct media_device *mdev; - int ret = 0; - - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); -@@ -2715,6 +2729,17 @@ static int bcm2835_codec_probe(struct pl - return -ENOMEM; - - drv->pdev = pdev; -+ mdev = &drv->mdev; -+ mdev->dev = &pdev->dev; -+ -+ strscpy(mdev->model, bcm2835_codec_videodev.name, sizeof(mdev->model)); -+ strscpy(mdev->serial, "0000", sizeof(mdev->serial)); -+ snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", -+ pdev->name); -+ -+ /* This should return the vgencmd version information or such .. */ -+ mdev->hw_revision = 1; -+ media_device_init(mdev); - - ret = bcm2835_codec_create(drv, &drv->decode, DECODE); - if (ret) -@@ -2728,6 +2753,10 @@ static int bcm2835_codec_probe(struct pl - if (ret) - goto out; - -+ /* Register the media device node */ -+ if (media_device_register(mdev) < 0) -+ goto out; -+ - platform_set_drvdata(pdev, drv); - - return 0; -@@ -2748,12 +2777,16 @@ static int bcm2835_codec_remove(struct p - { - struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev); - -+ media_device_unregister(&drv->mdev); -+ - bcm2835_codec_destroy(drv->isp); - - bcm2835_codec_destroy(drv->encode); - - bcm2835_codec_destroy(drv->decode); - -+ media_device_cleanup(&drv->mdev); -+ - return 0; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0307-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch b/target/linux/bcm27xx/patches-5.4/950-0307-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch new file mode 100644 index 0000000000..5855d0057b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0307-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch @@ -0,0 +1,238 @@ +From 59c54c8b3b5afe051ca627fb42a685909b58d631 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= + +Date: Thu, 12 Sep 2019 14:57:32 +0200 +Subject: [PATCH] Add Hifiberry DAC+DSP soundcard driver (#3224) + +Adds the driver for the Hifiberry DAC+DSP. It supports capture and +playback depending on the DSP firmware. + +Signed-off-by: Joerg Schambacher +--- + sound/soc/bcm/Kconfig | 7 ++ + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/hifiberry_dacplusadcpro.c | 28 +++----- + sound/soc/bcm/hifiberry_dacplusdsp.c | 90 +++++++++++++++++++++++++ + sound/soc/bcm/rpi-simple-soundcard.c | 23 +++++++ + 5 files changed, 132 insertions(+), 18 deletions(-) + create mode 100644 sound/soc/bcm/hifiberry_dacplusdsp.c + +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -59,6 +59,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + help + Say Y or M if you want to add support for HifiBerry DAC+ADC PRO. + ++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP ++ tristate "Support for HifiBerry DAC+DSP" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_RPI_SIMPLE_SOUNDCARD ++ help ++ Say Y or M if you want to add support for HifiBerry DSP-DAC. ++ + config SND_BCM2708_SOC_HIFIBERRY_DIGI + tristate "Support for HifiBerry Digi" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -16,6 +16,7 @@ snd-soc-googlevoicehat-codec-objs := goo + snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o + snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o + snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o ++snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o + snd-soc-justboom-dac-objs := justboom-dac.o + snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-proto-objs := rpi-proto.o +@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICE + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o +--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c ++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c +@@ -445,29 +445,21 @@ static struct snd_soc_ops snd_rpi_hifibe + .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown, + }; + +-static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = { +- { +- .name = "pcm512x.1-004d", +- .dai_name = "pcm512x-hifi", +- }, +- { +- .name = "pcm186x.1-004a", +- .dai_name = "pcm1863-aif", +- }, +-}; ++SND_SOC_DAILINK_DEFS(hifi, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"), ++ COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); + + static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = { + { + .name = "HiFiBerry DAC+ADC PRO", + .stream_name = "HiFiBerry DAC+ADC PRO HiFi", +- .cpu_dai_name = "bcm2708-i2s.0", +- .platform_name = "bcm2708-i2s.0", +- .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs, +- .num_codecs = 2, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ops = &snd_rpi_hifiberry_dacplusadcpro_ops, + .init = snd_rpi_hifiberry_dacplusadcpro_init, ++ SND_SOC_DAILINK_REG(hifi), + }, + }; + +@@ -495,10 +487,10 @@ static int snd_rpi_hifiberry_dacplusadcp + "i2s-controller", 0); + if (i2s_node) { + for (i = 0; i < card->num_links; i++) { +- dai->cpu_dai_name = NULL; +- dai->cpu_of_node = i2s_node; +- dai->platform_name = NULL; +- dai->platform_of_node = i2s_node; ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; + } + } + } +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_dacplusdsp.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * ASoC Driver for HiFiBerry DAC + DSP ++ * ++ * Author: Joerg Schambacher ++ * Copyright 2018 ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++ ++static struct snd_soc_component_driver dacplusdsp_component_driver; ++ ++static struct snd_soc_dai_driver dacplusdsp_dai = { ++ .name = "dacplusdsp-hifi", ++ .capture = { ++ .stream_name = "DAC+DSP Capture", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE, ++ }, ++ .playback = { ++ .stream_name = "DACP+DSP Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE, ++ }, ++ .symmetric_rates = 1}; ++ ++#ifdef CONFIG_OF ++static const struct of_device_id dacplusdsp_ids[] = { ++ { ++ .compatible = "hifiberry,dacplusdsp", ++ }, ++ {} }; ++MODULE_DEVICE_TABLE(of, dacplusdsp_ids); ++#endif ++ ++static int dacplusdsp_platform_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ret = snd_soc_register_component(&pdev->dev, ++ &dacplusdsp_component_driver, &dacplusdsp_dai, 1); ++ if (ret) { ++ pr_alert("snd_soc_register_component failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int dacplusdsp_platform_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_component(&pdev->dev); ++ return 0; ++} ++ ++static struct platform_driver dacplusdsp_driver = { ++ .driver = { ++ .name = "hifiberry-dacplusdsp-codec", ++ .of_match_table = of_match_ptr(dacplusdsp_ids), ++ }, ++ .probe = dacplusdsp_platform_probe, ++ .remove = dacplusdsp_platform_remove, ++}; ++ ++module_platform_driver(dacplusdsp_driver); ++ ++MODULE_AUTHOR("Joerg Schambacher "); ++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+DSP"); ++MODULE_LICENSE("GPL v2"); +--- a/sound/soc/bcm/rpi-simple-soundcard.c ++++ b/sound/soc/bcm/rpi-simple-soundcard.c +@@ -144,6 +144,27 @@ static struct snd_rpi_simple_drvdata drv + .dai = snd_googlevoicehat_soundcard_dai, + }; + ++SND_SOC_DAILINK_DEFS(hifiberry_dacplusdsp, ++ DAILINK_COMP_ARRAY(COMP_EMPTY()), ++ DAILINK_COMP_ARRAY(COMP_CODEC("dacplusdsp-codec", "dacplusdsp-hifi")), ++ DAILINK_COMP_ARRAY(COMP_EMPTY())); ++ ++static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = { ++{ ++ .name = "Hifiberry DAC+DSP SoundCard", ++ .stream_name = "Hifiberry DAC+DSP SoundCard HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ SND_SOC_DAILINK_REG(hifiberry_dacplusdsp), ++}, ++}; ++ ++static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = { ++ .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard", ++ .dai = snd_hifiberrydacplusdsp_soundcard_dai, ++}; ++ + SND_SOC_DAILINK_DEFS(hifiberry_amp, + DAILINK_COMP_ARRAY(COMP_EMPTY()), + DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")), +@@ -213,6 +234,8 @@ static const struct of_device_id snd_rpi + .data = (void *) &drvdata_adau1977 }, + { .compatible = "googlevoicehat,googlevoicehat-soundcard", + .data = (void *) &drvdata_googlevoicehat }, ++ { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard", ++ .data = (void *) &drvdata_hifiberrydacplusdsp }, + { .compatible = "hifiberry,hifiberry-amp", + .data = (void *) &drvdata_hifiberry_amp }, + { .compatible = "hifiberry,hifiberry-dac", diff --git a/target/linux/bcm27xx/patches-5.4/950-0307-v4l2-Add-a-Greyworld-AWB-mode.patch b/target/linux/bcm27xx/patches-5.4/950-0307-v4l2-Add-a-Greyworld-AWB-mode.patch deleted file mode 100644 index 459646e7e7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0307-v4l2-Add-a-Greyworld-AWB-mode.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 1b14387d6b699c4cfc8218867997b1508a67167a Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 6 Sep 2019 15:04:51 +0100 -Subject: [PATCH] v4l2: Add a Greyworld AWB mode. - -Adds a simple greyworld white balance preset, mainly for use -with cameras without an IR filter (eg Raspberry Pi NoIR) - -Signed-off-by: Dave Stevenson ---- - drivers/media/v4l2-core/v4l2-ctrls.c | 1 + - include/uapi/linux/v4l2-controls.h | 1 + - 2 files changed, 2 insertions(+) - ---- a/drivers/media/v4l2-core/v4l2-ctrls.c -+++ b/drivers/media/v4l2-core/v4l2-ctrls.c -@@ -271,6 +271,7 @@ const char * const *v4l2_ctrl_get_menu(u - "Flash", - "Cloudy", - "Shade", -+ "Greyworld", - NULL, - }; - static const char * const camera_iso_sensitivity_auto[] = { ---- a/include/uapi/linux/v4l2-controls.h -+++ b/include/uapi/linux/v4l2-controls.h -@@ -850,6 +850,7 @@ enum v4l2_auto_n_preset_white_balance { - V4L2_WHITE_BALANCE_FLASH = 7, - V4L2_WHITE_BALANCE_CLOUDY = 8, - V4L2_WHITE_BALANCE_SHADE = 9, -+ V4L2_WHITE_BALANCE_GREYWORLD = 10, - }; - - #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21) diff --git a/target/linux/bcm27xx/patches-5.4/950-0308-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch b/target/linux/bcm27xx/patches-5.4/950-0308-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch deleted file mode 100644 index e29c3800c4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0308-staging-bcm2835-camera-Add-greyworld-AWB-mode.patch +++ /dev/null @@ -1,48 +0,0 @@ -From a1504ea7c24e74fe4d10b024d8105dc66115b01e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 6 Sep 2019 15:13:06 +0100 -Subject: [PATCH] staging: bcm2835-camera: Add greyworld AWB mode - -This is mainly used for the NoIR camera which has no IR -filter and can completely confuse normal AWB presets. - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/bcm2835-camera/controls.c | 8 ++++++-- - .../staging/vc04_services/vchiq-mmal/mmal-parameters.h | 1 + - 2 files changed, 7 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-camera/controls.c -+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c -@@ -477,6 +477,10 @@ static int ctrl_set_awb_mode(struct bm28 - case V4L2_WHITE_BALANCE_SHADE: - u32_value = MMAL_PARAM_AWBMODE_SHADE; - break; -+ -+ case V4L2_WHITE_BALANCE_GREYWORLD: -+ u32_value = MMAL_PARAM_AWBMODE_GREYWORLD; -+ break; - } - - return vchiq_mmal_port_parameter_set(dev->instance, control, -@@ -1014,8 +1018,8 @@ static const struct bm2835_mmal_v4l2_ctr - { - V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, - MMAL_CONTROL_TYPE_STD_MENU, -- ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0, -- NULL, -+ ~0x7ff, V4L2_WHITE_BALANCE_GREYWORLD, V4L2_WHITE_BALANCE_AUTO, -+ 0, NULL, - MMAL_PARAMETER_AWB_MODE, - ctrl_set_awb_mode, - false ---- a/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h -+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-parameters.h -@@ -313,6 +313,7 @@ enum mmal_parameter_awbmode { - MMAL_PARAM_AWBMODE_INCANDESCENT, - MMAL_PARAM_AWBMODE_FLASH, - MMAL_PARAM_AWBMODE_HORIZON, -+ MMAL_PARAM_AWBMODE_GREYWORLD, - }; - - enum mmal_parameter_imagefx { diff --git a/target/linux/bcm27xx/patches-5.4/950-0308-staging-bcm2835-codec-Allow-height-of-1920.patch b/target/linux/bcm27xx/patches-5.4/950-0308-staging-bcm2835-codec-Allow-height-of-1920.patch new file mode 100644 index 0000000000..862737f383 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0308-staging-bcm2835-codec-Allow-height-of-1920.patch @@ -0,0 +1,27 @@ +From 59c8c7740d6f236431fa792957fefe9f67611b27 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 6 Sep 2019 17:24:55 +0100 +Subject: [PATCH] staging: bcm2835-codec: Allow height of 1920. + +The codec is happy with video up to 1920 high if the width +is suitably reduced to stay within level limits. eg 1080x1920 +is OK to decode. + +Increase the height limit accordingly. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -92,7 +92,7 @@ static const char * const components[] = + #define MIN_W 32 + #define MIN_H 32 + #define MAX_W 1920 +-#define MAX_H 1088 ++#define MAX_H 1920 + #define BPL_ALIGN 32 + #define DEFAULT_WIDTH 640 + #define DEFAULT_HEIGHT 480 diff --git a/target/linux/bcm27xx/patches-5.4/950-0309-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch b/target/linux/bcm27xx/patches-5.4/950-0309-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch deleted file mode 100644 index f6391e0b96..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0309-drm-vc4-Fix-for-margins-in-composite-SDTV-mode-3223.patch +++ /dev/null @@ -1,34 +0,0 @@ -From ae66baa23455df9f7593b98c5c2f02818dbaf41b Mon Sep 17 00:00:00 2001 -From: James Hughes -Date: Wed, 11 Sep 2019 14:57:18 +0100 -Subject: [PATCH] drm/vc4: Fix for margins in composite/SDTV mode - (#3223) - -Margins were incorrectly assumed to be setup in SDTV mode, but were -not actually done, so this make the setup non-conditional on mode. - -Signed-off-by: James Hughes ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 11 +++-------- - 1 file changed, 3 insertions(+), 8 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -1612,14 +1612,9 @@ vc4_fkms_connector_init(struct drm_devic - connector->interlace_allowed = 0; - } - -- /* Create and attach TV margin props to this connector. -- * Already done for SDTV outputs. -- */ -- if (fkms_connector->display_type != DRM_MODE_ENCODER_TVDAC) { -- ret = drm_mode_create_tv_margin_properties(dev); -- if (ret) -- goto fail; -- } -+ ret = drm_mode_create_tv_margin_properties(dev); -+ if (ret) -+ goto fail; - - drm_connector_attach_tv_margin_properties(connector); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0309-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch b/target/linux/bcm27xx/patches-5.4/950-0309-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch new file mode 100644 index 0000000000..a91bcc3111 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0309-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch @@ -0,0 +1,107 @@ +From c8a466aecf6b7d0bdc1fea9e32f80327b641cd03 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 13 Sep 2019 15:11:47 +0100 +Subject: [PATCH] staging: bcm2835-codec: Correct g/s_selection API + MPLANE support + +The g_selection and s_selection API is messed up and requires +the driver to expect the non-MPLANE buffer types, not the MPLANE +ones even if they are supported. The V4L2 core will convert the +MPLANE ones to non-MPLANE should they be passed in + +Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 67 +++++++++++++------ + 1 file changed, 47 insertions(+), 20 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1260,17 +1260,30 @@ static int vidioc_g_selection(struct fil + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + struct bcm2835_codec_q_data *q_data; +- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? +- true : false; + +- if ((ctx->dev->role == DECODE && !capture_queue) || +- (ctx->dev->role == ENCODE && capture_queue)) +- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ +- return -EINVAL; +- +- q_data = get_q_data(ctx, s->type); +- if (!q_data) ++ /* ++ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and ++ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE ++ * API. The V4L2 core will have converted the MPLANE variants to ++ * non-MPLANE. ++ * Open code this instead of using get_q_data in this case. ++ */ ++ switch (s->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ /* CAPTURE on encoder is not valid. */ ++ if (ctx->dev->role == ENCODE) ++ return -EINVAL; ++ q_data = &ctx->q_data[V4L2_M2M_DST]; ++ break; ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ /* OUTPUT on deoder is not valid. */ ++ if (ctx->dev->role == DECODE) ++ return -EINVAL; ++ q_data = &ctx->q_data[V4L2_M2M_SRC]; ++ break; ++ default: + return -EINVAL; ++ } + + switch (ctx->dev->role) { + case DECODE: +@@ -1323,22 +1336,36 @@ static int vidioc_s_selection(struct fil + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + struct bcm2835_codec_q_data *q_data = NULL; +- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? +- true : false; ++ ++ /* ++ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and ++ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE ++ * API. The V4L2 core will have converted the MPLANE variants to ++ * non-MPLANE. ++ * ++ * Open code this instead of using get_q_data in this case. ++ */ ++ switch (s->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ /* CAPTURE on encoder is not valid. */ ++ if (ctx->dev->role == ENCODE) ++ return -EINVAL; ++ q_data = &ctx->q_data[V4L2_M2M_DST]; ++ break; ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ /* OUTPUT on deoder is not valid. */ ++ if (ctx->dev->role == DECODE) ++ return -EINVAL; ++ q_data = &ctx->q_data[V4L2_M2M_SRC]; ++ break; ++ default: ++ return -EINVAL; ++ } + + v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n", + __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top, + s->r.width, s->r.height); + +- if ((ctx->dev->role == DECODE && !capture_queue) || +- (ctx->dev->role == ENCODE && capture_queue)) +- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ +- return -EINVAL; +- +- q_data = get_q_data(ctx, s->type); +- if (!q_data) +- return -EINVAL; +- + switch (ctx->dev->role) { + case DECODE: + switch (s->target) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0310-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch b/target/linux/bcm27xx/patches-5.4/950-0310-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch deleted file mode 100644 index 5855d0057b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0310-Add-Hifiberry-DAC-DSP-soundcard-driver-3224.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 59c54c8b3b5afe051ca627fb42a685909b58d631 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= - -Date: Thu, 12 Sep 2019 14:57:32 +0200 -Subject: [PATCH] Add Hifiberry DAC+DSP soundcard driver (#3224) - -Adds the driver for the Hifiberry DAC+DSP. It supports capture and -playback depending on the DSP firmware. - -Signed-off-by: Joerg Schambacher ---- - sound/soc/bcm/Kconfig | 7 ++ - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/hifiberry_dacplusadcpro.c | 28 +++----- - sound/soc/bcm/hifiberry_dacplusdsp.c | 90 +++++++++++++++++++++++++ - sound/soc/bcm/rpi-simple-soundcard.c | 23 +++++++ - 5 files changed, 132 insertions(+), 18 deletions(-) - create mode 100644 sound/soc/bcm/hifiberry_dacplusdsp.c - ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -59,6 +59,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - help - Say Y or M if you want to add support for HifiBerry DAC+ADC PRO. - -+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP -+ tristate "Support for HifiBerry DAC+DSP" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_RPI_SIMPLE_SOUNDCARD -+ help -+ Say Y or M if you want to add support for HifiBerry DSP-DAC. -+ - config SND_BCM2708_SOC_HIFIBERRY_DIGI - tristate "Support for HifiBerry Digi" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -16,6 +16,7 @@ snd-soc-googlevoicehat-codec-objs := goo - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o - snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o - snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o -+snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o - snd-soc-justboom-dac-objs := justboom-dac.o - snd-soc-rpi-cirrus-objs := rpi-cirrus.o - snd-soc-rpi-proto-objs := rpi-proto.o -@@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICE - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o - obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o ---- a/sound/soc/bcm/hifiberry_dacplusadcpro.c -+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c -@@ -445,29 +445,21 @@ static struct snd_soc_ops snd_rpi_hifibe - .shutdown = snd_rpi_hifiberry_dacplusadcpro_shutdown, - }; - --static struct snd_soc_dai_link_component snd_rpi_hifiberry_dacplusadcpro_codecs[] = { -- { -- .name = "pcm512x.1-004d", -- .dai_name = "pcm512x-hifi", -- }, -- { -- .name = "pcm186x.1-004a", -- .dai_name = "pcm1863-aif", -- }, --}; -+SND_SOC_DAILINK_DEFS(hifi, -+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), -+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"), -+ COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")), -+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); - - static struct snd_soc_dai_link snd_rpi_hifiberry_dacplusadcpro_dai[] = { - { - .name = "HiFiBerry DAC+ADC PRO", - .stream_name = "HiFiBerry DAC+ADC PRO HiFi", -- .cpu_dai_name = "bcm2708-i2s.0", -- .platform_name = "bcm2708-i2s.0", -- .codecs = snd_rpi_hifiberry_dacplusadcpro_codecs, -- .num_codecs = 2, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, - .ops = &snd_rpi_hifiberry_dacplusadcpro_ops, - .init = snd_rpi_hifiberry_dacplusadcpro_init, -+ SND_SOC_DAILINK_REG(hifi), - }, - }; - -@@ -495,10 +487,10 @@ static int snd_rpi_hifiberry_dacplusadcp - "i2s-controller", 0); - if (i2s_node) { - for (i = 0; i < card->num_links; i++) { -- dai->cpu_dai_name = NULL; -- dai->cpu_of_node = i2s_node; -- dai->platform_name = NULL; -- dai->platform_of_node = i2s_node; -+ dai->cpus->dai_name = NULL; -+ dai->cpus->of_node = i2s_node; -+ dai->platforms->name = NULL; -+ dai->platforms->of_node = i2s_node; - } - } - } ---- /dev/null -+++ b/sound/soc/bcm/hifiberry_dacplusdsp.c -@@ -0,0 +1,90 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * ASoC Driver for HiFiBerry DAC + DSP -+ * -+ * Author: Joerg Schambacher -+ * Copyright 2018 -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+ -+static struct snd_soc_component_driver dacplusdsp_component_driver; -+ -+static struct snd_soc_dai_driver dacplusdsp_dai = { -+ .name = "dacplusdsp-hifi", -+ .capture = { -+ .stream_name = "DAC+DSP Capture", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_CONTINUOUS, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE, -+ }, -+ .playback = { -+ .stream_name = "DACP+DSP Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_CONTINUOUS, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S24_LE | -+ SNDRV_PCM_FMTBIT_S32_LE, -+ }, -+ .symmetric_rates = 1}; -+ -+#ifdef CONFIG_OF -+static const struct of_device_id dacplusdsp_ids[] = { -+ { -+ .compatible = "hifiberry,dacplusdsp", -+ }, -+ {} }; -+MODULE_DEVICE_TABLE(of, dacplusdsp_ids); -+#endif -+ -+static int dacplusdsp_platform_probe(struct platform_device *pdev) -+{ -+ int ret; -+ -+ ret = snd_soc_register_component(&pdev->dev, -+ &dacplusdsp_component_driver, &dacplusdsp_dai, 1); -+ if (ret) { -+ pr_alert("snd_soc_register_component failed\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int dacplusdsp_platform_remove(struct platform_device *pdev) -+{ -+ snd_soc_unregister_component(&pdev->dev); -+ return 0; -+} -+ -+static struct platform_driver dacplusdsp_driver = { -+ .driver = { -+ .name = "hifiberry-dacplusdsp-codec", -+ .of_match_table = of_match_ptr(dacplusdsp_ids), -+ }, -+ .probe = dacplusdsp_platform_probe, -+ .remove = dacplusdsp_platform_remove, -+}; -+ -+module_platform_driver(dacplusdsp_driver); -+ -+MODULE_AUTHOR("Joerg Schambacher "); -+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+DSP"); -+MODULE_LICENSE("GPL v2"); ---- a/sound/soc/bcm/rpi-simple-soundcard.c -+++ b/sound/soc/bcm/rpi-simple-soundcard.c -@@ -144,6 +144,27 @@ static struct snd_rpi_simple_drvdata drv - .dai = snd_googlevoicehat_soundcard_dai, - }; - -+SND_SOC_DAILINK_DEFS(hifiberry_dacplusdsp, -+ DAILINK_COMP_ARRAY(COMP_EMPTY()), -+ DAILINK_COMP_ARRAY(COMP_CODEC("dacplusdsp-codec", "dacplusdsp-hifi")), -+ DAILINK_COMP_ARRAY(COMP_EMPTY())); -+ -+static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = { -+{ -+ .name = "Hifiberry DAC+DSP SoundCard", -+ .stream_name = "Hifiberry DAC+DSP SoundCard HiFi", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ SND_SOC_DAILINK_REG(hifiberry_dacplusdsp), -+}, -+}; -+ -+static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = { -+ .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard", -+ .dai = snd_hifiberrydacplusdsp_soundcard_dai, -+}; -+ - SND_SOC_DAILINK_DEFS(hifiberry_amp, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")), -@@ -213,6 +234,8 @@ static const struct of_device_id snd_rpi - .data = (void *) &drvdata_adau1977 }, - { .compatible = "googlevoicehat,googlevoicehat-soundcard", - .data = (void *) &drvdata_googlevoicehat }, -+ { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard", -+ .data = (void *) &drvdata_hifiberrydacplusdsp }, - { .compatible = "hifiberry,hifiberry-amp", - .data = (void *) &drvdata_hifiberry_amp }, - { .compatible = "hifiberry,hifiberry-dac", diff --git a/target/linux/bcm27xx/patches-5.4/950-0310-drm-v3d-Delete-pm_runtime-support.patch b/target/linux/bcm27xx/patches-5.4/950-0310-drm-v3d-Delete-pm_runtime-support.patch new file mode 100644 index 0000000000..642be233ad --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0310-drm-v3d-Delete-pm_runtime-support.patch @@ -0,0 +1,62 @@ +From 4fad98821e9ccd74b9b828d98cbe9df8c7437605 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 18 Sep 2019 17:22:36 +0100 +Subject: [PATCH] drm/v3d: Delete pm_runtime support + +The pm_runtime was blocking changelist submission, so delete it as a +temporary workaround. + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/v3d_gem.c | 5 ----- + drivers/gpu/drm/v3d/v3d_mmu.c | 11 ----------- + 2 files changed, 16 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -478,10 +478,6 @@ v3d_job_init(struct v3d_dev *v3d, struct + job->v3d = v3d; + job->free = free; + +- ret = pm_runtime_get_sync(v3d->dev); +- if (ret < 0) +- return ret; +- + xa_init_flags(&job->deps, XA_FLAGS_ALLOC); + + ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &in_fence); +@@ -498,7 +494,6 @@ v3d_job_init(struct v3d_dev *v3d, struct + return 0; + fail: + xa_destroy(&job->deps); +- pm_runtime_put_autosuspend(v3d->dev); + return ret; + } + +--- a/drivers/gpu/drm/v3d/v3d_mmu.c ++++ b/drivers/gpu/drm/v3d/v3d_mmu.c +@@ -36,14 +36,6 @@ static int v3d_mmu_flush_all(struct v3d_ + { + int ret; + +- /* Keep power on the device on until we're done with this +- * call, but skip the flush if the device is off and will be +- * reset when powered back on. +- */ +- ret = pm_runtime_get_if_in_use(v3d->dev); +- if (ret == 0) +- return 0; +- + /* Make sure that another flush isn't already running when we + * start this one. + */ +@@ -71,9 +63,6 @@ static int v3d_mmu_flush_all(struct v3d_ + if (ret) + dev_err(v3d->dev, "MMUC flush wait idle failed\n"); + +- pm_runtime_mark_last_busy(v3d->dev); +- pm_runtime_put_autosuspend(v3d->dev); +- + return ret; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0311-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch b/target/linux/bcm27xx/patches-5.4/950-0311-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch new file mode 100644 index 0000000000..c7eccdeed4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0311-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch @@ -0,0 +1,30 @@ +From 849dc86116416161d0f13bf929ab712ea2bade7e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 18 Sep 2019 09:02:10 +0100 +Subject: [PATCH] dts: Add DTS for Pi 2B rev 1.2 with BCM2837 (#3235) + +Signed-off-by: Phil Elwell +--- + arch/arm64/boot/dts/broadcom/Makefile | 2 ++ + arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts | 3 +++ + 2 files changed, 5 insertions(+) + create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts + +--- a/arch/arm64/boot/dts/broadcom/Makefile ++++ b/arch/arm64/boot/dts/broadcom/Makefile +@@ -3,7 +3,9 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rp + bcm2837-rpi-3-b.dtb \ + bcm2837-rpi-3-b-plus.dtb \ + bcm2837-rpi-cm3-io3.dtb ++dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-2-b.dtb + dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb ++dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb +--- /dev/null ++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts +@@ -0,0 +1,3 @@ ++#define RPI364 ++ ++#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts" diff --git a/target/linux/bcm27xx/patches-5.4/950-0311-staging-bcm2835-codec-Allow-height-of-1920.patch b/target/linux/bcm27xx/patches-5.4/950-0311-staging-bcm2835-codec-Allow-height-of-1920.patch deleted file mode 100644 index 862737f383..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0311-staging-bcm2835-codec-Allow-height-of-1920.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 59c8c7740d6f236431fa792957fefe9f67611b27 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 6 Sep 2019 17:24:55 +0100 -Subject: [PATCH] staging: bcm2835-codec: Allow height of 1920. - -The codec is happy with video up to 1920 high if the width -is suitably reduced to stay within level limits. eg 1080x1920 -is OK to decode. - -Increase the height limit accordingly. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -92,7 +92,7 @@ static const char * const components[] = - #define MIN_W 32 - #define MIN_H 32 - #define MAX_W 1920 --#define MAX_H 1088 -+#define MAX_H 1920 - #define BPL_ALIGN 32 - #define DEFAULT_WIDTH 640 - #define DEFAULT_HEIGHT 480 diff --git a/target/linux/bcm27xx/patches-5.4/950-0312-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch b/target/linux/bcm27xx/patches-5.4/950-0312-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch new file mode 100644 index 0000000000..961c0cc92b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0312-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch @@ -0,0 +1,164 @@ +From 141da39c2ce8dbf77773c54182244c14d96b301d Mon Sep 17 00:00:00 2001 +From: Iago Toral Quiroga +Date: Tue, 3 Sep 2019 08:45:24 +0200 +Subject: [PATCH] drm/v3d: clean caches at the end of render jobs on + request from user space + +Extends the user space ioctl for CL submissions so it can include a request +to flush the cache once the CL execution has completed. Fixes memory +write violation messages reported by the kernel in workloads involving +shader memory writes (SSBOs, shader images, scratch, etc) which sometimes +also lead to GPU resets during Piglit and CTS workloads. + +v2: if v3d_job_init() fails we need to kfree() the job instead of + v3d_job_put() it (Eric Anholt). + +v3 (Eric Anholt): + - Drop _FLAG suffix from the new flag name. + - Add a new param so userspace can tell whether cache flushing is + implemented in the kernel. + +Signed-off-by: Iago Toral Quiroga +--- + drivers/gpu/drm/v3d/v3d_drv.c | 3 +++ + drivers/gpu/drm/v3d/v3d_gem.c | 48 ++++++++++++++++++++++++++++++----- + include/uapi/drm/v3d_drm.h | 6 +++-- + 3 files changed, 49 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -120,6 +120,9 @@ static int v3d_get_param_ioctl(struct dr + case DRM_V3D_PARAM_SUPPORTS_CSD: + args->value = v3d_has_csd(v3d); + return 0; ++ case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH: ++ args->value = 1; ++ return 0; + default: + DRM_DEBUG("Unknown parameter %d\n", args->param); + return -EINVAL; +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -565,13 +565,16 @@ v3d_submit_cl_ioctl(struct drm_device *d + struct drm_v3d_submit_cl *args = data; + struct v3d_bin_job *bin = NULL; + struct v3d_render_job *render; ++ struct v3d_job *clean_job = NULL; ++ struct v3d_job *last_job; + struct ww_acquire_ctx acquire_ctx; + int ret = 0; + + trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); + +- if (args->pad != 0) { +- DRM_INFO("pad must be zero: %d\n", args->pad); ++ if (args->flags != 0 && ++ args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { ++ DRM_INFO("invalid flags: %d\n", args->flags); + return -EINVAL; + } + +@@ -613,12 +616,31 @@ v3d_submit_cl_ioctl(struct drm_device *d + bin->render = render; + } + +- ret = v3d_lookup_bos(dev, file_priv, &render->base, ++ if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { ++ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL); ++ if (!clean_job) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ ++ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0); ++ if (ret) { ++ kfree(clean_job); ++ clean_job = NULL; ++ goto fail; ++ } ++ ++ last_job = clean_job; ++ } else { ++ last_job = &render->base; ++ } ++ ++ ret = v3d_lookup_bos(dev, file_priv, last_job, + args->bo_handles, args->bo_handle_count); + if (ret) + goto fail; + +- ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx); ++ ret = v3d_lock_bo_reservations(last_job, &acquire_ctx); + if (ret) + goto fail; + +@@ -637,17 +659,29 @@ v3d_submit_cl_ioctl(struct drm_device *d + ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER); + if (ret) + goto fail_unreserve; ++ ++ if (clean_job) { ++ ret = drm_gem_fence_array_add(&clean_job->deps, ++ dma_fence_get(render->base.done_fence)); ++ if (ret) ++ goto fail_unreserve; ++ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN); ++ if (ret) ++ goto fail_unreserve; ++ } + mutex_unlock(&v3d->sched_lock); + + v3d_attach_fences_and_unlock_reservation(file_priv, +- &render->base, ++ last_job, + &acquire_ctx, + args->out_sync, +- render->base.done_fence); ++ last_job->done_fence); + + if (bin) + v3d_job_put(&bin->base); + v3d_job_put(&render->base); ++ if (clean_job) ++ v3d_job_put(clean_job); + + return 0; + +@@ -659,6 +693,8 @@ fail: + if (bin) + v3d_job_put(&bin->base); + v3d_job_put(&render->base); ++ if (clean_job) ++ v3d_job_put(clean_job); + + return ret; + } +--- a/include/uapi/drm/v3d_drm.h ++++ b/include/uapi/drm/v3d_drm.h +@@ -48,6 +48,8 @@ extern "C" { + #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu) + #define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd) + ++#define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01 ++ + /** + * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D + * engine. +@@ -124,8 +126,7 @@ struct drm_v3d_submit_cl { + /* Number of BO handles passed in (size is that times 4). */ + __u32 bo_handle_count; + +- /* Pad, must be zero-filled. */ +- __u32 pad; ++ __u32 flags; + }; + + /** +@@ -193,6 +194,7 @@ enum drm_v3d_param { + DRM_V3D_PARAM_V3D_CORE0_IDENT2, + DRM_V3D_PARAM_SUPPORTS_TFU, + DRM_V3D_PARAM_SUPPORTS_CSD, ++ DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH, + }; + + struct drm_v3d_get_param { diff --git a/target/linux/bcm27xx/patches-5.4/950-0312-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch b/target/linux/bcm27xx/patches-5.4/950-0312-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch deleted file mode 100644 index a91bcc3111..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0312-staging-bcm2835-codec-Correct-g-s_selection-API-MPLA.patch +++ /dev/null @@ -1,107 +0,0 @@ -From c8a466aecf6b7d0bdc1fea9e32f80327b641cd03 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 13 Sep 2019 15:11:47 +0100 -Subject: [PATCH] staging: bcm2835-codec: Correct g/s_selection API - MPLANE support - -The g_selection and s_selection API is messed up and requires -the driver to expect the non-MPLANE buffer types, not the MPLANE -ones even if they are supported. The V4L2 core will convert the -MPLANE ones to non-MPLANE should they be passed in - -Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 67 +++++++++++++------ - 1 file changed, 47 insertions(+), 20 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1260,17 +1260,30 @@ static int vidioc_g_selection(struct fil - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - struct bcm2835_codec_q_data *q_data; -- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? -- true : false; - -- if ((ctx->dev->role == DECODE && !capture_queue) || -- (ctx->dev->role == ENCODE && capture_queue)) -- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ -- return -EINVAL; -- -- q_data = get_q_data(ctx, s->type); -- if (!q_data) -+ /* -+ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and -+ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE -+ * API. The V4L2 core will have converted the MPLANE variants to -+ * non-MPLANE. -+ * Open code this instead of using get_q_data in this case. -+ */ -+ switch (s->type) { -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: -+ /* CAPTURE on encoder is not valid. */ -+ if (ctx->dev->role == ENCODE) -+ return -EINVAL; -+ q_data = &ctx->q_data[V4L2_M2M_DST]; -+ break; -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT: -+ /* OUTPUT on deoder is not valid. */ -+ if (ctx->dev->role == DECODE) -+ return -EINVAL; -+ q_data = &ctx->q_data[V4L2_M2M_SRC]; -+ break; -+ default: - return -EINVAL; -+ } - - switch (ctx->dev->role) { - case DECODE: -@@ -1323,22 +1336,36 @@ static int vidioc_s_selection(struct fil - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - struct bcm2835_codec_q_data *q_data = NULL; -- bool capture_queue = s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? -- true : false; -+ -+ /* -+ * The selection API takes V4L2_BUF_TYPE_VIDEO_CAPTURE and -+ * V4L2_BUF_TYPE_VIDEO_OUTPUT, even if the device implements the MPLANE -+ * API. The V4L2 core will have converted the MPLANE variants to -+ * non-MPLANE. -+ * -+ * Open code this instead of using get_q_data in this case. -+ */ -+ switch (s->type) { -+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: -+ /* CAPTURE on encoder is not valid. */ -+ if (ctx->dev->role == ENCODE) -+ return -EINVAL; -+ q_data = &ctx->q_data[V4L2_M2M_DST]; -+ break; -+ case V4L2_BUF_TYPE_VIDEO_OUTPUT: -+ /* OUTPUT on deoder is not valid. */ -+ if (ctx->dev->role == DECODE) -+ return -EINVAL; -+ q_data = &ctx->q_data[V4L2_M2M_SRC]; -+ break; -+ default: -+ return -EINVAL; -+ } - - v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s: ctx %p, type %d, q_data %p, target %d, rect x/y %d/%d, w/h %ux%u\n", - __func__, ctx, s->type, q_data, s->target, s->r.left, s->r.top, - s->r.width, s->r.height); - -- if ((ctx->dev->role == DECODE && !capture_queue) || -- (ctx->dev->role == ENCODE && capture_queue)) -- /* OUTPUT on decoder and CAPTURE on encoder are not valid. */ -- return -EINVAL; -- -- q_data = get_q_data(ctx, s->type); -- if (!q_data) -- return -EINVAL; -- - switch (ctx->dev->role) { - case DECODE: - switch (s->target) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0313-drm-v3d-Delete-pm_runtime-support.patch b/target/linux/bcm27xx/patches-5.4/950-0313-drm-v3d-Delete-pm_runtime-support.patch deleted file mode 100644 index 642be233ad..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0313-drm-v3d-Delete-pm_runtime-support.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 4fad98821e9ccd74b9b828d98cbe9df8c7437605 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 18 Sep 2019 17:22:36 +0100 -Subject: [PATCH] drm/v3d: Delete pm_runtime support - -The pm_runtime was blocking changelist submission, so delete it as a -temporary workaround. - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/v3d_gem.c | 5 ----- - drivers/gpu/drm/v3d/v3d_mmu.c | 11 ----------- - 2 files changed, 16 deletions(-) - ---- a/drivers/gpu/drm/v3d/v3d_gem.c -+++ b/drivers/gpu/drm/v3d/v3d_gem.c -@@ -478,10 +478,6 @@ v3d_job_init(struct v3d_dev *v3d, struct - job->v3d = v3d; - job->free = free; - -- ret = pm_runtime_get_sync(v3d->dev); -- if (ret < 0) -- return ret; -- - xa_init_flags(&job->deps, XA_FLAGS_ALLOC); - - ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &in_fence); -@@ -498,7 +494,6 @@ v3d_job_init(struct v3d_dev *v3d, struct - return 0; - fail: - xa_destroy(&job->deps); -- pm_runtime_put_autosuspend(v3d->dev); - return ret; - } - ---- a/drivers/gpu/drm/v3d/v3d_mmu.c -+++ b/drivers/gpu/drm/v3d/v3d_mmu.c -@@ -36,14 +36,6 @@ static int v3d_mmu_flush_all(struct v3d_ - { - int ret; - -- /* Keep power on the device on until we're done with this -- * call, but skip the flush if the device is off and will be -- * reset when powered back on. -- */ -- ret = pm_runtime_get_if_in_use(v3d->dev); -- if (ret == 0) -- return 0; -- - /* Make sure that another flush isn't already running when we - * start this one. - */ -@@ -71,9 +63,6 @@ static int v3d_mmu_flush_all(struct v3d_ - if (ret) - dev_err(v3d->dev, "MMUC flush wait idle failed\n"); - -- pm_runtime_mark_last_busy(v3d->dev); -- pm_runtime_put_autosuspend(v3d->dev); -- - return ret; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0313-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch b/target/linux/bcm27xx/patches-5.4/950-0313-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch new file mode 100644 index 0000000000..d36f3eb802 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0313-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch @@ -0,0 +1,36 @@ +From 7542fb08d2726606057c4283b3a454abb195a0f5 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 23 Sep 2019 09:26:41 +0100 +Subject: [PATCH] kbuild: Allow .dtbo overlays to be built piecemeal + +Before 4.20, it was possible to build an arbitrary overlay by copying +it to arm/boot/dts/overlays/mytest-overlay.dts and running: + + make ARCH=arm overlays/mytest.dtbo + +In 4.20 the .dtb build rules were centralised, requiring the dowstream +.dtbo build rules to be changed. They were, enough to support "make ... +dtbs", but not sufficiently to allow this ad-hoc, one-off building of +individual files. + +Add the missing makefile rule to support this way of building. + +See: https://github.com/raspberrypi/linux/issues/3250 + +Signed-off-by: Phil Elwell +--- + Makefile | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/Makefile ++++ b/Makefile +@@ -1261,6 +1261,9 @@ ifneq ($(dtstree),) + %.dtb: include/config/kernel.release scripts_dtc + $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ + ++%.dtbo: prepare3 scripts_dtc ++ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ ++ + PHONY += dtbs dtbs_install dtbs_check + dtbs: include/config/kernel.release scripts_dtc + $(Q)$(MAKE) $(build)=$(dtstree) diff --git a/target/linux/bcm27xx/patches-5.4/950-0314-dma-direct-Temporary-DMA-fix-on-arm64.patch b/target/linux/bcm27xx/patches-5.4/950-0314-dma-direct-Temporary-DMA-fix-on-arm64.patch new file mode 100644 index 0000000000..327a77c424 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0314-dma-direct-Temporary-DMA-fix-on-arm64.patch @@ -0,0 +1,23 @@ +From afde0ffa449eef528deb2fe455a512acd0569be4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 25 Sep 2019 09:49:58 +0100 +Subject: [PATCH] dma-direct: Temporary DMA fix on arm64 + +See: https://github.com/raspberrypi/linux/issues/3251 + +Signed-off-by: Phil Elwell +--- + kernel/dma/direct.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -398,7 +398,7 @@ int dma_direct_supported(struct device * + if (IS_ENABLED(CONFIG_ZONE_DMA)) + min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS); + else +- min_mask = DMA_BIT_MASK(32); ++ min_mask = DMA_BIT_MASK(30); + + min_mask = min_t(u64, min_mask, (max_pfn - 1) << PAGE_SHIFT); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0314-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch b/target/linux/bcm27xx/patches-5.4/950-0314-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch deleted file mode 100644 index c7eccdeed4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0314-dts-Add-DTS-for-Pi-2B-rev-1.2-with-BCM2837-3235.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 849dc86116416161d0f13bf929ab712ea2bade7e Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 18 Sep 2019 09:02:10 +0100 -Subject: [PATCH] dts: Add DTS for Pi 2B rev 1.2 with BCM2837 (#3235) - -Signed-off-by: Phil Elwell ---- - arch/arm64/boot/dts/broadcom/Makefile | 2 ++ - arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts | 3 +++ - 2 files changed, 5 insertions(+) - create mode 100644 arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts - ---- a/arch/arm64/boot/dts/broadcom/Makefile -+++ b/arch/arm64/boot/dts/broadcom/Makefile -@@ -3,7 +3,9 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2837-rp - bcm2837-rpi-3-b.dtb \ - bcm2837-rpi-3-b-plus.dtb \ - bcm2837-rpi-cm3-io3.dtb -+dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-2-b.dtb - dtb-$(CONFIG_ARCH_BCM2709) += bcm2710-rpi-3-b.dtb -+dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-2-b.dtb - dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b.dtb - dtb-$(CONFIG_ARCH_BCM2835) += bcm2711-rpi-4-b.dtb - dtb-$(CONFIG_ARCH_BCM2835) += bcm2710-rpi-3-b-plus.dtb ---- /dev/null -+++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts -@@ -0,0 +1,3 @@ -+#define RPI364 -+ -+#include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts" diff --git a/target/linux/bcm27xx/patches-5.4/950-0315-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch b/target/linux/bcm27xx/patches-5.4/950-0315-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch new file mode 100644 index 0000000000..254a621c83 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0315-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch @@ -0,0 +1,26 @@ +From 7a226e4533daa54a2ca625005b06ddeffe5de994 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Thu, 19 Sep 2019 20:45:30 +0200 +Subject: [PATCH] ARM: bcm: Switch board, clk and pinctrl to bcm2711 + compatible + +After the decision to use bcm2711 compatible for upstream, we should +switch all accepted compatibles to bcm2711. So we can boot with +one DTB the down- and the upstream kernel. + +Signed-off-by: Stefan Wahren +--- + arch/arm/mach-bcm/board_bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/mach-bcm/board_bcm2835.c ++++ b/arch/arm/mach-bcm/board_bcm2835.c +@@ -109,7 +109,7 @@ static const char * const bcm2835_compat + #ifdef CONFIG_ARCH_MULTI_V7 + "brcm,bcm2836", + "brcm,bcm2837", +- "brcm,bcm2838", ++ "brcm,bcm2711", + #endif + NULL + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0315-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch b/target/linux/bcm27xx/patches-5.4/950-0315-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch deleted file mode 100644 index 961c0cc92b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0315-drm-v3d-clean-caches-at-the-end-of-render-jobs-on-re.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 141da39c2ce8dbf77773c54182244c14d96b301d Mon Sep 17 00:00:00 2001 -From: Iago Toral Quiroga -Date: Tue, 3 Sep 2019 08:45:24 +0200 -Subject: [PATCH] drm/v3d: clean caches at the end of render jobs on - request from user space - -Extends the user space ioctl for CL submissions so it can include a request -to flush the cache once the CL execution has completed. Fixes memory -write violation messages reported by the kernel in workloads involving -shader memory writes (SSBOs, shader images, scratch, etc) which sometimes -also lead to GPU resets during Piglit and CTS workloads. - -v2: if v3d_job_init() fails we need to kfree() the job instead of - v3d_job_put() it (Eric Anholt). - -v3 (Eric Anholt): - - Drop _FLAG suffix from the new flag name. - - Add a new param so userspace can tell whether cache flushing is - implemented in the kernel. - -Signed-off-by: Iago Toral Quiroga ---- - drivers/gpu/drm/v3d/v3d_drv.c | 3 +++ - drivers/gpu/drm/v3d/v3d_gem.c | 48 ++++++++++++++++++++++++++++++----- - include/uapi/drm/v3d_drm.h | 6 +++-- - 3 files changed, 49 insertions(+), 8 deletions(-) - ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -120,6 +120,9 @@ static int v3d_get_param_ioctl(struct dr - case DRM_V3D_PARAM_SUPPORTS_CSD: - args->value = v3d_has_csd(v3d); - return 0; -+ case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH: -+ args->value = 1; -+ return 0; - default: - DRM_DEBUG("Unknown parameter %d\n", args->param); - return -EINVAL; ---- a/drivers/gpu/drm/v3d/v3d_gem.c -+++ b/drivers/gpu/drm/v3d/v3d_gem.c -@@ -565,13 +565,16 @@ v3d_submit_cl_ioctl(struct drm_device *d - struct drm_v3d_submit_cl *args = data; - struct v3d_bin_job *bin = NULL; - struct v3d_render_job *render; -+ struct v3d_job *clean_job = NULL; -+ struct v3d_job *last_job; - struct ww_acquire_ctx acquire_ctx; - int ret = 0; - - trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); - -- if (args->pad != 0) { -- DRM_INFO("pad must be zero: %d\n", args->pad); -+ if (args->flags != 0 && -+ args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { -+ DRM_INFO("invalid flags: %d\n", args->flags); - return -EINVAL; - } - -@@ -613,12 +616,31 @@ v3d_submit_cl_ioctl(struct drm_device *d - bin->render = render; - } - -- ret = v3d_lookup_bos(dev, file_priv, &render->base, -+ if (args->flags & DRM_V3D_SUBMIT_CL_FLUSH_CACHE) { -+ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL); -+ if (!clean_job) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0); -+ if (ret) { -+ kfree(clean_job); -+ clean_job = NULL; -+ goto fail; -+ } -+ -+ last_job = clean_job; -+ } else { -+ last_job = &render->base; -+ } -+ -+ ret = v3d_lookup_bos(dev, file_priv, last_job, - args->bo_handles, args->bo_handle_count); - if (ret) - goto fail; - -- ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx); -+ ret = v3d_lock_bo_reservations(last_job, &acquire_ctx); - if (ret) - goto fail; - -@@ -637,17 +659,29 @@ v3d_submit_cl_ioctl(struct drm_device *d - ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER); - if (ret) - goto fail_unreserve; -+ -+ if (clean_job) { -+ ret = drm_gem_fence_array_add(&clean_job->deps, -+ dma_fence_get(render->base.done_fence)); -+ if (ret) -+ goto fail_unreserve; -+ ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN); -+ if (ret) -+ goto fail_unreserve; -+ } - mutex_unlock(&v3d->sched_lock); - - v3d_attach_fences_and_unlock_reservation(file_priv, -- &render->base, -+ last_job, - &acquire_ctx, - args->out_sync, -- render->base.done_fence); -+ last_job->done_fence); - - if (bin) - v3d_job_put(&bin->base); - v3d_job_put(&render->base); -+ if (clean_job) -+ v3d_job_put(clean_job); - - return 0; - -@@ -659,6 +693,8 @@ fail: - if (bin) - v3d_job_put(&bin->base); - v3d_job_put(&render->base); -+ if (clean_job) -+ v3d_job_put(clean_job); - - return ret; - } ---- a/include/uapi/drm/v3d_drm.h -+++ b/include/uapi/drm/v3d_drm.h -@@ -48,6 +48,8 @@ extern "C" { - #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu) - #define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd) - -+#define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01 -+ - /** - * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D - * engine. -@@ -124,8 +126,7 @@ struct drm_v3d_submit_cl { - /* Number of BO handles passed in (size is that times 4). */ - __u32 bo_handle_count; - -- /* Pad, must be zero-filled. */ -- __u32 pad; -+ __u32 flags; - }; - - /** -@@ -193,6 +194,7 @@ enum drm_v3d_param { - DRM_V3D_PARAM_V3D_CORE0_IDENT2, - DRM_V3D_PARAM_SUPPORTS_TFU, - DRM_V3D_PARAM_SUPPORTS_CSD, -+ DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH, - }; - - struct drm_v3d_get_param { diff --git a/target/linux/bcm27xx/patches-5.4/950-0316-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch b/target/linux/bcm27xx/patches-5.4/950-0316-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch deleted file mode 100644 index d36f3eb802..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0316-kbuild-Allow-.dtbo-overlays-to-be-built-piecemeal.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 7542fb08d2726606057c4283b3a454abb195a0f5 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 23 Sep 2019 09:26:41 +0100 -Subject: [PATCH] kbuild: Allow .dtbo overlays to be built piecemeal - -Before 4.20, it was possible to build an arbitrary overlay by copying -it to arm/boot/dts/overlays/mytest-overlay.dts and running: - - make ARCH=arm overlays/mytest.dtbo - -In 4.20 the .dtb build rules were centralised, requiring the dowstream -.dtbo build rules to be changed. They were, enough to support "make ... -dtbs", but not sufficiently to allow this ad-hoc, one-off building of -individual files. - -Add the missing makefile rule to support this way of building. - -See: https://github.com/raspberrypi/linux/issues/3250 - -Signed-off-by: Phil Elwell ---- - Makefile | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/Makefile -+++ b/Makefile -@@ -1261,6 +1261,9 @@ ifneq ($(dtstree),) - %.dtb: include/config/kernel.release scripts_dtc - $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ - -+%.dtbo: prepare3 scripts_dtc -+ $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@ -+ - PHONY += dtbs dtbs_install dtbs_check - dtbs: include/config/kernel.release scripts_dtc - $(Q)$(MAKE) $(build)=$(dtstree) diff --git a/target/linux/bcm27xx/patches-5.4/950-0316-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch b/target/linux/bcm27xx/patches-5.4/950-0316-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch new file mode 100644 index 0000000000..2ad17cb17c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0316-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch @@ -0,0 +1,40 @@ +From cf658ebc86b3e22c0b77e136fbbf19b580c7c256 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Sun, 21 Jul 2019 16:01:36 +0200 +Subject: [PATCH] pinctrl: bcm2835: Add support for BCM2711 pull-up + functionality + +commit e38a9a437fb93ddafab5030165e4c6a3a5021669 upstream. + +The BCM2711 has a new way of selecting the pull-up/pull-down setting +for a GPIO pin. The registers used for the BCM2835, GP_PUD and +GP_PUDCLKn0, are no longer connected. A new set of registers, +GP_GPIO_PUP_PDN_CNTRL_REGx must be used. This commit will add +a new compatible string "brcm,bcm2711-gpio" and the kernel +driver will use it to select which method is used to select +pull-up/pull-down. + +This patch based on a patch by Al Cooper which was intended for the +BCM7211. This is a bugfixed and improved version. + +Signed-off-by: Stefan Wahren +Acked-by: Eric Anholt +--- + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +@@ -1168,6 +1168,12 @@ static int bcm2835_pinctrl_probe(struct + (const struct pinconf_ops *)match->data; + } + ++ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); ++ if (match) { ++ bcm2835_pinctrl_desc.confops = ++ (const struct pinconf_ops *)match->data; ++ } ++ + pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc); + if (IS_ERR(pc->pctl_dev)) { + gpiochip_remove(&pc->gpio_chip); diff --git a/target/linux/bcm27xx/patches-5.4/950-0317-dma-direct-Temporary-DMA-fix-on-arm64.patch b/target/linux/bcm27xx/patches-5.4/950-0317-dma-direct-Temporary-DMA-fix-on-arm64.patch deleted file mode 100644 index 327a77c424..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0317-dma-direct-Temporary-DMA-fix-on-arm64.patch +++ /dev/null @@ -1,23 +0,0 @@ -From afde0ffa449eef528deb2fe455a512acd0569be4 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 25 Sep 2019 09:49:58 +0100 -Subject: [PATCH] dma-direct: Temporary DMA fix on arm64 - -See: https://github.com/raspberrypi/linux/issues/3251 - -Signed-off-by: Phil Elwell ---- - kernel/dma/direct.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/kernel/dma/direct.c -+++ b/kernel/dma/direct.c -@@ -398,7 +398,7 @@ int dma_direct_supported(struct device * - if (IS_ENABLED(CONFIG_ZONE_DMA)) - min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS); - else -- min_mask = DMA_BIT_MASK(32); -+ min_mask = DMA_BIT_MASK(30); - - min_mask = min_t(u64, min_mask, (max_pfn - 1) << PAGE_SHIFT); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0317-vchiq_2835_arm-suppress-warning.patch b/target/linux/bcm27xx/patches-5.4/950-0317-vchiq_2835_arm-suppress-warning.patch new file mode 100644 index 0000000000..1be935caf4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0317-vchiq_2835_arm-suppress-warning.patch @@ -0,0 +1,32 @@ +From a822f97a094991b08a50352355b0a376086b46c4 Mon Sep 17 00:00:00 2001 +From: Matteo Croce +Date: Sun, 6 Oct 2019 03:23:15 +0200 +Subject: [PATCH] vchiq_2835_arm: suppress warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Suppress the following warning by casting the pointer to and uintptr_t +before void*: + + drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c: In function ‘vchiq_prepare_bulk_data’: + drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c:260:15: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] + bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr); + ^ + +Signed-off-by: Matteo Croce +--- + .../staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +@@ -255,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul + if (!pagelistinfo) + return VCHIQ_ERROR; + +- bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr); ++ bulk->data = (void *)(uintptr_t)VC_SAFE(pagelistinfo->dma_addr); + + /* + * Store the pagelistinfo address in remote_data, diff --git a/target/linux/bcm27xx/patches-5.4/950-0318-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch b/target/linux/bcm27xx/patches-5.4/950-0318-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch deleted file mode 100644 index 254a621c83..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0318-ARM-bcm-Switch-board-clk-and-pinctrl-to-bcm2711-comp.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 7a226e4533daa54a2ca625005b06ddeffe5de994 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Thu, 19 Sep 2019 20:45:30 +0200 -Subject: [PATCH] ARM: bcm: Switch board, clk and pinctrl to bcm2711 - compatible - -After the decision to use bcm2711 compatible for upstream, we should -switch all accepted compatibles to bcm2711. So we can boot with -one DTB the down- and the upstream kernel. - -Signed-off-by: Stefan Wahren ---- - arch/arm/mach-bcm/board_bcm2835.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/mach-bcm/board_bcm2835.c -+++ b/arch/arm/mach-bcm/board_bcm2835.c -@@ -109,7 +109,7 @@ static const char * const bcm2835_compat - #ifdef CONFIG_ARCH_MULTI_V7 - "brcm,bcm2836", - "brcm,bcm2837", -- "brcm,bcm2838", -+ "brcm,bcm2711", - #endif - NULL - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0318-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch b/target/linux/bcm27xx/patches-5.4/950-0318-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch new file mode 100644 index 0000000000..8ec836621d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0318-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch @@ -0,0 +1,139 @@ +From 95709d5c58c57f31a70e96fe9ebb8d34c046f877 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Tue, 24 Sep 2019 18:26:55 +0100 +Subject: [PATCH] Rename HDMI ALSA device names, check for enable state + +HDMI Alsa devices renamed to match names used by DRM, to +HDMI 1 and HDMI 2 + +Check for which HDMI devices are connected and only create +devices for those that are present. + +The rename of the devices might cause some backwards compatibility +issues, but since this particular part of the driver needs to be +specifically enabled, I suspect the number of people who will see +the problem will be very small. + +Signed-off-by: James Hughes +--- + .../vc04_services/bcm2835-audio/bcm2835.c | 70 +++++++++++++++++-- + 1 file changed, 63 insertions(+), 7 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c ++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c +@@ -9,8 +9,9 @@ + #include + + #include "bcm2835.h" ++#include + +-static bool enable_hdmi; ++static bool enable_hdmi, enable_hdmi0, enable_hdmi1; + static bool enable_headphones; + static bool enable_compat_alsa = true; + +@@ -115,8 +116,8 @@ static struct bcm2835_audio_driver bcm28 + .name = "bcm2835_hdmi", + .owner = THIS_MODULE, + }, +- .shortname = "bcm2835 HDMI", +- .longname = "bcm2835 HDMI", ++ .shortname = "bcm2835 HDMI 1", ++ .longname = "bcm2835 HDMI 1", + .minchannels = 1, + .newpcm = bcm2835_audio_simple_newpcm, + .newctl = snd_bcm2835_new_hdmi_ctl, +@@ -128,8 +129,8 @@ static struct bcm2835_audio_driver bcm28 + .name = "bcm2835_hdmi", + .owner = THIS_MODULE, + }, +- .shortname = "bcm2835 HDMI 1", +- .longname = "bcm2835 HDMI 1", ++ .shortname = "bcm2835 HDMI 2", ++ .longname = "bcm2835 HDMI 2", + .minchannels = 1, + .newpcm = bcm2835_audio_simple_newpcm, + .newctl = snd_bcm2835_new_hdmi_ctl, +@@ -161,11 +162,11 @@ static struct bcm2835_audio_drivers chil + }, + { + .audio_driver = &bcm2835_audio_hdmi0, +- .is_enabled = &enable_hdmi, ++ .is_enabled = &enable_hdmi0, + }, + { + .audio_driver = &bcm2835_audio_hdmi1, +- .is_enabled = &enable_hdmi, ++ .is_enabled = &enable_hdmi1, + }, + { + .audio_driver = &bcm2835_audio_headphones, +@@ -312,6 +313,53 @@ static int snd_add_child_devices(struct + return 0; + } + ++static void set_hdmi_enables(struct device *dev) ++{ ++ struct device_node *firmware_node; ++ struct rpi_firmware *firmware; ++ u32 num_displays, i, display_id; ++ int ret; ++ ++ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); ++ firmware = rpi_firmware_get(firmware_node); ++ ++ if (!firmware) ++ return; ++ ++ of_node_put(firmware_node); ++ ++ ret = rpi_firmware_property(firmware, ++ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, ++ &num_displays, sizeof(u32)); ++ ++ if (ret) ++ return; ++ ++ for (i = 0; i < num_displays; i++) { ++ display_id = i; ++ ret = rpi_firmware_property(firmware, ++ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID, ++ &display_id, sizeof(display_id)); ++ if (!ret) { ++ if (display_id == 2) ++ enable_hdmi0 = true; ++ if (display_id == 7) ++ enable_hdmi1 = true; ++ } ++ } ++ ++ if (!enable_hdmi0 && enable_hdmi1) { ++ /* Swap them over and reassign route. This means ++ * that if we only have one connected, it is always named ++ * HDMI1, irrespective of if its on port HDMI0 or HDMI1. ++ * This should match with the naming of HDMI ports in DRM ++ */ ++ enable_hdmi0 = true; ++ enable_hdmi1 = false; ++ bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1; ++ } ++} ++ + static int snd_bcm2835_alsa_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -332,6 +380,14 @@ static int snd_bcm2835_alsa_probe(struct + numchans); + } + ++ if (!enable_compat_alsa) { ++ set_hdmi_enables(dev); ++ // In this mode, always enable analog output ++ enable_headphones = true; ++ } else { ++ enable_hdmi0 = enable_hdmi; ++ } ++ + err = bcm2835_devm_add_vchi_ctx(dev); + if (err) + return err; diff --git a/target/linux/bcm27xx/patches-5.4/950-0319-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch b/target/linux/bcm27xx/patches-5.4/950-0319-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch new file mode 100644 index 0000000000..d7e6bbc561 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0319-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch @@ -0,0 +1,138 @@ +From fb76c3ded8c771e8b9287d62b5e13666037f890e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 17 Sep 2019 18:28:17 +0100 +Subject: [PATCH] drm/vc4: Add support for YUV color encodings and + ranges + +The BT601/BT709 color encoding and limited vs full +range properties were not being exposed, defaulting +always to BT601 limited range. + +Expose the parameters and set the registers appropriately. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_plane.c | 72 +++++++++++++++++++++++++++++++-- + drivers/gpu/drm/vc4/vc4_regs.h | 3 ++ + 2 files changed, 72 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_plane.c ++++ b/drivers/gpu/drm/vc4/vc4_plane.c +@@ -585,6 +585,53 @@ static int vc4_plane_allocate_lbm(struct + return 0; + } + ++/* The colorspace conversion matrices are held in 3 entries in the dlist. ++ * Create an array of them, with entries for each full and limited mode, and ++ * each supported colorspace. ++ */ ++#define VC4_LIMITED_RANGE 0 ++#define VC4_FULL_RANGE 1 ++ ++static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = { ++ { ++ /* Limited range */ ++ { ++ /* BT601 */ ++ SCALER_CSC0_ITR_R_601_5, ++ SCALER_CSC1_ITR_R_601_5, ++ SCALER_CSC2_ITR_R_601_5, ++ }, { ++ /* BT709 */ ++ SCALER_CSC0_ITR_R_709_3, ++ SCALER_CSC1_ITR_R_709_3, ++ SCALER_CSC2_ITR_R_709_3, ++ }, { ++ /* BT2020. Not supported yet - copy 601 */ ++ SCALER_CSC0_ITR_R_601_5, ++ SCALER_CSC1_ITR_R_601_5, ++ SCALER_CSC2_ITR_R_601_5, ++ } ++ }, { ++ /* Full range */ ++ { ++ /* JFIF */ ++ SCALER_CSC0_JPEG_JFIF, ++ SCALER_CSC1_JPEG_JFIF, ++ SCALER_CSC2_JPEG_JFIF, ++ }, { ++ /* BT709 */ ++ SCALER_CSC0_ITR_R_709_3_FR, ++ SCALER_CSC1_ITR_R_709_3_FR, ++ SCALER_CSC2_ITR_R_709_3_FR, ++ }, { ++ /* BT2020. Not supported yet - copy JFIF */ ++ SCALER_CSC0_JPEG_JFIF, ++ SCALER_CSC1_JPEG_JFIF, ++ SCALER_CSC2_JPEG_JFIF, ++ } ++ } ++}; ++ + /* Writes out a full display list for an active plane to the plane's + * private dlist state. + */ +@@ -864,9 +911,20 @@ static int vc4_plane_mode_set(struct drm + + /* Colorspace conversion words */ + if (vc4_state->is_yuv) { +- vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5); +- vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5); +- vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); ++ enum drm_color_encoding color_encoding = state->color_encoding; ++ enum drm_color_range color_range = state->color_range; ++ const u32 *ccm; ++ ++ if (color_encoding >= DRM_COLOR_ENCODING_MAX) ++ color_encoding = DRM_COLOR_YCBCR_BT601; ++ if (color_range >= DRM_COLOR_RANGE_MAX) ++ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; ++ ++ ccm = colorspace_coeffs[color_range][color_encoding]; ++ ++ vc4_dlist_write(vc4_state, ccm[0]); ++ vc4_dlist_write(vc4_state, ccm[1]); ++ vc4_dlist_write(vc4_state, ccm[2]); + } + + vc4_state->lbm_offset = 0; +@@ -1275,5 +1333,13 @@ struct drm_plane *vc4_plane_init(struct + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y); + ++ drm_plane_create_color_properties(plane, ++ BIT(DRM_COLOR_YCBCR_BT601) | ++ BIT(DRM_COLOR_YCBCR_BT709), ++ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | ++ BIT(DRM_COLOR_YCBCR_FULL_RANGE), ++ DRM_COLOR_YCBCR_BT709, ++ DRM_COLOR_YCBCR_LIMITED_RANGE); ++ + return plane; + } +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -950,6 +950,7 @@ enum hvs_pixel_format { + #define SCALER_CSC0_ITR_R_601_5 0x00f00000 + #define SCALER_CSC0_ITR_R_709_3 0x00f00000 + #define SCALER_CSC0_JPEG_JFIF 0x00000000 ++#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000 + + /* S2.8 contribution of Cb to Green */ + #define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22) +@@ -966,6 +967,7 @@ enum hvs_pixel_format { + #define SCALER_CSC1_ITR_R_601_5 0xe73304a8 + #define SCALER_CSC1_ITR_R_709_3 0xf2b784a8 + #define SCALER_CSC1_JPEG_JFIF 0xea34a400 ++#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400 + + /* S2.8 contribution of Cb to Red */ + #define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20) +@@ -979,6 +981,7 @@ enum hvs_pixel_format { + #define SCALER_CSC2_ITR_R_601_5 0x00066204 + #define SCALER_CSC2_ITR_R_709_3 0x00072a1c + #define SCALER_CSC2_JPEG_JFIF 0x000599c5 ++#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb + + #define SCALER_TPZ0_VERT_RECALC BIT(31) + #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8) diff --git a/target/linux/bcm27xx/patches-5.4/950-0319-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch b/target/linux/bcm27xx/patches-5.4/950-0319-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch deleted file mode 100644 index 2ad17cb17c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0319-pinctrl-bcm2835-Add-support-for-BCM2711-pull-up-func.patch +++ /dev/null @@ -1,40 +0,0 @@ -From cf658ebc86b3e22c0b77e136fbbf19b580c7c256 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Sun, 21 Jul 2019 16:01:36 +0200 -Subject: [PATCH] pinctrl: bcm2835: Add support for BCM2711 pull-up - functionality - -commit e38a9a437fb93ddafab5030165e4c6a3a5021669 upstream. - -The BCM2711 has a new way of selecting the pull-up/pull-down setting -for a GPIO pin. The registers used for the BCM2835, GP_PUD and -GP_PUDCLKn0, are no longer connected. A new set of registers, -GP_GPIO_PUP_PDN_CNTRL_REGx must be used. This commit will add -a new compatible string "brcm,bcm2711-gpio" and the kernel -driver will use it to select which method is used to select -pull-up/pull-down. - -This patch based on a patch by Al Cooper which was intended for the -BCM7211. This is a bugfixed and improved version. - -Signed-off-by: Stefan Wahren -Acked-by: Eric Anholt ---- - drivers/pinctrl/bcm/pinctrl-bcm2835.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c -+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -@@ -1168,6 +1168,12 @@ static int bcm2835_pinctrl_probe(struct - (const struct pinconf_ops *)match->data; - } - -+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); -+ if (match) { -+ bcm2835_pinctrl_desc.confops = -+ (const struct pinconf_ops *)match->data; -+ } -+ - pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc); - if (IS_ERR(pc->pctl_dev)) { - gpiochip_remove(&pc->gpio_chip); diff --git a/target/linux/bcm27xx/patches-5.4/950-0320-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch b/target/linux/bcm27xx/patches-5.4/950-0320-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch new file mode 100644 index 0000000000..f98002e99c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0320-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch @@ -0,0 +1,87 @@ +From 23ed834712dfc0d25451f16b46ae9c19abb675b5 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 18 Sep 2019 15:49:13 +0100 +Subject: [PATCH] drm/vc4: Correct handling of rotation parameter in + fkms + +One bit within DRM_MODE_ROTATE_MASK will always be set to +determine the base rotation 0/90/180/270, and then REFLECT_X +and REFLECT_Y are on top. + +Correct the handling which was assuming that REFLECT_[X|Y] +was instead of ROTATE_x. + +Signed-off-by: Dave Stevenson +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 ++++++++++---------------- + 1 file changed, 14 insertions(+), 23 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -82,11 +82,6 @@ struct set_plane { + #define TRANSFORM_FLIP_HRIZ BIT(16) + #define TRANSFORM_FLIP_VERT BIT(17) + +-#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \ +- DRM_MODE_ROTATE_180 | \ +- DRM_MODE_REFLECT_X | \ +- DRM_MODE_REFLECT_Y) +- + struct mailbox_set_plane { + struct rpi_firmware_property_tag_header tag; + struct set_plane plane; +@@ -525,7 +520,7 @@ static int vc4_plane_to_mb(struct drm_pl + const struct vc_image_format *vc_fmt = + vc4_get_vc_image_fmt(drm_fmt->format); + int num_planes = fb->format->num_planes; +- unsigned int rotation = SUPPORTED_ROTATIONS; ++ unsigned int rotation; + + mb->plane.vc_image_type = vc_fmt->vc_image; + mb->plane.width = fb->width; +@@ -546,23 +541,16 @@ static int vc4_plane_to_mb(struct drm_pl + mb->plane.is_vu = vc_fmt->is_vu; + mb->plane.planes[0] = bo->paddr + fb->offsets[0]; + +- rotation = drm_rotation_simplify(state->rotation, rotation); +- +- switch (rotation) { +- default: +- case DRM_MODE_ROTATE_0: +- mb->plane.transform = TRANSFORM_NO_ROTATE; +- break; +- case DRM_MODE_ROTATE_180: +- mb->plane.transform = TRANSFORM_ROTATE_180; +- break; +- case DRM_MODE_REFLECT_X: +- mb->plane.transform = TRANSFORM_FLIP_HRIZ; +- break; +- case DRM_MODE_REFLECT_Y: +- mb->plane.transform = TRANSFORM_FLIP_VERT; +- break; +- } ++ rotation = drm_rotation_simplify(state->rotation, ++ DRM_MODE_ROTATE_0 | ++ DRM_MODE_REFLECT_X | ++ DRM_MODE_REFLECT_Y); ++ ++ mb->plane.transform = TRANSFORM_NO_ROTATE; ++ if (rotation & DRM_MODE_REFLECT_X) ++ mb->plane.transform |= TRANSFORM_FLIP_HRIZ; ++ if (rotation & DRM_MODE_REFLECT_Y) ++ mb->plane.transform |= TRANSFORM_FLIP_VERT; + + vc4_fkms_margins_adj(state, &mb->plane); + +@@ -803,7 +791,10 @@ static struct drm_plane *vc4_fkms_plane_ + + drm_plane_create_alpha_property(plane); + drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, +- SUPPORTED_ROTATIONS); ++ DRM_MODE_ROTATE_0 | ++ DRM_MODE_ROTATE_180 | ++ DRM_MODE_REFLECT_X | ++ DRM_MODE_REFLECT_Y); + drm_plane_create_color_properties(plane, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709) | diff --git a/target/linux/bcm27xx/patches-5.4/950-0320-vchiq_2835_arm-suppress-warning.patch b/target/linux/bcm27xx/patches-5.4/950-0320-vchiq_2835_arm-suppress-warning.patch deleted file mode 100644 index 1be935caf4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0320-vchiq_2835_arm-suppress-warning.patch +++ /dev/null @@ -1,32 +0,0 @@ -From a822f97a094991b08a50352355b0a376086b46c4 Mon Sep 17 00:00:00 2001 -From: Matteo Croce -Date: Sun, 6 Oct 2019 03:23:15 +0200 -Subject: [PATCH] vchiq_2835_arm: suppress warning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Suppress the following warning by casting the pointer to and uintptr_t -before void*: - - drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c: In function ‘vchiq_prepare_bulk_data’: - drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c:260:15: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] - bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr); - ^ - -Signed-off-by: Matteo Croce ---- - .../staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -@@ -255,7 +255,7 @@ vchiq_prepare_bulk_data(struct vchiq_bul - if (!pagelistinfo) - return VCHIQ_ERROR; - -- bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr); -+ bulk->data = (void *)(uintptr_t)VC_SAFE(pagelistinfo->dma_addr); - - /* - * Store the pagelistinfo address in remote_data, diff --git a/target/linux/bcm27xx/patches-5.4/950-0321-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch b/target/linux/bcm27xx/patches-5.4/950-0321-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch deleted file mode 100644 index 8ec836621d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0321-Rename-HDMI-ALSA-device-names-check-for-enable-state.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 95709d5c58c57f31a70e96fe9ebb8d34c046f877 Mon Sep 17 00:00:00 2001 -From: James Hughes -Date: Tue, 24 Sep 2019 18:26:55 +0100 -Subject: [PATCH] Rename HDMI ALSA device names, check for enable state - -HDMI Alsa devices renamed to match names used by DRM, to -HDMI 1 and HDMI 2 - -Check for which HDMI devices are connected and only create -devices for those that are present. - -The rename of the devices might cause some backwards compatibility -issues, but since this particular part of the driver needs to be -specifically enabled, I suspect the number of people who will see -the problem will be very small. - -Signed-off-by: James Hughes ---- - .../vc04_services/bcm2835-audio/bcm2835.c | 70 +++++++++++++++++-- - 1 file changed, 63 insertions(+), 7 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c -@@ -9,8 +9,9 @@ - #include - - #include "bcm2835.h" -+#include - --static bool enable_hdmi; -+static bool enable_hdmi, enable_hdmi0, enable_hdmi1; - static bool enable_headphones; - static bool enable_compat_alsa = true; - -@@ -115,8 +116,8 @@ static struct bcm2835_audio_driver bcm28 - .name = "bcm2835_hdmi", - .owner = THIS_MODULE, - }, -- .shortname = "bcm2835 HDMI", -- .longname = "bcm2835 HDMI", -+ .shortname = "bcm2835 HDMI 1", -+ .longname = "bcm2835 HDMI 1", - .minchannels = 1, - .newpcm = bcm2835_audio_simple_newpcm, - .newctl = snd_bcm2835_new_hdmi_ctl, -@@ -128,8 +129,8 @@ static struct bcm2835_audio_driver bcm28 - .name = "bcm2835_hdmi", - .owner = THIS_MODULE, - }, -- .shortname = "bcm2835 HDMI 1", -- .longname = "bcm2835 HDMI 1", -+ .shortname = "bcm2835 HDMI 2", -+ .longname = "bcm2835 HDMI 2", - .minchannels = 1, - .newpcm = bcm2835_audio_simple_newpcm, - .newctl = snd_bcm2835_new_hdmi_ctl, -@@ -161,11 +162,11 @@ static struct bcm2835_audio_drivers chil - }, - { - .audio_driver = &bcm2835_audio_hdmi0, -- .is_enabled = &enable_hdmi, -+ .is_enabled = &enable_hdmi0, - }, - { - .audio_driver = &bcm2835_audio_hdmi1, -- .is_enabled = &enable_hdmi, -+ .is_enabled = &enable_hdmi1, - }, - { - .audio_driver = &bcm2835_audio_headphones, -@@ -312,6 +313,53 @@ static int snd_add_child_devices(struct - return 0; - } - -+static void set_hdmi_enables(struct device *dev) -+{ -+ struct device_node *firmware_node; -+ struct rpi_firmware *firmware; -+ u32 num_displays, i, display_id; -+ int ret; -+ -+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0); -+ firmware = rpi_firmware_get(firmware_node); -+ -+ if (!firmware) -+ return; -+ -+ of_node_put(firmware_node); -+ -+ ret = rpi_firmware_property(firmware, -+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS, -+ &num_displays, sizeof(u32)); -+ -+ if (ret) -+ return; -+ -+ for (i = 0; i < num_displays; i++) { -+ display_id = i; -+ ret = rpi_firmware_property(firmware, -+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID, -+ &display_id, sizeof(display_id)); -+ if (!ret) { -+ if (display_id == 2) -+ enable_hdmi0 = true; -+ if (display_id == 7) -+ enable_hdmi1 = true; -+ } -+ } -+ -+ if (!enable_hdmi0 && enable_hdmi1) { -+ /* Swap them over and reassign route. This means -+ * that if we only have one connected, it is always named -+ * HDMI1, irrespective of if its on port HDMI0 or HDMI1. -+ * This should match with the naming of HDMI ports in DRM -+ */ -+ enable_hdmi0 = true; -+ enable_hdmi1 = false; -+ bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1; -+ } -+} -+ - static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -332,6 +380,14 @@ static int snd_bcm2835_alsa_probe(struct - numchans); - } - -+ if (!enable_compat_alsa) { -+ set_hdmi_enables(dev); -+ // In this mode, always enable analog output -+ enable_headphones = true; -+ } else { -+ enable_hdmi0 = enable_hdmi; -+ } -+ - err = bcm2835_devm_add_vchi_ctx(dev); - if (err) - return err; diff --git a/target/linux/bcm27xx/patches-5.4/950-0321-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch b/target/linux/bcm27xx/patches-5.4/950-0321-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch new file mode 100644 index 0000000000..6f487bf7c6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0321-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch @@ -0,0 +1,66 @@ +From 5db0abcd74512cf7013c2ea87d347cd158726be3 Mon Sep 17 00:00:00 2001 +From: Markus Proeller +Date: Thu, 10 Oct 2019 19:12:08 +0200 +Subject: [PATCH] dt-bindings: Add binding for the Infineon IRS1125 + sensor + +Adds a binding for the Infineon IRS1125 time-of-flight depth +sensor. + +Signed-off-by: Markus Proeller +--- + .../devicetree/bindings/media/i2c/irs1125.txt | 48 +++++++++++++++++++ + 1 file changed, 48 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/i2c/irs1125.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/irs1125.txt +@@ -0,0 +1,48 @@ ++* Infineon irs1125 time of flight sensor ++ ++The Infineon irs1125 is a time of flight digital image sensor with ++an active array size of 352H x 286V. It is programmable through I2C ++interface. The I2C address defaults to 0x3D, but can be reconfigured ++to address 0x3C or 0x41 via I2C commands. Image data is sent through ++MIPI CSI-2, which is configured as either 1 or 2 data lanes. ++ ++Required Properties: ++- compatible: value should be "infineon,irs1125" for irs1125 sensor ++- reg: I2C bus address of the device ++- clocks: reference to the xclk input clock. ++- pwdn-gpios: reference to the GPIO connected to the reset pin. ++ This is an active low signal to the iirs1125. ++ ++The irs1125 device node should contain one 'port' child node with ++an 'endpoint' subnode. For further reading on port node refer to ++Documentation/devicetree/bindings/media/video-interfaces.txt. ++ ++Endpoint node required properties for CSI-2 connection are: ++- remote-endpoint: a phandle to the bus receiver's endpoint node. ++- clock-lanes: should be set to <0> (clock lane on hardware lane 0) ++- data-lanes: should be set to <1> or <1 2> (one or two lane CSI-2 ++ supported) ++ ++Example: ++ sensor@10 { ++ compatible = "infineon,irs1125"; ++ reg = <0x3D>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&irs1125_clk>; ++ pwdn-gpios = <&gpio 5 0>; ++ ++ irs1125_clk: camera-clk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <26000000>; ++ }; ++ ++ port { ++ sensor_out: endpoint { ++ remote-endpoint = <&csiss_in>; ++ clock-lanes = <0>; ++ data-lanes = <1 2>; ++ }; ++ }; ++ }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0322-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch b/target/linux/bcm27xx/patches-5.4/950-0322-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch deleted file mode 100644 index d7e6bbc561..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0322-drm-vc4-Add-support-for-YUV-color-encodings-and-rang.patch +++ /dev/null @@ -1,138 +0,0 @@ -From fb76c3ded8c771e8b9287d62b5e13666037f890e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 17 Sep 2019 18:28:17 +0100 -Subject: [PATCH] drm/vc4: Add support for YUV color encodings and - ranges - -The BT601/BT709 color encoding and limited vs full -range properties were not being exposed, defaulting -always to BT601 limited range. - -Expose the parameters and set the registers appropriately. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_plane.c | 72 +++++++++++++++++++++++++++++++-- - drivers/gpu/drm/vc4/vc4_regs.h | 3 ++ - 2 files changed, 72 insertions(+), 3 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_plane.c -+++ b/drivers/gpu/drm/vc4/vc4_plane.c -@@ -585,6 +585,53 @@ static int vc4_plane_allocate_lbm(struct - return 0; - } - -+/* The colorspace conversion matrices are held in 3 entries in the dlist. -+ * Create an array of them, with entries for each full and limited mode, and -+ * each supported colorspace. -+ */ -+#define VC4_LIMITED_RANGE 0 -+#define VC4_FULL_RANGE 1 -+ -+static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = { -+ { -+ /* Limited range */ -+ { -+ /* BT601 */ -+ SCALER_CSC0_ITR_R_601_5, -+ SCALER_CSC1_ITR_R_601_5, -+ SCALER_CSC2_ITR_R_601_5, -+ }, { -+ /* BT709 */ -+ SCALER_CSC0_ITR_R_709_3, -+ SCALER_CSC1_ITR_R_709_3, -+ SCALER_CSC2_ITR_R_709_3, -+ }, { -+ /* BT2020. Not supported yet - copy 601 */ -+ SCALER_CSC0_ITR_R_601_5, -+ SCALER_CSC1_ITR_R_601_5, -+ SCALER_CSC2_ITR_R_601_5, -+ } -+ }, { -+ /* Full range */ -+ { -+ /* JFIF */ -+ SCALER_CSC0_JPEG_JFIF, -+ SCALER_CSC1_JPEG_JFIF, -+ SCALER_CSC2_JPEG_JFIF, -+ }, { -+ /* BT709 */ -+ SCALER_CSC0_ITR_R_709_3_FR, -+ SCALER_CSC1_ITR_R_709_3_FR, -+ SCALER_CSC2_ITR_R_709_3_FR, -+ }, { -+ /* BT2020. Not supported yet - copy JFIF */ -+ SCALER_CSC0_JPEG_JFIF, -+ SCALER_CSC1_JPEG_JFIF, -+ SCALER_CSC2_JPEG_JFIF, -+ } -+ } -+}; -+ - /* Writes out a full display list for an active plane to the plane's - * private dlist state. - */ -@@ -864,9 +911,20 @@ static int vc4_plane_mode_set(struct drm - - /* Colorspace conversion words */ - if (vc4_state->is_yuv) { -- vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5); -- vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5); -- vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); -+ enum drm_color_encoding color_encoding = state->color_encoding; -+ enum drm_color_range color_range = state->color_range; -+ const u32 *ccm; -+ -+ if (color_encoding >= DRM_COLOR_ENCODING_MAX) -+ color_encoding = DRM_COLOR_YCBCR_BT601; -+ if (color_range >= DRM_COLOR_RANGE_MAX) -+ color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; -+ -+ ccm = colorspace_coeffs[color_range][color_encoding]; -+ -+ vc4_dlist_write(vc4_state, ccm[0]); -+ vc4_dlist_write(vc4_state, ccm[1]); -+ vc4_dlist_write(vc4_state, ccm[2]); - } - - vc4_state->lbm_offset = 0; -@@ -1275,5 +1333,13 @@ struct drm_plane *vc4_plane_init(struct - DRM_MODE_REFLECT_X | - DRM_MODE_REFLECT_Y); - -+ drm_plane_create_color_properties(plane, -+ BIT(DRM_COLOR_YCBCR_BT601) | -+ BIT(DRM_COLOR_YCBCR_BT709), -+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | -+ BIT(DRM_COLOR_YCBCR_FULL_RANGE), -+ DRM_COLOR_YCBCR_BT709, -+ DRM_COLOR_YCBCR_LIMITED_RANGE); -+ - return plane; - } ---- a/drivers/gpu/drm/vc4/vc4_regs.h -+++ b/drivers/gpu/drm/vc4/vc4_regs.h -@@ -950,6 +950,7 @@ enum hvs_pixel_format { - #define SCALER_CSC0_ITR_R_601_5 0x00f00000 - #define SCALER_CSC0_ITR_R_709_3 0x00f00000 - #define SCALER_CSC0_JPEG_JFIF 0x00000000 -+#define SCALER_CSC0_ITR_R_709_3_FR 0x00000000 - - /* S2.8 contribution of Cb to Green */ - #define SCALER_CSC1_COEF_CB_GRN_MASK VC4_MASK(31, 22) -@@ -966,6 +967,7 @@ enum hvs_pixel_format { - #define SCALER_CSC1_ITR_R_601_5 0xe73304a8 - #define SCALER_CSC1_ITR_R_709_3 0xf2b784a8 - #define SCALER_CSC1_JPEG_JFIF 0xea34a400 -+#define SCALER_CSC1_ITR_R_709_3_FR 0xe23d0400 - - /* S2.8 contribution of Cb to Red */ - #define SCALER_CSC2_COEF_CB_RED_MASK VC4_MASK(29, 20) -@@ -979,6 +981,7 @@ enum hvs_pixel_format { - #define SCALER_CSC2_ITR_R_601_5 0x00066204 - #define SCALER_CSC2_ITR_R_709_3 0x00072a1c - #define SCALER_CSC2_JPEG_JFIF 0x000599c5 -+#define SCALER_CSC2_ITR_R_709_3_FR 0x00064ddb - - #define SCALER_TPZ0_VERT_RECALC BIT(31) - #define SCALER_TPZ0_SCALE_MASK VC4_MASK(28, 8) diff --git a/target/linux/bcm27xx/patches-5.4/950-0322-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch b/target/linux/bcm27xx/patches-5.4/950-0322-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch new file mode 100644 index 0000000000..71e218d9ec --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0322-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch @@ -0,0 +1,1231 @@ +From 54e4ff9b3cae743ca90b86a8fef72810d431e143 Mon Sep 17 00:00:00 2001 +From: Markus Proeller +Date: Thu, 10 Oct 2019 19:12:36 +0200 +Subject: [PATCH] media: i2c: Add a driver for the Infineon IRS1125 + depth sensor + +The Infineon IRS1125 is a time of flight depth sensor that +has a CSI-2 interface. + +Add a V4L2 subdevice driver for this device. + +Signed-off-by: Markus Proeller +--- + drivers/media/i2c/Kconfig | 12 + + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/irs1125.c | 1112 +++++++++++++++++++++++++++++++++++ + drivers/media/i2c/irs1125.h | 61 ++ + 4 files changed, 1186 insertions(+) + create mode 100644 drivers/media/i2c/irs1125.c + create mode 100644 drivers/media/i2c/irs1125.h + +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -839,6 +839,18 @@ config VIDEO_OV13858 + This is a Video4Linux2 sensor driver for the OmniVision + OV13858 camera. + ++config VIDEO_IRS1125 ++ tristate "Infineon IRS1125 sensor support" ++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ++ depends on MEDIA_CAMERA_SUPPORT ++ select V4L2_FWNODE ++ help ++ This is a Video4Linux2 sensor-level driver for the Infineon ++ IRS1125 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called irs1125. ++ + config VIDEO_VS6624 + tristate "ST VS6624 sensor support" + depends on VIDEO_V4L2 && I2C +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -82,6 +82,7 @@ obj-$(CONFIG_VIDEO_OV8856) += ov8856.o + obj-$(CONFIG_VIDEO_OV9640) += ov9640.o + obj-$(CONFIG_VIDEO_OV9650) += ov9650.o + obj-$(CONFIG_VIDEO_OV13858) += ov13858.o ++obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o + obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o + obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o + obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o +--- /dev/null ++++ b/drivers/media/i2c/irs1125.c +@@ -0,0 +1,1112 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Infineon IRS1125 TOF cameras. ++ * Copyright (C) 2018, pieye GmbH ++ * ++ * Based on V4L2 OmniVision OV5647 Image Sensor driver ++ * Copyright (C) 2016 Ramiro Oliveira ++ * ++ * DT / fwnode changes, and GPIO control taken from ov5640.c ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2014-2017 Mentor Graphics Inc. ++ * ++ */ ++ ++#include "irs1125.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CHECK_BIT(val, pos) ((val) & BIT(pos)) ++ ++#define SENSOR_NAME "irs1125" ++ ++#define RESET_ACTIVE_DELAY_MS 20 ++ ++#define IRS1125_ALTERNATE_FW "irs1125_af.bin" ++ ++#define IRS1125_REG_CSICFG 0xA882 ++#define IRS1125_REG_DESIGN_STEP 0xB0AD ++#define IRS1125_REG_EFUSEVAL2 0xB09F ++#define IRS1125_REG_EFUSEVAL3 0xB0A0 ++#define IRS1125_REG_EFUSEVAL4 0xB0A1 ++#define IRS1125_REG_DMEM_SHADOW 0xC320 ++ ++#define IRS1125_DESIGN_STEP_EXPECTED 0x0a12 ++ ++#define IRS1125_ROW_START_DEF 0 ++#define IRS1125_COLUMN_START_DEF 0 ++#define IRS1125_WINDOW_HEIGHT_DEF 288 ++#define IRS1125_WINDOW_WIDTH_DEF 352 ++ ++struct regval_list { ++ u16 addr; ++ u16 data; ++}; ++ ++struct irs1125 { ++ struct v4l2_subdev sd; ++ struct media_pad pad; ++ /* the parsed DT endpoint info */ ++ struct v4l2_fwnode_endpoint ep; ++ ++ struct clk *xclk; ++ struct v4l2_ctrl_handler ctrl_handler; ++ ++ /* To serialize asynchronus callbacks */ ++ struct mutex lock; ++ ++ /* image data layout */ ++ unsigned int num_seq; ++ ++ /* reset pin */ ++ struct gpio_desc *reset; ++ ++ /* V4l2 Controls to grab */ ++ struct v4l2_ctrl *ctrl_modplls; ++ struct v4l2_ctrl *ctrl_numseq; ++ ++ int power_count; ++}; ++ ++static inline struct irs1125 *to_state(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct irs1125, sd); ++} ++ ++static struct regval_list irs1125_26MHz[] = { ++ {0xB017, 0x0413}, ++ {0xB086, 0x3535}, ++ {0xB0AE, 0xEF02}, ++ {0xA000, 0x0004}, ++ {0xFFFF, 100}, ++ ++ {0xB062, 0x6383}, ++ {0xB063, 0x55A8}, ++ {0xB068, 0x7628}, ++ {0xB069, 0x03E2}, ++ ++ {0xFFFF, 100}, ++ {0xB05A, 0x01C5}, ++ {0xB05C, 0x0206}, ++ {0xB05D, 0x01C5}, ++ {0xB05F, 0x0206}, ++ {0xB016, 0x1335}, ++ {0xFFFF, 100}, ++ {0xA893, 0x8261}, ++ {0xA894, 0x89d8}, ++ {0xA895, 0x131d}, ++ {0xA896, 0x4251}, ++ {0xA897, 0x9D8A}, ++ {0xA898, 0x0BD8}, ++ {0xA899, 0x2245}, ++ {0xA89A, 0xAB9B}, ++ {0xA89B, 0x03B9}, ++ {0xA89C, 0x8041}, ++ {0xA89D, 0xE07E}, ++ {0xA89E, 0x0307}, ++ {0xFFFF, 100}, ++ {0xA88D, 0x0004}, ++ {0xA800, 0x0E68}, ++ {0xA801, 0x0000}, ++ {0xA802, 0x000C}, ++ {0xA803, 0x0000}, ++ {0xA804, 0x0E68}, ++ {0xA805, 0x0000}, ++ {0xA806, 0x0440}, ++ {0xA807, 0x0000}, ++ {0xA808, 0x0E68}, ++ {0xA809, 0x0000}, ++ {0xA80A, 0x0884}, ++ {0xA80B, 0x0000}, ++ {0xA80C, 0x0E68}, ++ {0xA80D, 0x0000}, ++ {0xA80E, 0x0CC8}, ++ {0xA80F, 0x0000}, ++ {0xA810, 0x0E68}, ++ {0xA811, 0x0000}, ++ {0xA812, 0x2000}, ++ {0xA813, 0x0000}, ++ {0xA882, 0x0081}, ++ {0xA88C, 0x403A}, ++ {0xA88F, 0x031E}, ++ {0xA892, 0x0351}, ++ {0x9813, 0x13FF}, ++ {0x981B, 0x7608}, ++ ++ {0xB008, 0x0000}, ++ {0xB015, 0x1513}, ++ ++ {0xFFFF, 100} ++}; ++ ++static struct regval_list irs1125_seq_cfg[] = { ++ {0xC3A0, 0x823D}, ++ {0xC3A1, 0xB13B}, ++ {0xC3A2, 0x0313}, ++ {0xC3A3, 0x4659}, ++ {0xC3A4, 0xC4EC}, ++ {0xC3A5, 0x03CE}, ++ {0xC3A6, 0x4259}, ++ {0xC3A7, 0xC4EC}, ++ {0xC3A8, 0x03CE}, ++ {0xC3A9, 0x8839}, ++ {0xC3AA, 0x89D8}, ++ {0xC3AB, 0x031D}, ++ ++ {0xC24C, 0x5529}, ++ {0xC24D, 0x0000}, ++ {0xC24E, 0x1200}, ++ {0xC24F, 0x6CB2}, ++ {0xC250, 0x0000}, ++ {0xC251, 0x5529}, ++ {0xC252, 0x42F4}, ++ {0xC253, 0xD1AF}, ++ {0xC254, 0x8A18}, ++ {0xC255, 0x0002}, ++ {0xC256, 0x5529}, ++ {0xC257, 0x6276}, ++ {0xC258, 0x11A7}, ++ {0xC259, 0xD907}, ++ {0xC25A, 0x0000}, ++ {0xC25B, 0x5529}, ++ {0xC25C, 0x07E0}, ++ {0xC25D, 0x7BFE}, ++ {0xC25E, 0x6402}, ++ {0xC25F, 0x0019}, ++ ++ {0xC3AC, 0x0007}, ++ {0xC3AD, 0xED88}, ++ {0xC320, 0x003E}, ++ {0xC321, 0x0000}, ++ {0xC322, 0x2000}, ++ {0xC323, 0x0000}, ++ {0xC324, 0x0271}, ++ {0xC325, 0x0000}, ++ {0xC326, 0x000C}, ++ {0xC327, 0x0000}, ++ {0xC328, 0x0271}, ++ {0xC329, 0x0000}, ++ {0xC32A, 0x0440}, ++ {0xC32B, 0x0000}, ++ {0xC32C, 0x0271}, ++ {0xC32D, 0x0000}, ++ {0xC32E, 0x0884}, ++ {0xC32F, 0x0000}, ++ {0xC330, 0x0271}, ++ {0xC331, 0x0000}, ++ {0xC332, 0x0CC8}, ++ {0xC333, 0x0000}, ++ {0xA88D, 0x0004}, ++ ++ {0xA890, 0x0000}, ++ {0xC219, 0x0002}, ++ {0xC21A, 0x0000}, ++ {0xC21B, 0x0000}, ++ {0xC21C, 0x00CD}, ++ {0xC21D, 0x0009}, ++ {0xC21E, 0x00CD}, ++ {0xC21F, 0x0009}, ++ ++ {0xA87C, 0x0000}, ++ {0xC032, 0x0001}, ++ {0xC034, 0x0000}, ++ {0xC035, 0x0001}, ++ {0xC039, 0x0000}, ++ {0xC401, 0x0002}, ++ ++ {0xFFFF, 1}, ++ {0xA87C, 0x0001} ++}; ++ ++static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val) ++{ ++ int ret; ++ unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff}; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ ret = i2c_master_send(client, data, 4); ++ if (ret < 0) ++ dev_err(&client->dev, "%s: i2c write error, reg: %x\n", ++ __func__, reg); ++ ++ return ret; ++} ++ ++static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val) ++{ ++ int ret; ++ unsigned char data_w[2] = { reg >> 8, reg & 0xff }; ++ char rdval[2]; ++ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ ret = i2c_master_send(client, data_w, 2); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", ++ __func__, reg); ++ return ret; ++ } ++ ++ ret = i2c_master_recv(client, rdval, 2); ++ if (ret < 0) ++ dev_err(&client->dev, "%s: i2c read error, reg: %x\n", ++ __func__, reg); ++ ++ *val = rdval[1] | (rdval[0] << 8); ++ ++ return ret; ++} ++ ++static int irs1125_write_array(struct v4l2_subdev *sd, ++ struct regval_list *regs, int array_size) ++{ ++ int i, ret; ++ ++ for (i = 0; i < array_size; i++) { ++ if (regs[i].addr == 0xFFFF) { ++ msleep(regs[i].data); ++ } else { ++ ret = irs1125_write(sd, regs[i].addr, regs[i].data); ++ if (ret < 0) ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int irs1125_stream_on(struct v4l2_subdev *sd) ++{ ++ int ret; ++ struct irs1125 *irs1125 = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ v4l2_ctrl_grab(irs1125->ctrl_numseq, 1); ++ v4l2_ctrl_grab(irs1125->ctrl_modplls, 1); ++ ++ ret = irs1125_write(sd, 0xC400, 0x0001); ++ if (ret < 0) { ++ dev_err(&client->dev, "error enabling firmware: %d", ret); ++ return ret; ++ } ++ ++ msleep(100); ++ ++ return irs1125_write(sd, 0xA87C, 0x0001); ++} ++ ++static int irs1125_stream_off(struct v4l2_subdev *sd) ++{ ++ int ret; ++ struct irs1125 *irs1125 = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ v4l2_ctrl_grab(irs1125->ctrl_numseq, 0); ++ v4l2_ctrl_grab(irs1125->ctrl_modplls, 0); ++ ++ ret = irs1125_write(sd, 0xA87C, 0x0000); ++ if (ret < 0) { ++ dev_err(&client->dev, "error disabling trigger: %d", ret); ++ return ret; ++ } ++ ++ msleep(100); ++ ++ return irs1125_write(sd, 0xC400, 0x0002); ++} ++ ++static int __sensor_init(struct v4l2_subdev *sd) ++{ ++ unsigned int cnt, idx; ++ int ret; ++ u16 val; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct irs1125 *irs1125 = to_state(sd); ++ const struct firmware *fw; ++ struct regval_list *reg_data; ++ ++ cnt = 0; ++ while (1) { ++ ret = irs1125_read(sd, 0xC40F, &val); ++ if (ret < 0) { ++ dev_err(&client->dev, "read register 0xC40F failed\n"); ++ return ret; ++ } ++ if (CHECK_BIT(val, 14) == 0) ++ break; ++ ++ if (cnt >= 5) { ++ dev_err(&client->dev, "timeout waiting for 0xC40F\n"); ++ return -EAGAIN; ++ } ++ ++ cnt++; ++ } ++ ++ ret = irs1125_write_array(sd, irs1125_26MHz, ++ ARRAY_SIZE(irs1125_26MHz)); ++ if (ret < 0) { ++ dev_err(&client->dev, "write sensor default regs error\n"); ++ return ret; ++ } ++ ++ /* set CSI-2 number of data lanes */ ++ if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) { ++ val = 0x0001; ++ } else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) { ++ val = 0x0081; ++ } else { ++ dev_err(&client->dev, "invalid number of data lanes %d\n", ++ irs1125->ep.bus.mipi_csi2.num_data_lanes); ++ return -EINVAL; ++ } ++ ++ ret = irs1125_write(sd, IRS1125_REG_CSICFG, val); ++ if (ret < 0) { ++ dev_err(&client->dev, "write sensor csi2 config error\n"); ++ return ret; ++ } ++ ++ /* request the firmware, this will block and timeout */ ++ ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev); ++ if (ret) { ++ dev_err(&client->dev, ++ "did not find the firmware file '%s' (status %d)\n", ++ IRS1125_ALTERNATE_FW, ret); ++ return ret; ++ } ++ ++ if (fw->size % 4) { ++ dev_err(&client->dev, "firmware file '%s' invalid\n", ++ IRS1125_ALTERNATE_FW); ++ release_firmware(fw); ++ return -EINVAL; ++ } ++ ++ for (idx = 0; idx < fw->size; idx += 4) { ++ reg_data = (struct regval_list *)&fw->data[idx]; ++ ret = irs1125_write(sd, reg_data->addr, reg_data->data); ++ if (ret < 0) { ++ dev_err(&client->dev, "firmware write error\n"); ++ release_firmware(fw); ++ return ret; ++ } ++ } ++ release_firmware(fw); ++ ++ ret = irs1125_write_array(sd, irs1125_seq_cfg, ++ ARRAY_SIZE(irs1125_seq_cfg)); ++ if (ret < 0) { ++ dev_err(&client->dev, "write default sequence failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int irs1125_sensor_power(struct v4l2_subdev *sd, int on) ++{ ++ int ret = 0; ++ struct irs1125 *irs1125 = to_state(sd); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ mutex_lock(&irs1125->lock); ++ ++ if (on && !irs1125->power_count) { ++ gpiod_set_value_cansleep(irs1125->reset, 1); ++ msleep(RESET_ACTIVE_DELAY_MS); ++ ++ ret = clk_prepare_enable(irs1125->xclk); ++ if (ret < 0) { ++ dev_err(&client->dev, "clk prepare enable failed\n"); ++ goto out; ++ } ++ ++ ret = __sensor_init(sd); ++ if (ret < 0) { ++ clk_disable_unprepare(irs1125->xclk); ++ dev_err(&client->dev, ++ "Camera not available, check Power\n"); ++ goto out; ++ } ++ } else if (!on && irs1125->power_count == 1) { ++ gpiod_set_value_cansleep(irs1125->reset, 0); ++ } ++ ++ /* Update the power count. */ ++ irs1125->power_count += on ? 1 : -1; ++ WARN_ON(irs1125->power_count < 0); ++ ++out: ++ mutex_unlock(&irs1125->lock); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int irs1125_sensor_get_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ u16 val; ++ int ret; ++ ++ ret = irs1125_read(sd, reg->reg & 0xffff, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = 1; ++ ++ return 0; ++} ++ ++static int irs1125_sensor_set_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff); ++} ++#endif ++ ++static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = { ++ .s_power = irs1125_sensor_power, ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = irs1125_sensor_get_register, ++ .s_register = irs1125_sensor_set_register, ++#endif ++}; ++ ++static int irs1125_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ if (enable) ++ return irs1125_stream_on(sd); ++ else ++ return irs1125_stream_off(sd); ++} ++ ++static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = { ++ .s_stream = irs1125_s_stream, ++}; ++ ++static int irs1125_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ if (code->index > 0) ++ return -EINVAL; ++ ++ code->code = MEDIA_BUS_FMT_Y12_1X12; ++ ++ return 0; ++} ++ ++static int irs1125_set_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *fmt = &format->format; ++ struct irs1125 *irs1125 = to_state(sd); ++ ++ if (format->pad != 0) ++ return -EINVAL; ++ ++ /* Only one format is supported, so return that */ ++ memset(fmt, 0, sizeof(*fmt)); ++ fmt->code = MEDIA_BUS_FMT_Y12_1X12; ++ fmt->colorspace = V4L2_COLORSPACE_RAW; ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->width = IRS1125_WINDOW_WIDTH_DEF; ++ fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq; ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = { ++ .enum_mbus_code = irs1125_enum_mbus_code, ++ .set_fmt = irs1125_set_get_fmt, ++ .get_fmt = irs1125_set_get_fmt, ++}; ++ ++static const struct v4l2_subdev_ops irs1125_subdev_ops = { ++ .core = &irs1125_subdev_core_ops, ++ .video = &irs1125_subdev_video_ops, ++ .pad = &irs1125_subdev_pad_ops, ++}; ++ ++static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct irs1125 *dev = container_of(ctrl->handler, ++ struct irs1125, ctrl_handler); ++ struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); ++ int err, i; ++ struct irs1125_mod_pll *mod_cur, *mod_new; ++ struct irs1125_seq_cfg *cfg_cur, *cfg_new; ++ u16 addr, val; ++ ++ err = 0; ++ ++ switch (ctrl->id) { ++ case IRS1125_CID_SAFE_RECONFIG: ++ { ++ struct irs1125_illu *illu_cur, *illu_new; ++ ++ illu_new = (struct irs1125_illu *)ctrl->p_new.p; ++ illu_cur = (struct irs1125_illu *)ctrl->p_cur.p; ++ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) { ++ if (illu_cur[i].exposure != illu_new[i].exposure) { ++ addr = 0xA850 + i * 2; ++ val = illu_new[i].exposure; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (illu_cur[i].framerate != illu_new[i].framerate) { ++ addr = 0xA851 + i * 2; ++ val = illu_new[i].framerate; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ } ++ break; ++ } ++ case IRS1125_CID_MOD_PLL: ++ mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p; ++ mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p; ++ for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) { ++ if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) { ++ addr = 0xC3A0 + i * 3; ++ val = mod_new[i].pllcfg1; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) { ++ addr = 0xC3A1 + i * 3; ++ val = mod_new[i].pllcfg2; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) { ++ addr = 0xC3A2 + i * 3; ++ val = mod_new[i].pllcfg3; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) { ++ addr = 0xC24C + i * 5; ++ val = mod_new[i].pllcfg4; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) { ++ addr = 0xC24D + i * 5; ++ val = mod_new[i].pllcfg5; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) { ++ addr = 0xC24E + i * 5; ++ val = mod_new[i].pllcfg6; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) { ++ addr = 0xC24F + i * 5; ++ val = mod_new[i].pllcfg7; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) { ++ addr = 0xC250 + i * 5; ++ val = mod_new[i].pllcfg8; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ } ++ break; ++ case IRS1125_CID_SEQ_CONFIG: ++ cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p; ++ cfg_cur = (struct irs1125_seq_cfg *)ctrl->p_cur.p; ++ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) { ++ if (cfg_cur[i].exposure != cfg_new[i].exposure) { ++ addr = IRS1125_REG_DMEM_SHADOW + i * 4; ++ val = cfg_new[i].exposure; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (cfg_cur[i].framerate != cfg_new[i].framerate) { ++ addr = IRS1125_REG_DMEM_SHADOW + 1 + i * 4; ++ val = cfg_new[i].framerate; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (cfg_cur[i].ps != cfg_new[i].ps) { ++ addr = IRS1125_REG_DMEM_SHADOW + 2 + i * 4; ++ val = cfg_new[i].ps; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ if (cfg_cur[i].pll != cfg_new[i].pll) { ++ addr = IRS1125_REG_DMEM_SHADOW + 3 + i * 4; ++ val = cfg_new[i].pll; ++ err = irs1125_write(&dev->sd, addr, val); ++ if (err < 0) ++ break; ++ } ++ } ++ break; ++ case IRS1125_CID_NUM_SEQS: ++ err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1); ++ if (err >= 0) ++ dev->num_seq = ctrl->val; ++ break; ++ case IRS1125_CID_CONTINUOUS_TRIG: ++ if (ctrl->val == 0) ++ err = irs1125_write(&dev->sd, 0xA87C, 0); ++ else ++ err = irs1125_write(&dev->sd, 0xA87C, 1); ++ break; ++ case IRS1125_CID_TRIGGER: ++ if (ctrl->val != 0) { ++ err = irs1125_write(&dev->sd, 0xA87C, 1); ++ if (err >= 0) ++ err = irs1125_write(&dev->sd, 0xA87C, 0); ++ } ++ break; ++ case IRS1125_CID_RECONFIG: ++ if (ctrl->val != 0) ++ err = irs1125_write(&dev->sd, 0xA87A, 1); ++ break; ++ case IRS1125_CID_ILLU_ON: ++ if (ctrl->val == 0) ++ err = irs1125_write(&dev->sd, 0xA892, 0x377); ++ else ++ err = irs1125_write(&dev->sd, 0xA892, 0x355); ++ break; ++ default: ++ break; ++ } ++ ++ if (err < 0) ++ dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d", ++ ctrl->id, ctrl->val, err); ++ else ++ err = 0; ++ ++ return err; ++} ++ ++static const struct v4l2_ctrl_ops irs1125_ctrl_ops = { ++ .s_ctrl = irs1125_s_ctrl, ++}; ++ ++static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = { ++ { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_NUM_SEQS, ++ .name = "Change number of sequences", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT, ++ .min = 1, ++ .max = 20, ++ .step = 1, ++ .def = 5, ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_MOD_PLL, ++ .name = "Reconfigure modulation PLLs", ++ .type = V4L2_CTRL_TYPE_U16, ++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD, ++ .min = 0, ++ .max = U16_MAX, ++ .step = 1, ++ .def = 0, ++ .elem_size = sizeof(u16), ++ .dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16), ++ IRS1125_NUM_MOD_PLLS} ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_SAFE_RECONFIG, ++ .name = "Change exposure and pause of single seq", ++ .type = V4L2_CTRL_TYPE_U16, ++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD, ++ .min = 0, ++ .max = U16_MAX, ++ .step = 1, ++ .def = 0, ++ .elem_size = sizeof(u16), ++ .dims = {sizeof(struct irs1125_illu) / sizeof(u16), ++ IRS1125_NUM_SEQ_ENTRIES} ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_SEQ_CONFIG, ++ .name = "Change sequence settings", ++ .type = V4L2_CTRL_TYPE_U16, ++ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD, ++ .min = 0, ++ .max = U16_MAX, ++ .step = 1, ++ .def = 0, ++ .elem_size = sizeof(u16), ++ .dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16), ++ IRS1125_NUM_SEQ_ENTRIES} ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_CONTINUOUS_TRIG, ++ .name = "Enable/disable continuous trigger", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 0 ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_TRIGGER, ++ .name = "Capture a single sequence", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 0 ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_RECONFIG, ++ .name = "Trigger imager reconfiguration", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 0 ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_ILLU_ON, ++ .name = "Turn illu on or off", ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, ++ .min = 0, ++ .max = 1, ++ .step = 1, ++ .def = 1 ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_IDENT0, ++ .name = "Get ident 0 information", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .flags = V4L2_CTRL_FLAG_READ_ONLY, ++ .min = S32_MIN, ++ .max = S32_MAX, ++ .step = 1, ++ .def = 0 ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_IDENT1, ++ .name = "Get ident 1 information", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .flags = V4L2_CTRL_FLAG_READ_ONLY, ++ .min = S32_MIN, ++ .max = S32_MAX, ++ .step = 1, ++ .def = 0 ++ }, { ++ .ops = &irs1125_ctrl_ops, ++ .id = IRS1125_CID_IDENT2, ++ .name = "Get ident 2 information", ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .flags = V4L2_CTRL_FLAG_READ_ONLY, ++ .min = S32_MIN, ++ .max = S32_MAX, ++ .step = 1, ++ .def = 0 ++ } ++}; ++ ++static int irs1125_detect(struct v4l2_subdev *sd) ++{ ++ u16 read; ++ int ret; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read); ++ if (ret < 0) { ++ dev_err(&client->dev, "error reading from i2c\n"); ++ return ret; ++ } ++ ++ if (read != IRS1125_DESIGN_STEP_EXPECTED) { ++ dev_err(&client->dev, "Design step expected 0x%x got 0x%x", ++ IRS1125_DESIGN_STEP_EXPECTED, read); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ++{ ++ struct v4l2_mbus_framefmt *format = ++ v4l2_subdev_get_try_format(sd, fh->pad, 0); ++ ++ format->code = MEDIA_BUS_FMT_Y12_1X12; ++ format->width = IRS1125_WINDOW_WIDTH_DEF; ++ format->height = IRS1125_WINDOW_HEIGHT_DEF; ++ format->field = V4L2_FIELD_NONE; ++ format->colorspace = V4L2_COLORSPACE_RAW; ++ ++ return 0; ++} ++ ++static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = { ++ .open = irs1125_open, ++}; ++ ++static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev) ++{ ++ struct v4l2_ctrl *ctrl; ++ int err, i; ++ struct v4l2_ctrl_handler *hdl; ++ ++ hdl = &sensor->ctrl_handler; ++ v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls)); ++ ++ for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++) { ++ ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i], ++ NULL); ++ if (!ctrl) ++ dev_err(dev, "Failed to init custom control %s\n", ++ irs1125_custom_ctrls[i].name); ++ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS) ++ sensor->ctrl_numseq = ctrl; ++ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL) ++ sensor->ctrl_modplls = ctrl; ++ } ++ ++ if (hdl->error) { ++ dev_err(dev, "Error %d adding controls\n", hdl->error); ++ err = hdl->error; ++ goto error_ctrls; ++ } ++ ++ sensor->sd.ctrl_handler = hdl; ++ return 0; ++ ++error_ctrls: ++ v4l2_ctrl_handler_free(&sensor->ctrl_handler); ++ return -err; ++} ++ ++static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev) ++{ ++ int ret; ++ struct v4l2_ctrl *ctrl; ++ struct v4l2_subdev *sd; ++ u16 read; ++ ++ sd = &sensor->sd; ++ ++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0); ++ if (!ctrl) { ++ dev_err(dev, "could not find device ctrl.\n"); ++ return -EINVAL; ++ } ++ ++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read); ++ if (ret < 0) { ++ dev_err(dev, "error reading from i2c\n"); ++ return -EIO; ++ } ++ ++ v4l2_ctrl_s_ctrl(ctrl, read); ++ ++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1); ++ if (!ctrl) { ++ dev_err(dev, "could not find device ctrl.\n"); ++ return -EINVAL; ++ } ++ ++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read); ++ if (ret < 0) { ++ dev_err(dev, "error reading from i2c\n"); ++ return -EIO; ++ } ++ ++ v4l2_ctrl_s_ctrl(ctrl, read); ++ ++ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2); ++ if (!ctrl) { ++ dev_err(dev, "could not find device ctrl.\n"); ++ return -EINVAL; ++ } ++ ++ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read); ++ if (ret < 0) { ++ dev_err(dev, "error reading from i2c\n"); ++ return -EIO; ++ } ++ v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC); ++ ++ return 0; ++} ++ ++static int irs1125_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct irs1125 *sensor; ++ int ret; ++ struct fwnode_handle *endpoint; ++ u32 xclk_freq; ++ int gpio_num; ++ ++ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); ++ if (!sensor) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops); ++ ++ /* Get CSI2 bus config */ ++ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(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; ++ } ++ ++ /* get system clock (xclk) */ ++ sensor->xclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(sensor->xclk)) { ++ dev_err(dev, "could not get xclk"); ++ return PTR_ERR(sensor->xclk); ++ } ++ ++ xclk_freq = clk_get_rate(sensor->xclk); ++ if (xclk_freq != 26000000) { ++ dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq); ++ return -EINVAL; ++ } ++ ++ sensor->num_seq = 5; ++ ++ /* Request the power down GPIO */ ++ sensor->reset = devm_gpiod_get(&client->dev, "pwdn", ++ GPIOD_OUT_LOW); ++ ++ if (IS_ERR(sensor->reset)) { ++ dev_err(dev, "could not get reset"); ++ return PTR_ERR(sensor->reset); ++ } ++ ++ gpio_num = desc_to_gpio(sensor->reset); ++ ++ mutex_init(&sensor->lock); ++ ++ ret = irs1125_ctrls_init(sensor, dev); ++ if (ret < 0) ++ goto mutex_remove; ++ ++ sensor->sd.internal_ops = &irs1125_subdev_internal_ops; ++ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ++ sensor->pad.flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); ++ if (ret < 0) ++ goto mutex_remove; ++ ++ gpiod_set_value_cansleep(sensor->reset, 1); ++ msleep(RESET_ACTIVE_DELAY_MS); ++ ++ ret = irs1125_detect(&sensor->sd); ++ if (ret < 0) ++ goto error; ++ ++ ret = irs1125_ident_setup(sensor, dev); ++ if (ret < 0) ++ goto error; ++ ++ gpiod_set_value_cansleep(sensor->reset, 0); ++ ++ ret = v4l2_async_register_subdev(&sensor->sd); ++ if (ret < 0) ++ goto error; ++ ++ dev_dbg(dev, "Infineon IRS1125 camera driver probed\n"); ++ ++ return 0; ++ ++error: ++ media_entity_cleanup(&sensor->sd.entity); ++mutex_remove: ++ mutex_destroy(&sensor->lock); ++ return ret; ++} ++ ++static int irs1125_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct irs1125 *irs1125 = to_state(sd); ++ ++ v4l2_async_unregister_subdev(&irs1125->sd); ++ media_entity_cleanup(&irs1125->sd.entity); ++ v4l2_device_unregister_subdev(sd); ++ mutex_destroy(&irs1125->lock); ++ v4l2_ctrl_handler_free(&irs1125->ctrl_handler); ++ ++ return 0; ++} ++ ++#if IS_ENABLED(CONFIG_OF) ++static const struct of_device_id irs1125_of_match[] = { ++ { .compatible = "infineon,irs1125" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, irs1125_of_match); ++#endif ++ ++static struct i2c_driver irs1125_driver = { ++ .driver = { ++ .of_match_table = of_match_ptr(irs1125_of_match), ++ .name = SENSOR_NAME, ++ }, ++ .probe = irs1125_probe, ++ .remove = irs1125_remove, ++}; ++ ++module_i2c_driver(irs1125_driver); ++ ++MODULE_AUTHOR("Markus Proeller "); ++MODULE_DESCRIPTION("Infineon irs1125 sensor driver"); ++MODULE_LICENSE("GPL v2"); ++ +--- /dev/null ++++ b/drivers/media/i2c/irs1125.h +@@ -0,0 +1,61 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * A V4L2 driver for Infineon IRS1125 TOF cameras. ++ * Copyright (C) 2018, pieye GmbH ++ * ++ * Based on V4L2 OmniVision OV5647 Image Sensor driver ++ * Copyright (C) 2016 Ramiro Oliveira ++ * ++ * DT / fwnode changes, and GPIO control taken from ov5640.c ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2014-2017 Mentor Graphics Inc. ++ * ++ */ ++ ++#ifndef IRS1125_H ++#define IRS1125_H ++ ++#include ++#include ++ ++#define IRS1125_NUM_SEQ_ENTRIES 20 ++#define IRS1125_NUM_MOD_PLLS 4 ++ ++#define IRS1125_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) ++#define IRS1125_CID_SAFE_RECONFIG (IRS1125_CID_CUSTOM_BASE + 0) ++#define IRS1125_CID_CONTINUOUS_TRIG (IRS1125_CID_CUSTOM_BASE + 1) ++#define IRS1125_CID_TRIGGER (IRS1125_CID_CUSTOM_BASE + 2) ++#define IRS1125_CID_RECONFIG (IRS1125_CID_CUSTOM_BASE + 3) ++#define IRS1125_CID_ILLU_ON (IRS1125_CID_CUSTOM_BASE + 4) ++#define IRS1125_CID_NUM_SEQS (IRS1125_CID_CUSTOM_BASE + 5) ++#define IRS1125_CID_MOD_PLL (IRS1125_CID_CUSTOM_BASE + 6) ++#define IRS1125_CID_SEQ_CONFIG (IRS1125_CID_CUSTOM_BASE + 7) ++#define IRS1125_CID_IDENT0 (IRS1125_CID_CUSTOM_BASE + 8) ++#define IRS1125_CID_IDENT1 (IRS1125_CID_CUSTOM_BASE + 9) ++#define IRS1125_CID_IDENT2 (IRS1125_CID_CUSTOM_BASE + 10) ++ ++struct irs1125_seq_cfg { ++ __u16 exposure; ++ __u16 framerate; ++ __u16 ps; ++ __u16 pll; ++}; ++ ++struct irs1125_illu { ++ __u16 exposure; ++ __u16 framerate; ++}; ++ ++struct irs1125_mod_pll { ++ __u16 pllcfg1; ++ __u16 pllcfg2; ++ __u16 pllcfg3; ++ __u16 pllcfg4; ++ __u16 pllcfg5; ++ __u16 pllcfg6; ++ __u16 pllcfg7; ++ __u16 pllcfg8; ++}; ++ ++#endif /* IRS1125 */ ++ diff --git a/target/linux/bcm27xx/patches-5.4/950-0323-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch b/target/linux/bcm27xx/patches-5.4/950-0323-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch deleted file mode 100644 index f98002e99c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0323-drm-vc4-Correct-handling-of-rotation-parameter-in-fk.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 23ed834712dfc0d25451f16b46ae9c19abb675b5 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 18 Sep 2019 15:49:13 +0100 -Subject: [PATCH] drm/vc4: Correct handling of rotation parameter in - fkms - -One bit within DRM_MODE_ROTATE_MASK will always be set to -determine the base rotation 0/90/180/270, and then REFLECT_X -and REFLECT_Y are on top. - -Correct the handling which was assuming that REFLECT_[X|Y] -was instead of ROTATE_x. - -Signed-off-by: Dave Stevenson ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 ++++++++++---------------- - 1 file changed, 14 insertions(+), 23 deletions(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -82,11 +82,6 @@ struct set_plane { - #define TRANSFORM_FLIP_HRIZ BIT(16) - #define TRANSFORM_FLIP_VERT BIT(17) - --#define SUPPORTED_ROTATIONS (DRM_MODE_ROTATE_0 | \ -- DRM_MODE_ROTATE_180 | \ -- DRM_MODE_REFLECT_X | \ -- DRM_MODE_REFLECT_Y) -- - struct mailbox_set_plane { - struct rpi_firmware_property_tag_header tag; - struct set_plane plane; -@@ -525,7 +520,7 @@ static int vc4_plane_to_mb(struct drm_pl - const struct vc_image_format *vc_fmt = - vc4_get_vc_image_fmt(drm_fmt->format); - int num_planes = fb->format->num_planes; -- unsigned int rotation = SUPPORTED_ROTATIONS; -+ unsigned int rotation; - - mb->plane.vc_image_type = vc_fmt->vc_image; - mb->plane.width = fb->width; -@@ -546,23 +541,16 @@ static int vc4_plane_to_mb(struct drm_pl - mb->plane.is_vu = vc_fmt->is_vu; - mb->plane.planes[0] = bo->paddr + fb->offsets[0]; - -- rotation = drm_rotation_simplify(state->rotation, rotation); -- -- switch (rotation) { -- default: -- case DRM_MODE_ROTATE_0: -- mb->plane.transform = TRANSFORM_NO_ROTATE; -- break; -- case DRM_MODE_ROTATE_180: -- mb->plane.transform = TRANSFORM_ROTATE_180; -- break; -- case DRM_MODE_REFLECT_X: -- mb->plane.transform = TRANSFORM_FLIP_HRIZ; -- break; -- case DRM_MODE_REFLECT_Y: -- mb->plane.transform = TRANSFORM_FLIP_VERT; -- break; -- } -+ rotation = drm_rotation_simplify(state->rotation, -+ DRM_MODE_ROTATE_0 | -+ DRM_MODE_REFLECT_X | -+ DRM_MODE_REFLECT_Y); -+ -+ mb->plane.transform = TRANSFORM_NO_ROTATE; -+ if (rotation & DRM_MODE_REFLECT_X) -+ mb->plane.transform |= TRANSFORM_FLIP_HRIZ; -+ if (rotation & DRM_MODE_REFLECT_Y) -+ mb->plane.transform |= TRANSFORM_FLIP_VERT; - - vc4_fkms_margins_adj(state, &mb->plane); - -@@ -803,7 +791,10 @@ static struct drm_plane *vc4_fkms_plane_ - - drm_plane_create_alpha_property(plane); - drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, -- SUPPORTED_ROTATIONS); -+ DRM_MODE_ROTATE_0 | -+ DRM_MODE_ROTATE_180 | -+ DRM_MODE_REFLECT_X | -+ DRM_MODE_REFLECT_Y); - drm_plane_create_color_properties(plane, - BIT(DRM_COLOR_YCBCR_BT601) | - BIT(DRM_COLOR_YCBCR_BT709) | diff --git a/target/linux/bcm27xx/patches-5.4/950-0323-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch b/target/linux/bcm27xx/patches-5.4/950-0323-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch new file mode 100644 index 0000000000..ab3a971608 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0323-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch @@ -0,0 +1,98 @@ +From 3d9d9ae68a1fb5451d12b46b65289e67cca2a340 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 13 Sep 2019 17:19:33 +0100 +Subject: [PATCH] staging:bcm2835-codec: Add support for + ENUM_FRAMESIZES + +Required for compliance testing for the encoder. + +Signed-off-by: Dave Stevenson +--- + .../bcm2835-codec/bcm2835-v4l2-codec.c | 48 +++++++++++++++++-- + 1 file changed, 44 insertions(+), 4 deletions(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -496,9 +496,10 @@ struct bcm2835_codec_fmt *get_default_fo + return &dev->supported_fmts[capture ? 1 : 0].list[0]; + } + +-static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, +- struct bcm2835_codec_dev *dev, +- bool capture) ++static ++struct bcm2835_codec_fmt *find_format_pix_fmt(u32 pix_fmt, ++ struct bcm2835_codec_dev *dev, ++ bool capture) + { + struct bcm2835_codec_fmt *fmt; + unsigned int k; +@@ -507,7 +508,7 @@ static struct bcm2835_codec_fmt *find_fo + + for (k = 0; k < fmts->num_entries; k++) { + fmt = &fmts->list[k]; +- if (fmt->fourcc == f->fmt.pix_mp.pixelformat) ++ if (fmt->fourcc == pix_fmt) + break; + } + if (k == fmts->num_entries) +@@ -516,6 +517,14 @@ static struct bcm2835_codec_fmt *find_fo + return &fmts->list[k]; + } + ++static inline ++struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, ++ struct bcm2835_codec_dev *dev, ++ bool capture) ++{ ++ return find_format_pix_fmt(f->fmt.pix_mp.pixelformat, dev, capture); ++} ++ + static inline struct bcm2835_codec_ctx *file2ctx(struct file *file) + { + return container_of(file->private_data, struct bcm2835_codec_ctx, fh); +@@ -1792,6 +1801,36 @@ static int vidioc_encoder_cmd(struct fil + return 0; + } + ++static int vidioc_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct bcm2835_codec_fmt *fmt; ++ ++ fmt = find_format_pix_fmt(fsize->pixel_format, file2ctx(file)->dev, ++ true); ++ if (!fmt) ++ fmt = find_format_pix_fmt(fsize->pixel_format, ++ file2ctx(file)->dev, ++ false); ++ ++ if (!fmt) ++ return -EINVAL; ++ ++ if (fsize->index) ++ return -EINVAL; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; ++ ++ fsize->stepwise.min_width = MIN_W; ++ fsize->stepwise.max_width = MAX_W; ++ fsize->stepwise.step_width = 1; ++ fsize->stepwise.min_height = MIN_H; ++ fsize->stepwise.max_height = MAX_H; ++ fsize->stepwise.step_height = 1; ++ ++ return 0; ++} ++ + static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + +@@ -1829,6 +1868,7 @@ static const struct v4l2_ioctl_ops bcm28 + .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, + .vidioc_encoder_cmd = vidioc_encoder_cmd, + .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, ++ .vidioc_enum_framesizes = vidioc_enum_framesizes, + }; + + static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx) diff --git a/target/linux/bcm27xx/patches-5.4/950-0324-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch b/target/linux/bcm27xx/patches-5.4/950-0324-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch deleted file mode 100644 index 6f487bf7c6..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0324-dt-bindings-Add-binding-for-the-Infineon-IRS1125-sen.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 5db0abcd74512cf7013c2ea87d347cd158726be3 Mon Sep 17 00:00:00 2001 -From: Markus Proeller -Date: Thu, 10 Oct 2019 19:12:08 +0200 -Subject: [PATCH] dt-bindings: Add binding for the Infineon IRS1125 - sensor - -Adds a binding for the Infineon IRS1125 time-of-flight depth -sensor. - -Signed-off-by: Markus Proeller ---- - .../devicetree/bindings/media/i2c/irs1125.txt | 48 +++++++++++++++++++ - 1 file changed, 48 insertions(+) - create mode 100644 Documentation/devicetree/bindings/media/i2c/irs1125.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/i2c/irs1125.txt -@@ -0,0 +1,48 @@ -+* Infineon irs1125 time of flight sensor -+ -+The Infineon irs1125 is a time of flight digital image sensor with -+an active array size of 352H x 286V. It is programmable through I2C -+interface. The I2C address defaults to 0x3D, but can be reconfigured -+to address 0x3C or 0x41 via I2C commands. Image data is sent through -+MIPI CSI-2, which is configured as either 1 or 2 data lanes. -+ -+Required Properties: -+- compatible: value should be "infineon,irs1125" for irs1125 sensor -+- reg: I2C bus address of the device -+- clocks: reference to the xclk input clock. -+- pwdn-gpios: reference to the GPIO connected to the reset pin. -+ This is an active low signal to the iirs1125. -+ -+The irs1125 device node should contain one 'port' child node with -+an 'endpoint' subnode. For further reading on port node refer to -+Documentation/devicetree/bindings/media/video-interfaces.txt. -+ -+Endpoint node required properties for CSI-2 connection are: -+- remote-endpoint: a phandle to the bus receiver's endpoint node. -+- clock-lanes: should be set to <0> (clock lane on hardware lane 0) -+- data-lanes: should be set to <1> or <1 2> (one or two lane CSI-2 -+ supported) -+ -+Example: -+ sensor@10 { -+ compatible = "infineon,irs1125"; -+ reg = <0x3D>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&irs1125_clk>; -+ pwdn-gpios = <&gpio 5 0>; -+ -+ irs1125_clk: camera-clk { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <26000000>; -+ }; -+ -+ port { -+ sensor_out: endpoint { -+ remote-endpoint = <&csiss_in>; -+ clock-lanes = <0>; -+ data-lanes = <1 2>; -+ }; -+ }; -+ }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0324-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch b/target/linux/bcm27xx/patches-5.4/950-0324-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch new file mode 100644 index 0000000000..fb60b16e56 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0324-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch @@ -0,0 +1,25 @@ +From 0ff5cd805e7db4003ad5a0d783b4d029b23b7ece Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 13 Sep 2019 17:22:08 +0100 +Subject: [PATCH] staging: bcm2835-codec: Correct buffer type check on + G_PARM + +The output queue buffer type is now OUTPUT_MPLANE. + +Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1438,7 +1438,7 @@ static int vidioc_g_parm(struct file *fi + { + struct bcm2835_codec_ctx *ctx = file2ctx(file); + +- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; diff --git a/target/linux/bcm27xx/patches-5.4/950-0325-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch b/target/linux/bcm27xx/patches-5.4/950-0325-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch deleted file mode 100644 index 71e218d9ec..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0325-media-i2c-Add-a-driver-for-the-Infineon-IRS1125-dept.patch +++ /dev/null @@ -1,1231 +0,0 @@ -From 54e4ff9b3cae743ca90b86a8fef72810d431e143 Mon Sep 17 00:00:00 2001 -From: Markus Proeller -Date: Thu, 10 Oct 2019 19:12:36 +0200 -Subject: [PATCH] media: i2c: Add a driver for the Infineon IRS1125 - depth sensor - -The Infineon IRS1125 is a time of flight depth sensor that -has a CSI-2 interface. - -Add a V4L2 subdevice driver for this device. - -Signed-off-by: Markus Proeller ---- - drivers/media/i2c/Kconfig | 12 + - drivers/media/i2c/Makefile | 1 + - drivers/media/i2c/irs1125.c | 1112 +++++++++++++++++++++++++++++++++++ - drivers/media/i2c/irs1125.h | 61 ++ - 4 files changed, 1186 insertions(+) - create mode 100644 drivers/media/i2c/irs1125.c - create mode 100644 drivers/media/i2c/irs1125.h - ---- a/drivers/media/i2c/Kconfig -+++ b/drivers/media/i2c/Kconfig -@@ -839,6 +839,18 @@ config VIDEO_OV13858 - This is a Video4Linux2 sensor driver for the OmniVision - OV13858 camera. - -+config VIDEO_IRS1125 -+ tristate "Infineon IRS1125 sensor support" -+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API -+ depends on MEDIA_CAMERA_SUPPORT -+ select V4L2_FWNODE -+ help -+ This is a Video4Linux2 sensor-level driver for the Infineon -+ IRS1125 camera. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called irs1125. -+ - config VIDEO_VS6624 - tristate "ST VS6624 sensor support" - depends on VIDEO_V4L2 && I2C ---- a/drivers/media/i2c/Makefile -+++ b/drivers/media/i2c/Makefile -@@ -82,6 +82,7 @@ obj-$(CONFIG_VIDEO_OV8856) += ov8856.o - obj-$(CONFIG_VIDEO_OV9640) += ov9640.o - obj-$(CONFIG_VIDEO_OV9650) += ov9650.o - obj-$(CONFIG_VIDEO_OV13858) += ov13858.o -+obj-$(CONFIG_VIDEO_IRS1125) += irs1125.o - obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o - obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o - obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o ---- /dev/null -+++ b/drivers/media/i2c/irs1125.c -@@ -0,0 +1,1112 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * A V4L2 driver for Infineon IRS1125 TOF cameras. -+ * Copyright (C) 2018, pieye GmbH -+ * -+ * Based on V4L2 OmniVision OV5647 Image Sensor driver -+ * Copyright (C) 2016 Ramiro Oliveira -+ * -+ * DT / fwnode changes, and GPIO control taken from ov5640.c -+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. -+ * Copyright (C) 2014-2017 Mentor Graphics Inc. -+ * -+ */ -+ -+#include "irs1125.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define CHECK_BIT(val, pos) ((val) & BIT(pos)) -+ -+#define SENSOR_NAME "irs1125" -+ -+#define RESET_ACTIVE_DELAY_MS 20 -+ -+#define IRS1125_ALTERNATE_FW "irs1125_af.bin" -+ -+#define IRS1125_REG_CSICFG 0xA882 -+#define IRS1125_REG_DESIGN_STEP 0xB0AD -+#define IRS1125_REG_EFUSEVAL2 0xB09F -+#define IRS1125_REG_EFUSEVAL3 0xB0A0 -+#define IRS1125_REG_EFUSEVAL4 0xB0A1 -+#define IRS1125_REG_DMEM_SHADOW 0xC320 -+ -+#define IRS1125_DESIGN_STEP_EXPECTED 0x0a12 -+ -+#define IRS1125_ROW_START_DEF 0 -+#define IRS1125_COLUMN_START_DEF 0 -+#define IRS1125_WINDOW_HEIGHT_DEF 288 -+#define IRS1125_WINDOW_WIDTH_DEF 352 -+ -+struct regval_list { -+ u16 addr; -+ u16 data; -+}; -+ -+struct irs1125 { -+ struct v4l2_subdev sd; -+ struct media_pad pad; -+ /* the parsed DT endpoint info */ -+ struct v4l2_fwnode_endpoint ep; -+ -+ struct clk *xclk; -+ struct v4l2_ctrl_handler ctrl_handler; -+ -+ /* To serialize asynchronus callbacks */ -+ struct mutex lock; -+ -+ /* image data layout */ -+ unsigned int num_seq; -+ -+ /* reset pin */ -+ struct gpio_desc *reset; -+ -+ /* V4l2 Controls to grab */ -+ struct v4l2_ctrl *ctrl_modplls; -+ struct v4l2_ctrl *ctrl_numseq; -+ -+ int power_count; -+}; -+ -+static inline struct irs1125 *to_state(struct v4l2_subdev *sd) -+{ -+ return container_of(sd, struct irs1125, sd); -+} -+ -+static struct regval_list irs1125_26MHz[] = { -+ {0xB017, 0x0413}, -+ {0xB086, 0x3535}, -+ {0xB0AE, 0xEF02}, -+ {0xA000, 0x0004}, -+ {0xFFFF, 100}, -+ -+ {0xB062, 0x6383}, -+ {0xB063, 0x55A8}, -+ {0xB068, 0x7628}, -+ {0xB069, 0x03E2}, -+ -+ {0xFFFF, 100}, -+ {0xB05A, 0x01C5}, -+ {0xB05C, 0x0206}, -+ {0xB05D, 0x01C5}, -+ {0xB05F, 0x0206}, -+ {0xB016, 0x1335}, -+ {0xFFFF, 100}, -+ {0xA893, 0x8261}, -+ {0xA894, 0x89d8}, -+ {0xA895, 0x131d}, -+ {0xA896, 0x4251}, -+ {0xA897, 0x9D8A}, -+ {0xA898, 0x0BD8}, -+ {0xA899, 0x2245}, -+ {0xA89A, 0xAB9B}, -+ {0xA89B, 0x03B9}, -+ {0xA89C, 0x8041}, -+ {0xA89D, 0xE07E}, -+ {0xA89E, 0x0307}, -+ {0xFFFF, 100}, -+ {0xA88D, 0x0004}, -+ {0xA800, 0x0E68}, -+ {0xA801, 0x0000}, -+ {0xA802, 0x000C}, -+ {0xA803, 0x0000}, -+ {0xA804, 0x0E68}, -+ {0xA805, 0x0000}, -+ {0xA806, 0x0440}, -+ {0xA807, 0x0000}, -+ {0xA808, 0x0E68}, -+ {0xA809, 0x0000}, -+ {0xA80A, 0x0884}, -+ {0xA80B, 0x0000}, -+ {0xA80C, 0x0E68}, -+ {0xA80D, 0x0000}, -+ {0xA80E, 0x0CC8}, -+ {0xA80F, 0x0000}, -+ {0xA810, 0x0E68}, -+ {0xA811, 0x0000}, -+ {0xA812, 0x2000}, -+ {0xA813, 0x0000}, -+ {0xA882, 0x0081}, -+ {0xA88C, 0x403A}, -+ {0xA88F, 0x031E}, -+ {0xA892, 0x0351}, -+ {0x9813, 0x13FF}, -+ {0x981B, 0x7608}, -+ -+ {0xB008, 0x0000}, -+ {0xB015, 0x1513}, -+ -+ {0xFFFF, 100} -+}; -+ -+static struct regval_list irs1125_seq_cfg[] = { -+ {0xC3A0, 0x823D}, -+ {0xC3A1, 0xB13B}, -+ {0xC3A2, 0x0313}, -+ {0xC3A3, 0x4659}, -+ {0xC3A4, 0xC4EC}, -+ {0xC3A5, 0x03CE}, -+ {0xC3A6, 0x4259}, -+ {0xC3A7, 0xC4EC}, -+ {0xC3A8, 0x03CE}, -+ {0xC3A9, 0x8839}, -+ {0xC3AA, 0x89D8}, -+ {0xC3AB, 0x031D}, -+ -+ {0xC24C, 0x5529}, -+ {0xC24D, 0x0000}, -+ {0xC24E, 0x1200}, -+ {0xC24F, 0x6CB2}, -+ {0xC250, 0x0000}, -+ {0xC251, 0x5529}, -+ {0xC252, 0x42F4}, -+ {0xC253, 0xD1AF}, -+ {0xC254, 0x8A18}, -+ {0xC255, 0x0002}, -+ {0xC256, 0x5529}, -+ {0xC257, 0x6276}, -+ {0xC258, 0x11A7}, -+ {0xC259, 0xD907}, -+ {0xC25A, 0x0000}, -+ {0xC25B, 0x5529}, -+ {0xC25C, 0x07E0}, -+ {0xC25D, 0x7BFE}, -+ {0xC25E, 0x6402}, -+ {0xC25F, 0x0019}, -+ -+ {0xC3AC, 0x0007}, -+ {0xC3AD, 0xED88}, -+ {0xC320, 0x003E}, -+ {0xC321, 0x0000}, -+ {0xC322, 0x2000}, -+ {0xC323, 0x0000}, -+ {0xC324, 0x0271}, -+ {0xC325, 0x0000}, -+ {0xC326, 0x000C}, -+ {0xC327, 0x0000}, -+ {0xC328, 0x0271}, -+ {0xC329, 0x0000}, -+ {0xC32A, 0x0440}, -+ {0xC32B, 0x0000}, -+ {0xC32C, 0x0271}, -+ {0xC32D, 0x0000}, -+ {0xC32E, 0x0884}, -+ {0xC32F, 0x0000}, -+ {0xC330, 0x0271}, -+ {0xC331, 0x0000}, -+ {0xC332, 0x0CC8}, -+ {0xC333, 0x0000}, -+ {0xA88D, 0x0004}, -+ -+ {0xA890, 0x0000}, -+ {0xC219, 0x0002}, -+ {0xC21A, 0x0000}, -+ {0xC21B, 0x0000}, -+ {0xC21C, 0x00CD}, -+ {0xC21D, 0x0009}, -+ {0xC21E, 0x00CD}, -+ {0xC21F, 0x0009}, -+ -+ {0xA87C, 0x0000}, -+ {0xC032, 0x0001}, -+ {0xC034, 0x0000}, -+ {0xC035, 0x0001}, -+ {0xC039, 0x0000}, -+ {0xC401, 0x0002}, -+ -+ {0xFFFF, 1}, -+ {0xA87C, 0x0001} -+}; -+ -+static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val) -+{ -+ int ret; -+ unsigned char data[4] = { reg >> 8, reg & 0xff, val >> 8, val & 0xff}; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ ret = i2c_master_send(client, data, 4); -+ if (ret < 0) -+ dev_err(&client->dev, "%s: i2c write error, reg: %x\n", -+ __func__, reg); -+ -+ return ret; -+} -+ -+static int irs1125_read(struct v4l2_subdev *sd, u16 reg, u16 *val) -+{ -+ int ret; -+ unsigned char data_w[2] = { reg >> 8, reg & 0xff }; -+ char rdval[2]; -+ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ ret = i2c_master_send(client, data_w, 2); -+ if (ret < 0) { -+ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", -+ __func__, reg); -+ return ret; -+ } -+ -+ ret = i2c_master_recv(client, rdval, 2); -+ if (ret < 0) -+ dev_err(&client->dev, "%s: i2c read error, reg: %x\n", -+ __func__, reg); -+ -+ *val = rdval[1] | (rdval[0] << 8); -+ -+ return ret; -+} -+ -+static int irs1125_write_array(struct v4l2_subdev *sd, -+ struct regval_list *regs, int array_size) -+{ -+ int i, ret; -+ -+ for (i = 0; i < array_size; i++) { -+ if (regs[i].addr == 0xFFFF) { -+ msleep(regs[i].data); -+ } else { -+ ret = irs1125_write(sd, regs[i].addr, regs[i].data); -+ if (ret < 0) -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int irs1125_stream_on(struct v4l2_subdev *sd) -+{ -+ int ret; -+ struct irs1125 *irs1125 = to_state(sd); -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ v4l2_ctrl_grab(irs1125->ctrl_numseq, 1); -+ v4l2_ctrl_grab(irs1125->ctrl_modplls, 1); -+ -+ ret = irs1125_write(sd, 0xC400, 0x0001); -+ if (ret < 0) { -+ dev_err(&client->dev, "error enabling firmware: %d", ret); -+ return ret; -+ } -+ -+ msleep(100); -+ -+ return irs1125_write(sd, 0xA87C, 0x0001); -+} -+ -+static int irs1125_stream_off(struct v4l2_subdev *sd) -+{ -+ int ret; -+ struct irs1125 *irs1125 = to_state(sd); -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ v4l2_ctrl_grab(irs1125->ctrl_numseq, 0); -+ v4l2_ctrl_grab(irs1125->ctrl_modplls, 0); -+ -+ ret = irs1125_write(sd, 0xA87C, 0x0000); -+ if (ret < 0) { -+ dev_err(&client->dev, "error disabling trigger: %d", ret); -+ return ret; -+ } -+ -+ msleep(100); -+ -+ return irs1125_write(sd, 0xC400, 0x0002); -+} -+ -+static int __sensor_init(struct v4l2_subdev *sd) -+{ -+ unsigned int cnt, idx; -+ int ret; -+ u16 val; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct irs1125 *irs1125 = to_state(sd); -+ const struct firmware *fw; -+ struct regval_list *reg_data; -+ -+ cnt = 0; -+ while (1) { -+ ret = irs1125_read(sd, 0xC40F, &val); -+ if (ret < 0) { -+ dev_err(&client->dev, "read register 0xC40F failed\n"); -+ return ret; -+ } -+ if (CHECK_BIT(val, 14) == 0) -+ break; -+ -+ if (cnt >= 5) { -+ dev_err(&client->dev, "timeout waiting for 0xC40F\n"); -+ return -EAGAIN; -+ } -+ -+ cnt++; -+ } -+ -+ ret = irs1125_write_array(sd, irs1125_26MHz, -+ ARRAY_SIZE(irs1125_26MHz)); -+ if (ret < 0) { -+ dev_err(&client->dev, "write sensor default regs error\n"); -+ return ret; -+ } -+ -+ /* set CSI-2 number of data lanes */ -+ if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 1) { -+ val = 0x0001; -+ } else if (irs1125->ep.bus.mipi_csi2.num_data_lanes == 2) { -+ val = 0x0081; -+ } else { -+ dev_err(&client->dev, "invalid number of data lanes %d\n", -+ irs1125->ep.bus.mipi_csi2.num_data_lanes); -+ return -EINVAL; -+ } -+ -+ ret = irs1125_write(sd, IRS1125_REG_CSICFG, val); -+ if (ret < 0) { -+ dev_err(&client->dev, "write sensor csi2 config error\n"); -+ return ret; -+ } -+ -+ /* request the firmware, this will block and timeout */ -+ ret = request_firmware(&fw, IRS1125_ALTERNATE_FW, &client->dev); -+ if (ret) { -+ dev_err(&client->dev, -+ "did not find the firmware file '%s' (status %d)\n", -+ IRS1125_ALTERNATE_FW, ret); -+ return ret; -+ } -+ -+ if (fw->size % 4) { -+ dev_err(&client->dev, "firmware file '%s' invalid\n", -+ IRS1125_ALTERNATE_FW); -+ release_firmware(fw); -+ return -EINVAL; -+ } -+ -+ for (idx = 0; idx < fw->size; idx += 4) { -+ reg_data = (struct regval_list *)&fw->data[idx]; -+ ret = irs1125_write(sd, reg_data->addr, reg_data->data); -+ if (ret < 0) { -+ dev_err(&client->dev, "firmware write error\n"); -+ release_firmware(fw); -+ return ret; -+ } -+ } -+ release_firmware(fw); -+ -+ ret = irs1125_write_array(sd, irs1125_seq_cfg, -+ ARRAY_SIZE(irs1125_seq_cfg)); -+ if (ret < 0) { -+ dev_err(&client->dev, "write default sequence failed\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int irs1125_sensor_power(struct v4l2_subdev *sd, int on) -+{ -+ int ret = 0; -+ struct irs1125 *irs1125 = to_state(sd); -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ mutex_lock(&irs1125->lock); -+ -+ if (on && !irs1125->power_count) { -+ gpiod_set_value_cansleep(irs1125->reset, 1); -+ msleep(RESET_ACTIVE_DELAY_MS); -+ -+ ret = clk_prepare_enable(irs1125->xclk); -+ if (ret < 0) { -+ dev_err(&client->dev, "clk prepare enable failed\n"); -+ goto out; -+ } -+ -+ ret = __sensor_init(sd); -+ if (ret < 0) { -+ clk_disable_unprepare(irs1125->xclk); -+ dev_err(&client->dev, -+ "Camera not available, check Power\n"); -+ goto out; -+ } -+ } else if (!on && irs1125->power_count == 1) { -+ gpiod_set_value_cansleep(irs1125->reset, 0); -+ } -+ -+ /* Update the power count. */ -+ irs1125->power_count += on ? 1 : -1; -+ WARN_ON(irs1125->power_count < 0); -+ -+out: -+ mutex_unlock(&irs1125->lock); -+ -+ return ret; -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int irs1125_sensor_get_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ u16 val; -+ int ret; -+ -+ ret = irs1125_read(sd, reg->reg & 0xffff, &val); -+ if (ret < 0) -+ return ret; -+ -+ reg->val = val; -+ reg->size = 1; -+ -+ return 0; -+} -+ -+static int irs1125_sensor_set_register(struct v4l2_subdev *sd, -+ const struct v4l2_dbg_register *reg) -+{ -+ return irs1125_write(sd, reg->reg & 0xffff, reg->val & 0xffff); -+} -+#endif -+ -+static const struct v4l2_subdev_core_ops irs1125_subdev_core_ops = { -+ .s_power = irs1125_sensor_power, -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = irs1125_sensor_get_register, -+ .s_register = irs1125_sensor_set_register, -+#endif -+}; -+ -+static int irs1125_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ if (enable) -+ return irs1125_stream_on(sd); -+ else -+ return irs1125_stream_off(sd); -+} -+ -+static const struct v4l2_subdev_video_ops irs1125_subdev_video_ops = { -+ .s_stream = irs1125_s_stream, -+}; -+ -+static int irs1125_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_mbus_code_enum *code) -+{ -+ if (code->index > 0) -+ return -EINVAL; -+ -+ code->code = MEDIA_BUS_FMT_Y12_1X12; -+ -+ return 0; -+} -+ -+static int irs1125_set_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct v4l2_mbus_framefmt *fmt = &format->format; -+ struct irs1125 *irs1125 = to_state(sd); -+ -+ if (format->pad != 0) -+ return -EINVAL; -+ -+ /* Only one format is supported, so return that */ -+ memset(fmt, 0, sizeof(*fmt)); -+ fmt->code = MEDIA_BUS_FMT_Y12_1X12; -+ fmt->colorspace = V4L2_COLORSPACE_RAW; -+ fmt->field = V4L2_FIELD_NONE; -+ fmt->width = IRS1125_WINDOW_WIDTH_DEF; -+ fmt->height = IRS1125_WINDOW_HEIGHT_DEF * irs1125->num_seq; -+ -+ return 0; -+} -+ -+static const struct v4l2_subdev_pad_ops irs1125_subdev_pad_ops = { -+ .enum_mbus_code = irs1125_enum_mbus_code, -+ .set_fmt = irs1125_set_get_fmt, -+ .get_fmt = irs1125_set_get_fmt, -+}; -+ -+static const struct v4l2_subdev_ops irs1125_subdev_ops = { -+ .core = &irs1125_subdev_core_ops, -+ .video = &irs1125_subdev_video_ops, -+ .pad = &irs1125_subdev_pad_ops, -+}; -+ -+static int irs1125_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct irs1125 *dev = container_of(ctrl->handler, -+ struct irs1125, ctrl_handler); -+ struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); -+ int err, i; -+ struct irs1125_mod_pll *mod_cur, *mod_new; -+ struct irs1125_seq_cfg *cfg_cur, *cfg_new; -+ u16 addr, val; -+ -+ err = 0; -+ -+ switch (ctrl->id) { -+ case IRS1125_CID_SAFE_RECONFIG: -+ { -+ struct irs1125_illu *illu_cur, *illu_new; -+ -+ illu_new = (struct irs1125_illu *)ctrl->p_new.p; -+ illu_cur = (struct irs1125_illu *)ctrl->p_cur.p; -+ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) { -+ if (illu_cur[i].exposure != illu_new[i].exposure) { -+ addr = 0xA850 + i * 2; -+ val = illu_new[i].exposure; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (illu_cur[i].framerate != illu_new[i].framerate) { -+ addr = 0xA851 + i * 2; -+ val = illu_new[i].framerate; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ } -+ break; -+ } -+ case IRS1125_CID_MOD_PLL: -+ mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p; -+ mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p; -+ for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) { -+ if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) { -+ addr = 0xC3A0 + i * 3; -+ val = mod_new[i].pllcfg1; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) { -+ addr = 0xC3A1 + i * 3; -+ val = mod_new[i].pllcfg2; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) { -+ addr = 0xC3A2 + i * 3; -+ val = mod_new[i].pllcfg3; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) { -+ addr = 0xC24C + i * 5; -+ val = mod_new[i].pllcfg4; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) { -+ addr = 0xC24D + i * 5; -+ val = mod_new[i].pllcfg5; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) { -+ addr = 0xC24E + i * 5; -+ val = mod_new[i].pllcfg6; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) { -+ addr = 0xC24F + i * 5; -+ val = mod_new[i].pllcfg7; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) { -+ addr = 0xC250 + i * 5; -+ val = mod_new[i].pllcfg8; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ } -+ break; -+ case IRS1125_CID_SEQ_CONFIG: -+ cfg_new = (struct irs1125_seq_cfg *)ctrl->p_new.p; -+ cfg_cur = (struct irs1125_seq_cfg *)ctrl->p_cur.p; -+ for (i = 0; i < IRS1125_NUM_SEQ_ENTRIES; i++) { -+ if (cfg_cur[i].exposure != cfg_new[i].exposure) { -+ addr = IRS1125_REG_DMEM_SHADOW + i * 4; -+ val = cfg_new[i].exposure; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (cfg_cur[i].framerate != cfg_new[i].framerate) { -+ addr = IRS1125_REG_DMEM_SHADOW + 1 + i * 4; -+ val = cfg_new[i].framerate; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (cfg_cur[i].ps != cfg_new[i].ps) { -+ addr = IRS1125_REG_DMEM_SHADOW + 2 + i * 4; -+ val = cfg_new[i].ps; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ if (cfg_cur[i].pll != cfg_new[i].pll) { -+ addr = IRS1125_REG_DMEM_SHADOW + 3 + i * 4; -+ val = cfg_new[i].pll; -+ err = irs1125_write(&dev->sd, addr, val); -+ if (err < 0) -+ break; -+ } -+ } -+ break; -+ case IRS1125_CID_NUM_SEQS: -+ err = irs1125_write(&dev->sd, 0xA88D, ctrl->val - 1); -+ if (err >= 0) -+ dev->num_seq = ctrl->val; -+ break; -+ case IRS1125_CID_CONTINUOUS_TRIG: -+ if (ctrl->val == 0) -+ err = irs1125_write(&dev->sd, 0xA87C, 0); -+ else -+ err = irs1125_write(&dev->sd, 0xA87C, 1); -+ break; -+ case IRS1125_CID_TRIGGER: -+ if (ctrl->val != 0) { -+ err = irs1125_write(&dev->sd, 0xA87C, 1); -+ if (err >= 0) -+ err = irs1125_write(&dev->sd, 0xA87C, 0); -+ } -+ break; -+ case IRS1125_CID_RECONFIG: -+ if (ctrl->val != 0) -+ err = irs1125_write(&dev->sd, 0xA87A, 1); -+ break; -+ case IRS1125_CID_ILLU_ON: -+ if (ctrl->val == 0) -+ err = irs1125_write(&dev->sd, 0xA892, 0x377); -+ else -+ err = irs1125_write(&dev->sd, 0xA892, 0x355); -+ break; -+ default: -+ break; -+ } -+ -+ if (err < 0) -+ dev_err(&client->dev, "Error executing control ID: %d, val %d, err %d", -+ ctrl->id, ctrl->val, err); -+ else -+ err = 0; -+ -+ return err; -+} -+ -+static const struct v4l2_ctrl_ops irs1125_ctrl_ops = { -+ .s_ctrl = irs1125_s_ctrl, -+}; -+ -+static const struct v4l2_ctrl_config irs1125_custom_ctrls[] = { -+ { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_NUM_SEQS, -+ .name = "Change number of sequences", -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT, -+ .min = 1, -+ .max = 20, -+ .step = 1, -+ .def = 5, -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_MOD_PLL, -+ .name = "Reconfigure modulation PLLs", -+ .type = V4L2_CTRL_TYPE_U16, -+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD, -+ .min = 0, -+ .max = U16_MAX, -+ .step = 1, -+ .def = 0, -+ .elem_size = sizeof(u16), -+ .dims = {sizeof(struct irs1125_mod_pll) / sizeof(u16), -+ IRS1125_NUM_MOD_PLLS} -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_SAFE_RECONFIG, -+ .name = "Change exposure and pause of single seq", -+ .type = V4L2_CTRL_TYPE_U16, -+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD, -+ .min = 0, -+ .max = U16_MAX, -+ .step = 1, -+ .def = 0, -+ .elem_size = sizeof(u16), -+ .dims = {sizeof(struct irs1125_illu) / sizeof(u16), -+ IRS1125_NUM_SEQ_ENTRIES} -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_SEQ_CONFIG, -+ .name = "Change sequence settings", -+ .type = V4L2_CTRL_TYPE_U16, -+ .flags = V4L2_CTRL_FLAG_HAS_PAYLOAD, -+ .min = 0, -+ .max = U16_MAX, -+ .step = 1, -+ .def = 0, -+ .elem_size = sizeof(u16), -+ .dims = {sizeof(struct irs1125_seq_cfg) / sizeof(u16), -+ IRS1125_NUM_SEQ_ENTRIES} -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_CONTINUOUS_TRIG, -+ .name = "Enable/disable continuous trigger", -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def = 0 -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_TRIGGER, -+ .name = "Capture a single sequence", -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def = 0 -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_RECONFIG, -+ .name = "Trigger imager reconfiguration", -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def = 0 -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_ILLU_ON, -+ .name = "Turn illu on or off", -+ .type = V4L2_CTRL_TYPE_BOOLEAN, -+ .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, -+ .min = 0, -+ .max = 1, -+ .step = 1, -+ .def = 1 -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_IDENT0, -+ .name = "Get ident 0 information", -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .flags = V4L2_CTRL_FLAG_READ_ONLY, -+ .min = S32_MIN, -+ .max = S32_MAX, -+ .step = 1, -+ .def = 0 -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_IDENT1, -+ .name = "Get ident 1 information", -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .flags = V4L2_CTRL_FLAG_READ_ONLY, -+ .min = S32_MIN, -+ .max = S32_MAX, -+ .step = 1, -+ .def = 0 -+ }, { -+ .ops = &irs1125_ctrl_ops, -+ .id = IRS1125_CID_IDENT2, -+ .name = "Get ident 2 information", -+ .type = V4L2_CTRL_TYPE_INTEGER, -+ .flags = V4L2_CTRL_FLAG_READ_ONLY, -+ .min = S32_MIN, -+ .max = S32_MAX, -+ .step = 1, -+ .def = 0 -+ } -+}; -+ -+static int irs1125_detect(struct v4l2_subdev *sd) -+{ -+ u16 read; -+ int ret; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ -+ ret = irs1125_read(sd, IRS1125_REG_DESIGN_STEP, &read); -+ if (ret < 0) { -+ dev_err(&client->dev, "error reading from i2c\n"); -+ return ret; -+ } -+ -+ if (read != IRS1125_DESIGN_STEP_EXPECTED) { -+ dev_err(&client->dev, "Design step expected 0x%x got 0x%x", -+ IRS1125_DESIGN_STEP_EXPECTED, read); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static int irs1125_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -+{ -+ struct v4l2_mbus_framefmt *format = -+ v4l2_subdev_get_try_format(sd, fh->pad, 0); -+ -+ format->code = MEDIA_BUS_FMT_Y12_1X12; -+ format->width = IRS1125_WINDOW_WIDTH_DEF; -+ format->height = IRS1125_WINDOW_HEIGHT_DEF; -+ format->field = V4L2_FIELD_NONE; -+ format->colorspace = V4L2_COLORSPACE_RAW; -+ -+ return 0; -+} -+ -+static const struct v4l2_subdev_internal_ops irs1125_subdev_internal_ops = { -+ .open = irs1125_open, -+}; -+ -+static int irs1125_ctrls_init(struct irs1125 *sensor, struct device *dev) -+{ -+ struct v4l2_ctrl *ctrl; -+ int err, i; -+ struct v4l2_ctrl_handler *hdl; -+ -+ hdl = &sensor->ctrl_handler; -+ v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(irs1125_custom_ctrls)); -+ -+ for (i = 0; i < ARRAY_SIZE(irs1125_custom_ctrls); i++) { -+ ctrl = v4l2_ctrl_new_custom(hdl, &irs1125_custom_ctrls[i], -+ NULL); -+ if (!ctrl) -+ dev_err(dev, "Failed to init custom control %s\n", -+ irs1125_custom_ctrls[i].name); -+ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_NUM_SEQS) -+ sensor->ctrl_numseq = ctrl; -+ else if (irs1125_custom_ctrls[i].id == IRS1125_CID_MOD_PLL) -+ sensor->ctrl_modplls = ctrl; -+ } -+ -+ if (hdl->error) { -+ dev_err(dev, "Error %d adding controls\n", hdl->error); -+ err = hdl->error; -+ goto error_ctrls; -+ } -+ -+ sensor->sd.ctrl_handler = hdl; -+ return 0; -+ -+error_ctrls: -+ v4l2_ctrl_handler_free(&sensor->ctrl_handler); -+ return -err; -+} -+ -+static int irs1125_ident_setup(struct irs1125 *sensor, struct device *dev) -+{ -+ int ret; -+ struct v4l2_ctrl *ctrl; -+ struct v4l2_subdev *sd; -+ u16 read; -+ -+ sd = &sensor->sd; -+ -+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT0); -+ if (!ctrl) { -+ dev_err(dev, "could not find device ctrl.\n"); -+ return -EINVAL; -+ } -+ -+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL2, &read); -+ if (ret < 0) { -+ dev_err(dev, "error reading from i2c\n"); -+ return -EIO; -+ } -+ -+ v4l2_ctrl_s_ctrl(ctrl, read); -+ -+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT1); -+ if (!ctrl) { -+ dev_err(dev, "could not find device ctrl.\n"); -+ return -EINVAL; -+ } -+ -+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL3, &read); -+ if (ret < 0) { -+ dev_err(dev, "error reading from i2c\n"); -+ return -EIO; -+ } -+ -+ v4l2_ctrl_s_ctrl(ctrl, read); -+ -+ ctrl = v4l2_ctrl_find(&sensor->ctrl_handler, IRS1125_CID_IDENT2); -+ if (!ctrl) { -+ dev_err(dev, "could not find device ctrl.\n"); -+ return -EINVAL; -+ } -+ -+ ret = irs1125_read(sd, IRS1125_REG_EFUSEVAL4, &read); -+ if (ret < 0) { -+ dev_err(dev, "error reading from i2c\n"); -+ return -EIO; -+ } -+ v4l2_ctrl_s_ctrl(ctrl, read & 0xFFFC); -+ -+ return 0; -+} -+ -+static int irs1125_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct device *dev = &client->dev; -+ struct irs1125 *sensor; -+ int ret; -+ struct fwnode_handle *endpoint; -+ u32 xclk_freq; -+ int gpio_num; -+ -+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); -+ if (!sensor) -+ return -ENOMEM; -+ -+ v4l2_i2c_subdev_init(&sensor->sd, client, &irs1125_subdev_ops); -+ -+ /* Get CSI2 bus config */ -+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(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; -+ } -+ -+ /* get system clock (xclk) */ -+ sensor->xclk = devm_clk_get(dev, NULL); -+ if (IS_ERR(sensor->xclk)) { -+ dev_err(dev, "could not get xclk"); -+ return PTR_ERR(sensor->xclk); -+ } -+ -+ xclk_freq = clk_get_rate(sensor->xclk); -+ if (xclk_freq != 26000000) { -+ dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq); -+ return -EINVAL; -+ } -+ -+ sensor->num_seq = 5; -+ -+ /* Request the power down GPIO */ -+ sensor->reset = devm_gpiod_get(&client->dev, "pwdn", -+ GPIOD_OUT_LOW); -+ -+ if (IS_ERR(sensor->reset)) { -+ dev_err(dev, "could not get reset"); -+ return PTR_ERR(sensor->reset); -+ } -+ -+ gpio_num = desc_to_gpio(sensor->reset); -+ -+ mutex_init(&sensor->lock); -+ -+ ret = irs1125_ctrls_init(sensor, dev); -+ if (ret < 0) -+ goto mutex_remove; -+ -+ sensor->sd.internal_ops = &irs1125_subdev_internal_ops; -+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; -+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE; -+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); -+ if (ret < 0) -+ goto mutex_remove; -+ -+ gpiod_set_value_cansleep(sensor->reset, 1); -+ msleep(RESET_ACTIVE_DELAY_MS); -+ -+ ret = irs1125_detect(&sensor->sd); -+ if (ret < 0) -+ goto error; -+ -+ ret = irs1125_ident_setup(sensor, dev); -+ if (ret < 0) -+ goto error; -+ -+ gpiod_set_value_cansleep(sensor->reset, 0); -+ -+ ret = v4l2_async_register_subdev(&sensor->sd); -+ if (ret < 0) -+ goto error; -+ -+ dev_dbg(dev, "Infineon IRS1125 camera driver probed\n"); -+ -+ return 0; -+ -+error: -+ media_entity_cleanup(&sensor->sd.entity); -+mutex_remove: -+ mutex_destroy(&sensor->lock); -+ return ret; -+} -+ -+static int irs1125_remove(struct i2c_client *client) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(client); -+ struct irs1125 *irs1125 = to_state(sd); -+ -+ v4l2_async_unregister_subdev(&irs1125->sd); -+ media_entity_cleanup(&irs1125->sd.entity); -+ v4l2_device_unregister_subdev(sd); -+ mutex_destroy(&irs1125->lock); -+ v4l2_ctrl_handler_free(&irs1125->ctrl_handler); -+ -+ return 0; -+} -+ -+#if IS_ENABLED(CONFIG_OF) -+static const struct of_device_id irs1125_of_match[] = { -+ { .compatible = "infineon,irs1125" }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, irs1125_of_match); -+#endif -+ -+static struct i2c_driver irs1125_driver = { -+ .driver = { -+ .of_match_table = of_match_ptr(irs1125_of_match), -+ .name = SENSOR_NAME, -+ }, -+ .probe = irs1125_probe, -+ .remove = irs1125_remove, -+}; -+ -+module_i2c_driver(irs1125_driver); -+ -+MODULE_AUTHOR("Markus Proeller "); -+MODULE_DESCRIPTION("Infineon irs1125 sensor driver"); -+MODULE_LICENSE("GPL v2"); -+ ---- /dev/null -+++ b/drivers/media/i2c/irs1125.h -@@ -0,0 +1,61 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * A V4L2 driver for Infineon IRS1125 TOF cameras. -+ * Copyright (C) 2018, pieye GmbH -+ * -+ * Based on V4L2 OmniVision OV5647 Image Sensor driver -+ * Copyright (C) 2016 Ramiro Oliveira -+ * -+ * DT / fwnode changes, and GPIO control taken from ov5640.c -+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. -+ * Copyright (C) 2014-2017 Mentor Graphics Inc. -+ * -+ */ -+ -+#ifndef IRS1125_H -+#define IRS1125_H -+ -+#include -+#include -+ -+#define IRS1125_NUM_SEQ_ENTRIES 20 -+#define IRS1125_NUM_MOD_PLLS 4 -+ -+#define IRS1125_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) -+#define IRS1125_CID_SAFE_RECONFIG (IRS1125_CID_CUSTOM_BASE + 0) -+#define IRS1125_CID_CONTINUOUS_TRIG (IRS1125_CID_CUSTOM_BASE + 1) -+#define IRS1125_CID_TRIGGER (IRS1125_CID_CUSTOM_BASE + 2) -+#define IRS1125_CID_RECONFIG (IRS1125_CID_CUSTOM_BASE + 3) -+#define IRS1125_CID_ILLU_ON (IRS1125_CID_CUSTOM_BASE + 4) -+#define IRS1125_CID_NUM_SEQS (IRS1125_CID_CUSTOM_BASE + 5) -+#define IRS1125_CID_MOD_PLL (IRS1125_CID_CUSTOM_BASE + 6) -+#define IRS1125_CID_SEQ_CONFIG (IRS1125_CID_CUSTOM_BASE + 7) -+#define IRS1125_CID_IDENT0 (IRS1125_CID_CUSTOM_BASE + 8) -+#define IRS1125_CID_IDENT1 (IRS1125_CID_CUSTOM_BASE + 9) -+#define IRS1125_CID_IDENT2 (IRS1125_CID_CUSTOM_BASE + 10) -+ -+struct irs1125_seq_cfg { -+ __u16 exposure; -+ __u16 framerate; -+ __u16 ps; -+ __u16 pll; -+}; -+ -+struct irs1125_illu { -+ __u16 exposure; -+ __u16 framerate; -+}; -+ -+struct irs1125_mod_pll { -+ __u16 pllcfg1; -+ __u16 pllcfg2; -+ __u16 pllcfg3; -+ __u16 pllcfg4; -+ __u16 pllcfg5; -+ __u16 pllcfg6; -+ __u16 pllcfg7; -+ __u16 pllcfg8; -+}; -+ -+#endif /* IRS1125 */ -+ diff --git a/target/linux/bcm27xx/patches-5.4/950-0325-staging-bcm2835-codec-Set-default-and-error-check-ti.patch b/target/linux/bcm27xx/patches-5.4/950-0325-staging-bcm2835-codec-Set-default-and-error-check-ti.patch new file mode 100644 index 0000000000..124b7ae742 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0325-staging-bcm2835-codec-Set-default-and-error-check-ti.patch @@ -0,0 +1,37 @@ +From 6680d139ee23cf655c0aa43581604a7c5de31803 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Fri, 13 Sep 2019 17:23:26 +0100 +Subject: [PATCH] staging: bcm2835-codec: Set default and error check + timeperframe + +G_PARM default was invalid as 0/0, and the driver didn't check +the value set in S_PARM wasn't 0/0. + +Signed-off-by: Dave Stevenson +--- + .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -1423,6 +1423,10 @@ static int vidioc_s_parm(struct file *fi + if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + ++ if (!parm->parm.output.timeperframe.denominator || ++ !parm->parm.output.timeperframe.numerator) ++ return -EINVAL; ++ + ctx->framerate_num = + parm->parm.output.timeperframe.denominator; + ctx->framerate_denom = +@@ -2390,6 +2394,9 @@ static int bcm2835_codec_open(struct fil + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->bitrate = 10 * 1000 * 1000; + ++ ctx->framerate_num = 30; ++ ctx->framerate_denom = 1; ++ + /* Initialise V4L2 contexts */ + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; diff --git a/target/linux/bcm27xx/patches-5.4/950-0326-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch b/target/linux/bcm27xx/patches-5.4/950-0326-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch deleted file mode 100644 index ab3a971608..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0326-staging-bcm2835-codec-Add-support-for-ENUM_FRAMESIZE.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 3d9d9ae68a1fb5451d12b46b65289e67cca2a340 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 13 Sep 2019 17:19:33 +0100 -Subject: [PATCH] staging:bcm2835-codec: Add support for - ENUM_FRAMESIZES - -Required for compliance testing for the encoder. - -Signed-off-by: Dave Stevenson ---- - .../bcm2835-codec/bcm2835-v4l2-codec.c | 48 +++++++++++++++++-- - 1 file changed, 44 insertions(+), 4 deletions(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -496,9 +496,10 @@ struct bcm2835_codec_fmt *get_default_fo - return &dev->supported_fmts[capture ? 1 : 0].list[0]; - } - --static struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, -- struct bcm2835_codec_dev *dev, -- bool capture) -+static -+struct bcm2835_codec_fmt *find_format_pix_fmt(u32 pix_fmt, -+ struct bcm2835_codec_dev *dev, -+ bool capture) - { - struct bcm2835_codec_fmt *fmt; - unsigned int k; -@@ -507,7 +508,7 @@ static struct bcm2835_codec_fmt *find_fo - - for (k = 0; k < fmts->num_entries; k++) { - fmt = &fmts->list[k]; -- if (fmt->fourcc == f->fmt.pix_mp.pixelformat) -+ if (fmt->fourcc == pix_fmt) - break; - } - if (k == fmts->num_entries) -@@ -516,6 +517,14 @@ static struct bcm2835_codec_fmt *find_fo - return &fmts->list[k]; - } - -+static inline -+struct bcm2835_codec_fmt *find_format(struct v4l2_format *f, -+ struct bcm2835_codec_dev *dev, -+ bool capture) -+{ -+ return find_format_pix_fmt(f->fmt.pix_mp.pixelformat, dev, capture); -+} -+ - static inline struct bcm2835_codec_ctx *file2ctx(struct file *file) - { - return container_of(file->private_data, struct bcm2835_codec_ctx, fh); -@@ -1792,6 +1801,36 @@ static int vidioc_encoder_cmd(struct fil - return 0; - } - -+static int vidioc_enum_framesizes(struct file *file, void *fh, -+ struct v4l2_frmsizeenum *fsize) -+{ -+ struct bcm2835_codec_fmt *fmt; -+ -+ fmt = find_format_pix_fmt(fsize->pixel_format, file2ctx(file)->dev, -+ true); -+ if (!fmt) -+ fmt = find_format_pix_fmt(fsize->pixel_format, -+ file2ctx(file)->dev, -+ false); -+ -+ if (!fmt) -+ return -EINVAL; -+ -+ if (fsize->index) -+ return -EINVAL; -+ -+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; -+ -+ fsize->stepwise.min_width = MIN_W; -+ fsize->stepwise.max_width = MAX_W; -+ fsize->stepwise.step_width = 1; -+ fsize->stepwise.min_height = MIN_H; -+ fsize->stepwise.max_height = MAX_H; -+ fsize->stepwise.step_height = 1; -+ -+ return 0; -+} -+ - static const struct v4l2_ioctl_ops bcm2835_codec_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - -@@ -1829,6 +1868,7 @@ static const struct v4l2_ioctl_ops bcm28 - .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, - .vidioc_encoder_cmd = vidioc_encoder_cmd, - .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, -+ .vidioc_enum_framesizes = vidioc_enum_framesizes, - }; - - static int bcm2835_codec_set_ctrls(struct bcm2835_codec_ctx *ctx) diff --git a/target/linux/bcm27xx/patches-5.4/950-0326-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch b/target/linux/bcm27xx/patches-5.4/950-0326-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch new file mode 100644 index 0000000000..f0fdfd29c8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0326-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch @@ -0,0 +1,30 @@ +From 0c941589b9bfb07cd31c792b445e630817e956d1 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 7 Oct 2019 14:02:57 +0100 +Subject: [PATCH] staging: bcm2835-codec: Fix imbalance in + dma_buf_get/dma_buf_put + +When represented with a dmabuf buffer that had previously been +imported, there was a call to dma_buf_get without a matching +dma_buf_put. This left dmabufs in limbo after all users had +supposedly released them. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -2112,6 +2112,11 @@ static int bcm2835_codec_buf_prepare(str + } + + buf->mmal.dma_buf = dma_buf; ++ } else { ++ /* We already have a reference count on the dmabuf, so ++ * release the one we acquired above. ++ */ ++ dma_buf_put(dma_buf); + } + ret = 0; + break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0327-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch b/target/linux/bcm27xx/patches-5.4/950-0327-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch new file mode 100644 index 0000000000..812f69643f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0327-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch @@ -0,0 +1,88 @@ +From b92ed4ca0f9be3c8cc1a21dbbef346338d336329 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Wed, 16 Oct 2019 14:49:23 +0100 +Subject: [PATCH] drm:vc4 Added calls for firmware display + blank/unblank + +Requires new display power mailbox call to be present. + +Signed-off-by: James Hughes +--- + drivers/gpu/drm/vc4/vc4_firmware_kms.c | 26 ++++++++++++++++++++++ + include/soc/bcm2835/raspberrypi-firmware.h | 2 +- + 2 files changed, 27 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c ++++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c +@@ -94,6 +94,12 @@ struct mailbox_blank_display { + u32 blank; + }; + ++struct mailbox_display_pwr { ++ struct rpi_firmware_property_tag_header tag1; ++ u32 display; ++ u32 state; ++}; ++ + struct mailbox_get_edid { + struct rpi_firmware_property_tag_header tag1; + u32 block; +@@ -274,6 +280,8 @@ to_vc4_crtc_state(struct drm_crtc_state + struct vc4_fkms_encoder { + struct drm_encoder base; + bool hdmi_monitor; ++ bool rgb_range_selectable; ++ int display_num; + }; + + static inline struct vc4_fkms_encoder * +@@ -1637,13 +1645,29 @@ static const struct drm_encoder_funcs vc + .destroy = vc4_fkms_encoder_destroy, + }; + ++static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power) ++{ ++ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); ++ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); ++ ++ struct mailbox_display_pwr pwr = { ++ .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, }, ++ .display = vc4_encoder->display_num, ++ .state = power ? 1 : 0, ++ }; ++ ++ rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr)); ++} ++ + static void vc4_fkms_encoder_enable(struct drm_encoder *encoder) + { ++ vc4_fkms_display_power(encoder, true); + DRM_DEBUG_KMS("Encoder_enable\n"); + } + + static void vc4_fkms_encoder_disable(struct drm_encoder *encoder) + { ++ vc4_fkms_display_power(encoder, false); + DRM_DEBUG_KMS("Encoder_disable\n"); + } + +@@ -1719,6 +1743,8 @@ static int vc4_fkms_create_screen(struct + if (!vc4_encoder) + return -ENOMEM; + vc4_crtc->encoder = &vc4_encoder->base; ++ ++ vc4_encoder->display_num = display_ref; + vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ; + + drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs, +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -153,7 +153,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, + RPI_FIRMWARE_SET_TIMING = 0x00048017, + RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018, +- ++ RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019, + RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, + RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0327-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch b/target/linux/bcm27xx/patches-5.4/950-0327-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch deleted file mode 100644 index fb60b16e56..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0327-staging-bcm2835-codec-Correct-buffer-type-check-on-G.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0ff5cd805e7db4003ad5a0d783b4d029b23b7ece Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 13 Sep 2019 17:22:08 +0100 -Subject: [PATCH] staging: bcm2835-codec: Correct buffer type check on - G_PARM - -The output queue buffer type is now OUTPUT_MPLANE. - -Fixes: 5e484a3 staging: bcm2835-codec: switch to multi-planar API -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1438,7 +1438,7 @@ static int vidioc_g_parm(struct file *fi - { - struct bcm2835_codec_ctx *ctx = file2ctx(file); - -- if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) -+ if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return -EINVAL; - - parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; diff --git a/target/linux/bcm27xx/patches-5.4/950-0328-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch b/target/linux/bcm27xx/patches-5.4/950-0328-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch new file mode 100644 index 0000000000..f2cf28433a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0328-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch @@ -0,0 +1,107 @@ +From b1d33d1e5a44afd2025c5a44a85dc2fab00ec6a7 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 5 Nov 2019 11:28:19 +0000 +Subject: [PATCH] Revert "pinctrl: bcm2835: Pass irqchip when adding + gpiochip" + +This reverts commit 73345a18d464b1b945b29f54f630ace6873344e2. +--- + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 55 +++++++++++++++------------ + 1 file changed, 30 insertions(+), 25 deletions(-) + +--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +@@ -78,6 +78,7 @@ + struct bcm2835_pinctrl { + struct device *dev; + void __iomem *base; ++ int irq[BCM2835_NUM_IRQS]; + + /* note: locking assumes each bank will have its own unsigned long */ + unsigned long enabled_irq_map[BCM2835_NUM_BANKS]; +@@ -381,14 +382,14 @@ static void bcm2835_gpio_irq_handler(str + int group; + int i; + +- for (i = 0; i < BCM2835_NUM_IRQS; i++) { +- if (chip->irq.parents[i] == irq) { ++ for (i = 0; i < ARRAY_SIZE(pc->irq); i++) { ++ if (pc->irq[i] == irq) { + group = i; + break; + } + } + /* This should not happen, every IRQ has a bank */ +- if (i == BCM2835_NUM_IRQS) ++ if (i == ARRAY_SIZE(pc->irq)) + BUG(); + + chained_irq_enter(host_chip, desc); +@@ -1086,7 +1087,6 @@ static int bcm2835_pinctrl_probe(struct + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct bcm2835_pinctrl *pc; +- struct gpio_irq_chip *girq; + struct resource iomem; + int err, i; + const struct of_device_id *match; +@@ -1135,33 +1135,38 @@ static int bcm2835_pinctrl_probe(struct + raw_spin_lock_init(&pc->irq_lock[i]); + } + +- girq = &pc->gpio_chip.irq; +- girq->chip = &bcm2835_gpio_irq_chip; +- girq->parent_handler = bcm2835_gpio_irq_handler; +- girq->num_parents = BCM2835_NUM_IRQS; +- girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS, +- sizeof(*girq->parents), +- GFP_KERNEL); +- if (!girq->parents) +- return -ENOMEM; +- /* +- * Use the same handler for all groups: this is necessary +- * since we use one gpiochip to cover all lines - the +- * irq handler then needs to figure out which group and +- * bank that was firing the IRQ and look up the per-group +- * and bank data. +- */ +- for (i = 0; i < BCM2835_NUM_IRQS; i++) +- girq->parents[i] = irq_of_parse_and_map(np, i); +- girq->default_type = IRQ_TYPE_NONE; +- girq->handler = handle_level_irq; +- + err = gpiochip_add_data(&pc->gpio_chip, pc); + if (err) { + dev_err(dev, "could not add GPIO chip\n"); + return err; + } + ++ err = gpiochip_irqchip_add(&pc->gpio_chip, &bcm2835_gpio_irq_chip, ++ 0, handle_level_irq, IRQ_TYPE_NONE); ++ if (err) { ++ dev_info(dev, "could not add irqchip\n"); ++ return err; ++ } ++ ++ for (i = 0; i < BCM2835_NUM_IRQS; i++) { ++ pc->irq[i] = irq_of_parse_and_map(np, i); ++ ++ if (pc->irq[i] == 0) ++ continue; ++ ++ /* ++ * Use the same handler for all groups: this is necessary ++ * since we use one gpiochip to cover all lines - the ++ * irq handler then needs to figure out which group and ++ * bank that was firing the IRQ and look up the per-group ++ * and bank data. ++ */ ++ gpiochip_set_chained_irqchip(&pc->gpio_chip, ++ &bcm2835_gpio_irq_chip, ++ pc->irq[i], ++ bcm2835_gpio_irq_handler); ++ } ++ + match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); + if (match) { + bcm2835_pinctrl_desc.confops = diff --git a/target/linux/bcm27xx/patches-5.4/950-0328-staging-bcm2835-codec-Set-default-and-error-check-ti.patch b/target/linux/bcm27xx/patches-5.4/950-0328-staging-bcm2835-codec-Set-default-and-error-check-ti.patch deleted file mode 100644 index 124b7ae742..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0328-staging-bcm2835-codec-Set-default-and-error-check-ti.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 6680d139ee23cf655c0aa43581604a7c5de31803 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Fri, 13 Sep 2019 17:23:26 +0100 -Subject: [PATCH] staging: bcm2835-codec: Set default and error check - timeperframe - -G_PARM default was invalid as 0/0, and the driver didn't check -the value set in S_PARM wasn't 0/0. - -Signed-off-by: Dave Stevenson ---- - .../vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -1423,6 +1423,10 @@ static int vidioc_s_parm(struct file *fi - if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return -EINVAL; - -+ if (!parm->parm.output.timeperframe.denominator || -+ !parm->parm.output.timeperframe.numerator) -+ return -EINVAL; -+ - ctx->framerate_num = - parm->parm.output.timeperframe.denominator; - ctx->framerate_denom = -@@ -2390,6 +2394,9 @@ static int bcm2835_codec_open(struct fil - ctx->colorspace = V4L2_COLORSPACE_REC709; - ctx->bitrate = 10 * 1000 * 1000; - -+ ctx->framerate_num = 30; -+ ctx->framerate_denom = 1; -+ - /* Initialise V4L2 contexts */ - v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; diff --git a/target/linux/bcm27xx/patches-5.4/950-0329-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch b/target/linux/bcm27xx/patches-5.4/950-0329-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch new file mode 100644 index 0000000000..a4a9dc817b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0329-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch @@ -0,0 +1,34 @@ +From e2d8a52d3ade83f5c114b1edba601ebcf2c39517 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 11 Nov 2019 14:01:41 +0000 +Subject: [PATCH] drm/v3d: Don't clear MMU control bits on exception + +MMU exception conditions are reported in the V3D_MMU_CTRL register as +write-1-to-clear (W1C) bits. The MMU interrupt handling code clears any +exceptions, but does so by masking out any other bits and writing the +result back. There are some important control bits in that register, +including MMU_ENABLE, so a safer approach is to simply write back the +value just read unaltered. + +This patch doesn't remove the cause of the apparent PTE errors, but it +does reduce the impact to just an error in the kernel log. + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/v3d_irq.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_irq.c ++++ b/drivers/gpu/drm/v3d/v3d_irq.c +@@ -178,10 +178,7 @@ v3d_hub_irq(int irq, void *arg) + }; + const char *client = "?"; + +- V3D_WRITE(V3D_MMU_CTL, +- V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED | +- V3D_MMU_CTL_PT_INVALID | +- V3D_MMU_CTL_WRITE_VIOLATION)); ++ V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL)); + + if (v3d->ver >= 41) { + axi_id = axi_id >> 5; diff --git a/target/linux/bcm27xx/patches-5.4/950-0329-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch b/target/linux/bcm27xx/patches-5.4/950-0329-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch deleted file mode 100644 index f0fdfd29c8..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0329-staging-bcm2835-codec-Fix-imbalance-in-dma_buf_get-d.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0c941589b9bfb07cd31c792b445e630817e956d1 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Mon, 7 Oct 2019 14:02:57 +0100 -Subject: [PATCH] staging: bcm2835-codec: Fix imbalance in - dma_buf_get/dma_buf_put - -When represented with a dmabuf buffer that had previously been -imported, there was a call to dma_buf_get without a matching -dma_buf_put. This left dmabufs in limbo after all users had -supposedly released them. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -2112,6 +2112,11 @@ static int bcm2835_codec_buf_prepare(str - } - - buf->mmal.dma_buf = dma_buf; -+ } else { -+ /* We already have a reference count on the dmabuf, so -+ * release the one we acquired above. -+ */ -+ dma_buf_put(dma_buf); - } - ret = 0; - break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0330-drm-v3d-Suppress-all-but-the-first-MMU-error.patch b/target/linux/bcm27xx/patches-5.4/950-0330-drm-v3d-Suppress-all-but-the-first-MMU-error.patch new file mode 100644 index 0000000000..58f3a44aff --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0330-drm-v3d-Suppress-all-but-the-first-MMU-error.patch @@ -0,0 +1,39 @@ +From f1f228c84864bad0bb07de1c72ceafaec035ac15 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 11 Nov 2019 20:18:08 +0000 +Subject: [PATCH] drm/v3d: Suppress all but the first MMU error + +The v3d driver currently encounters a lot of MMU PTE exceptions, so +only log the first to avoid swamping the kernel log. + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/v3d_irq.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/v3d/v3d_irq.c ++++ b/drivers/gpu/drm/v3d/v3d_irq.c +@@ -177,6 +177,7 @@ v3d_hub_irq(int irq, void *arg) + "GMP", + }; + const char *client = "?"; ++ static int logged_error; + + V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL)); + +@@ -186,6 +187,7 @@ v3d_hub_irq(int irq, void *arg) + client = v3d41_axi_ids[axi_id]; + } + ++ if (!logged_error) + dev_err(v3d->dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n", + client, axi_id, (long long)vio_addr, + ((intsts & V3D_HUB_INT_MMU_WRV) ? +@@ -194,6 +196,7 @@ v3d_hub_irq(int irq, void *arg) + ", pte invalid" : ""), + ((intsts & V3D_HUB_INT_MMU_CAP) ? + ", cap exceeded" : "")); ++ logged_error = 1; + status = IRQ_HANDLED; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0330-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch b/target/linux/bcm27xx/patches-5.4/950-0330-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch deleted file mode 100644 index 812f69643f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0330-drm-vc4-Added-calls-for-firmware-display-blank-unbla.patch +++ /dev/null @@ -1,88 +0,0 @@ -From b92ed4ca0f9be3c8cc1a21dbbef346338d336329 Mon Sep 17 00:00:00 2001 -From: James Hughes -Date: Wed, 16 Oct 2019 14:49:23 +0100 -Subject: [PATCH] drm:vc4 Added calls for firmware display - blank/unblank - -Requires new display power mailbox call to be present. - -Signed-off-by: James Hughes ---- - drivers/gpu/drm/vc4/vc4_firmware_kms.c | 26 ++++++++++++++++++++++ - include/soc/bcm2835/raspberrypi-firmware.h | 2 +- - 2 files changed, 27 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c -+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c -@@ -94,6 +94,12 @@ struct mailbox_blank_display { - u32 blank; - }; - -+struct mailbox_display_pwr { -+ struct rpi_firmware_property_tag_header tag1; -+ u32 display; -+ u32 state; -+}; -+ - struct mailbox_get_edid { - struct rpi_firmware_property_tag_header tag1; - u32 block; -@@ -274,6 +280,8 @@ to_vc4_crtc_state(struct drm_crtc_state - struct vc4_fkms_encoder { - struct drm_encoder base; - bool hdmi_monitor; -+ bool rgb_range_selectable; -+ int display_num; - }; - - static inline struct vc4_fkms_encoder * -@@ -1637,13 +1645,29 @@ static const struct drm_encoder_funcs vc - .destroy = vc4_fkms_encoder_destroy, - }; - -+static void vc4_fkms_display_power(struct drm_encoder *encoder, bool power) -+{ -+ struct vc4_fkms_encoder *vc4_encoder = to_vc4_fkms_encoder(encoder); -+ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); -+ -+ struct mailbox_display_pwr pwr = { -+ .tag1 = {RPI_FIRMWARE_SET_DISPLAY_POWER, 8, 0, }, -+ .display = vc4_encoder->display_num, -+ .state = power ? 1 : 0, -+ }; -+ -+ rpi_firmware_property_list(vc4->firmware, &pwr, sizeof(pwr)); -+} -+ - static void vc4_fkms_encoder_enable(struct drm_encoder *encoder) - { -+ vc4_fkms_display_power(encoder, true); - DRM_DEBUG_KMS("Encoder_enable\n"); - } - - static void vc4_fkms_encoder_disable(struct drm_encoder *encoder) - { -+ vc4_fkms_display_power(encoder, false); - DRM_DEBUG_KMS("Encoder_disable\n"); - } - -@@ -1719,6 +1743,8 @@ static int vc4_fkms_create_screen(struct - if (!vc4_encoder) - return -ENOMEM; - vc4_crtc->encoder = &vc4_encoder->base; -+ -+ vc4_encoder->display_num = display_ref; - vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ; - - drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs, ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -153,7 +153,7 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, - RPI_FIRMWARE_SET_TIMING = 0x00048017, - RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018, -- -+ RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019, - RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, - RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0331-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch b/target/linux/bcm27xx/patches-5.4/950-0331-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch deleted file mode 100644 index f2cf28433a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0331-Revert-pinctrl-bcm2835-Pass-irqchip-when-adding-gpio.patch +++ /dev/null @@ -1,107 +0,0 @@ -From b1d33d1e5a44afd2025c5a44a85dc2fab00ec6a7 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 5 Nov 2019 11:28:19 +0000 -Subject: [PATCH] Revert "pinctrl: bcm2835: Pass irqchip when adding - gpiochip" - -This reverts commit 73345a18d464b1b945b29f54f630ace6873344e2. ---- - drivers/pinctrl/bcm/pinctrl-bcm2835.c | 55 +++++++++++++++------------ - 1 file changed, 30 insertions(+), 25 deletions(-) - ---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c -+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -@@ -78,6 +78,7 @@ - struct bcm2835_pinctrl { - struct device *dev; - void __iomem *base; -+ int irq[BCM2835_NUM_IRQS]; - - /* note: locking assumes each bank will have its own unsigned long */ - unsigned long enabled_irq_map[BCM2835_NUM_BANKS]; -@@ -381,14 +382,14 @@ static void bcm2835_gpio_irq_handler(str - int group; - int i; - -- for (i = 0; i < BCM2835_NUM_IRQS; i++) { -- if (chip->irq.parents[i] == irq) { -+ for (i = 0; i < ARRAY_SIZE(pc->irq); i++) { -+ if (pc->irq[i] == irq) { - group = i; - break; - } - } - /* This should not happen, every IRQ has a bank */ -- if (i == BCM2835_NUM_IRQS) -+ if (i == ARRAY_SIZE(pc->irq)) - BUG(); - - chained_irq_enter(host_chip, desc); -@@ -1086,7 +1087,6 @@ static int bcm2835_pinctrl_probe(struct - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct bcm2835_pinctrl *pc; -- struct gpio_irq_chip *girq; - struct resource iomem; - int err, i; - const struct of_device_id *match; -@@ -1135,33 +1135,38 @@ static int bcm2835_pinctrl_probe(struct - raw_spin_lock_init(&pc->irq_lock[i]); - } - -- girq = &pc->gpio_chip.irq; -- girq->chip = &bcm2835_gpio_irq_chip; -- girq->parent_handler = bcm2835_gpio_irq_handler; -- girq->num_parents = BCM2835_NUM_IRQS; -- girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS, -- sizeof(*girq->parents), -- GFP_KERNEL); -- if (!girq->parents) -- return -ENOMEM; -- /* -- * Use the same handler for all groups: this is necessary -- * since we use one gpiochip to cover all lines - the -- * irq handler then needs to figure out which group and -- * bank that was firing the IRQ and look up the per-group -- * and bank data. -- */ -- for (i = 0; i < BCM2835_NUM_IRQS; i++) -- girq->parents[i] = irq_of_parse_and_map(np, i); -- girq->default_type = IRQ_TYPE_NONE; -- girq->handler = handle_level_irq; -- - err = gpiochip_add_data(&pc->gpio_chip, pc); - if (err) { - dev_err(dev, "could not add GPIO chip\n"); - return err; - } - -+ err = gpiochip_irqchip_add(&pc->gpio_chip, &bcm2835_gpio_irq_chip, -+ 0, handle_level_irq, IRQ_TYPE_NONE); -+ if (err) { -+ dev_info(dev, "could not add irqchip\n"); -+ return err; -+ } -+ -+ for (i = 0; i < BCM2835_NUM_IRQS; i++) { -+ pc->irq[i] = irq_of_parse_and_map(np, i); -+ -+ if (pc->irq[i] == 0) -+ continue; -+ -+ /* -+ * Use the same handler for all groups: this is necessary -+ * since we use one gpiochip to cover all lines - the -+ * irq handler then needs to figure out which group and -+ * bank that was firing the IRQ and look up the per-group -+ * and bank data. -+ */ -+ gpiochip_set_chained_irqchip(&pc->gpio_chip, -+ &bcm2835_gpio_irq_chip, -+ pc->irq[i], -+ bcm2835_gpio_irq_handler); -+ } -+ - match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); - if (match) { - bcm2835_pinctrl_desc.confops = diff --git a/target/linux/bcm27xx/patches-5.4/950-0331-drm-v3d-Plug-dma_fence-leak.patch b/target/linux/bcm27xx/patches-5.4/950-0331-drm-v3d-Plug-dma_fence-leak.patch new file mode 100644 index 0000000000..a79912df1e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0331-drm-v3d-Plug-dma_fence-leak.patch @@ -0,0 +1,28 @@ +From 9b2d99c0959e693e4dcea5f454bf84f229ca3d27 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 12 Nov 2019 16:41:21 +0000 +Subject: [PATCH] drm/v3d: Plug dma_fence leak + +The irq_fence and done_fence are given a reference that is never +released. The necessary dma_fence_put()s seem to have been +deleted in error in an earlier commit. + +Fixes: 0b73676836b2 ("drm/v3d: Clock V3D down when not in use.") + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/v3d_gem.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -410,6 +410,9 @@ v3d_job_free(struct kref *ref) + } + xa_destroy(&job->deps); + ++ dma_fence_put(job->irq_fence); ++ dma_fence_put(job->done_fence); ++ + v3d_clock_up_put(v3d); + + kfree(job); diff --git a/target/linux/bcm27xx/patches-5.4/950-0332-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch b/target/linux/bcm27xx/patches-5.4/950-0332-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch deleted file mode 100644 index a4a9dc817b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0332-drm-v3d-Don-t-clear-MMU-control-bits-on-exception.patch +++ /dev/null @@ -1,34 +0,0 @@ -From e2d8a52d3ade83f5c114b1edba601ebcf2c39517 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 11 Nov 2019 14:01:41 +0000 -Subject: [PATCH] drm/v3d: Don't clear MMU control bits on exception - -MMU exception conditions are reported in the V3D_MMU_CTRL register as -write-1-to-clear (W1C) bits. The MMU interrupt handling code clears any -exceptions, but does so by masking out any other bits and writing the -result back. There are some important control bits in that register, -including MMU_ENABLE, so a safer approach is to simply write back the -value just read unaltered. - -This patch doesn't remove the cause of the apparent PTE errors, but it -does reduce the impact to just an error in the kernel log. - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/v3d_irq.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - ---- a/drivers/gpu/drm/v3d/v3d_irq.c -+++ b/drivers/gpu/drm/v3d/v3d_irq.c -@@ -178,10 +178,7 @@ v3d_hub_irq(int irq, void *arg) - }; - const char *client = "?"; - -- V3D_WRITE(V3D_MMU_CTL, -- V3D_READ(V3D_MMU_CTL) & (V3D_MMU_CTL_CAP_EXCEEDED | -- V3D_MMU_CTL_PT_INVALID | -- V3D_MMU_CTL_WRITE_VIOLATION)); -+ V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL)); - - if (v3d->ver >= 41) { - axi_id = axi_id >> 5; diff --git a/target/linux/bcm27xx/patches-5.4/950-0332-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0332-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch new file mode 100644 index 0000000000..cf8d563c72 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0332-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch @@ -0,0 +1,40 @@ +From efe24599e8996ef5844e73feae1ca1b27d8740ab Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 6 Nov 2019 13:57:48 +0000 +Subject: [PATCH] staging: vchiq_arm: Register vcsm-cma as a platform + driver + +Following the same pattern as bcm2835-camera and bcm2835-audio, +register the vcsm-cma driver as a platform driver + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -140,6 +140,7 @@ static struct class *vchiq_class; + static DEFINE_SPINLOCK(msg_queue_spinlock); + static struct platform_device *bcm2835_camera; + static struct platform_device *bcm2835_audio; ++static struct platform_device *vcsm_cma; + + static struct vchiq_drvdata bcm2835_drvdata = { + .cache_line_size = 32, +@@ -3250,6 +3251,7 @@ static int vchiq_probe(struct platform_d + VCHIQ_VERSION, VCHIQ_VERSION_MIN, + MAJOR(vchiq_devid), MINOR(vchiq_devid)); + ++ vcsm_cma = vchiq_register_child(pdev, "vcsm-cma"); + bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera"); + bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio"); + +@@ -3266,6 +3268,7 @@ static int vchiq_remove(struct platform_ + { + platform_device_unregister(bcm2835_audio); + platform_device_unregister(bcm2835_camera); ++ platform_device_unregister(vcsm_cma); + vchiq_debugfs_deinit(); + device_destroy(vchiq_class, vchiq_devid); + cdev_del(&vchiq_cdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0333-drm-v3d-Suppress-all-but-the-first-MMU-error.patch b/target/linux/bcm27xx/patches-5.4/950-0333-drm-v3d-Suppress-all-but-the-first-MMU-error.patch deleted file mode 100644 index 58f3a44aff..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0333-drm-v3d-Suppress-all-but-the-first-MMU-error.patch +++ /dev/null @@ -1,39 +0,0 @@ -From f1f228c84864bad0bb07de1c72ceafaec035ac15 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 11 Nov 2019 20:18:08 +0000 -Subject: [PATCH] drm/v3d: Suppress all but the first MMU error - -The v3d driver currently encounters a lot of MMU PTE exceptions, so -only log the first to avoid swamping the kernel log. - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/v3d_irq.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/gpu/drm/v3d/v3d_irq.c -+++ b/drivers/gpu/drm/v3d/v3d_irq.c -@@ -177,6 +177,7 @@ v3d_hub_irq(int irq, void *arg) - "GMP", - }; - const char *client = "?"; -+ static int logged_error; - - V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL)); - -@@ -186,6 +187,7 @@ v3d_hub_irq(int irq, void *arg) - client = v3d41_axi_ids[axi_id]; - } - -+ if (!logged_error) - dev_err(v3d->dev, "MMU error from client %s (%d) at 0x%llx%s%s%s\n", - client, axi_id, (long long)vio_addr, - ((intsts & V3D_HUB_INT_MMU_WRV) ? -@@ -194,6 +196,7 @@ v3d_hub_irq(int irq, void *arg) - ", pte invalid" : ""), - ((intsts & V3D_HUB_INT_MMU_CAP) ? - ", cap exceeded" : "")); -+ logged_error = 1; - status = IRQ_HANDLED; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0333-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch b/target/linux/bcm27xx/patches-5.4/950-0333-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch new file mode 100644 index 0000000000..9e1b777cac --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0333-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch @@ -0,0 +1,40 @@ +From 16422635ebace7f01b42412e5c0d889f5ad7512e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 6 Nov 2019 13:57:58 +0000 +Subject: [PATCH] staging: vchiq_arm: Register bcm2835-codec as a + platform driver + +Following the same pattern as bcm2835-camera and bcm2835-audio, +register the V4L2 codec driver as a platform driver + +Signed-off-by: Dave Stevenson +--- + drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -140,6 +140,7 @@ static struct class *vchiq_class; + static DEFINE_SPINLOCK(msg_queue_spinlock); + static struct platform_device *bcm2835_camera; + static struct platform_device *bcm2835_audio; ++static struct platform_device *bcm2835_codec; + static struct platform_device *vcsm_cma; + + static struct vchiq_drvdata bcm2835_drvdata = { +@@ -3252,6 +3253,7 @@ static int vchiq_probe(struct platform_d + MAJOR(vchiq_devid), MINOR(vchiq_devid)); + + vcsm_cma = vchiq_register_child(pdev, "vcsm-cma"); ++ bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec"); + bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera"); + bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio"); + +@@ -3268,6 +3270,7 @@ static int vchiq_remove(struct platform_ + { + platform_device_unregister(bcm2835_audio); + platform_device_unregister(bcm2835_camera); ++ platform_device_unregister(bcm2835_codec); + platform_device_unregister(vcsm_cma); + vchiq_debugfs_deinit(); + device_destroy(vchiq_class, vchiq_devid); diff --git a/target/linux/bcm27xx/patches-5.4/950-0334-drm-v3d-Plug-dma_fence-leak.patch b/target/linux/bcm27xx/patches-5.4/950-0334-drm-v3d-Plug-dma_fence-leak.patch deleted file mode 100644 index a79912df1e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0334-drm-v3d-Plug-dma_fence-leak.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 9b2d99c0959e693e4dcea5f454bf84f229ca3d27 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 12 Nov 2019 16:41:21 +0000 -Subject: [PATCH] drm/v3d: Plug dma_fence leak - -The irq_fence and done_fence are given a reference that is never -released. The necessary dma_fence_put()s seem to have been -deleted in error in an earlier commit. - -Fixes: 0b73676836b2 ("drm/v3d: Clock V3D down when not in use.") - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/v3d_gem.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/gpu/drm/v3d/v3d_gem.c -+++ b/drivers/gpu/drm/v3d/v3d_gem.c -@@ -410,6 +410,9 @@ v3d_job_free(struct kref *ref) - } - xa_destroy(&job->deps); - -+ dma_fence_put(job->irq_fence); -+ dma_fence_put(job->done_fence); -+ - v3d_clock_up_put(v3d); - - kfree(job); diff --git a/target/linux/bcm27xx/patches-5.4/950-0334-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch b/target/linux/bcm27xx/patches-5.4/950-0334-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch new file mode 100644 index 0000000000..915ca1a29f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0334-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch @@ -0,0 +1,29 @@ +From 6d59110f7aa7c86caf2c3a29169ace33556f690b Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 6 Nov 2019 13:58:08 +0000 +Subject: [PATCH] staging: bcm2835-codec: Fix potential memory leak of + isp instance + +"d867785 staging: bcm2835-codec: add media controller support" added +a new error path that jumped to end, but didn't add the free +of the ISP device should that path be taken. +Fix this. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c ++++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c +@@ -2841,6 +2841,10 @@ static int bcm2835_codec_probe(struct pl + return 0; + + out: ++ if (drv->isp) { ++ bcm2835_codec_destroy(drv->isp); ++ drv->isp = NULL; ++ } + if (drv->encode) { + bcm2835_codec_destroy(drv->encode); + drv->encode = NULL; diff --git a/target/linux/bcm27xx/patches-5.4/950-0335-net-bcmgenet-The-second-IRQ-is-optional.patch b/target/linux/bcm27xx/patches-5.4/950-0335-net-bcmgenet-The-second-IRQ-is-optional.patch new file mode 100644 index 0000000000..d48e6948d3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0335-net-bcmgenet-The-second-IRQ-is-optional.patch @@ -0,0 +1,24 @@ +From c2863af34286fda317891bb893f8a2e16bf5707e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 14 Nov 2019 11:59:01 +0000 +Subject: [PATCH] net: bcmgenet: The second IRQ is optional + +As of 5.4, the kernel logs errors for absent IRQs unless requested +with platform_get_irq_optional. + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/v3d_irq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/v3d/v3d_irq.c ++++ b/drivers/gpu/drm/v3d/v3d_irq.c +@@ -217,7 +217,7 @@ v3d_irq_init(struct v3d_dev *v3d) + V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); + V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); + +- irq1 = platform_get_irq(v3d->pdev, 1); ++ irq1 = platform_get_irq_optional(v3d->pdev, 1); + if (irq1 == -EPROBE_DEFER) + return irq1; + if (irq1 > 0) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0335-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0335-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch deleted file mode 100644 index cf8d563c72..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0335-staging-vchiq_arm-Register-vcsm-cma-as-a-platform-dr.patch +++ /dev/null @@ -1,40 +0,0 @@ -From efe24599e8996ef5844e73feae1ca1b27d8740ab Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 6 Nov 2019 13:57:48 +0000 -Subject: [PATCH] staging: vchiq_arm: Register vcsm-cma as a platform - driver - -Following the same pattern as bcm2835-camera and bcm2835-audio, -register the vcsm-cma driver as a platform driver - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -140,6 +140,7 @@ static struct class *vchiq_class; - static DEFINE_SPINLOCK(msg_queue_spinlock); - static struct platform_device *bcm2835_camera; - static struct platform_device *bcm2835_audio; -+static struct platform_device *vcsm_cma; - - static struct vchiq_drvdata bcm2835_drvdata = { - .cache_line_size = 32, -@@ -3250,6 +3251,7 @@ static int vchiq_probe(struct platform_d - VCHIQ_VERSION, VCHIQ_VERSION_MIN, - MAJOR(vchiq_devid), MINOR(vchiq_devid)); - -+ vcsm_cma = vchiq_register_child(pdev, "vcsm-cma"); - bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera"); - bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio"); - -@@ -3266,6 +3268,7 @@ static int vchiq_remove(struct platform_ - { - platform_device_unregister(bcm2835_audio); - platform_device_unregister(bcm2835_camera); -+ platform_device_unregister(vcsm_cma); - vchiq_debugfs_deinit(); - device_destroy(vchiq_class, vchiq_devid); - cdev_del(&vchiq_cdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0336-drm-v3d-The-third-IRQ-is-optional.patch b/target/linux/bcm27xx/patches-5.4/950-0336-drm-v3d-The-third-IRQ-is-optional.patch new file mode 100644 index 0000000000..97ff76a6a3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0336-drm-v3d-The-third-IRQ-is-optional.patch @@ -0,0 +1,24 @@ +From 92f17eecf263f3705a6e1a4f27ecb273ed3a33e5 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 14 Nov 2019 12:00:43 +0000 +Subject: [PATCH] drm/v3d: The third IRQ is optional + +As of 5.4, the kernel logs errors for absent IRQs unless requested +with platform_get_irq_optional. + +Signed-off-by: Phil Elwell +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -3474,7 +3474,7 @@ static int bcmgenet_probe(struct platfor + priv = netdev_priv(dev); + priv->irq0 = platform_get_irq(pdev, 0); + priv->irq1 = platform_get_irq(pdev, 1); +- priv->wol_irq = platform_get_irq(pdev, 2); ++ priv->wol_irq = platform_get_irq_optional(pdev, 2); + if (!priv->irq0 || !priv->irq1) { + dev_err(&pdev->dev, "can't find IRQs\n"); + err = -EINVAL; diff --git a/target/linux/bcm27xx/patches-5.4/950-0336-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch b/target/linux/bcm27xx/patches-5.4/950-0336-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch deleted file mode 100644 index 9e1b777cac..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0336-staging-vchiq_arm-Register-bcm2835-codec-as-a-platfo.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 16422635ebace7f01b42412e5c0d889f5ad7512e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 6 Nov 2019 13:57:58 +0000 -Subject: [PATCH] staging: vchiq_arm: Register bcm2835-codec as a - platform driver - -Following the same pattern as bcm2835-camera and bcm2835-audio, -register the V4L2 codec driver as a platform driver - -Signed-off-by: Dave Stevenson ---- - drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -140,6 +140,7 @@ static struct class *vchiq_class; - static DEFINE_SPINLOCK(msg_queue_spinlock); - static struct platform_device *bcm2835_camera; - static struct platform_device *bcm2835_audio; -+static struct platform_device *bcm2835_codec; - static struct platform_device *vcsm_cma; - - static struct vchiq_drvdata bcm2835_drvdata = { -@@ -3252,6 +3253,7 @@ static int vchiq_probe(struct platform_d - MAJOR(vchiq_devid), MINOR(vchiq_devid)); - - vcsm_cma = vchiq_register_child(pdev, "vcsm-cma"); -+ bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec"); - bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera"); - bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio"); - -@@ -3268,6 +3270,7 @@ static int vchiq_remove(struct platform_ - { - platform_device_unregister(bcm2835_audio); - platform_device_unregister(bcm2835_camera); -+ platform_device_unregister(bcm2835_codec); - platform_device_unregister(vcsm_cma); - vchiq_debugfs_deinit(); - device_destroy(vchiq_class, vchiq_devid); diff --git a/target/linux/bcm27xx/patches-5.4/950-0337-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch b/target/linux/bcm27xx/patches-5.4/950-0337-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch new file mode 100644 index 0000000000..afd72da286 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0337-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch @@ -0,0 +1,27 @@ +From 941d43e29b1fa7352eb006b5ec37d6990ed3b877 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 15 Nov 2019 08:48:08 +0000 +Subject: [PATCH] dwc_otg: Declare DMA capability with HCD_DMA flag + +Following [1], USB controllers have to declare DMA capabilities in +order for them to be used by adding the HCD_DMA flag to their hc_driver +struct. + +[1] 7b81cb6bddd2 ("usb: add a HCD_DMA flag instead of guestimating DMA capabilities") + +Signed-off-by: Phil Elwell +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +@@ -119,7 +119,7 @@ static struct hc_driver dwc_otg_hc_drive + + .irq = dwc_otg_hcd_irq, + +- .flags = HCD_MEMORY | HCD_USB2, ++ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2, + + //.reset = + .start = hcd_start, diff --git a/target/linux/bcm27xx/patches-5.4/950-0337-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch b/target/linux/bcm27xx/patches-5.4/950-0337-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch deleted file mode 100644 index 915ca1a29f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0337-staging-bcm2835-codec-Fix-potential-memory-leak-of-i.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 6d59110f7aa7c86caf2c3a29169ace33556f690b Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 6 Nov 2019 13:58:08 +0000 -Subject: [PATCH] staging: bcm2835-codec: Fix potential memory leak of - isp instance - -"d867785 staging: bcm2835-codec: add media controller support" added -a new error path that jumped to end, but didn't add the free -of the ISP device should that path be taken. -Fix this. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c -@@ -2841,6 +2841,10 @@ static int bcm2835_codec_probe(struct pl - return 0; - - out: -+ if (drv->isp) { -+ bcm2835_codec_destroy(drv->isp); -+ drv->isp = NULL; -+ } - if (drv->encode) { - bcm2835_codec_destroy(drv->encode); - drv->encode = NULL; diff --git a/target/linux/bcm27xx/patches-5.4/950-0338-rpi-poe-fan-fix-def_pwm1-writes.patch b/target/linux/bcm27xx/patches-5.4/950-0338-rpi-poe-fan-fix-def_pwm1-writes.patch new file mode 100644 index 0000000000..8792d5954c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0338-rpi-poe-fan-fix-def_pwm1-writes.patch @@ -0,0 +1,21 @@ +From 3223b1605ea10821a90867ee7a79d9030d7ca44f Mon Sep 17 00:00:00 2001 +From: Serge Schneider +Date: Thu, 31 Oct 2019 13:37:16 +0000 +Subject: [PATCH] rpi-poe-fan: fix def_pwm1 writes + +Signed-off-by: Serge Schneider +--- + drivers/hwmon/rpi-poe-fan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/hwmon/rpi-poe-fan.c ++++ b/drivers/hwmon/rpi-poe-fan.c +@@ -110,7 +110,7 @@ static int __set_def_pwm(struct rpi_poe + if (ctx->def_pwm_value == def_pwm) + goto exit_set_def_pwm_err; + +- ret = write_reg(ctx->fw, POE_CUR_PWM, &def_pwm); ++ ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm); + if (!ret) + ctx->def_pwm_value = def_pwm; + exit_set_def_pwm_err: diff --git a/target/linux/bcm27xx/patches-5.4/950-0339-net-bcmgenet-The-second-IRQ-is-optional.patch b/target/linux/bcm27xx/patches-5.4/950-0339-net-bcmgenet-The-second-IRQ-is-optional.patch deleted file mode 100644 index d48e6948d3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0339-net-bcmgenet-The-second-IRQ-is-optional.patch +++ /dev/null @@ -1,24 +0,0 @@ -From c2863af34286fda317891bb893f8a2e16bf5707e Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 14 Nov 2019 11:59:01 +0000 -Subject: [PATCH] net: bcmgenet: The second IRQ is optional - -As of 5.4, the kernel logs errors for absent IRQs unless requested -with platform_get_irq_optional. - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/v3d_irq.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/gpu/drm/v3d/v3d_irq.c -+++ b/drivers/gpu/drm/v3d/v3d_irq.c -@@ -217,7 +217,7 @@ v3d_irq_init(struct v3d_dev *v3d) - V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS); - V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS); - -- irq1 = platform_get_irq(v3d->pdev, 1); -+ irq1 = platform_get_irq_optional(v3d->pdev, 1); - if (irq1 == -EPROBE_DEFER) - return irq1; - if (irq1 > 0) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0339-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch b/target/linux/bcm27xx/patches-5.4/950-0339-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch new file mode 100644 index 0000000000..b3e237fdf5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0339-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch @@ -0,0 +1,119 @@ +From eef2d9aeb08a227d0a9c5734214425a3b9693f50 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Thu, 31 Oct 2019 14:39:44 +0000 +Subject: [PATCH] net:phy:2711 Allow ethernet LED mode to be set via + device tree + +Add device tree entries and code to allow the specification of +the lighting modes for the LED's on the ethernet connector. + +Signed-off-by: James Hughes +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 3 +++ + arch/arm/boot/dts/bcm2838.dtsi | 1 + + arch/arm/boot/dts/overlays/README | 28 +++++++++++++++++++-------- + drivers/net/phy/broadcom.c | 9 +++++++-- + 4 files changed, 31 insertions(+), 10 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -334,5 +334,8 @@ + pwr_led_gpio = <&pwr_led>,"gpios:4"; + pwr_led_activelow = <&pwr_led>,"gpios:8"; + pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; ++ ++ eth_led0 = <&phy1>,"led-modes:0"; ++ eth_led1 = <&phy1>,"led-modes:4"; + }; + }; +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -380,6 +380,7 @@ + /* No interrupts - use PHY_POLL */ + max-speed = <1000>; + reg = <0x1>; ++ led-modes = <0x02 0x02>; + }; + }; + }; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -102,26 +102,38 @@ Params: + + eee Enable Energy Efficient Ethernet support for + compatible devices (default "on"). See also +- "tx_lpi_timer". ++ "tx_lpi_timer". Pi3B+ only. + + eth_downshift_after Set the number of auto-negotiation failures + after which the 1000Mbps modes are disabled. + Legal values are 2, 3, 4, 5 and 0, where +- 0 means never downshift (default 2). ++ 0 means never downshift (default 2). Pi3B+ only. + +- eth_led0 Set mode of LED0 (usually orange) (default +- "1"). The legal values are: +- 0=link/activity 1=link1000/activity ++ eth_led0 Set mode of LED0 (usually orange). The legal ++ values are: ++ ++ Pi3B+ ++ ++ 0=link/activity 1=link1000/activity (default) + 2=link100/activity 3=link10/activity + 4=link100/1000/activity 5=link10/1000/activity + 6=link10/100/activity 14=off 15=on + +- eth_led1 Set mode of LED1 (usually green) (default +- "6"). See eth_led0 for legal values. ++ Pi4 ++ ++ 0=Speed/Activity (default) 1=Speed ++ 2=Speed/Flash activity 3=FDX ++ 4=Off 5=On ++ 6=Alt 7=Speed/Flash ++ 8=Link 9=Activity ++ ++ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default ++ "6", Pi4 default "0"). See eth_led0 for legal ++ values. + + eth_max_speed Set the maximum speed a link is allowed + to negotiate. Legal values are 10, 100 and +- 1000 (default 1000). ++ 1000 (default 1000). Pi3B+ only. + + i2c_arm Set to "on" to enable the ARM's i2c interface + (default "off") +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -267,6 +267,9 @@ static void bcm54xx_adjust_rxrefclk(stru + static int bcm54xx_config_init(struct phy_device *phydev) + { + int reg, err, val; ++ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT, ++ BCM_LED_MULTICOLOR_LINK_ACT}; ++ struct device_node *np = phydev->mdio.dev.of_node; + + reg = phy_read(phydev, MII_BCM54XX_ECR); + if (reg < 0) +@@ -318,6 +321,8 @@ static int bcm54xx_config_init(struct ph + + bcm54xx_phydsp_config(phydev); + ++ of_property_read_u32_array(np, "led-modes", led_modes, 2); ++ + /* Encode link speed into LED1 and LED3 pair (green/amber). + * Also flash these two LEDs on activity. This means configuring + * them for MULTICOLOR and encoding link/activity into them. +@@ -327,8 +332,8 @@ static int bcm54xx_config_init(struct ph + bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); + + val = BCM_LED_MULTICOLOR_IN_PHASE | +- BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | +- BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); ++ BCM5482_SHD_LEDS1_LED1(led_modes[0]) | ++ BCM5482_SHD_LEDS1_LED3(led_modes[1]); + bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); + + return 0; diff --git a/target/linux/bcm27xx/patches-5.4/950-0340-drm-v3d-The-third-IRQ-is-optional.patch b/target/linux/bcm27xx/patches-5.4/950-0340-drm-v3d-The-third-IRQ-is-optional.patch deleted file mode 100644 index 97ff76a6a3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0340-drm-v3d-The-third-IRQ-is-optional.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 92f17eecf263f3705a6e1a4f27ecb273ed3a33e5 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 14 Nov 2019 12:00:43 +0000 -Subject: [PATCH] drm/v3d: The third IRQ is optional - -As of 5.4, the kernel logs errors for absent IRQs unless requested -with platform_get_irq_optional. - -Signed-off-by: Phil Elwell ---- - drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c -+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c -@@ -3474,7 +3474,7 @@ static int bcmgenet_probe(struct platfor - priv = netdev_priv(dev); - priv->irq0 = platform_get_irq(pdev, 0); - priv->irq1 = platform_get_irq(pdev, 1); -- priv->wol_irq = platform_get_irq(pdev, 2); -+ priv->wol_irq = platform_get_irq_optional(pdev, 2); - if (!priv->irq0 || !priv->irq1) { - dev_err(&pdev->dev, "can't find IRQs\n"); - err = -EINVAL; diff --git a/target/linux/bcm27xx/patches-5.4/950-0340-overlays-smi-fix-typo-in-comment-3320.patch b/target/linux/bcm27xx/patches-5.4/950-0340-overlays-smi-fix-typo-in-comment-3320.patch new file mode 100644 index 0000000000..0a4f630a4c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0340-overlays-smi-fix-typo-in-comment-3320.patch @@ -0,0 +1,23 @@ +From 2a65ed9d89f32a0e87d99ccdfd21ab140637063a Mon Sep 17 00:00:00 2001 +From: Pierre-jean Texier +Date: Wed, 6 Nov 2019 10:00:43 +0100 +Subject: [PATCH] overlays: smi: fix typo in comment (#3320) + +5 represent alt1 function not alt0. + +Signed-off-by: Pierre-Jean Texier +--- + arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/smi-overlay.dts ++++ b/arch/arm/boot/dts/overlays/smi-overlay.dts +@@ -24,7 +24,7 @@ + these are already used as ID_SD and ID_SC */ + brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 16 17 18 19 20 21 22 23 24 25>; +- /* Alt 0: SMI */ ++ /* Alt 1: SMI */ + brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 + 5 5 5 5 5 5 5 5 5>; + /* /CS, /WE and /OE are pulled high, as they are diff --git a/target/linux/bcm27xx/patches-5.4/950-0341-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch b/target/linux/bcm27xx/patches-5.4/950-0341-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch deleted file mode 100644 index afd72da286..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0341-dwc_otg-Declare-DMA-capability-with-HCD_DMA-flag.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 941d43e29b1fa7352eb006b5ec37d6990ed3b877 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 15 Nov 2019 08:48:08 +0000 -Subject: [PATCH] dwc_otg: Declare DMA capability with HCD_DMA flag - -Following [1], USB controllers have to declare DMA capabilities in -order for them to be used by adding the HCD_DMA flag to their hc_driver -struct. - -[1] 7b81cb6bddd2 ("usb: add a HCD_DMA flag instead of guestimating DMA capabilities") - -Signed-off-by: Phil Elwell ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -119,7 +119,7 @@ static struct hc_driver dwc_otg_hc_drive - - .irq = dwc_otg_hcd_irq, - -- .flags = HCD_MEMORY | HCD_USB2, -+ .flags = HCD_MEMORY | HCD_DMA | HCD_USB2, - - //.reset = - .start = hcd_start, diff --git a/target/linux/bcm27xx/patches-5.4/950-0341-net-phy-2711-Change-the-default-ethernet-LED-actions.patch b/target/linux/bcm27xx/patches-5.4/950-0341-net-phy-2711-Change-the-default-ethernet-LED-actions.patch new file mode 100644 index 0000000000..d76fd0ec0d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0341-net-phy-2711-Change-the-default-ethernet-LED-actions.patch @@ -0,0 +1,33 @@ +From e459a2c448d7d71718769a9966543a964d1803bd Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Thu, 7 Nov 2019 14:59:59 +0000 +Subject: [PATCH] net:phy:2711 Change the default ethernet LED actions + +This should return default behaviour back to that of previous +releases. +--- + drivers/net/phy/broadcom.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -268,7 +268,7 @@ static int bcm54xx_config_init(struct ph + { + int reg, err, val; + u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT, +- BCM_LED_MULTICOLOR_LINK_ACT}; ++ BCM_LED_MULTICOLOR_LINK}; + struct device_node *np = phydev->mdio.dev.of_node; + + reg = phy_read(phydev, MII_BCM54XX_ECR); +@@ -323,10 +323,6 @@ static int bcm54xx_config_init(struct ph + + of_property_read_u32_array(np, "led-modes", led_modes, 2); + +- /* Encode link speed into LED1 and LED3 pair (green/amber). +- * Also flash these two LEDs on activity. This means configuring +- * them for MULTICOLOR and encoding link/activity into them. +- */ + val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | + BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); + bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); diff --git a/target/linux/bcm27xx/patches-5.4/950-0342-overlays-Add-apds9960-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0342-overlays-Add-apds9960-overlay.patch new file mode 100644 index 0000000000..f0f5368076 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0342-overlays-Add-apds9960-overlay.patch @@ -0,0 +1,103 @@ +From 62cd48ebf18c1eb0bbddba080476201bdfae4126 Mon Sep 17 00:00:00 2001 +From: Michael Kaplan +Date: Fri, 8 Nov 2019 10:35:57 +0100 +Subject: [PATCH] overlays: Add apds9960 overlay + +Add an overlay for the AVAGO APDS9960 digital proximity, ambient light, rgb and gesture sensor. +Also update overlay README and Makefile. + +Signed-off-by: Michael Kaplan +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 8 +++ + .../boot/dts/overlays/apds9960-overlay.dts | 57 +++++++++++++++++++ + 3 files changed, 66 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/apds9960-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + allo-katana-dac-audio.dtbo \ + allo-piano-dac-pcm512x-audio.dtbo \ + allo-piano-dac-plus-pcm512x-audio.dtbo \ ++ apds9960.dtbo \ + applepi-dac.dtbo \ + at86rf233.dtbo \ + audioinjector-addons.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -441,6 +441,14 @@ Params: 24db_digital_gain Allow ga + better voice quality. (default Off) + + ++Name: apds9960 ++Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and ++ gesture sensor ++Load: dtoverlay=apds9960,= ++Params: gpiopin GPIO used for INT (default 4) ++ noints Disable the interrupt GPIO line. ++ ++ + Name: applepi-dac + Info: Configures the Orchard Audio ApplePi-DAC audio card + Load: dtoverlay=applepi-dac +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/apds9960-overlay.dts +@@ -0,0 +1,57 @@ ++// Definitions for APDS-9960 ambient light and gesture sensor ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ apds9960_pins: apds9960_pins@39 { ++ brcm,pins = <4>; ++ brcm,function = <0>; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ apds9960: apds@39 { ++ compatible = "avago,apds9960"; ++ reg = <0x39>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c1>; ++ __overlay__ { ++ apds9960_irq: apds@39 { ++ #interrupt-cells=<2>; ++ interrupt-parent = <&gpio>; ++ interrupts = <4 1>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ gpiopin = <&apds9960_pins>,"brcm,pins:0", ++ <&apds9960_irq>,"interrupts:0"; ++ noints = <0>,"!1!3"; ++ }; ++}; ++ diff --git a/target/linux/bcm27xx/patches-5.4/950-0342-rpi-poe-fan-fix-def_pwm1-writes.patch b/target/linux/bcm27xx/patches-5.4/950-0342-rpi-poe-fan-fix-def_pwm1-writes.patch deleted file mode 100644 index 8792d5954c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0342-rpi-poe-fan-fix-def_pwm1-writes.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 3223b1605ea10821a90867ee7a79d9030d7ca44f Mon Sep 17 00:00:00 2001 -From: Serge Schneider -Date: Thu, 31 Oct 2019 13:37:16 +0000 -Subject: [PATCH] rpi-poe-fan: fix def_pwm1 writes - -Signed-off-by: Serge Schneider ---- - drivers/hwmon/rpi-poe-fan.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/hwmon/rpi-poe-fan.c -+++ b/drivers/hwmon/rpi-poe-fan.c -@@ -110,7 +110,7 @@ static int __set_def_pwm(struct rpi_poe - if (ctx->def_pwm_value == def_pwm) - goto exit_set_def_pwm_err; - -- ret = write_reg(ctx->fw, POE_CUR_PWM, &def_pwm); -+ ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm); - if (!ret) - ctx->def_pwm_value = def_pwm; - exit_set_def_pwm_err: diff --git a/target/linux/bcm27xx/patches-5.4/950-0343-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch b/target/linux/bcm27xx/patches-5.4/950-0343-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch deleted file mode 100644 index b3e237fdf5..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0343-net-phy-2711-Allow-ethernet-LED-mode-to-be-set-via-d.patch +++ /dev/null @@ -1,119 +0,0 @@ -From eef2d9aeb08a227d0a9c5734214425a3b9693f50 Mon Sep 17 00:00:00 2001 -From: James Hughes -Date: Thu, 31 Oct 2019 14:39:44 +0000 -Subject: [PATCH] net:phy:2711 Allow ethernet LED mode to be set via - device tree - -Add device tree entries and code to allow the specification of -the lighting modes for the LED's on the ethernet connector. - -Signed-off-by: James Hughes ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 3 +++ - arch/arm/boot/dts/bcm2838.dtsi | 1 + - arch/arm/boot/dts/overlays/README | 28 +++++++++++++++++++-------- - drivers/net/phy/broadcom.c | 9 +++++++-- - 4 files changed, 31 insertions(+), 10 deletions(-) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -334,5 +334,8 @@ - pwr_led_gpio = <&pwr_led>,"gpios:4"; - pwr_led_activelow = <&pwr_led>,"gpios:8"; - pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; -+ -+ eth_led0 = <&phy1>,"led-modes:0"; -+ eth_led1 = <&phy1>,"led-modes:4"; - }; - }; ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -380,6 +380,7 @@ - /* No interrupts - use PHY_POLL */ - max-speed = <1000>; - reg = <0x1>; -+ led-modes = <0x02 0x02>; - }; - }; - }; ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -102,26 +102,38 @@ Params: - - eee Enable Energy Efficient Ethernet support for - compatible devices (default "on"). See also -- "tx_lpi_timer". -+ "tx_lpi_timer". Pi3B+ only. - - eth_downshift_after Set the number of auto-negotiation failures - after which the 1000Mbps modes are disabled. - Legal values are 2, 3, 4, 5 and 0, where -- 0 means never downshift (default 2). -+ 0 means never downshift (default 2). Pi3B+ only. - -- eth_led0 Set mode of LED0 (usually orange) (default -- "1"). The legal values are: -- 0=link/activity 1=link1000/activity -+ eth_led0 Set mode of LED0 (usually orange). The legal -+ values are: -+ -+ Pi3B+ -+ -+ 0=link/activity 1=link1000/activity (default) - 2=link100/activity 3=link10/activity - 4=link100/1000/activity 5=link10/1000/activity - 6=link10/100/activity 14=off 15=on - -- eth_led1 Set mode of LED1 (usually green) (default -- "6"). See eth_led0 for legal values. -+ Pi4 -+ -+ 0=Speed/Activity (default) 1=Speed -+ 2=Speed/Flash activity 3=FDX -+ 4=Off 5=On -+ 6=Alt 7=Speed/Flash -+ 8=Link 9=Activity -+ -+ eth_led1 Set mode of LED1 (usually green) (Pi3B+ default -+ "6", Pi4 default "0"). See eth_led0 for legal -+ values. - - eth_max_speed Set the maximum speed a link is allowed - to negotiate. Legal values are 10, 100 and -- 1000 (default 1000). -+ 1000 (default 1000). Pi3B+ only. - - i2c_arm Set to "on" to enable the ARM's i2c interface - (default "off") ---- a/drivers/net/phy/broadcom.c -+++ b/drivers/net/phy/broadcom.c -@@ -267,6 +267,9 @@ static void bcm54xx_adjust_rxrefclk(stru - static int bcm54xx_config_init(struct phy_device *phydev) - { - int reg, err, val; -+ u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT, -+ BCM_LED_MULTICOLOR_LINK_ACT}; -+ struct device_node *np = phydev->mdio.dev.of_node; - - reg = phy_read(phydev, MII_BCM54XX_ECR); - if (reg < 0) -@@ -318,6 +321,8 @@ static int bcm54xx_config_init(struct ph - - bcm54xx_phydsp_config(phydev); - -+ of_property_read_u32_array(np, "led-modes", led_modes, 2); -+ - /* Encode link speed into LED1 and LED3 pair (green/amber). - * Also flash these two LEDs on activity. This means configuring - * them for MULTICOLOR and encoding link/activity into them. -@@ -327,8 +332,8 @@ static int bcm54xx_config_init(struct ph - bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); - - val = BCM_LED_MULTICOLOR_IN_PHASE | -- BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | -- BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); -+ BCM5482_SHD_LEDS1_LED1(led_modes[0]) | -+ BCM5482_SHD_LEDS1_LED3(led_modes[1]); - bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); - - return 0; diff --git a/target/linux/bcm27xx/patches-5.4/950-0343-overlays-Remove-hack-from-uart0-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0343-overlays-Remove-hack-from-uart0-overlay.patch new file mode 100644 index 0000000000..ac70b35413 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0343-overlays-Remove-hack-from-uart0-overlay.patch @@ -0,0 +1,45 @@ +From d24bb9c4b5d3b0bb2bd5dd922bae3fce894ab87e Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 1 Oct 2019 10:19:50 +0100 +Subject: [PATCH] overlays: Remove hack from uart0 overlay + +The uart0 overlay contained a hack to return GPIOs 14 and 15 to inputs +when the UART0 function was moved to alternative pins. This has the +unwanted side effect of claiming GPIOs 14 & 15, preventing them being +used for something else. + +See: https://github.com/raspberrypi/linux/issues/2856 + https://www.raspberrypi.org/forums/viewtopic.php?f=98&t=252911 + +Signed-off-by: Stefan Enge +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/uart0-overlay.dts | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +--- a/arch/arm/boot/dts/overlays/uart0-overlay.dts ++++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts +@@ -17,17 +17,16 @@ + target = <&gpio>; + __overlay__ { + uart0_pins: uart0_pins { +- brcm,pins = <14 15 14 15>; +- brcm,function = <0 0 4 4>; /* alt0 */ +- brcm,pull = <0 0 0 2>; ++ brcm,pins = <14 15>; ++ brcm,function = <4>; /* alt0 */ ++ brcm,pull = <0 2>; + }; + }; + }; + + __overrides__ { +- txd0_pin = <&uart0_pins>,"brcm,pins:8"; +- rxd0_pin = <&uart0_pins>,"brcm,pins:12"; +- pin_func = <&uart0_pins>,"brcm,function:8", +- <&uart0_pins>,"brcm,function:12"; ++ txd0_pin = <&uart0_pins>,"brcm,pins:0"; ++ rxd0_pin = <&uart0_pins>,"brcm,pins:4"; ++ pin_func = <&uart0_pins>,"brcm,function:0"; + }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0344-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch b/target/linux/bcm27xx/patches-5.4/950-0344-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch new file mode 100644 index 0000000000..ba19abb895 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0344-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch @@ -0,0 +1,27 @@ +From 47a9af99289ef0b9d60a72cd7147958e4745468c Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Sun, 17 Nov 2019 16:20:24 +0000 +Subject: [PATCH] arm: dts: overlays: pitft35-resistive: add upstream + compatible + +The upstream hx8357d driver uses "adafruit,yx350hv15" for the compatible +string explicitly for this screen config and not a hx8357d generic for +the controller so add that in as well so it will work with an unmodified +upstream kernel driver. We leave the downstream as the priority. + +Signed-off-by: Peter Robinson +--- + arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts +@@ -49,7 +49,7 @@ + #size-cells = <0>; + + pitft: pitft@0{ +- compatible = "himax,hx8357d"; ++ compatible = "himax,hx8357d", "adafruit,yx350hv15"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pitft_pins>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0344-overlays-smi-fix-typo-in-comment-3320.patch b/target/linux/bcm27xx/patches-5.4/950-0344-overlays-smi-fix-typo-in-comment-3320.patch deleted file mode 100644 index 0a4f630a4c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0344-overlays-smi-fix-typo-in-comment-3320.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 2a65ed9d89f32a0e87d99ccdfd21ab140637063a Mon Sep 17 00:00:00 2001 -From: Pierre-jean Texier -Date: Wed, 6 Nov 2019 10:00:43 +0100 -Subject: [PATCH] overlays: smi: fix typo in comment (#3320) - -5 represent alt1 function not alt0. - -Signed-off-by: Pierre-Jean Texier ---- - arch/arm/boot/dts/overlays/smi-overlay.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/smi-overlay.dts -+++ b/arch/arm/boot/dts/overlays/smi-overlay.dts -@@ -24,7 +24,7 @@ - these are already used as ID_SD and ID_SC */ - brcm,pins = <2 3 4 5 6 7 8 9 10 11 12 13 14 15 - 16 17 18 19 20 21 22 23 24 25>; -- /* Alt 0: SMI */ -+ /* Alt 1: SMI */ - brcm,function = <5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - 5 5 5 5 5 5 5 5 5>; - /* /CS, /WE and /OE are pulled high, as they are diff --git a/target/linux/bcm27xx/patches-5.4/950-0345-net-phy-2711-Change-the-default-ethernet-LED-actions.patch b/target/linux/bcm27xx/patches-5.4/950-0345-net-phy-2711-Change-the-default-ethernet-LED-actions.patch deleted file mode 100644 index d76fd0ec0d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0345-net-phy-2711-Change-the-default-ethernet-LED-actions.patch +++ /dev/null @@ -1,33 +0,0 @@ -From e459a2c448d7d71718769a9966543a964d1803bd Mon Sep 17 00:00:00 2001 -From: James Hughes -Date: Thu, 7 Nov 2019 14:59:59 +0000 -Subject: [PATCH] net:phy:2711 Change the default ethernet LED actions - -This should return default behaviour back to that of previous -releases. ---- - drivers/net/phy/broadcom.c | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - ---- a/drivers/net/phy/broadcom.c -+++ b/drivers/net/phy/broadcom.c -@@ -268,7 +268,7 @@ static int bcm54xx_config_init(struct ph - { - int reg, err, val; - u32 led_modes[] = {BCM_LED_MULTICOLOR_LINK_ACT, -- BCM_LED_MULTICOLOR_LINK_ACT}; -+ BCM_LED_MULTICOLOR_LINK}; - struct device_node *np = phydev->mdio.dev.of_node; - - reg = phy_read(phydev, MII_BCM54XX_ECR); -@@ -323,10 +323,6 @@ static int bcm54xx_config_init(struct ph - - of_property_read_u32_array(np, "led-modes", led_modes, 2); - -- /* Encode link speed into LED1 and LED3 pair (green/amber). -- * Also flash these two LEDs on activity. This means configuring -- * them for MULTICOLOR and encoding link/activity into them. -- */ - val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | - BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); - bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); diff --git a/target/linux/bcm27xx/patches-5.4/950-0345-v3d_drv-Handle-missing-clock-more-gracefully.patch b/target/linux/bcm27xx/patches-5.4/950-0345-v3d_drv-Handle-missing-clock-more-gracefully.patch new file mode 100644 index 0000000000..812d6f1311 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0345-v3d_drv-Handle-missing-clock-more-gracefully.patch @@ -0,0 +1,25 @@ +From 43406ddc1adaebe9b03d010fd024a96cee139cc2 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 23 Aug 2019 16:34:38 +0100 +Subject: [PATCH] v3d_drv: Handle missing clock more gracefully + +Signed-off-by: popcornmix +--- + drivers/gpu/drm/v3d/v3d_drv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -286,9 +286,9 @@ static int v3d_platform_drm_probe(struct + } + + v3d->clk = devm_clk_get(dev, NULL); +- if (IS_ERR(v3d->clk)) { +- if (ret != -EPROBE_DEFER) +- dev_err(dev, "Failed to get clock\n"); ++ if (IS_ERR_OR_NULL(v3d->clk)) { ++ if (PTR_ERR(v3d->clk) != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk)); + goto dev_free; + } + v3d->clk_up_rate = clk_get_rate(v3d->clk); diff --git a/target/linux/bcm27xx/patches-5.4/950-0346-overlays-Add-apds9960-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0346-overlays-Add-apds9960-overlay.patch deleted file mode 100644 index f0f5368076..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0346-overlays-Add-apds9960-overlay.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 62cd48ebf18c1eb0bbddba080476201bdfae4126 Mon Sep 17 00:00:00 2001 -From: Michael Kaplan -Date: Fri, 8 Nov 2019 10:35:57 +0100 -Subject: [PATCH] overlays: Add apds9960 overlay - -Add an overlay for the AVAGO APDS9960 digital proximity, ambient light, rgb and gesture sensor. -Also update overlay README and Makefile. - -Signed-off-by: Michael Kaplan ---- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 8 +++ - .../boot/dts/overlays/apds9960-overlay.dts | 57 +++++++++++++++++++ - 3 files changed, 66 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/apds9960-overlay.dts - ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - allo-katana-dac-audio.dtbo \ - allo-piano-dac-pcm512x-audio.dtbo \ - allo-piano-dac-plus-pcm512x-audio.dtbo \ -+ apds9960.dtbo \ - applepi-dac.dtbo \ - at86rf233.dtbo \ - audioinjector-addons.dtbo \ ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -441,6 +441,14 @@ Params: 24db_digital_gain Allow ga - better voice quality. (default Off) - - -+Name: apds9960 -+Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and -+ gesture sensor -+Load: dtoverlay=apds9960,= -+Params: gpiopin GPIO used for INT (default 4) -+ noints Disable the interrupt GPIO line. -+ -+ - Name: applepi-dac - Info: Configures the Orchard Audio ApplePi-DAC audio card - Load: dtoverlay=applepi-dac ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/apds9960-overlay.dts -@@ -0,0 +1,57 @@ -+// Definitions for APDS-9960 ambient light and gesture sensor -+ -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&i2c1>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&gpio>; -+ __overlay__ { -+ apds9960_pins: apds9960_pins@39 { -+ brcm,pins = <4>; -+ brcm,function = <0>; -+ }; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&i2c1>; -+ __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ apds9960: apds@39 { -+ compatible = "avago,apds9960"; -+ reg = <0x39>; -+ status = "okay"; -+ }; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&i2c1>; -+ __overlay__ { -+ apds9960_irq: apds@39 { -+ #interrupt-cells=<2>; -+ interrupt-parent = <&gpio>; -+ interrupts = <4 1>; -+ }; -+ }; -+ }; -+ -+ __overrides__ { -+ gpiopin = <&apds9960_pins>,"brcm,pins:0", -+ <&apds9960_irq>,"interrupts:0"; -+ noints = <0>,"!1!3"; -+ }; -+}; -+ diff --git a/target/linux/bcm27xx/patches-5.4/950-0346-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch b/target/linux/bcm27xx/patches-5.4/950-0346-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch new file mode 100644 index 0000000000..1892a145fa --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0346-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch @@ -0,0 +1,27 @@ +From dfc842c139ef08e21647c43c19c2a23090b65b27 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 5 Sep 2019 17:59:14 +0100 +Subject: [PATCH] v3d_gem: Kick the clock so firmware knows we are + using firmware clock interface + +Setting the v3d clock to low value allows firmware to handle dvfs in case +where v3d hardware is not being actively used (e.g. console use). + +Signed-off-by: popcornmix +--- + drivers/gpu/drm/v3d/v3d_gem.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -918,6 +918,10 @@ v3d_gem_init(struct drm_device *dev) + mutex_init(&v3d->clk_lock); + INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work); + ++ /* kick the clock so firmware knows we are using firmware clock interface */ ++ v3d_clock_up_get(v3d); ++ v3d_clock_up_put(v3d); ++ + /* Note: We don't allocate address 0. Various bits of HW + * treat 0 as special, such as the occlusion query counters + * where 0 means "disabled". diff --git a/target/linux/bcm27xx/patches-5.4/950-0347-clk-bcm2835-Disable-v3d-clock.patch b/target/linux/bcm27xx/patches-5.4/950-0347-clk-bcm2835-Disable-v3d-clock.patch new file mode 100644 index 0000000000..a7a5221fab --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0347-clk-bcm2835-Disable-v3d-clock.patch @@ -0,0 +1,58 @@ +From 6c37f43308f29a59bc67d4ed010f8fbbf076ec79 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 3 Sep 2019 20:28:00 +0100 +Subject: [PATCH] clk-bcm2835: Disable v3d clock + +This is controlled by firmware, see clk-raspberrypi.c + +Signed-off-by: popcornmix +--- + drivers/clk/bcm/clk-bcm2835.c | 30 ++++++++++++------------------ + 1 file changed, 12 insertions(+), 18 deletions(-) + +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -1734,16 +1734,12 @@ static const struct bcm2835_clk_desc clk + .hold_mask = CM_PLLA_HOLDCORE, + .fixed_divider = 1, + .flags = CLK_SET_RATE_PARENT), +- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( +- SOC_ALL, +- .name = "plla_per", +- .source_pll = "plla", +- .cm_reg = CM_PLLA, +- .a2w_reg = A2W_PLLA_PER, +- .load_mask = CM_PLLA_LOADPER, +- .hold_mask = CM_PLLA_HOLDPER, +- .fixed_divider = 1, +- .flags = CLK_SET_RATE_PARENT), ++ ++ /* ++ * PLLA_PER is used for gpu clocks. Controlled by firmware, see ++ * clk-raspberrypi.c. ++ */ ++ + [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( + SOC_ALL, + .name = "plla_dsi0", +@@ -2021,14 +2017,12 @@ static const struct bcm2835_clk_desc clk + .int_bits = 6, + .frac_bits = 0, + .tcnt_mux = 3), +- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( +- SOC_ALL, +- .name = "v3d", +- .ctl_reg = CM_V3DCTL, +- .div_reg = CM_V3DDIV, +- .int_bits = 4, +- .frac_bits = 8, +- .tcnt_mux = 4), ++ ++ /* ++ * CLOCK_V3D is used for v3d clock. Controlled by firmware, see ++ * clk-raspberrypi.c. ++ */ ++ + /* + * VPU clock. This doesn't have an enable bit, since it drives + * the bus for everything else, and is special so it doesn't need diff --git a/target/linux/bcm27xx/patches-5.4/950-0347-overlays-Remove-hack-from-uart0-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0347-overlays-Remove-hack-from-uart0-overlay.patch deleted file mode 100644 index ac70b35413..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0347-overlays-Remove-hack-from-uart0-overlay.patch +++ /dev/null @@ -1,45 +0,0 @@ -From d24bb9c4b5d3b0bb2bd5dd922bae3fce894ab87e Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 1 Oct 2019 10:19:50 +0100 -Subject: [PATCH] overlays: Remove hack from uart0 overlay - -The uart0 overlay contained a hack to return GPIOs 14 and 15 to inputs -when the UART0 function was moved to alternative pins. This has the -unwanted side effect of claiming GPIOs 14 & 15, preventing them being -used for something else. - -See: https://github.com/raspberrypi/linux/issues/2856 - https://www.raspberrypi.org/forums/viewtopic.php?f=98&t=252911 - -Signed-off-by: Stefan Enge -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/uart0-overlay.dts | 13 ++++++------- - 1 file changed, 6 insertions(+), 7 deletions(-) - ---- a/arch/arm/boot/dts/overlays/uart0-overlay.dts -+++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts -@@ -17,17 +17,16 @@ - target = <&gpio>; - __overlay__ { - uart0_pins: uart0_pins { -- brcm,pins = <14 15 14 15>; -- brcm,function = <0 0 4 4>; /* alt0 */ -- brcm,pull = <0 0 0 2>; -+ brcm,pins = <14 15>; -+ brcm,function = <4>; /* alt0 */ -+ brcm,pull = <0 2>; - }; - }; - }; - - __overrides__ { -- txd0_pin = <&uart0_pins>,"brcm,pins:8"; -- rxd0_pin = <&uart0_pins>,"brcm,pins:12"; -- pin_func = <&uart0_pins>,"brcm,function:8", -- <&uart0_pins>,"brcm,function:12"; -+ txd0_pin = <&uart0_pins>,"brcm,pins:0"; -+ rxd0_pin = <&uart0_pins>,"brcm,pins:4"; -+ pin_func = <&uart0_pins>,"brcm,function:0"; - }; - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0348-arm-dts-Correct-Pi-4B-LED-values.patch b/target/linux/bcm27xx/patches-5.4/950-0348-arm-dts-Correct-Pi-4B-LED-values.patch new file mode 100644 index 0000000000..a3bae521e7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0348-arm-dts-Correct-Pi-4B-LED-values.patch @@ -0,0 +1,39 @@ +From 4768e4d0e87e5814d3f315f7a575cad123fc2e36 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 22 Nov 2019 15:08:25 +0000 +Subject: [PATCH] arm/dts: Correct Pi 4B LED values + +The initial PHY LED settings are wrong Pi 4B (the correct values got +dropped somewhere along the way). The PHY declaration should arguably +go in a separate file included by bcm2711-rpi-4-b.dts, but we can +fix that as we switch over to using more of the upstream BCM2711 +support in 5.4 and later. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2838.dtsi | 2 +- + arch/arm/boot/dts/overlays/README | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -380,7 +380,7 @@ + /* No interrupts - use PHY_POLL */ + max-speed = <1000>; + reg = <0x1>; +- led-modes = <0x02 0x02>; ++ led-modes = <0x00 0x08>; /* link/activity link */ + }; + }; + }; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -128,7 +128,7 @@ Params: + 8=Link 9=Activity + + eth_led1 Set mode of LED1 (usually green) (Pi3B+ default +- "6", Pi4 default "0"). See eth_led0 for legal ++ "6", Pi4 default "8"). See eth_led0 for legal + values. + + eth_max_speed Set the maximum speed a link is allowed diff --git a/target/linux/bcm27xx/patches-5.4/950-0348-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch b/target/linux/bcm27xx/patches-5.4/950-0348-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch deleted file mode 100644 index ba19abb895..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0348-arm-dts-overlays-pitft35-resistive-add-upstream-comp.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 47a9af99289ef0b9d60a72cd7147958e4745468c Mon Sep 17 00:00:00 2001 -From: Peter Robinson -Date: Sun, 17 Nov 2019 16:20:24 +0000 -Subject: [PATCH] arm: dts: overlays: pitft35-resistive: add upstream - compatible - -The upstream hx8357d driver uses "adafruit,yx350hv15" for the compatible -string explicitly for this screen config and not a hx8357d generic for -the controller so add that in as well so it will work with an unmodified -upstream kernel driver. We leave the downstream as the priority. - -Signed-off-by: Peter Robinson ---- - arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts -+++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts -@@ -49,7 +49,7 @@ - #size-cells = <0>; - - pitft: pitft@0{ -- compatible = "himax,hx8357d"; -+ compatible = "himax,hx8357d", "adafruit,yx350hv15"; - reg = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&pitft_pins>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0349-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch b/target/linux/bcm27xx/patches-5.4/950-0349-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch new file mode 100644 index 0000000000..67cdd44f29 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0349-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch @@ -0,0 +1,27 @@ +From 159ccf0090f202cf031fa429df22e8b3f775ece8 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 22 Nov 2019 16:23:32 +0000 +Subject: [PATCH] drm/v3d: Set dma_mask as well as coherent_dma_mask + +Both coherent_dma_mask and dma_mask act as constraints on allocations +and bounce buffer usage, so be sure to set dma_mask to the appropriate +value otherwise the effective mask could be incorrect. + +Signed-off-by: Phil Elwell +--- + drivers/gpu/drm/v3d/v3d_drv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/v3d/v3d_drv.c ++++ b/drivers/gpu/drm/v3d/v3d_drv.c +@@ -259,8 +259,8 @@ static int v3d_platform_drm_probe(struct + goto dev_free; + + mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); +- dev->coherent_dma_mask = +- DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); ++ dma_set_mask_and_coherent(dev, ++ DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH))); + v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); + + ident1 = V3D_READ(V3D_HUB_IDENT1); diff --git a/target/linux/bcm27xx/patches-5.4/950-0349-v3d_drv-Handle-missing-clock-more-gracefully.patch b/target/linux/bcm27xx/patches-5.4/950-0349-v3d_drv-Handle-missing-clock-more-gracefully.patch deleted file mode 100644 index 812d6f1311..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0349-v3d_drv-Handle-missing-clock-more-gracefully.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 43406ddc1adaebe9b03d010fd024a96cee139cc2 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 23 Aug 2019 16:34:38 +0100 -Subject: [PATCH] v3d_drv: Handle missing clock more gracefully - -Signed-off-by: popcornmix ---- - drivers/gpu/drm/v3d/v3d_drv.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -286,9 +286,9 @@ static int v3d_platform_drm_probe(struct - } - - v3d->clk = devm_clk_get(dev, NULL); -- if (IS_ERR(v3d->clk)) { -- if (ret != -EPROBE_DEFER) -- dev_err(dev, "Failed to get clock\n"); -+ if (IS_ERR_OR_NULL(v3d->clk)) { -+ if (PTR_ERR(v3d->clk) != -EPROBE_DEFER) -+ dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk)); - goto dev_free; - } - v3d->clk_up_rate = clk_get_rate(v3d->clk); diff --git a/target/linux/bcm27xx/patches-5.4/950-0350-arm-dts-2711-Add-pcie0-alias.patch b/target/linux/bcm27xx/patches-5.4/950-0350-arm-dts-2711-Add-pcie0-alias.patch new file mode 100644 index 0000000000..fa00fb1974 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0350-arm-dts-2711-Add-pcie0-alias.patch @@ -0,0 +1,24 @@ +From ea94fb0b5693c354e5281eb3fcdbc9700cdd3d7f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 28 Nov 2019 15:49:08 +0000 +Subject: [PATCH] arm/dts: 2711: Add 'pcie0' alias + +It is useful for the firmware to be able to locate the pcie DT node, +so add an alias pointing to it in the same way that "ethernet0" +points to the genet. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -30,6 +30,7 @@ + /delete-property/ ethernet; + /delete-property/ intc; + ethernet0 = &genet; ++ pcie0 = &pcie_0; + }; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0350-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch b/target/linux/bcm27xx/patches-5.4/950-0350-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch deleted file mode 100644 index 1892a145fa..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0350-v3d_gem-Kick-the-clock-so-firmware-knows-we-are-usin.patch +++ /dev/null @@ -1,27 +0,0 @@ -From dfc842c139ef08e21647c43c19c2a23090b65b27 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 5 Sep 2019 17:59:14 +0100 -Subject: [PATCH] v3d_gem: Kick the clock so firmware knows we are - using firmware clock interface - -Setting the v3d clock to low value allows firmware to handle dvfs in case -where v3d hardware is not being actively used (e.g. console use). - -Signed-off-by: popcornmix ---- - drivers/gpu/drm/v3d/v3d_gem.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/gpu/drm/v3d/v3d_gem.c -+++ b/drivers/gpu/drm/v3d/v3d_gem.c -@@ -918,6 +918,10 @@ v3d_gem_init(struct drm_device *dev) - mutex_init(&v3d->clk_lock); - INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work); - -+ /* kick the clock so firmware knows we are using firmware clock interface */ -+ v3d_clock_up_get(v3d); -+ v3d_clock_up_put(v3d); -+ - /* Note: We don't allocate address 0. Various bits of HW - * treat 0 as special, such as the occlusion query counters - * where 0 means "disabled". diff --git a/target/linux/bcm27xx/patches-5.4/950-0351-clk-bcm2835-Disable-v3d-clock.patch b/target/linux/bcm27xx/patches-5.4/950-0351-clk-bcm2835-Disable-v3d-clock.patch deleted file mode 100644 index a7a5221fab..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0351-clk-bcm2835-Disable-v3d-clock.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 6c37f43308f29a59bc67d4ed010f8fbbf076ec79 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 3 Sep 2019 20:28:00 +0100 -Subject: [PATCH] clk-bcm2835: Disable v3d clock - -This is controlled by firmware, see clk-raspberrypi.c - -Signed-off-by: popcornmix ---- - drivers/clk/bcm/clk-bcm2835.c | 30 ++++++++++++------------------ - 1 file changed, 12 insertions(+), 18 deletions(-) - ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -1734,16 +1734,12 @@ static const struct bcm2835_clk_desc clk - .hold_mask = CM_PLLA_HOLDCORE, - .fixed_divider = 1, - .flags = CLK_SET_RATE_PARENT), -- [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( -- SOC_ALL, -- .name = "plla_per", -- .source_pll = "plla", -- .cm_reg = CM_PLLA, -- .a2w_reg = A2W_PLLA_PER, -- .load_mask = CM_PLLA_LOADPER, -- .hold_mask = CM_PLLA_HOLDPER, -- .fixed_divider = 1, -- .flags = CLK_SET_RATE_PARENT), -+ -+ /* -+ * PLLA_PER is used for gpu clocks. Controlled by firmware, see -+ * clk-raspberrypi.c. -+ */ -+ - [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( - SOC_ALL, - .name = "plla_dsi0", -@@ -2021,14 +2017,12 @@ static const struct bcm2835_clk_desc clk - .int_bits = 6, - .frac_bits = 0, - .tcnt_mux = 3), -- [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( -- SOC_ALL, -- .name = "v3d", -- .ctl_reg = CM_V3DCTL, -- .div_reg = CM_V3DDIV, -- .int_bits = 4, -- .frac_bits = 8, -- .tcnt_mux = 4), -+ -+ /* -+ * CLOCK_V3D is used for v3d clock. Controlled by firmware, see -+ * clk-raspberrypi.c. -+ */ -+ - /* - * VPU clock. This doesn't have an enable bit, since it drives - * the bus for everything else, and is special so it doesn't need diff --git a/target/linux/bcm27xx/patches-5.4/950-0351-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch b/target/linux/bcm27xx/patches-5.4/950-0351-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch new file mode 100644 index 0000000000..61f49d5ae4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0351-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch @@ -0,0 +1,123 @@ +From 01f45f7d4403e40f28f626296bec3ccae1b1f65b Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sat, 30 Nov 2019 23:10:26 +0100 +Subject: [PATCH] rpi-cirrus-wm5102-overlay: fix pinctrl configuration + +Separate GPIOs connected to wm5102 and wm8804 into 2 pinctrl +blocks and properly reference them from the DT nodes to have +correct pinmux owners. + +Setup spi0 to use only one CS line on GPIO7 so that GPIO8 is +no longer claimed by spi0 but can be used by wm8804. + +Signed-off-by: Matthias Reichl +--- + .../overlays/rpi-cirrus-wm5102-overlay.dts | 40 ++++++++++++++----- + 1 file changed, 30 insertions(+), 10 deletions(-) + +--- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts +@@ -18,19 +18,31 @@ + fragment@1 { + target = <&gpio>; + __overlay__ { +- wlf_pins: wlf_pins { +- brcm,pins = <17 22 27 8>; ++ wlf_5102_pins: wlf_5102_pins { ++ brcm,pins = <17 22 27>; + brcm,function = < + BCM2835_FSEL_GPIO_OUT + BCM2835_FSEL_GPIO_OUT + BCM2835_FSEL_GPIO_IN +- BCM2835_FSEL_GPIO_OUT + >; + }; ++ wlf_8804_pins: wlf_8804_pins { ++ brcm,pins = <8>; ++ brcm,function = ; ++ }; + }; + }; + + fragment@2 { ++ target = <&spi0_cs_pins>; ++ __overlay__ { ++ brcm,pins = <7>; ++ brcm,function = ; ++ }; ++ }; ++ ++ ++ fragment@3 { + target-path = "/"; + __overlay__ { + rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 { +@@ -43,30 +55,34 @@ + }; + }; + +- fragment@3 { ++ fragment@4 { + target = <&spidev0>; + __overlay__ { + status = "disabled"; + }; + }; + +- fragment@4 { ++ fragment@5 { + target = <&spidev1>; + __overlay__ { + status = "disabled"; + }; + }; + +- fragment@5 { ++ fragment@6 { + target = <&spi0>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; ++ cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; + +- wm5102@1{ ++ wm5102@0{ + compatible = "wlf,wm5102"; +- reg = <1>; ++ reg = <0>; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wlf_5102_pins>; + + spi-max-frequency = <500000>; + +@@ -123,7 +139,7 @@ + }; + }; + +- fragment@6 { ++ fragment@7 { + target = <&i2c1>; + __overlay__ { + status = "okay"; +@@ -134,6 +150,10 @@ + compatible = "wlf,wm8804"; + reg = <0x3b>; + status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wlf_8804_pins>; ++ + PVDD-supply = <&vdd_3v3_reg>; + DVDD-supply = <&vdd_3v3_reg>; + wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>; +@@ -141,7 +161,7 @@ + }; + }; + +- fragment@7 { ++ fragment@8 { + target = <&sound>; + __overlay__ { + compatible = "wlf,rpi-cirrus"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0352-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch b/target/linux/bcm27xx/patches-5.4/950-0352-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch deleted file mode 100644 index 192b13b69a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0352-raspberrypi-cpufreq-Only-report-integer-pll-divisor-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 814af1a008845b61a08111f2f9cf7e66511ab362 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 13 Sep 2019 13:45:11 +0100 -Subject: [PATCH] raspberrypi-cpufreq: Only report integer pll divisor - frequencies - ---- - drivers/cpufreq/raspberrypi-cpufreq.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - ---- a/drivers/cpufreq/raspberrypi-cpufreq.c -+++ b/drivers/cpufreq/raspberrypi-cpufreq.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -22,6 +23,7 @@ static int raspberrypi_cpufreq_probe(str - unsigned long min, max; - unsigned long rate; - struct clk *clk; -+ int div; - int ret; - - cpu_dev = get_cpu_device(0); -@@ -44,7 +46,10 @@ static int raspberrypi_cpufreq_probe(str - max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL); - clk_put(clk); - -- for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) { -+ for (div = 2; ; div++) { -+ rate = div_u64((u64)max * 2, div); -+ if (rate < min) -+ break; - ret = dev_pm_opp_add(cpu_dev, rate, 0); - if (ret) - goto remove_opp; diff --git a/target/linux/bcm27xx/patches-5.4/950-0352-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch b/target/linux/bcm27xx/patches-5.4/950-0352-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch new file mode 100644 index 0000000000..0a6660b893 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0352-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch @@ -0,0 +1,33 @@ +From a9b691174273348a6818213b9f008ae555e1c98c Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 29 Jan 2019 16:13:25 +0000 +Subject: [PATCH] staging: vchiq_arm: Set up dma ranges on child + devices + +The VCHIQ driver now loads the audio, camera, codec, and vc-sm +drivers as platform drivers. However they were not being given +the correct DMA configuration. + +Call of_dma_configure with the parent (VCHIQ) parameters to be +inherited by the child. + +Signed-off-by: Dave Stevenson +--- + .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -3195,6 +3195,12 @@ vchiq_register_child(struct platform_dev + child = NULL; + } + ++ /* ++ * We want the dma-ranges etc to be copied from the parent VCHIQ device ++ * to be passed on to the children too. ++ */ ++ of_dma_configure(&new_dev->dev, pdev->dev.of_node, true); ++ + return child; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0353-arm-dts-Correct-Pi-4B-LED-values.patch b/target/linux/bcm27xx/patches-5.4/950-0353-arm-dts-Correct-Pi-4B-LED-values.patch deleted file mode 100644 index a3bae521e7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0353-arm-dts-Correct-Pi-4B-LED-values.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 4768e4d0e87e5814d3f315f7a575cad123fc2e36 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 22 Nov 2019 15:08:25 +0000 -Subject: [PATCH] arm/dts: Correct Pi 4B LED values - -The initial PHY LED settings are wrong Pi 4B (the correct values got -dropped somewhere along the way). The PHY declaration should arguably -go in a separate file included by bcm2711-rpi-4-b.dts, but we can -fix that as we switch over to using more of the upstream BCM2711 -support in 5.4 and later. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2838.dtsi | 2 +- - arch/arm/boot/dts/overlays/README | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -380,7 +380,7 @@ - /* No interrupts - use PHY_POLL */ - max-speed = <1000>; - reg = <0x1>; -- led-modes = <0x02 0x02>; -+ led-modes = <0x00 0x08>; /* link/activity link */ - }; - }; - }; ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -128,7 +128,7 @@ Params: - 8=Link 9=Activity - - eth_led1 Set mode of LED1 (usually green) (Pi3B+ default -- "6", Pi4 default "0"). See eth_led0 for legal -+ "6", Pi4 default "8"). See eth_led0 for legal - values. - - eth_max_speed Set the maximum speed a link is allowed diff --git a/target/linux/bcm27xx/patches-5.4/950-0353-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch b/target/linux/bcm27xx/patches-5.4/950-0353-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch new file mode 100644 index 0000000000..eb35a81023 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0353-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch @@ -0,0 +1,51 @@ +From 6aa74a52e014952b1a144def670a03a7deb0e112 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 18 Jun 2019 12:15:50 +0100 +Subject: [PATCH] staging: vchiq: Use the old dma controller for OF + config on platform devices + +vchiq on Pi4 is no longer under the soc node, therefore it +doesn't get the dma-ranges for the VPU. + +Switch to using the configuration of the old dma controller as +that will set the dma-ranges correctly. + +Signed-off-by: Dave Stevenson +--- + .../interface/vchiq_arm/vchiq_arm.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -3181,6 +3181,7 @@ vchiq_register_child(struct platform_dev + { + struct platform_device_info pdevinfo; + struct platform_device *child; ++ struct device_node *np; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + +@@ -3196,10 +3197,20 @@ vchiq_register_child(struct platform_dev + } + + /* +- * We want the dma-ranges etc to be copied from the parent VCHIQ device +- * to be passed on to the children too. ++ * We want the dma-ranges etc to be copied from a device with the ++ * correct dma-ranges for the VPU. ++ * VCHIQ on Pi4 is now under scb which doesn't get those dma-ranges. ++ * Take the "dma" node as going to be suitable as it sees the world ++ * through the same eyes as the VPU. + */ +- of_dma_configure(&new_dev->dev, pdev->dev.of_node, true); ++ np = of_find_node_by_path("dma"); ++ if (!np) ++ np = pdev->dev.of_node; ++ ++ of_dma_configure(&child->dev, np, true); ++ ++ if (np != pdev->dev.of_node) ++ of_node_put(np); + + return child; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0354-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch b/target/linux/bcm27xx/patches-5.4/950-0354-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch deleted file mode 100644 index 67cdd44f29..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0354-drm-v3d-Set-dma_mask-as-well-as-coherent_dma_mask.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 159ccf0090f202cf031fa429df22e8b3f775ece8 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 22 Nov 2019 16:23:32 +0000 -Subject: [PATCH] drm/v3d: Set dma_mask as well as coherent_dma_mask - -Both coherent_dma_mask and dma_mask act as constraints on allocations -and bounce buffer usage, so be sure to set dma_mask to the appropriate -value otherwise the effective mask could be incorrect. - -Signed-off-by: Phil Elwell ---- - drivers/gpu/drm/v3d/v3d_drv.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/gpu/drm/v3d/v3d_drv.c -+++ b/drivers/gpu/drm/v3d/v3d_drv.c -@@ -259,8 +259,8 @@ static int v3d_platform_drm_probe(struct - goto dev_free; - - mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); -- dev->coherent_dma_mask = -- DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); -+ dma_set_mask_and_coherent(dev, -+ DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH))); - v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); - - ident1 = V3D_READ(V3D_HUB_IDENT1); diff --git a/target/linux/bcm27xx/patches-5.4/950-0354-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch b/target/linux/bcm27xx/patches-5.4/950-0354-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch new file mode 100644 index 0000000000..3bc9abde27 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0354-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch @@ -0,0 +1,59 @@ +From 271a9dfee2eb426ca9ec1ef51c6205de8496b803 Mon Sep 17 00:00:00 2001 +From: Hui Wang +Date: Sun, 17 Nov 2019 10:31:46 +0800 +Subject: [PATCH] dwc_otg: checking the urb->transfer_buffer too early + (#3332) + +After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't +work well on Pi2/3 boards with 1G physical ram. Users experience +the failure when copying a file of 600M size to the USB stick. And +at the same time, the dmesg shows: +usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg +sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK +blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0 + +When this happens, the sg_buf sent to the driver is located in the +highmem region, the usb_sg_init() in the core/message.c will leave +transfer_buffer to NULL if the sg_buf is in highmem, but in the +dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer +is NULL. + +The driver can handle the situation of buffer to be NULL, if it is in +DMA mode, it will convert an address from transfer_dma. + +But if the conversion fails or it is in the PIO mode, we should check +buffer and return -EINVAL if it is NULL. + +BugLink: https://bugs.launchpad.net/bugs/1852510 +Signed-off-by: Hui Wang +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +@@ -782,10 +782,6 @@ static int dwc_otg_urb_enqueue(struct us + dump_urb_info(urb, "dwc_otg_urb_enqueue"); + } + #endif +- +- if (!urb->transfer_buffer && urb->transfer_buffer_length) +- return -EINVAL; +- + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { + if (!dwc_otg_hcd_is_bandwidth_allocated +@@ -842,6 +838,13 @@ static int dwc_otg_urb_enqueue(struct us + &urb->transfer_dma, buf); + } + ++ if (!buf && urb->transfer_buffer_length) { ++ DWC_FREE(dwc_otg_urb); ++ DWC_ERROR("transfer_buffer is NULL in PIO mode or both " ++ "transfer_buffer and transfer_dma are NULL in DMA mode\n"); ++ return -EINVAL; ++ } ++ + if (!(urb->transfer_flags & URB_NO_INTERRUPT)) + flags |= URB_GIVEBACK_ASAP; + if (urb->transfer_flags & URB_ZERO_PACKET) diff --git a/target/linux/bcm27xx/patches-5.4/950-0355-arm-dts-2711-Add-pcie0-alias.patch b/target/linux/bcm27xx/patches-5.4/950-0355-arm-dts-2711-Add-pcie0-alias.patch deleted file mode 100644 index fa00fb1974..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0355-arm-dts-2711-Add-pcie0-alias.patch +++ /dev/null @@ -1,24 +0,0 @@ -From ea94fb0b5693c354e5281eb3fcdbc9700cdd3d7f Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 28 Nov 2019 15:49:08 +0000 -Subject: [PATCH] arm/dts: 2711: Add 'pcie0' alias - -It is useful for the firmware to be able to locate the pcie DT node, -so add an alias pointing to it in the same way that "ethernet0" -points to the genet. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 1 + - 1 file changed, 1 insertion(+) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -30,6 +30,7 @@ - /delete-property/ ethernet; - /delete-property/ intc; - ethernet0 = &genet; -+ pcie0 = &pcie_0; - }; - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0355-overlays-Make-mcp342x-run-time-compatible.patch b/target/linux/bcm27xx/patches-5.4/950-0355-overlays-Make-mcp342x-run-time-compatible.patch new file mode 100644 index 0000000000..1b4809db0d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0355-overlays-Make-mcp342x-run-time-compatible.patch @@ -0,0 +1,209 @@ +From 00f01136b1c165e0f4a190fcb5ec8aa11428362f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 9 Dec 2019 12:32:20 +0000 +Subject: [PATCH] overlays: Make mcp342x run-time compatible + +The order of processing of run-time overlays differs from that done by +the firmware. This means that certain parameter processing techniques +are not compatible with run-time use. The mcp342x overlay is one such +overlay, but it is easy to change the implementation without changing +the interface. + +See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=258294 + +Signed-off-by: Phil Elwell +--- + .../arm/boot/dts/overlays/mcp342x-overlay.dts | 133 ++++++++++++++---- + 1 file changed, 102 insertions(+), 31 deletions(-) + +--- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts +@@ -8,14 +8,15 @@ + + fragment@0 { + target = <&i2c1>; +- __overlay__ { ++ __dormant__ { + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + +- mcp342x: mcp@68 { ++ mcp3421: mcp@68 { + reg = <0x68>; ++ compatible = "microchip,mcp3421"; + + status = "okay"; + }; +@@ -23,71 +24,141 @@ + }; + + fragment@1 { +- target = <&mcp342x>; ++ target = <&i2c1>; + __dormant__ { +- compatible = "microchip,mcp3421"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ mcp3422: mcp@68 { ++ reg = <0x68>; ++ compatible = "microchip,mcp3422"; ++ ++ status = "okay"; ++ }; + }; + }; + + fragment@2 { +- target = <&mcp342x>; ++ target = <&i2c1>; + __dormant__ { +- compatible = "microchip,mcp3422"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ mcp3423: mcp@68 { ++ reg = <0x68>; ++ compatible = "microchip,mcp3423"; ++ ++ status = "okay"; ++ }; + }; + }; + + fragment@3 { +- target = <&mcp342x>; ++ target = <&i2c1>; + __dormant__ { +- compatible = "microchip,mcp3423"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ mcp3424: mcp@68 { ++ reg = <0x68>; ++ compatible = "microchip,mcp3424"; ++ ++ status = "okay"; ++ }; + }; + }; + + fragment@4 { +- target = <&mcp342x>; ++ target = <&i2c1>; + __dormant__ { +- compatible = "microchip,mcp3424"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ mcp3425: mcp@68 { ++ reg = <0x68>; ++ compatible = "microchip,mcp3425","mcp3425"; ++ ++ status = "okay"; ++ }; + }; + }; + + fragment@5 { +- target = <&mcp342x>; ++ target = <&i2c1>; + __dormant__ { +- compatible = "microchip,mcp3425"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ mcp3426: mcp@68 { ++ reg = <0x68>; ++ compatible = "microchip,mcp3426"; ++ ++ status = "okay"; ++ }; + }; + }; + + fragment@6 { +- target = <&mcp342x>; ++ target = <&i2c1>; + __dormant__ { +- compatible = "microchip,mcp3426"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ mcp3427: mcp@68 { ++ reg = <0x68>; ++ compatible = "microchip,mcp3427"; ++ ++ status = "okay"; ++ }; + }; + }; + + fragment@7 { +- target = <&mcp342x>; ++ target = <&i2c1>; + __dormant__ { +- compatible = "microchip,mcp3427"; +- }; +- }; ++ #address-cells = <1>; ++ #size-cells = <0>; + +- fragment@8 { +- target = <&mcp342x>; +- __dormant__ { +- compatible = "microchip,mcp3428"; ++ status = "okay"; ++ ++ mcp3428: mcp@68 { ++ reg = <0x68>; ++ compatible = "microchip,mcp3428"; ++ ++ status = "okay"; ++ }; + }; + }; + + __overrides__ { +- addr = <&mcp342x>,"reg:0"; +- mcp3421 = <0>,"=1"; +- mcp3422 = <0>,"=2"; +- mcp3423 = <0>,"=3"; +- mcp3424 = <0>,"=4"; +- mcp3425 = <0>,"=5"; +- mcp3426 = <0>,"=6"; +- mcp3427 = <0>,"=7"; +- mcp3428 = <0>,"=8"; ++ addr = <&mcp3421>,"reg:0", ++ <&mcp3422>,"reg:0", ++ <&mcp3423>,"reg:0", ++ <&mcp3424>,"reg:0", ++ <&mcp3425>,"reg:0", ++ <&mcp3426>,"reg:0", ++ <&mcp3427>,"reg:0", ++ <&mcp3428>,"reg:0"; ++ mcp3421 = <0>,"=0"; ++ mcp3422 = <0>,"=1"; ++ mcp3423 = <0>,"=2"; ++ mcp3424 = <0>,"=3"; ++ mcp3425 = <0>,"=4"; ++ mcp3426 = <0>,"=5"; ++ mcp3427 = <0>,"=6"; ++ mcp3428 = <0>,"=7"; + }; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0356-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch b/target/linux/bcm27xx/patches-5.4/950-0356-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch deleted file mode 100644 index 61f49d5ae4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0356-rpi-cirrus-wm5102-overlay-fix-pinctrl-configuration.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 01f45f7d4403e40f28f626296bec3ccae1b1f65b Mon Sep 17 00:00:00 2001 -From: Matthias Reichl -Date: Sat, 30 Nov 2019 23:10:26 +0100 -Subject: [PATCH] rpi-cirrus-wm5102-overlay: fix pinctrl configuration - -Separate GPIOs connected to wm5102 and wm8804 into 2 pinctrl -blocks and properly reference them from the DT nodes to have -correct pinmux owners. - -Setup spi0 to use only one CS line on GPIO7 so that GPIO8 is -no longer claimed by spi0 but can be used by wm8804. - -Signed-off-by: Matthias Reichl ---- - .../overlays/rpi-cirrus-wm5102-overlay.dts | 40 ++++++++++++++----- - 1 file changed, 30 insertions(+), 10 deletions(-) - ---- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts -+++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts -@@ -18,19 +18,31 @@ - fragment@1 { - target = <&gpio>; - __overlay__ { -- wlf_pins: wlf_pins { -- brcm,pins = <17 22 27 8>; -+ wlf_5102_pins: wlf_5102_pins { -+ brcm,pins = <17 22 27>; - brcm,function = < - BCM2835_FSEL_GPIO_OUT - BCM2835_FSEL_GPIO_OUT - BCM2835_FSEL_GPIO_IN -- BCM2835_FSEL_GPIO_OUT - >; - }; -+ wlf_8804_pins: wlf_8804_pins { -+ brcm,pins = <8>; -+ brcm,function = ; -+ }; - }; - }; - - fragment@2 { -+ target = <&spi0_cs_pins>; -+ __overlay__ { -+ brcm,pins = <7>; -+ brcm,function = ; -+ }; -+ }; -+ -+ -+ fragment@3 { - target-path = "/"; - __overlay__ { - rpi_cirrus_reg_1v8: rpi_cirrus_reg_1v8 { -@@ -43,30 +55,34 @@ - }; - }; - -- fragment@3 { -+ fragment@4 { - target = <&spidev0>; - __overlay__ { - status = "disabled"; - }; - }; - -- fragment@4 { -+ fragment@5 { - target = <&spidev1>; - __overlay__ { - status = "disabled"; - }; - }; - -- fragment@5 { -+ fragment@6 { - target = <&spi0>; - __overlay__ { - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; -+ cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; - -- wm5102@1{ -+ wm5102@0{ - compatible = "wlf,wm5102"; -- reg = <1>; -+ reg = <0>; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wlf_5102_pins>; - - spi-max-frequency = <500000>; - -@@ -123,7 +139,7 @@ - }; - }; - -- fragment@6 { -+ fragment@7 { - target = <&i2c1>; - __overlay__ { - status = "okay"; -@@ -134,6 +150,10 @@ - compatible = "wlf,wm8804"; - reg = <0x3b>; - status = "okay"; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&wlf_8804_pins>; -+ - PVDD-supply = <&vdd_3v3_reg>; - DVDD-supply = <&vdd_3v3_reg>; - wlf,reset-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>; -@@ -141,7 +161,7 @@ - }; - }; - -- fragment@7 { -+ fragment@8 { - target = <&sound>; - __overlay__ { - compatible = "wlf,rpi-cirrus"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0356-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch b/target/linux/bcm27xx/patches-5.4/950-0356-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch new file mode 100644 index 0000000000..e1ffd3b0b7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0356-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch @@ -0,0 +1,26 @@ +From ea2cfc97596be37164d2f5d3d1a4f5e2d6cca062 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Mon, 16 Dec 2019 23:25:44 +0100 +Subject: [PATCH] rpi-cirrus-wm5102-overlay: use reset-gpios instead of + wlf,reset + +wlf,reset has been deprecated in favour of the standard reset-gpios +DT property in commit fced2963d84b44990f4aa99ed7268223c294c0df so +let's use that instead of the old property. + +Signed-off-by: Matthias Reichl +--- + arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts ++++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts +@@ -104,7 +104,7 @@ + SPKVDDR-supply = <&vdd_5v0_reg>; + DCVDD-supply = <&arizona_ldo1>; + +- wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>; + wlf,gpio-defaults = < + ARIZONA_GP_DEFAULT diff --git a/target/linux/bcm27xx/patches-5.4/950-0357-sound-soc-only-first-codec-is-master-in-multicodec-s.patch b/target/linux/bcm27xx/patches-5.4/950-0357-sound-soc-only-first-codec-is-master-in-multicodec-s.patch new file mode 100644 index 0000000000..263f3532f3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0357-sound-soc-only-first-codec-is-master-in-multicodec-s.patch @@ -0,0 +1,34 @@ +From 3a0fad11000e1533c3132e024304cbe8b4f0f826 Mon Sep 17 00:00:00 2001 +From: Johannes Krude +Date: Sat, 16 Nov 2019 12:41:06 +0100 +Subject: [PATCH] sound/soc: only first codec is master in multicodec + setup + +When using multiple codecs, at most one codec should generate the master +clock. All codecs except the first are therefore configured for slave +mode. + +Signed-off-by: Johannes Krude +--- + sound/soc/soc-core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -1656,7 +1656,15 @@ int snd_soc_runtime_set_dai_fmt(struct s + int ret; + + for_each_rtd_codec_dai(rtd, i, codec_dai) { +- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); ++ unsigned int codec_dai_fmt = dai_fmt; ++ ++ // there can only be one master when using multiple codecs ++ if (i && (codec_dai_fmt & SND_SOC_DAIFMT_MASTER_MASK)) { ++ codec_dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; ++ codec_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; ++ } ++ ++ ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + if (ret != 0 && ret != -ENOTSUPP) { + dev_warn(codec_dai->dev, + "ASoC: Failed to set DAI format: %d\n", ret); diff --git a/target/linux/bcm27xx/patches-5.4/950-0357-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch b/target/linux/bcm27xx/patches-5.4/950-0357-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch deleted file mode 100644 index 0a6660b893..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0357-staging-vchiq_arm-Set-up-dma-ranges-on-child-devices.patch +++ /dev/null @@ -1,33 +0,0 @@ -From a9b691174273348a6818213b9f008ae555e1c98c Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 29 Jan 2019 16:13:25 +0000 -Subject: [PATCH] staging: vchiq_arm: Set up dma ranges on child - devices - -The VCHIQ driver now loads the audio, camera, codec, and vc-sm -drivers as platform drivers. However they were not being given -the correct DMA configuration. - -Call of_dma_configure with the parent (VCHIQ) parameters to be -inherited by the child. - -Signed-off-by: Dave Stevenson ---- - .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -3195,6 +3195,12 @@ vchiq_register_child(struct platform_dev - child = NULL; - } - -+ /* -+ * We want the dma-ranges etc to be copied from the parent VCHIQ device -+ * to be passed on to the children too. -+ */ -+ of_dma_configure(&new_dev->dev, pdev->dev.of_node, true); -+ - return child; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0358-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch b/target/linux/bcm27xx/patches-5.4/950-0358-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch new file mode 100644 index 0000000000..d0d1e28757 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0358-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch @@ -0,0 +1,432 @@ +From eecd29a4a5ede49427e48ea27e372b96d11f3d04 Mon Sep 17 00:00:00 2001 +From: Johannes Krude +Date: Sat, 16 Nov 2019 13:14:43 +0100 +Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi + +Signed-off-by: Johannes Krude +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 20 ++ + .../dts/overlays/justboom-both-overlay.dts | 65 +++++ + sound/soc/bcm/Kconfig | 12 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/justboom-both.c | 266 ++++++++++++++++++ + 11 files changed, 371 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts + create mode 100644 sound/soc/bcm/justboom-both.c + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + iqaudio-digi-wm8804-audio.dtbo \ + irs1125.dtbo \ + jedec-spi-nor.dtbo \ ++ justboom-both.dtbo \ + justboom-dac.dtbo \ + justboom-digi.dtbo \ + ltc294x.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1388,6 +1388,26 @@ Params: flash-spi- Enables + on SPI, CS#. + + ++Name: justboom-both ++Info: Simultaneous usage of an justboom-dac and justboom-digi based ++ card ++Load: dtoverlay=justboom-both,= ++Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec ++ Digital volume control. Enable with ++ "dtoverlay=justboom-dac,24db_digital_gain" ++ (The default behaviour is that the Digital ++ volume control is limited to a maximum of ++ 0dB. ie. it can attenuate but not provide ++ gain. For most users, this will be desired ++ as it will prevent clipping. By appending ++ the 24dB_digital_gain parameter, the Digital ++ volume control will allow up to 24dB of ++ gain. If this parameter is enabled, it is the ++ responsibility of the user to ensure that ++ the Digital volume control is set to a value ++ that does not result in clipping/distortion!) ++ ++ + Name: justboom-dac + Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio + cards +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts +@@ -0,0 +1,65 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Definitions for JustBoom Both (Digi+DAC) ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&i2s>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ wm8804@3b { ++ #sound-dai-cells = <0>; ++ compatible = "wlf,wm8804"; ++ reg = <0x3b>; ++ PVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pcm5122@4d { ++ #sound-dai-cells = <0>; ++ compatible = "ti,pcm5122"; ++ reg = <0x4d>; ++ AVDD-supply = <&vdd_3v3_reg>; ++ DVDD-supply = <&vdd_3v3_reg>; ++ CPVDD-supply = <&vdd_3v3_reg>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ frag3: __overlay__ { ++ compatible = "justboom,justboom-both"; ++ i2s-controller = <&i2s>; ++ status = "okay"; ++ }; ++ }; ++ ++ __overrides__ { ++ 24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?"; ++ }; ++}; +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -105,6 +105,18 @@ config SND_BCM2708_SOC_RPI_PROTO + help + Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731). + ++config SND_BCM2708_SOC_JUSTBOOM_BOTH ++ tristate "Support for simultaneous JustBoom Digi and JustBoom DAC" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_WM8804 ++ select SND_SOC_PCM512x ++ help ++ Say Y or M if you want to add support for simultaneous ++ JustBoom Digi and JustBoom DAC. ++ ++ This is not the right choice if you only have one but both of ++ these cards. ++ + config SND_BCM2708_SOC_JUSTBOOM_DAC + tristate "Support for JustBoom DAC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -17,6 +17,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe + snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o + snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o + snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o ++snd-soc-justboom-both-objs := justboom-both.o + snd-soc-justboom-dac-objs := justboom-dac.o + snd-soc-rpi-cirrus-objs := rpi-cirrus.o + snd-soc-rpi-proto-objs := rpi-proto.o +@@ -43,6 +44,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o ++obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o + obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o +--- /dev/null ++++ b/sound/soc/bcm/justboom-both.c +@@ -0,0 +1,266 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard. ++ * ++ * Authors: Johannes Krude ++ * justboom-dac.c ++ * by Milan Neskovic ++ * ++ * 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. ++ * ++ * 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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/wm8804.h" ++#include "../codecs/pcm512x.h" ++ ++ ++static bool digital_gain_0db_limit = true; ++ ++static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_component *digi = rtd->codec_dais[0]->component; ++ struct snd_soc_component *dac = rtd->codec_dais[1]->component; ++ ++ /* enable TX output */ ++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0); ++ ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08); ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02); ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ ++ if (digital_gain_0db_limit) { ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ ++ ret = snd_soc_limit_volume(card, "Digital Playback Volume", ++ 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ++ ret); ++ } ++ ++ return 0; ++} ++ ++static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_component *digi = rtd->codec_dais[0]->component; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ int sysclk = 27000000; /* This is fixed on this board */ ++ ++ long mclk_freq = 0; ++ int mclk_div = 1; ++ int sampling_freq = 1; ++ ++ int ret; ++ ++ int samplerate = params_rate(params); ++ ++ if (samplerate <= 96000) { ++ mclk_freq = samplerate*256; ++ mclk_div = WM8804_MCLKDIV_256FS; ++ } else { ++ mclk_freq = samplerate*128; ++ mclk_div = WM8804_MCLKDIV_128FS; ++ } ++ ++ switch (samplerate) { ++ case 32000: ++ sampling_freq = 0x03; ++ break; ++ case 44100: ++ sampling_freq = 0x00; ++ break; ++ case 48000: ++ sampling_freq = 0x02; ++ break; ++ case 88200: ++ sampling_freq = 0x08; ++ break; ++ case 96000: ++ sampling_freq = 0x0a; ++ break; ++ case 176400: ++ sampling_freq = 0x0c; ++ break; ++ case 192000: ++ sampling_freq = 0x0e; ++ break; ++ default: ++ dev_err(rtd->card->dev, ++ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n", ++ samplerate); ++ } ++ ++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div); ++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); ++ ++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL, ++ sysclk, SND_SOC_CLOCK_OUT); ++ if (ret < 0) { ++ dev_err(rtd->card->dev, ++ "Failed to set WM8804 SYSCLK: %d\n", ret); ++ return ret; ++ } ++ ++ /* Enable TX output */ ++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0); ++ ++ /* Power on */ ++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0); ++ ++ /* set sampling frequency status bits */ ++ snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq); ++ ++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64); ++} ++ ++static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *digi = rtd->codec_dais[0]->component; ++ struct snd_soc_component *dac = rtd->codec_dais[1]->component; ++ ++ /* turn on digital output */ ++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00); ++ ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ ++ return 0; ++} ++ ++static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_component *digi = rtd->codec_dais[0]->component; ++ struct snd_soc_component *dac = rtd->codec_dais[1]->component; ++ ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); ++ ++ /* turn off output */ ++ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_justboom_both_ops = { ++ .hw_params = snd_rpi_justboom_both_hw_params, ++ .startup = snd_rpi_justboom_both_startup, ++ .shutdown = snd_rpi_justboom_both_shutdown, ++}; ++ ++SND_SOC_DAILINK_DEFS(rpi_justboom_both, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"), ++ COMP_CODEC("wm8804.1-003b", "wm8804-spdif")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); ++ ++static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = { ++{ ++ .name = "JustBoom Digi", ++ .stream_name = "JustBoom Digi HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM, ++ .ops = &snd_rpi_justboom_both_ops, ++ .init = snd_rpi_justboom_both_init, ++ SND_SOC_DAILINK_REG(rpi_justboom_both), ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_justboom_both = { ++ .name = "snd_rpi_justboom_both", ++ .driver_name = "JustBoomBoth", ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_justboom_both_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai), ++}; ++ ++static int snd_rpi_justboom_both_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct snd_soc_card *card = &snd_rpi_justboom_both; ++ ++ snd_rpi_justboom_both.dev = &pdev->dev; ++ ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0]; ++ ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ ++ if (i2s_node) { ++ int i; ++ ++ for (i = 0; i < card->num_links; i++) { ++ dai->cpus->dai_name = NULL; ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->name = NULL; ++ dai->platforms->of_node = i2s_node; ++ } ++ } ++ ++ digital_gain_0db_limit = !of_property_read_bool( ++ pdev->dev.of_node, "justboom,24db_digital_gain"); ++ } ++ ++ ret = snd_soc_register_card(card); ++ if (ret && ret != -EPROBE_DEFER) { ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ } ++ ++ return ret; ++} ++ ++static int snd_rpi_justboom_both_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_justboom_both); ++} ++ ++static const struct of_device_id snd_rpi_justboom_both_of_match[] = { ++ { .compatible = "justboom,justboom-both", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match); ++ ++static struct platform_driver snd_rpi_justboom_both_driver = { ++ .driver = { ++ .name = "snd-rpi-justboom-both", ++ .owner = THIS_MODULE, ++ .of_match_table = snd_rpi_justboom_both_of_match, ++ }, ++ .probe = snd_rpi_justboom_both_probe, ++ .remove = snd_rpi_justboom_both_remove, ++}; ++ ++module_platform_driver(snd_rpi_justboom_both_driver); ++ ++MODULE_AUTHOR("Johannes Krude "); ++MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0358-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch b/target/linux/bcm27xx/patches-5.4/950-0358-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch deleted file mode 100644 index eb35a81023..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0358-staging-vchiq-Use-the-old-dma-controller-for-OF-conf.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 6aa74a52e014952b1a144def670a03a7deb0e112 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 18 Jun 2019 12:15:50 +0100 -Subject: [PATCH] staging: vchiq: Use the old dma controller for OF - config on platform devices - -vchiq on Pi4 is no longer under the soc node, therefore it -doesn't get the dma-ranges for the VPU. - -Switch to using the configuration of the old dma controller as -that will set the dma-ranges correctly. - -Signed-off-by: Dave Stevenson ---- - .../interface/vchiq_arm/vchiq_arm.c | 17 ++++++++++++++--- - 1 file changed, 14 insertions(+), 3 deletions(-) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -3181,6 +3181,7 @@ vchiq_register_child(struct platform_dev - { - struct platform_device_info pdevinfo; - struct platform_device *child; -+ struct device_node *np; - - memset(&pdevinfo, 0, sizeof(pdevinfo)); - -@@ -3196,10 +3197,20 @@ vchiq_register_child(struct platform_dev - } - - /* -- * We want the dma-ranges etc to be copied from the parent VCHIQ device -- * to be passed on to the children too. -+ * We want the dma-ranges etc to be copied from a device with the -+ * correct dma-ranges for the VPU. -+ * VCHIQ on Pi4 is now under scb which doesn't get those dma-ranges. -+ * Take the "dma" node as going to be suitable as it sees the world -+ * through the same eyes as the VPU. - */ -- of_dma_configure(&new_dev->dev, pdev->dev.of_node, true); -+ np = of_find_node_by_path("dma"); -+ if (!np) -+ np = pdev->dev.of_node; -+ -+ of_dma_configure(&child->dev, np, true); -+ -+ if (np != pdev->dev.of_node) -+ of_node_put(np); - - return child; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0359-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch b/target/linux/bcm27xx/patches-5.4/950-0359-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch deleted file mode 100644 index 3bc9abde27..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0359-dwc_otg-checking-the-urb-transfer_buffer-too-early-3.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 271a9dfee2eb426ca9ec1ef51c6205de8496b803 Mon Sep 17 00:00:00 2001 -From: Hui Wang -Date: Sun, 17 Nov 2019 10:31:46 +0800 -Subject: [PATCH] dwc_otg: checking the urb->transfer_buffer too early - (#3332) - -After enable the HIGHMEM and VMSPLIT_3G, the dwc_otg driver doesn't -work well on Pi2/3 boards with 1G physical ram. Users experience -the failure when copying a file of 600M size to the USB stick. And -at the same time, the dmesg shows: -usb 1-1.1.2: reset high-speed USB device number 8 using dwc_otg -sd 0:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK -blk_update_request: I/O error, dev sda, sector 3024048 op 0x1:(WRITE) flags 0x4000 phys_seg 15 prio class 0 - -When this happens, the sg_buf sent to the driver is located in the -highmem region, the usb_sg_init() in the core/message.c will leave -transfer_buffer to NULL if the sg_buf is in highmem, but in the -dwc_otg driver, it returns -EINVAL unconditionally if transfer_buffer -is NULL. - -The driver can handle the situation of buffer to be NULL, if it is in -DMA mode, it will convert an address from transfer_dma. - -But if the conversion fails or it is in the PIO mode, we should check -buffer and return -EINVAL if it is NULL. - -BugLink: https://bugs.launchpad.net/bugs/1852510 -Signed-off-by: Hui Wang ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c -@@ -782,10 +782,6 @@ static int dwc_otg_urb_enqueue(struct us - dump_urb_info(urb, "dwc_otg_urb_enqueue"); - } - #endif -- -- if (!urb->transfer_buffer && urb->transfer_buffer_length) -- return -EINVAL; -- - if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) - || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { - if (!dwc_otg_hcd_is_bandwidth_allocated -@@ -842,6 +838,13 @@ static int dwc_otg_urb_enqueue(struct us - &urb->transfer_dma, buf); - } - -+ if (!buf && urb->transfer_buffer_length) { -+ DWC_FREE(dwc_otg_urb); -+ DWC_ERROR("transfer_buffer is NULL in PIO mode or both " -+ "transfer_buffer and transfer_dma are NULL in DMA mode\n"); -+ return -EINVAL; -+ } -+ - if (!(urb->transfer_flags & URB_NO_INTERRUPT)) - flags |= URB_GIVEBACK_ASAP; - if (urb->transfer_flags & URB_ZERO_PACKET) diff --git a/target/linux/bcm27xx/patches-5.4/950-0359-overlays-dht11-Allow-multiple-instantiation.patch b/target/linux/bcm27xx/patches-5.4/950-0359-overlays-dht11-Allow-multiple-instantiation.patch new file mode 100644 index 0000000000..b75f1d4988 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0359-overlays-dht11-Allow-multiple-instantiation.patch @@ -0,0 +1,34 @@ +From 5c1a2df946720816c155ff38b01bcd49a0f44f78 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 18 Dec 2019 10:41:33 +0000 +Subject: [PATCH] overlays: dht11: Allow multiple instantiation + +Add addresses to the dht11 and dht11_pins nodes to allow unique names +to be generated by assigning to the "reg" property. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/dht11-overlay.dts | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/dht11-overlay.dts ++++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts +@@ -24,7 +24,7 @@ + fragment@1 { + target = <&gpio>; + __overlay__ { +- dht11_pins: dht11_pins { ++ dht11_pins: dht11_pins@0 { + brcm,pins = <4>; + brcm,function = <0>; // in + brcm,pull = <0>; // off +@@ -34,6 +34,8 @@ + + __overrides__ { + gpiopin = <&dht11_pins>,"brcm,pins:0", +- <&dht11>,"gpios:4"; ++ <&dht11_pins>, "reg:0", ++ <&dht11>,"gpios:4", ++ <&dht11>,"reg:0"; + }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0360-overlays-Make-mcp342x-run-time-compatible.patch b/target/linux/bcm27xx/patches-5.4/950-0360-overlays-Make-mcp342x-run-time-compatible.patch deleted file mode 100644 index 1b4809db0d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0360-overlays-Make-mcp342x-run-time-compatible.patch +++ /dev/null @@ -1,209 +0,0 @@ -From 00f01136b1c165e0f4a190fcb5ec8aa11428362f Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 9 Dec 2019 12:32:20 +0000 -Subject: [PATCH] overlays: Make mcp342x run-time compatible - -The order of processing of run-time overlays differs from that done by -the firmware. This means that certain parameter processing techniques -are not compatible with run-time use. The mcp342x overlay is one such -overlay, but it is easy to change the implementation without changing -the interface. - -See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=258294 - -Signed-off-by: Phil Elwell ---- - .../arm/boot/dts/overlays/mcp342x-overlay.dts | 133 ++++++++++++++---- - 1 file changed, 102 insertions(+), 31 deletions(-) - ---- a/arch/arm/boot/dts/overlays/mcp342x-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mcp342x-overlay.dts -@@ -8,14 +8,15 @@ - - fragment@0 { - target = <&i2c1>; -- __overlay__ { -+ __dormant__ { - #address-cells = <1>; - #size-cells = <0>; - - status = "okay"; - -- mcp342x: mcp@68 { -+ mcp3421: mcp@68 { - reg = <0x68>; -+ compatible = "microchip,mcp3421"; - - status = "okay"; - }; -@@ -23,71 +24,141 @@ - }; - - fragment@1 { -- target = <&mcp342x>; -+ target = <&i2c1>; - __dormant__ { -- compatible = "microchip,mcp3421"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ mcp3422: mcp@68 { -+ reg = <0x68>; -+ compatible = "microchip,mcp3422"; -+ -+ status = "okay"; -+ }; - }; - }; - - fragment@2 { -- target = <&mcp342x>; -+ target = <&i2c1>; - __dormant__ { -- compatible = "microchip,mcp3422"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ mcp3423: mcp@68 { -+ reg = <0x68>; -+ compatible = "microchip,mcp3423"; -+ -+ status = "okay"; -+ }; - }; - }; - - fragment@3 { -- target = <&mcp342x>; -+ target = <&i2c1>; - __dormant__ { -- compatible = "microchip,mcp3423"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ mcp3424: mcp@68 { -+ reg = <0x68>; -+ compatible = "microchip,mcp3424"; -+ -+ status = "okay"; -+ }; - }; - }; - - fragment@4 { -- target = <&mcp342x>; -+ target = <&i2c1>; - __dormant__ { -- compatible = "microchip,mcp3424"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ mcp3425: mcp@68 { -+ reg = <0x68>; -+ compatible = "microchip,mcp3425","mcp3425"; -+ -+ status = "okay"; -+ }; - }; - }; - - fragment@5 { -- target = <&mcp342x>; -+ target = <&i2c1>; - __dormant__ { -- compatible = "microchip,mcp3425"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ mcp3426: mcp@68 { -+ reg = <0x68>; -+ compatible = "microchip,mcp3426"; -+ -+ status = "okay"; -+ }; - }; - }; - - fragment@6 { -- target = <&mcp342x>; -+ target = <&i2c1>; - __dormant__ { -- compatible = "microchip,mcp3426"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "okay"; -+ -+ mcp3427: mcp@68 { -+ reg = <0x68>; -+ compatible = "microchip,mcp3427"; -+ -+ status = "okay"; -+ }; - }; - }; - - fragment@7 { -- target = <&mcp342x>; -+ target = <&i2c1>; - __dormant__ { -- compatible = "microchip,mcp3427"; -- }; -- }; -+ #address-cells = <1>; -+ #size-cells = <0>; - -- fragment@8 { -- target = <&mcp342x>; -- __dormant__ { -- compatible = "microchip,mcp3428"; -+ status = "okay"; -+ -+ mcp3428: mcp@68 { -+ reg = <0x68>; -+ compatible = "microchip,mcp3428"; -+ -+ status = "okay"; -+ }; - }; - }; - - __overrides__ { -- addr = <&mcp342x>,"reg:0"; -- mcp3421 = <0>,"=1"; -- mcp3422 = <0>,"=2"; -- mcp3423 = <0>,"=3"; -- mcp3424 = <0>,"=4"; -- mcp3425 = <0>,"=5"; -- mcp3426 = <0>,"=6"; -- mcp3427 = <0>,"=7"; -- mcp3428 = <0>,"=8"; -+ addr = <&mcp3421>,"reg:0", -+ <&mcp3422>,"reg:0", -+ <&mcp3423>,"reg:0", -+ <&mcp3424>,"reg:0", -+ <&mcp3425>,"reg:0", -+ <&mcp3426>,"reg:0", -+ <&mcp3427>,"reg:0", -+ <&mcp3428>,"reg:0"; -+ mcp3421 = <0>,"=0"; -+ mcp3422 = <0>,"=1"; -+ mcp3423 = <0>,"=2"; -+ mcp3424 = <0>,"=3"; -+ mcp3425 = <0>,"=4"; -+ mcp3426 = <0>,"=5"; -+ mcp3427 = <0>,"=6"; -+ mcp3428 = <0>,"=7"; - }; - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0360-overlays-i2c-rtc-Add-pcf85363-support.patch b/target/linux/bcm27xx/patches-5.4/950-0360-overlays-i2c-rtc-Add-pcf85363-support.patch new file mode 100644 index 0000000000..93a699a66a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0360-overlays-i2c-rtc-Add-pcf85363-support.patch @@ -0,0 +1,56 @@ +From 32dbe4ebb10b96eed117852f1643bf1f854d96c0 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Sun, 22 Dec 2019 15:29:40 +0000 +Subject: [PATCH] overlays: i2c-rtc: Add pcf85363 support + +See: https://github.com/raspberrypi/firmware/issues/1309 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 16 ++++++++++++++++ + 2 files changed, 18 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1078,6 +1078,8 @@ Params: abx80x Select o + + pcf8523 Select the PCF8523 device + ++ pcf85363 Select the PCF85363 device ++ + pcf8563 Select the PCF8563 device + + rv3028 Select the Micro Crystal RV3028 device +--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts +@@ -188,6 +188,21 @@ + }; + }; + ++ fragment@12 { ++ target = <&i2c_arm>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pcf85363@51 { ++ compatible = "nxp,pcf85363"; ++ reg = <0x51>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ + __overrides__ { + abx80x = <0>,"+0"; + ds1307 = <0>,"+1"; +@@ -201,6 +216,7 @@ + m41t62 = <0>,"+9"; + rv3028 = <0>,"+10"; + pcf2129 = <0>,"+11"; ++ pcf85363 = <0>,"+12"; + + addr = <&abx80x>, "reg:0", + <&ds1307>, "reg:0", diff --git a/target/linux/bcm27xx/patches-5.4/950-0361-pinctrl-bcm2835-Remove-gpiochip-on-error.patch b/target/linux/bcm27xx/patches-5.4/950-0361-pinctrl-bcm2835-Remove-gpiochip-on-error.patch new file mode 100644 index 0000000000..31a1a24caf --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0361-pinctrl-bcm2835-Remove-gpiochip-on-error.patch @@ -0,0 +1,25 @@ +From 0cddfafa817a776063ba6f00fb439d9a415235f9 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 6 Jan 2020 16:04:30 +0000 +Subject: [PATCH] pinctrl: bcm2835: Remove gpiochip on error + +A failure in gpiochip_irqchip_add leads to a leak of a gpiochip. Fix +the leak with the use of devm_gpiochip_add_data. + +Fixes: 85ae9e512f43 ("pinctrl: bcm2835: switch to GPIOLIB_IRQCHIP") +Signed-off-by: Phil Elwell +--- + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +@@ -1135,7 +1135,7 @@ static int bcm2835_pinctrl_probe(struct + raw_spin_lock_init(&pc->irq_lock[i]); + } + +- err = gpiochip_add_data(&pc->gpio_chip, pc); ++ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); + if (err) { + dev_err(dev, "could not add GPIO chip\n"); + return err; diff --git a/target/linux/bcm27xx/patches-5.4/950-0361-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch b/target/linux/bcm27xx/patches-5.4/950-0361-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch deleted file mode 100644 index e1ffd3b0b7..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0361-rpi-cirrus-wm5102-overlay-use-reset-gpios-instead-of.patch +++ /dev/null @@ -1,26 +0,0 @@ -From ea2cfc97596be37164d2f5d3d1a4f5e2d6cca062 Mon Sep 17 00:00:00 2001 -From: Matthias Reichl -Date: Mon, 16 Dec 2019 23:25:44 +0100 -Subject: [PATCH] rpi-cirrus-wm5102-overlay: use reset-gpios instead of - wlf,reset - -wlf,reset has been deprecated in favour of the standard reset-gpios -DT property in commit fced2963d84b44990f4aa99ed7268223c294c0df so -let's use that instead of the old property. - -Signed-off-by: Matthias Reichl ---- - arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts -+++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts -@@ -104,7 +104,7 @@ - SPKVDDR-supply = <&vdd_5v0_reg>; - DCVDD-supply = <&arizona_ldo1>; - -- wlf,reset = <&gpio 17 GPIO_ACTIVE_HIGH>; -+ reset-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - wlf,ldoena = <&gpio 22 GPIO_ACTIVE_HIGH>; - wlf,gpio-defaults = < - ARIZONA_GP_DEFAULT diff --git a/target/linux/bcm27xx/patches-5.4/950-0362-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch b/target/linux/bcm27xx/patches-5.4/950-0362-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch new file mode 100644 index 0000000000..3865ae11fb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0362-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch @@ -0,0 +1,88 @@ +From 27cb8bf0442f677380a1df93b93b7589b7ce5243 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 6 Jan 2020 14:05:42 +0000 +Subject: [PATCH] pinctrl: bcm2835: Change init order for gpio hogs + +pinctrl-bcm2835 is a combined pinctrl/gpio driver. Currently the gpio +side is registered first, but this breaks gpio hogs (which are +configured during gpiochip_add_data). Part of the hog initialisation +is a call to pinctrl_gpio_request, and since the pinctrl driver hasn't +yet been registered this results in an -EPROBE_DEFER from which it can +never recover. + +Change the initialisation sequence to register the pinctrl driver +first. + +See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=260600 + +Signed-off-by: Phil Elwell +--- + drivers/pinctrl/bcm/pinctrl-bcm2835.c | 40 ++++++++++++--------------- + 1 file changed, 17 insertions(+), 23 deletions(-) + +--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c +@@ -1135,9 +1135,25 @@ static int bcm2835_pinctrl_probe(struct + raw_spin_lock_init(&pc->irq_lock[i]); + } + ++ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); ++ if (match) { ++ bcm2835_pinctrl_desc.confops = ++ (const struct pinconf_ops *)match->data; ++ } ++ ++ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc); ++ if (IS_ERR(pc->pctl_dev)) ++ return PTR_ERR(pc->pctl_dev); ++ ++ pc->gpio_range = bcm2835_pinctrl_gpio_range; ++ pc->gpio_range.base = pc->gpio_chip.base; ++ pc->gpio_range.gc = &pc->gpio_chip; ++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); ++ + err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); + if (err) { + dev_err(dev, "could not add GPIO chip\n"); ++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range); + return err; + } + +@@ -1145,6 +1161,7 @@ static int bcm2835_pinctrl_probe(struct + 0, handle_level_irq, IRQ_TYPE_NONE); + if (err) { + dev_info(dev, "could not add irqchip\n"); ++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range); + return err; + } + +@@ -1167,29 +1184,6 @@ static int bcm2835_pinctrl_probe(struct + bcm2835_gpio_irq_handler); + } + +- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); +- if (match) { +- bcm2835_pinctrl_desc.confops = +- (const struct pinconf_ops *)match->data; +- } +- +- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); +- if (match) { +- bcm2835_pinctrl_desc.confops = +- (const struct pinconf_ops *)match->data; +- } +- +- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc); +- if (IS_ERR(pc->pctl_dev)) { +- gpiochip_remove(&pc->gpio_chip); +- return PTR_ERR(pc->pctl_dev); +- } +- +- pc->gpio_range = bcm2835_pinctrl_gpio_range; +- pc->gpio_range.base = pc->gpio_chip.base; +- pc->gpio_range.gc = &pc->gpio_chip; +- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); +- + return 0; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0362-sound-soc-only-first-codec-is-master-in-multicodec-s.patch b/target/linux/bcm27xx/patches-5.4/950-0362-sound-soc-only-first-codec-is-master-in-multicodec-s.patch deleted file mode 100644 index 263f3532f3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0362-sound-soc-only-first-codec-is-master-in-multicodec-s.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 3a0fad11000e1533c3132e024304cbe8b4f0f826 Mon Sep 17 00:00:00 2001 -From: Johannes Krude -Date: Sat, 16 Nov 2019 12:41:06 +0100 -Subject: [PATCH] sound/soc: only first codec is master in multicodec - setup - -When using multiple codecs, at most one codec should generate the master -clock. All codecs except the first are therefore configured for slave -mode. - -Signed-off-by: Johannes Krude ---- - sound/soc/soc-core.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -1656,7 +1656,15 @@ int snd_soc_runtime_set_dai_fmt(struct s - int ret; - - for_each_rtd_codec_dai(rtd, i, codec_dai) { -- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); -+ unsigned int codec_dai_fmt = dai_fmt; -+ -+ // there can only be one master when using multiple codecs -+ if (i && (codec_dai_fmt & SND_SOC_DAIFMT_MASTER_MASK)) { -+ codec_dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK; -+ codec_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; -+ } -+ -+ ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); - if (ret != 0 && ret != -ENOTSUPP) { - dev_warn(codec_dai->dev, - "ASoC: Failed to set DAI format: %d\n", ret); diff --git a/target/linux/bcm27xx/patches-5.4/950-0363-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch b/target/linux/bcm27xx/patches-5.4/950-0363-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch deleted file mode 100644 index d0d1e28757..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0363-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch +++ /dev/null @@ -1,432 +0,0 @@ -From eecd29a4a5ede49427e48ea27e372b96d11f3d04 Mon Sep 17 00:00:00 2001 -From: Johannes Krude -Date: Sat, 16 Nov 2019 13:14:43 +0100 -Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi - -Signed-off-by: Johannes Krude ---- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 20 ++ - .../dts/overlays/justboom-both-overlay.dts | 65 +++++ - sound/soc/bcm/Kconfig | 12 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/justboom-both.c | 266 ++++++++++++++++++ - 11 files changed, 371 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts - create mode 100644 sound/soc/bcm/justboom-both.c - ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - iqaudio-digi-wm8804-audio.dtbo \ - irs1125.dtbo \ - jedec-spi-nor.dtbo \ -+ justboom-both.dtbo \ - justboom-dac.dtbo \ - justboom-digi.dtbo \ - ltc294x.dtbo \ ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -1388,6 +1388,26 @@ Params: flash-spi- Enables - on SPI, CS#. - - -+Name: justboom-both -+Info: Simultaneous usage of an justboom-dac and justboom-digi based -+ card -+Load: dtoverlay=justboom-both,= -+Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec -+ Digital volume control. Enable with -+ "dtoverlay=justboom-dac,24db_digital_gain" -+ (The default behaviour is that the Digital -+ volume control is limited to a maximum of -+ 0dB. ie. it can attenuate but not provide -+ gain. For most users, this will be desired -+ as it will prevent clipping. By appending -+ the 24dB_digital_gain parameter, the Digital -+ volume control will allow up to 24dB of -+ gain. If this parameter is enabled, it is the -+ responsibility of the user to ensure that -+ the Digital volume control is set to a value -+ that does not result in clipping/distortion!) -+ -+ - Name: justboom-dac - Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio - cards ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts -@@ -0,0 +1,65 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Definitions for JustBoom Both (Digi+DAC) -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&i2s>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&i2c1>; -+ __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ wm8804@3b { -+ #sound-dai-cells = <0>; -+ compatible = "wlf,wm8804"; -+ reg = <0x3b>; -+ PVDD-supply = <&vdd_3v3_reg>; -+ DVDD-supply = <&vdd_3v3_reg>; -+ status = "okay"; -+ }; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&i2c1>; -+ __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ pcm5122@4d { -+ #sound-dai-cells = <0>; -+ compatible = "ti,pcm5122"; -+ reg = <0x4d>; -+ AVDD-supply = <&vdd_3v3_reg>; -+ DVDD-supply = <&vdd_3v3_reg>; -+ CPVDD-supply = <&vdd_3v3_reg>; -+ status = "okay"; -+ }; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&sound>; -+ frag3: __overlay__ { -+ compatible = "justboom,justboom-both"; -+ i2s-controller = <&i2s>; -+ status = "okay"; -+ }; -+ }; -+ -+ __overrides__ { -+ 24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?"; -+ }; -+}; ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -105,6 +105,18 @@ config SND_BCM2708_SOC_RPI_PROTO - help - Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731). - -+config SND_BCM2708_SOC_JUSTBOOM_BOTH -+ tristate "Support for simultaneous JustBoom Digi and JustBoom DAC" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_WM8804 -+ select SND_SOC_PCM512x -+ help -+ Say Y or M if you want to add support for simultaneous -+ JustBoom Digi and JustBoom DAC. -+ -+ This is not the right choice if you only have one but both of -+ these cards. -+ - config SND_BCM2708_SOC_JUSTBOOM_DAC - tristate "Support for JustBoom DAC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -17,6 +17,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe - snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o - snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o - snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o -+snd-soc-justboom-both-objs := justboom-both.o - snd-soc-justboom-dac-objs := justboom-dac.o - snd-soc-rpi-cirrus-objs := rpi-cirrus.o - snd-soc-rpi-proto-objs := rpi-proto.o -@@ -43,6 +44,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o -+obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o - obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o ---- /dev/null -+++ b/sound/soc/bcm/justboom-both.c -@@ -0,0 +1,266 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard. -+ * -+ * Authors: Johannes Krude -+ * justboom-dac.c -+ * by Milan Neskovic -+ * -+ * 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. -+ * -+ * 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "../codecs/wm8804.h" -+#include "../codecs/pcm512x.h" -+ -+ -+static bool digital_gain_0db_limit = true; -+ -+static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_component *digi = rtd->codec_dais[0]->component; -+ struct snd_soc_component *dac = rtd->codec_dais[1]->component; -+ -+ /* enable TX output */ -+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0); -+ -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08); -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02); -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ -+ if (digital_gain_0db_limit) { -+ int ret; -+ struct snd_soc_card *card = rtd->card; -+ -+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", -+ 207); -+ if (ret < 0) -+ dev_warn(card->dev, "Failed to set volume limit: %d\n", -+ ret); -+ } -+ -+ return 0; -+} -+ -+static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_dai *codec_dai = rtd->codec_dai; -+ struct snd_soc_component *digi = rtd->codec_dais[0]->component; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ -+ int sysclk = 27000000; /* This is fixed on this board */ -+ -+ long mclk_freq = 0; -+ int mclk_div = 1; -+ int sampling_freq = 1; -+ -+ int ret; -+ -+ int samplerate = params_rate(params); -+ -+ if (samplerate <= 96000) { -+ mclk_freq = samplerate*256; -+ mclk_div = WM8804_MCLKDIV_256FS; -+ } else { -+ mclk_freq = samplerate*128; -+ mclk_div = WM8804_MCLKDIV_128FS; -+ } -+ -+ switch (samplerate) { -+ case 32000: -+ sampling_freq = 0x03; -+ break; -+ case 44100: -+ sampling_freq = 0x00; -+ break; -+ case 48000: -+ sampling_freq = 0x02; -+ break; -+ case 88200: -+ sampling_freq = 0x08; -+ break; -+ case 96000: -+ sampling_freq = 0x0a; -+ break; -+ case 176400: -+ sampling_freq = 0x0c; -+ break; -+ case 192000: -+ sampling_freq = 0x0e; -+ break; -+ default: -+ dev_err(rtd->card->dev, -+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n", -+ samplerate); -+ } -+ -+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div); -+ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); -+ -+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL, -+ sysclk, SND_SOC_CLOCK_OUT); -+ if (ret < 0) { -+ dev_err(rtd->card->dev, -+ "Failed to set WM8804 SYSCLK: %d\n", ret); -+ return ret; -+ } -+ -+ /* Enable TX output */ -+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0); -+ -+ /* Power on */ -+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0); -+ -+ /* set sampling frequency status bits */ -+ snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq); -+ -+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64); -+} -+ -+static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *digi = rtd->codec_dais[0]->component; -+ struct snd_soc_component *dac = rtd->codec_dais[1]->component; -+ -+ /* turn on digital output */ -+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00); -+ -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ -+ return 0; -+} -+ -+static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_component *digi = rtd->codec_dais[0]->component; -+ struct snd_soc_component *dac = rtd->codec_dais[1]->component; -+ -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); -+ -+ /* turn off output */ -+ snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c); -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_justboom_both_ops = { -+ .hw_params = snd_rpi_justboom_both_hw_params, -+ .startup = snd_rpi_justboom_both_startup, -+ .shutdown = snd_rpi_justboom_both_shutdown, -+}; -+ -+SND_SOC_DAILINK_DEFS(rpi_justboom_both, -+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), -+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"), -+ COMP_CODEC("wm8804.1-003b", "wm8804-spdif")), -+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); -+ -+static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = { -+{ -+ .name = "JustBoom Digi", -+ .stream_name = "JustBoom Digi HiFi", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBM_CFM, -+ .ops = &snd_rpi_justboom_both_ops, -+ .init = snd_rpi_justboom_both_init, -+ SND_SOC_DAILINK_REG(rpi_justboom_both), -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_justboom_both = { -+ .name = "snd_rpi_justboom_both", -+ .driver_name = "JustBoomBoth", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_justboom_both_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai), -+}; -+ -+static int snd_rpi_justboom_both_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ struct snd_soc_card *card = &snd_rpi_justboom_both; -+ -+ snd_rpi_justboom_both.dev = &pdev->dev; -+ -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0]; -+ -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ -+ if (i2s_node) { -+ int i; -+ -+ for (i = 0; i < card->num_links; i++) { -+ dai->cpus->dai_name = NULL; -+ dai->cpus->of_node = i2s_node; -+ dai->platforms->name = NULL; -+ dai->platforms->of_node = i2s_node; -+ } -+ } -+ -+ digital_gain_0db_limit = !of_property_read_bool( -+ pdev->dev.of_node, "justboom,24db_digital_gain"); -+ } -+ -+ ret = snd_soc_register_card(card); -+ if (ret && ret != -EPROBE_DEFER) { -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+static int snd_rpi_justboom_both_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_justboom_both); -+} -+ -+static const struct of_device_id snd_rpi_justboom_both_of_match[] = { -+ { .compatible = "justboom,justboom-both", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match); -+ -+static struct platform_driver snd_rpi_justboom_both_driver = { -+ .driver = { -+ .name = "snd-rpi-justboom-both", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_justboom_both_of_match, -+ }, -+ .probe = snd_rpi_justboom_both_probe, -+ .remove = snd_rpi_justboom_both_remove, -+}; -+ -+module_platform_driver(snd_rpi_justboom_both_driver); -+ -+MODULE_AUTHOR("Johannes Krude "); -+MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0363-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch b/target/linux/bcm27xx/patches-5.4/950-0363-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch new file mode 100644 index 0000000000..0221803993 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0363-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch @@ -0,0 +1,100 @@ +From 67dd4d137557909279a21c1b5de87a24c84903f9 Mon Sep 17 00:00:00 2001 +From: Giedrius +Date: Tue, 7 Jan 2020 11:04:21 +0200 +Subject: [PATCH] Pisound: MIDI communication fixes for scaled down + CPU. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +* Increased maximum SPI communication speed to avoid running too slow + when the CPU is scaled down and losing MIDI data. + +* Keep track of buffer usage in millibytes for higher precision. + +Signed-off-by: Giedrius Trainavičius +--- + sound/soc/bcm/pisound.c | 31 ++++++++++++++++++------------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +--- a/sound/soc/bcm/pisound.c ++++ b/sound/soc/bcm/pisound.c +@@ -1,6 +1,6 @@ + /* + * Pisound Linux kernel module. +- * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound ++ * Copyright (C) 2016-2020 Vilniaus Blokas UAB, https://blokas.io/pisound + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -326,7 +326,7 @@ static void spi_transfer(const uint8_t * + transfer.tx_buf = txbuf; + transfer.rx_buf = rxbuf; + transfer.len = len; +- transfer.speed_hz = 100000; ++ transfer.speed_hz = 150000; + transfer.delay_usecs = 10; + spi_message_add_tail(&transfer, &msg); + +@@ -403,9 +403,9 @@ static struct spi_device *pisnd_spi_find + static void pisnd_work_handler(struct work_struct *work) + { + enum { TRANSFER_SIZE = 4 }; +- enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 }; +- enum { MIDI_BYTES_PER_SECOND = 3125 }; +- int out_buffer_used = 0; ++ enum { PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES = 127 * 1000 }; ++ enum { MIDI_MILLIBYTES_PER_JIFFIE = (3125 * 1000) / HZ }; ++ int out_buffer_used_millibytes = 0; + unsigned long now; + uint8_t val; + uint8_t txbuf[TRANSFER_SIZE]; +@@ -445,7 +445,9 @@ static void pisnd_work_handler(struct wo + had_data = false; + memset(txbuf, 0, sizeof(txbuf)); + for (i = 0; i < sizeof(txbuf) && +- out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE; ++ ((out_buffer_used_millibytes+1000 < ++ PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES) || ++ g_ledFlashDurationChanged); + i += 2) { + + val = 0; +@@ -458,7 +460,7 @@ static void pisnd_work_handler(struct wo + } else if (kfifo_get(&spi_fifo_out, &val)) { + txbuf[i+0] = 0x0f; + txbuf[i+1] = val; +- ++out_buffer_used; ++ out_buffer_used_millibytes += 1000; + } + } + +@@ -469,12 +471,14 @@ static void pisnd_work_handler(struct wo + * rate. + */ + now = jiffies; +- out_buffer_used -= +- (MIDI_BYTES_PER_SECOND / HZ) / +- (now - last_transfer_at); +- if (out_buffer_used < 0) +- out_buffer_used = 0; +- last_transfer_at = now; ++ if (now != last_transfer_at) { ++ out_buffer_used_millibytes -= ++ (now - last_transfer_at) * ++ MIDI_MILLIBYTES_PER_JIFFIE; ++ if (out_buffer_used_millibytes < 0) ++ out_buffer_used_millibytes = 0; ++ last_transfer_at = now; ++ } + + for (i = 0; i < sizeof(rxbuf); i += 2) { + if (rxbuf[i]) { +@@ -489,6 +493,7 @@ static void pisnd_work_handler(struct wo + || !kfifo_is_empty(&spi_fifo_out) + || pisnd_spi_has_more() + || g_ledFlashDurationChanged ++ || out_buffer_used_millibytes != 0 + ); + + if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback) diff --git a/target/linux/bcm27xx/patches-5.4/950-0364-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0364-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch new file mode 100644 index 0000000000..db90055343 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0364-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch @@ -0,0 +1,51 @@ +From 238506ebdea7a0bb928af8403287d5b0d71cdfee Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Fri, 16 Aug 2019 22:32:02 +0200 +Subject: [PATCH] ARM: dts: bcm283x: Remove simple-bus from fixed + clocks + +commit 4b2d24662126b1e2a6b95c9dfe9e9044e105e5bd upstream. + +The fixed clocks doesn't form some kind of bus. So let's remove it. +This fixes the follow DT schema warnings: + +clocks: clock@3:reg:0: [3] is too short +clocks: clock@4:reg:0: [4] is too short +clocks: $nodename:0: 'clocks' does not match '^(bus|soc|axi|ahb|apb)(@[0-9a-f]+)?$' +clocks: #size-cells:0:0: 0 is not one of [1, 2] +clocks: 'ranges' is a required property +clock@3: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+' +clock@4: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+' + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm283x.dtsi | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -635,22 +635,16 @@ + }; + + clocks { +- compatible = "simple-bus"; +- #address-cells = <1>; +- #size-cells = <0>; +- + /* The oscillator is the root of the clock tree. */ +- clk_osc: clock@3 { ++ clk_osc: clk-osc { + compatible = "fixed-clock"; +- reg = <3>; + #clock-cells = <0>; + clock-output-names = "osc"; + clock-frequency = <19200000>; + }; + +- clk_usb: clock@4 { ++ clk_usb: clk-usb { + compatible = "fixed-clock"; +- reg = <4>; + #clock-cells = <0>; + clock-output-names = "otg"; + clock-frequency = <480000000>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0364-overlays-dht11-Allow-multiple-instantiation.patch b/target/linux/bcm27xx/patches-5.4/950-0364-overlays-dht11-Allow-multiple-instantiation.patch deleted file mode 100644 index b75f1d4988..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0364-overlays-dht11-Allow-multiple-instantiation.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 5c1a2df946720816c155ff38b01bcd49a0f44f78 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 18 Dec 2019 10:41:33 +0000 -Subject: [PATCH] overlays: dht11: Allow multiple instantiation - -Add addresses to the dht11 and dht11_pins nodes to allow unique names -to be generated by assigning to the "reg" property. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/dht11-overlay.dts | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - ---- a/arch/arm/boot/dts/overlays/dht11-overlay.dts -+++ b/arch/arm/boot/dts/overlays/dht11-overlay.dts -@@ -24,7 +24,7 @@ - fragment@1 { - target = <&gpio>; - __overlay__ { -- dht11_pins: dht11_pins { -+ dht11_pins: dht11_pins@0 { - brcm,pins = <4>; - brcm,function = <0>; // in - brcm,pull = <0>; // off -@@ -34,6 +34,8 @@ - - __overrides__ { - gpiopin = <&dht11_pins>,"brcm,pins:0", -- <&dht11>,"gpios:4"; -+ <&dht11_pins>, "reg:0", -+ <&dht11>,"gpios:4", -+ <&dht11>,"reg:0"; - }; - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0365-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0365-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch new file mode 100644 index 0000000000..3ececc8f92 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0365-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch @@ -0,0 +1,73 @@ +From fcd4bc412167d2a79bf63603e883f4960ca6b2a1 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Fri, 27 Dec 2019 11:15:00 +0100 +Subject: [PATCH] ARM: dts: bcm283x: Move system timer back to + bcm283x.dtsi + +During Raspberry Pi 4 upstream discussion Tim Gover confirmed that the +system timer also exists on BCM2711. So move it back to bcm283x.dtsi and +overwrite the interrupt definition in bcm2838.dtsi. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2835-common.dtsi | 11 ----------- + arch/arm/boot/dts/bcm2838.dtsi | 7 +++++++ + arch/arm/boot/dts/bcm283x.dtsi | 11 +++++++++++ + 3 files changed, 18 insertions(+), 11 deletions(-) + +--- a/arch/arm/boot/dts/bcm2835-common.dtsi ++++ b/arch/arm/boot/dts/bcm2835-common.dtsi +@@ -6,17 +6,6 @@ + + / { + soc { +- timer@7e003000 { +- compatible = "brcm,bcm2835-system-timer"; +- reg = <0x7e003000 0x1000>; +- interrupts = <1 0>, <1 1>, <1 2>, <1 3>; +- /* This could be a reference to BCM2835_CLOCK_TIMER, +- * but we don't have the driver using the common clock +- * support yet. +- */ +- clock-frequency = <1000000>; +- }; +- + intc: interrupt-controller@7e00b200 { + compatible = "brcm,bcm2835-armctrl-ic"; + reg = <0x7e00b200 0x200>; +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -711,6 +711,13 @@ + interrupts = ; + }; + ++&system_timer { ++ interrupts = , ++ , ++ , ++ ; ++}; ++ + &uart0 { + interrupts = ; + }; +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -56,6 +56,17 @@ + #address-cells = <1>; + #size-cells = <1>; + ++ system_timer: timer@7e003000 { ++ compatible = "brcm,bcm2835-system-timer"; ++ reg = <0x7e003000 0x1000>; ++ interrupts = <1 0>, <1 1>, <1 2>, <1 3>; ++ /* This could be a reference to BCM2835_CLOCK_TIMER, ++ * but we don't have the driver using the common clock ++ * support yet. ++ */ ++ clock-frequency = <1000000>; ++ }; ++ + txp: txp@7e004000 { + compatible = "brcm,bcm2835-txp"; + reg = <0x7e004000 0x20>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0365-overlays-i2c-rtc-Add-pcf85363-support.patch b/target/linux/bcm27xx/patches-5.4/950-0365-overlays-i2c-rtc-Add-pcf85363-support.patch deleted file mode 100644 index 93a699a66a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0365-overlays-i2c-rtc-Add-pcf85363-support.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 32dbe4ebb10b96eed117852f1643bf1f854d96c0 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Sun, 22 Dec 2019 15:29:40 +0000 -Subject: [PATCH] overlays: i2c-rtc: Add pcf85363 support - -See: https://github.com/raspberrypi/firmware/issues/1309 - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/README | 2 ++ - arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 16 ++++++++++++++++ - 2 files changed, 18 insertions(+) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -1078,6 +1078,8 @@ Params: abx80x Select o - - pcf8523 Select the PCF8523 device - -+ pcf85363 Select the PCF85363 device -+ - pcf8563 Select the PCF8563 device - - rv3028 Select the Micro Crystal RV3028 device ---- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts -+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts -@@ -188,6 +188,21 @@ - }; - }; - -+ fragment@12 { -+ target = <&i2c_arm>; -+ __dormant__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ pcf85363@51 { -+ compatible = "nxp,pcf85363"; -+ reg = <0x51>; -+ status = "okay"; -+ }; -+ }; -+ }; -+ - __overrides__ { - abx80x = <0>,"+0"; - ds1307 = <0>,"+1"; -@@ -201,6 +216,7 @@ - m41t62 = <0>,"+9"; - rv3028 = <0>,"+10"; - pcf2129 = <0>,"+11"; -+ pcf85363 = <0>,"+12"; - - addr = <&abx80x>, "reg:0", - <&ds1307>, "reg:0", diff --git a/target/linux/bcm27xx/patches-5.4/950-0366-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0366-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch new file mode 100644 index 0000000000..218a846fa3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0366-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch @@ -0,0 +1,112 @@ +From d884dfd722a8207749f5c6c08b69287f0c75a553 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Fri, 27 Dec 2019 16:06:13 +0100 +Subject: [PATCH] ARM: dts: bcm283x: Move pixelvalve to + bcm2835-common.dtsi + +According to Eric Anholt the pixelvalves doesn't exists on BCM2711. +So move it to bcm2835-common.dtsi. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2835-common.dtsi | 18 ++++++++++++++++++ + arch/arm/boot/dts/bcm2838.dtsi | 12 ------------ + arch/arm/boot/dts/bcm283x.dtsi | 18 ------------------ + 3 files changed, 18 insertions(+), 30 deletions(-) + +--- a/arch/arm/boot/dts/bcm2835-common.dtsi ++++ b/arch/arm/boot/dts/bcm2835-common.dtsi +@@ -13,6 +13,18 @@ + #interrupt-cells = <2>; + }; + ++ pixelvalve@7e206000 { ++ compatible = "brcm,bcm2835-pixelvalve0"; ++ reg = <0x7e206000 0x100>; ++ interrupts = <2 13>; /* pwa0 */ ++ }; ++ ++ pixelvalve@7e207000 { ++ compatible = "brcm,bcm2835-pixelvalve1"; ++ reg = <0x7e207000 0x100>; ++ interrupts = <2 14>; /* pwa1 */ ++ }; ++ + thermal: thermal@7e212000 { + compatible = "brcm,bcm2835-thermal"; + reg = <0x7e212000 0x8>; +@@ -21,6 +33,12 @@ + status = "disabled"; + }; + ++ pixelvalve@7e807000 { ++ compatible = "brcm,bcm2835-pixelvalve2"; ++ reg = <0x7e807000 0x100>; ++ interrupts = <2 10>; /* pixelvalve */ ++ }; ++ + v3d: v3d@7ec00000 { + compatible = "brcm,bcm2835-v3d"; + reg = <0x7ec00000 0x1000>; +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -188,14 +188,6 @@ + status = "disabled"; + }; + +- pixelvalve@7e206000 { +- interrupts = ; +- }; +- +- pixelvalve@7e207000 { +- interrupts = ; +- }; +- + pwm1: pwm@7e20c800 { + compatible = "brcm,bcm2835-pwm"; + reg = <0x7e20c800 0x28>; +@@ -217,10 +209,6 @@ + hvs@7e400000 { + interrupts = ; + }; +- +- pixelvalve@7e807000 { +- interrupts = ; +- }; + }; + + arm-pmu { +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -432,18 +432,6 @@ + status = "disabled"; + }; + +- pixelvalve@7e206000 { +- compatible = "brcm,bcm2835-pixelvalve0"; +- reg = <0x7e206000 0x100>; +- interrupts = <2 13>; /* pwa0 */ +- }; +- +- pixelvalve@7e207000 { +- compatible = "brcm,bcm2835-pixelvalve1"; +- reg = <0x7e207000 0x100>; +- interrupts = <2 14>; /* pwa1 */ +- }; +- + dpi: dpi@7e208000 { + compatible = "brcm,bcm2835-dpi"; + reg = <0x7e208000 0x8c>; +@@ -608,12 +596,6 @@ + status = "disabled"; + }; + +- pixelvalve@7e807000 { +- compatible = "brcm,bcm2835-pixelvalve2"; +- reg = <0x7e807000 0x100>; +- interrupts = <2 10>; /* pixelvalve */ +- }; +- + hdmi: hdmi@7e902000 { + compatible = "brcm,bcm2835-hdmi"; + reg = <0x7e902000 0x600>, diff --git a/target/linux/bcm27xx/patches-5.4/950-0366-pinctrl-bcm2835-Remove-gpiochip-on-error.patch b/target/linux/bcm27xx/patches-5.4/950-0366-pinctrl-bcm2835-Remove-gpiochip-on-error.patch deleted file mode 100644 index 31a1a24caf..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0366-pinctrl-bcm2835-Remove-gpiochip-on-error.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0cddfafa817a776063ba6f00fb439d9a415235f9 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 6 Jan 2020 16:04:30 +0000 -Subject: [PATCH] pinctrl: bcm2835: Remove gpiochip on error - -A failure in gpiochip_irqchip_add leads to a leak of a gpiochip. Fix -the leak with the use of devm_gpiochip_add_data. - -Fixes: 85ae9e512f43 ("pinctrl: bcm2835: switch to GPIOLIB_IRQCHIP") -Signed-off-by: Phil Elwell ---- - drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c -+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -@@ -1135,7 +1135,7 @@ static int bcm2835_pinctrl_probe(struct - raw_spin_lock_init(&pc->irq_lock[i]); - } - -- err = gpiochip_add_data(&pc->gpio_chip, pc); -+ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); - if (err) { - dev_err(dev, "could not add GPIO chip\n"); - return err; diff --git a/target/linux/bcm27xx/patches-5.4/950-0367-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch b/target/linux/bcm27xx/patches-5.4/950-0367-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch new file mode 100644 index 0000000000..1acf84b7ce --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0367-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch @@ -0,0 +1,26 @@ +From 91ebd8e0ceb2de047e89e1253ff8ddefbc8aa65e Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Wed, 25 Dec 2019 15:32:29 +0100 +Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Fix memory node + +We need to declare the proper device type, otherwise U-Boot won't boot +with this devicetree. While we are this let the bootloader set the actual +memory size. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts +@@ -14,7 +14,8 @@ + }; + + memory@0 { +- reg = <0 0 0x40000000>; ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0>; + }; + + leds { diff --git a/target/linux/bcm27xx/patches-5.4/950-0367-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch b/target/linux/bcm27xx/patches-5.4/950-0367-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch deleted file mode 100644 index 3865ae11fb..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0367-pinctrl-bcm2835-Change-init-order-for-gpio-hogs.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 27cb8bf0442f677380a1df93b93b7589b7ce5243 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 6 Jan 2020 14:05:42 +0000 -Subject: [PATCH] pinctrl: bcm2835: Change init order for gpio hogs - -pinctrl-bcm2835 is a combined pinctrl/gpio driver. Currently the gpio -side is registered first, but this breaks gpio hogs (which are -configured during gpiochip_add_data). Part of the hog initialisation -is a call to pinctrl_gpio_request, and since the pinctrl driver hasn't -yet been registered this results in an -EPROBE_DEFER from which it can -never recover. - -Change the initialisation sequence to register the pinctrl driver -first. - -See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=260600 - -Signed-off-by: Phil Elwell ---- - drivers/pinctrl/bcm/pinctrl-bcm2835.c | 40 ++++++++++++--------------- - 1 file changed, 17 insertions(+), 23 deletions(-) - ---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c -+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -@@ -1135,9 +1135,25 @@ static int bcm2835_pinctrl_probe(struct - raw_spin_lock_init(&pc->irq_lock[i]); - } - -+ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); -+ if (match) { -+ bcm2835_pinctrl_desc.confops = -+ (const struct pinconf_ops *)match->data; -+ } -+ -+ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc); -+ if (IS_ERR(pc->pctl_dev)) -+ return PTR_ERR(pc->pctl_dev); -+ -+ pc->gpio_range = bcm2835_pinctrl_gpio_range; -+ pc->gpio_range.base = pc->gpio_chip.base; -+ pc->gpio_range.gc = &pc->gpio_chip; -+ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); -+ - err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc); - if (err) { - dev_err(dev, "could not add GPIO chip\n"); -+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range); - return err; - } - -@@ -1145,6 +1161,7 @@ static int bcm2835_pinctrl_probe(struct - 0, handle_level_irq, IRQ_TYPE_NONE); - if (err) { - dev_info(dev, "could not add irqchip\n"); -+ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range); - return err; - } - -@@ -1167,29 +1184,6 @@ static int bcm2835_pinctrl_probe(struct - bcm2835_gpio_irq_handler); - } - -- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); -- if (match) { -- bcm2835_pinctrl_desc.confops = -- (const struct pinconf_ops *)match->data; -- } -- -- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node); -- if (match) { -- bcm2835_pinctrl_desc.confops = -- (const struct pinconf_ops *)match->data; -- } -- -- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc); -- if (IS_ERR(pc->pctl_dev)) { -- gpiochip_remove(&pc->gpio_chip); -- return PTR_ERR(pc->pctl_dev); -- } -- -- pc->gpio_range = bcm2835_pinctrl_gpio_range; -- pc->gpio_range.base = pc->gpio_chip.base; -- pc->gpio_range.gc = &pc->gpio_chip; -- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range); -- - return 0; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0368-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch b/target/linux/bcm27xx/patches-5.4/950-0368-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch new file mode 100644 index 0000000000..ce0b8811d0 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0368-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch @@ -0,0 +1,27 @@ +From 10430ccee66023c26c90cdbc0d6381b41dcecfb7 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Wed, 25 Dec 2019 15:43:41 +0100 +Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Backport BT part from + upstream + +The CYW43455 on the Raspberry Pi 4 doesn't use an external pin as lower +power clock anymore. So drop the GPIO clock from pinctrl. While we are at +this add the missing declaration of hardware flow control. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts +@@ -101,7 +101,8 @@ + /* uart0 communicates with the BT module */ + &uart0 { + pinctrl-names = "default"; +- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>; ++ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; ++ uart-has-rtscts; + status = "okay"; + + bluetooth { diff --git a/target/linux/bcm27xx/patches-5.4/950-0368-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch b/target/linux/bcm27xx/patches-5.4/950-0368-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch deleted file mode 100644 index 0221803993..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0368-Pisound-MIDI-communication-fixes-for-scaled-down-CPU.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 67dd4d137557909279a21c1b5de87a24c84903f9 Mon Sep 17 00:00:00 2001 -From: Giedrius -Date: Tue, 7 Jan 2020 11:04:21 +0200 -Subject: [PATCH] Pisound: MIDI communication fixes for scaled down - CPU. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -* Increased maximum SPI communication speed to avoid running too slow - when the CPU is scaled down and losing MIDI data. - -* Keep track of buffer usage in millibytes for higher precision. - -Signed-off-by: Giedrius Trainavičius ---- - sound/soc/bcm/pisound.c | 31 ++++++++++++++++++------------- - 1 file changed, 18 insertions(+), 13 deletions(-) - ---- a/sound/soc/bcm/pisound.c -+++ b/sound/soc/bcm/pisound.c -@@ -1,6 +1,6 @@ - /* - * Pisound Linux kernel module. -- * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound -+ * Copyright (C) 2016-2020 Vilniaus Blokas UAB, https://blokas.io/pisound - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License -@@ -326,7 +326,7 @@ static void spi_transfer(const uint8_t * - transfer.tx_buf = txbuf; - transfer.rx_buf = rxbuf; - transfer.len = len; -- transfer.speed_hz = 100000; -+ transfer.speed_hz = 150000; - transfer.delay_usecs = 10; - spi_message_add_tail(&transfer, &msg); - -@@ -403,9 +403,9 @@ static struct spi_device *pisnd_spi_find - static void pisnd_work_handler(struct work_struct *work) - { - enum { TRANSFER_SIZE = 4 }; -- enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 }; -- enum { MIDI_BYTES_PER_SECOND = 3125 }; -- int out_buffer_used = 0; -+ enum { PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES = 127 * 1000 }; -+ enum { MIDI_MILLIBYTES_PER_JIFFIE = (3125 * 1000) / HZ }; -+ int out_buffer_used_millibytes = 0; - unsigned long now; - uint8_t val; - uint8_t txbuf[TRANSFER_SIZE]; -@@ -445,7 +445,9 @@ static void pisnd_work_handler(struct wo - had_data = false; - memset(txbuf, 0, sizeof(txbuf)); - for (i = 0; i < sizeof(txbuf) && -- out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE; -+ ((out_buffer_used_millibytes+1000 < -+ PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES) || -+ g_ledFlashDurationChanged); - i += 2) { - - val = 0; -@@ -458,7 +460,7 @@ static void pisnd_work_handler(struct wo - } else if (kfifo_get(&spi_fifo_out, &val)) { - txbuf[i+0] = 0x0f; - txbuf[i+1] = val; -- ++out_buffer_used; -+ out_buffer_used_millibytes += 1000; - } - } - -@@ -469,12 +471,14 @@ static void pisnd_work_handler(struct wo - * rate. - */ - now = jiffies; -- out_buffer_used -= -- (MIDI_BYTES_PER_SECOND / HZ) / -- (now - last_transfer_at); -- if (out_buffer_used < 0) -- out_buffer_used = 0; -- last_transfer_at = now; -+ if (now != last_transfer_at) { -+ out_buffer_used_millibytes -= -+ (now - last_transfer_at) * -+ MIDI_MILLIBYTES_PER_JIFFIE; -+ if (out_buffer_used_millibytes < 0) -+ out_buffer_used_millibytes = 0; -+ last_transfer_at = now; -+ } - - for (i = 0; i < sizeof(rxbuf); i += 2) { - if (rxbuf[i]) { -@@ -489,6 +493,7 @@ static void pisnd_work_handler(struct wo - || !kfifo_is_empty(&spi_fifo_out) - || pisnd_spi_has_more() - || g_ledFlashDurationChanged -+ || out_buffer_used_millibytes != 0 - ); - - if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback) diff --git a/target/linux/bcm27xx/patches-5.4/950-0369-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0369-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch new file mode 100644 index 0000000000..fb3a6a3806 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0369-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch @@ -0,0 +1,42 @@ +From 92606b5e0000c25f5daae6c17b0ab71e9fb4c3b4 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Wed, 25 Dec 2019 15:55:29 +0100 +Subject: [PATCH] ARM: dts: bcm2838: Backport node names from upstream + +According to devicetree specification the node name should describe +the general class of device like ethernet or interrupt-controller. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2838.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -27,7 +27,7 @@ + reg = <0x40000000 0x100>; + }; + +- gicv2: gic400@40041000 { ++ gicv2: interrupt-controller@40041000 { + interrupt-controller; + #interrupt-cells = <3>; + compatible = "arm,gic-400"; +@@ -346,7 +346,7 @@ + status = "okay"; + }; + +- genet: genet@7d580000 { ++ genet: ethernet@7d580000 { + compatible = "brcm,genet-v5"; + reg = <0x0 0x7d580000 0x10000>; + status = "okay"; +@@ -362,7 +362,7 @@ + compatible = "brcm,genet-mdio-v5"; + reg = <0xe14 0x8>; + reg-names = "mdio"; +- phy1: genet-phy@0 { ++ phy1: ethernet-phy@0 { + compatible = + "ethernet-phy-ieee802.3-c22"; + /* No interrupts - use PHY_POLL */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0369-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch b/target/linux/bcm27xx/patches-5.4/950-0369-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch deleted file mode 100644 index db90055343..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0369-ARM-dts-bcm283x-Remove-simple-bus-from-fixed-clocks.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 238506ebdea7a0bb928af8403287d5b0d71cdfee Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Fri, 16 Aug 2019 22:32:02 +0200 -Subject: [PATCH] ARM: dts: bcm283x: Remove simple-bus from fixed - clocks - -commit 4b2d24662126b1e2a6b95c9dfe9e9044e105e5bd upstream. - -The fixed clocks doesn't form some kind of bus. So let's remove it. -This fixes the follow DT schema warnings: - -clocks: clock@3:reg:0: [3] is too short -clocks: clock@4:reg:0: [4] is too short -clocks: $nodename:0: 'clocks' does not match '^(bus|soc|axi|ahb|apb)(@[0-9a-f]+)?$' -clocks: #size-cells:0:0: 0 is not one of [1, 2] -clocks: 'ranges' is a required property -clock@3: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+' -clock@4: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+' - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm283x.dtsi | 10 ++-------- - 1 file changed, 2 insertions(+), 8 deletions(-) - ---- a/arch/arm/boot/dts/bcm283x.dtsi -+++ b/arch/arm/boot/dts/bcm283x.dtsi -@@ -635,22 +635,16 @@ - }; - - clocks { -- compatible = "simple-bus"; -- #address-cells = <1>; -- #size-cells = <0>; -- - /* The oscillator is the root of the clock tree. */ -- clk_osc: clock@3 { -+ clk_osc: clk-osc { - compatible = "fixed-clock"; -- reg = <3>; - #clock-cells = <0>; - clock-output-names = "osc"; - clock-frequency = <19200000>; - }; - -- clk_usb: clock@4 { -+ clk_usb: clk-usb { - compatible = "fixed-clock"; -- reg = <4>; - #clock-cells = <0>; - clock-output-names = "otg"; - clock-frequency = <480000000>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch new file mode 100644 index 0000000000..ef26293498 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch @@ -0,0 +1,36 @@ +From b124d4fdc62b91441173854872c26bea6e36d2e5 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Wed, 25 Dec 2019 18:01:57 +0100 +Subject: [PATCH] ARM: dts: bcm283x: Move intc label to + bcm2835-common.dtsi + +The intc label isn't defined in bcm283x.dtsi, so we cannot use it there. +So move it to bcm2835-common.dtsi. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2835-common.dtsi | 2 ++ + arch/arm/boot/dts/bcm283x.dtsi | 1 - + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2835-common.dtsi ++++ b/arch/arm/boot/dts/bcm2835-common.dtsi +@@ -5,6 +5,8 @@ + */ + + / { ++ interrupt-parent = <&intc>; ++ + soc { + intc: interrupt-controller@7e00b200 { + compatible = "brcm,bcm2835-armctrl-ic"; +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -18,7 +18,6 @@ + / { + compatible = "brcm,bcm2835"; + model = "BCM2835"; +- interrupt-parent = <&intc>; + #address-cells = <1>; + #size-cells = <1>; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch deleted file mode 100644 index 3ececc8f92..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0370-ARM-dts-bcm283x-Move-system-timer-back-to-bcm283x.dt.patch +++ /dev/null @@ -1,73 +0,0 @@ -From fcd4bc412167d2a79bf63603e883f4960ca6b2a1 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Fri, 27 Dec 2019 11:15:00 +0100 -Subject: [PATCH] ARM: dts: bcm283x: Move system timer back to - bcm283x.dtsi - -During Raspberry Pi 4 upstream discussion Tim Gover confirmed that the -system timer also exists on BCM2711. So move it back to bcm283x.dtsi and -overwrite the interrupt definition in bcm2838.dtsi. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2835-common.dtsi | 11 ----------- - arch/arm/boot/dts/bcm2838.dtsi | 7 +++++++ - arch/arm/boot/dts/bcm283x.dtsi | 11 +++++++++++ - 3 files changed, 18 insertions(+), 11 deletions(-) - ---- a/arch/arm/boot/dts/bcm2835-common.dtsi -+++ b/arch/arm/boot/dts/bcm2835-common.dtsi -@@ -6,17 +6,6 @@ - - / { - soc { -- timer@7e003000 { -- compatible = "brcm,bcm2835-system-timer"; -- reg = <0x7e003000 0x1000>; -- interrupts = <1 0>, <1 1>, <1 2>, <1 3>; -- /* This could be a reference to BCM2835_CLOCK_TIMER, -- * but we don't have the driver using the common clock -- * support yet. -- */ -- clock-frequency = <1000000>; -- }; -- - intc: interrupt-controller@7e00b200 { - compatible = "brcm,bcm2835-armctrl-ic"; - reg = <0x7e00b200 0x200>; ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -711,6 +711,13 @@ - interrupts = ; - }; - -+&system_timer { -+ interrupts = , -+ , -+ , -+ ; -+}; -+ - &uart0 { - interrupts = ; - }; ---- a/arch/arm/boot/dts/bcm283x.dtsi -+++ b/arch/arm/boot/dts/bcm283x.dtsi -@@ -56,6 +56,17 @@ - #address-cells = <1>; - #size-cells = <1>; - -+ system_timer: timer@7e003000 { -+ compatible = "brcm,bcm2835-system-timer"; -+ reg = <0x7e003000 0x1000>; -+ interrupts = <1 0>, <1 1>, <1 2>, <1 3>; -+ /* This could be a reference to BCM2835_CLOCK_TIMER, -+ * but we don't have the driver using the common clock -+ * support yet. -+ */ -+ clock-frequency = <1000000>; -+ }; -+ - txp: txp@7e004000 { - compatible = "brcm,bcm2835-txp"; - reg = <0x7e004000 0x20>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch b/target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch new file mode 100644 index 0000000000..0e2a78649f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch @@ -0,0 +1,23 @@ +From 2810c8dae6aa7749bc787329d1d5841d0fdaea97 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Wed, 25 Dec 2019 18:19:28 +0100 +Subject: [PATCH] ARM: dts: bcm2838: Remove always-on from armv7-timer + +After moving bcm2835-system-timer to bcm283x.dtsi there is no need for +the always-on for armv7-timer anymore. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2838.dtsi | 1 - + 1 file changed, 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -231,7 +231,6 @@ + ; + arm,cpu-registers-not-fw-configured; +- always-on; + }; + + cpus: cpus { diff --git a/target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch deleted file mode 100644 index 218a846fa3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0371-ARM-dts-bcm283x-Move-pixelvalve-to-bcm2835-common.dt.patch +++ /dev/null @@ -1,112 +0,0 @@ -From d884dfd722a8207749f5c6c08b69287f0c75a553 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Fri, 27 Dec 2019 16:06:13 +0100 -Subject: [PATCH] ARM: dts: bcm283x: Move pixelvalve to - bcm2835-common.dtsi - -According to Eric Anholt the pixelvalves doesn't exists on BCM2711. -So move it to bcm2835-common.dtsi. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2835-common.dtsi | 18 ++++++++++++++++++ - arch/arm/boot/dts/bcm2838.dtsi | 12 ------------ - arch/arm/boot/dts/bcm283x.dtsi | 18 ------------------ - 3 files changed, 18 insertions(+), 30 deletions(-) - ---- a/arch/arm/boot/dts/bcm2835-common.dtsi -+++ b/arch/arm/boot/dts/bcm2835-common.dtsi -@@ -13,6 +13,18 @@ - #interrupt-cells = <2>; - }; - -+ pixelvalve@7e206000 { -+ compatible = "brcm,bcm2835-pixelvalve0"; -+ reg = <0x7e206000 0x100>; -+ interrupts = <2 13>; /* pwa0 */ -+ }; -+ -+ pixelvalve@7e207000 { -+ compatible = "brcm,bcm2835-pixelvalve1"; -+ reg = <0x7e207000 0x100>; -+ interrupts = <2 14>; /* pwa1 */ -+ }; -+ - thermal: thermal@7e212000 { - compatible = "brcm,bcm2835-thermal"; - reg = <0x7e212000 0x8>; -@@ -21,6 +33,12 @@ - status = "disabled"; - }; - -+ pixelvalve@7e807000 { -+ compatible = "brcm,bcm2835-pixelvalve2"; -+ reg = <0x7e807000 0x100>; -+ interrupts = <2 10>; /* pixelvalve */ -+ }; -+ - v3d: v3d@7ec00000 { - compatible = "brcm,bcm2835-v3d"; - reg = <0x7ec00000 0x1000>; ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -188,14 +188,6 @@ - status = "disabled"; - }; - -- pixelvalve@7e206000 { -- interrupts = ; -- }; -- -- pixelvalve@7e207000 { -- interrupts = ; -- }; -- - pwm1: pwm@7e20c800 { - compatible = "brcm,bcm2835-pwm"; - reg = <0x7e20c800 0x28>; -@@ -217,10 +209,6 @@ - hvs@7e400000 { - interrupts = ; - }; -- -- pixelvalve@7e807000 { -- interrupts = ; -- }; - }; - - arm-pmu { ---- a/arch/arm/boot/dts/bcm283x.dtsi -+++ b/arch/arm/boot/dts/bcm283x.dtsi -@@ -432,18 +432,6 @@ - status = "disabled"; - }; - -- pixelvalve@7e206000 { -- compatible = "brcm,bcm2835-pixelvalve0"; -- reg = <0x7e206000 0x100>; -- interrupts = <2 13>; /* pwa0 */ -- }; -- -- pixelvalve@7e207000 { -- compatible = "brcm,bcm2835-pixelvalve1"; -- reg = <0x7e207000 0x100>; -- interrupts = <2 14>; /* pwa1 */ -- }; -- - dpi: dpi@7e208000 { - compatible = "brcm,bcm2835-dpi"; - reg = <0x7e208000 0x8c>; -@@ -608,12 +596,6 @@ - status = "disabled"; - }; - -- pixelvalve@7e807000 { -- compatible = "brcm,bcm2835-pixelvalve2"; -- reg = <0x7e807000 0x100>; -- interrupts = <2 10>; /* pixelvalve */ -- }; -- - hdmi: hdmi@7e902000 { - compatible = "brcm,bcm2835-hdmi"; - reg = <0x7e902000 0x600>, diff --git a/target/linux/bcm27xx/patches-5.4/950-0372-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch b/target/linux/bcm27xx/patches-5.4/950-0372-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch deleted file mode 100644 index 1acf84b7ce..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0372-ARM-dts-bcm2838-rpi-4-b-Fix-memory-node.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 91ebd8e0ceb2de047e89e1253ff8ddefbc8aa65e Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Wed, 25 Dec 2019 15:32:29 +0100 -Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Fix memory node - -We need to declare the proper device type, otherwise U-Boot won't boot -with this devicetree. While we are this let the bootloader set the actual -memory size. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts -@@ -14,7 +14,8 @@ - }; - - memory@0 { -- reg = <0 0 0x40000000>; -+ device_type = "memory"; -+ reg = <0x0 0x0 0x0>; - }; - - leds { diff --git a/target/linux/bcm27xx/patches-5.4/950-0372-net-bcmgenet-Add-RGMII_RXID-support.patch b/target/linux/bcm27xx/patches-5.4/950-0372-net-bcmgenet-Add-RGMII_RXID-support.patch new file mode 100644 index 0000000000..0e13394c7f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0372-net-bcmgenet-Add-RGMII_RXID-support.patch @@ -0,0 +1,28 @@ +From b0aff8993c458396b82ad7d0792199f971413bb8 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Wed, 25 Dec 2019 16:35:54 +0100 +Subject: [PATCH] net: bcmgenet: Add RGMII_RXID support + +This adds the missing support for the PHY mode RGMII_RXID. +It's necessary for the Raspberry Pi 4. + +Signed-off-by: Stefan Wahren +--- + drivers/net/ethernet/broadcom/genet/bcmmii.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c +@@ -274,10 +274,11 @@ int bcmgenet_mii_config(struct net_devic + id_mode_dis = BIT(16); + /* fall through */ + case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: + if (id_mode_dis) + phy_name = "external RGMII (no delay)"; + else +- phy_name = "external RGMII (TX delay)"; ++ phy_name = "external RGMII"; + bcmgenet_sys_writel(priv, + PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); + break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-Backport-genet-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-Backport-genet-from-upstream.patch new file mode 100644 index 0000000000..ffd7d8e540 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-Backport-genet-from-upstream.patch @@ -0,0 +1,97 @@ +From 30bd619480b6a2b92d404a61a1e90ddb76ae4be8 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Wed, 25 Dec 2019 16:40:47 +0100 +Subject: [PATCH] ARM: dts: bcm2838: Backport genet from upstream + +This backport all genet differences (different compatible, right PHY mode, +board specific stuff) from upstream. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 14 ++++++++++++++ + arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 14 ++++++++++++++ + arch/arm/boot/dts/bcm2838.dtsi | 17 ++++------------- + 3 files changed, 32 insertions(+), 13 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -134,6 +134,20 @@ + vqmmc-supply = <&sd_io_1v8_reg>; + }; + ++&genet { ++ phy-handle = <&phy1>; ++ phy-mode = "rgmii-rxid"; ++ status = "okay"; ++}; ++ ++&genet_mdio { ++ phy1: ethernet-phy@1 { ++ /* No PHY interrupt */ ++ reg = <0x1>; ++ led-modes = <0x00 0x08>; /* link/activity link */ ++ }; ++}; ++ + &leds { + act_led: act { + label = "led0"; +--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts +@@ -98,6 +98,20 @@ + vqmmc-supply = <&sd_io_1v8_reg>; + }; + ++&genet { ++ phy-handle = <&phy1>; ++ phy-mode = "rgmii-rxid"; ++ status = "okay"; ++}; ++ ++&genet_mdio { ++ phy1: ethernet-phy@1 { ++ /* No PHY interrupt */ ++ reg = <0x1>; ++ led-modes = <0x00 0x08>; /* link/activity link */ ++ }; ++}; ++ + /* uart0 communicates with the BT module */ + &uart0 { + pinctrl-names = "default"; +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -346,29 +346,20 @@ + }; + + genet: ethernet@7d580000 { +- compatible = "brcm,genet-v5"; ++ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5"; + reg = <0x0 0x7d580000 0x10000>; +- status = "okay"; + #address-cells = <0x1>; + #size-cells = <0x1>; + interrupts = , + ; +- phy-handle = <&phy1>; +- phy-mode = "rgmii"; +- mdio@e14 { ++ status = "disabled"; ++ ++ genet_mdio: mdio@e14 { + #address-cells = <0x0>; + #size-cells = <0x1>; + compatible = "brcm,genet-mdio-v5"; + reg = <0xe14 0x8>; + reg-names = "mdio"; +- phy1: ethernet-phy@0 { +- compatible = +- "ethernet-phy-ieee802.3-c22"; +- /* No interrupts - use PHY_POLL */ +- max-speed = <1000>; +- reg = <0x1>; +- led-modes = <0x00 0x08>; /* link/activity link */ +- }; + }; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch b/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch deleted file mode 100644 index ce0b8811d0..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0373-ARM-dts-bcm2838-rpi-4-b-Backport-BT-part-from-upstre.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 10430ccee66023c26c90cdbc0d6381b41dcecfb7 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Wed, 25 Dec 2019 15:43:41 +0100 -Subject: [PATCH] ARM: dts: bcm2838-rpi-4-b: Backport BT part from - upstream - -The CYW43455 on the Raspberry Pi 4 doesn't use an external pin as lower -power clock anymore. So drop the GPIO clock from pinctrl. While we are at -this add the missing declaration of hardware flow control. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts -@@ -101,7 +101,8 @@ - /* uart0 communicates with the BT module */ - &uart0 { - pinctrl-names = "default"; -- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>; -+ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; -+ uart-has-rtscts; - status = "okay"; - - bluetooth { diff --git a/target/linux/bcm27xx/patches-5.4/950-0374-ARM-bcm-Backport-BCM2711-support-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0374-ARM-bcm-Backport-BCM2711-support-from-upstream.patch new file mode 100644 index 0000000000..8d16152154 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0374-ARM-bcm-Backport-BCM2711-support-from-upstream.patch @@ -0,0 +1,86 @@ +From 88dacbcd946d2e0cd06337ab3f393064ab6aba82 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Fri, 27 Dec 2019 11:40:56 +0100 +Subject: [PATCH] ARM: bcm: Backport BCM2711 support from upstream + +Make the BCM2711 a different machine, but keep it in board_bcm2835. + +Signed-off-by: Stefan Wahren +--- + arch/arm/mach-bcm/Kconfig | 4 ++-- + arch/arm/mach-bcm/board_bcm2835.c | 17 +++++++++++++++-- + arch/arm64/Kconfig.platforms | 5 +++-- + 3 files changed, 20 insertions(+), 6 deletions(-) + +--- a/arch/arm/mach-bcm/Kconfig ++++ b/arch/arm/mach-bcm/Kconfig +@@ -161,7 +161,7 @@ config ARCH_BCM2835 + select GPIOLIB + select ARM_AMBA + select ARM_ERRATA_411920 if ARCH_MULTI_V6 +- select ARM_GIC ++ select ARM_GIC if ARCH_MULTI_V7 + select ARM_TIMER_SP804 + select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 + select TIMER_OF +@@ -175,7 +175,7 @@ config ARCH_BCM2835 + select ZONE_DMA if ARM_LPAE + select MFD_CORE + help +- This enables support for the Broadcom BCM2835 and BCM2836 SoCs. ++ This enables support for the Broadcom BCM2711 and BCM283x SoCs. + This SoC is used in the Raspberry Pi and Roku 2 devices. + + config ARCH_BCM_53573 +--- a/arch/arm/mach-bcm/board_bcm2835.c ++++ b/arch/arm/mach-bcm/board_bcm2835.c +@@ -109,17 +109,30 @@ static const char * const bcm2835_compat + #ifdef CONFIG_ARCH_MULTI_V7 + "brcm,bcm2836", + "brcm,bcm2837", +- "brcm,bcm2711", + #endif + NULL + }; + + DT_MACHINE_START(BCM2835, "BCM2835") ++ .map_io = bcm2835_map_io, ++ .init_machine = bcm2835_init, ++ .dt_compat = bcm2835_compat, ++ .smp = smp_ops(bcm2836_smp_ops), ++MACHINE_END ++ ++static const char * const bcm2711_compat[] = { ++#ifdef CONFIG_ARCH_MULTI_V7 ++ "brcm,bcm2711", ++#endif ++ NULL ++}; ++ ++DT_MACHINE_START(BCM2711, "BCM2711") + #if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) + .dma_zone_size = SZ_1G, + #endif + .map_io = bcm2835_map_io, + .init_machine = bcm2835_init, +- .dt_compat = bcm2835_compat, ++ .dt_compat = bcm2711_compat, + .smp = smp_ops(bcm2836_smp_ops), + MACHINE_END +--- a/arch/arm64/Kconfig.platforms ++++ b/arch/arm64/Kconfig.platforms +@@ -37,11 +37,12 @@ config ARCH_BCM2835 + select PINCTRL + select PINCTRL_BCM2835 + select ARM_AMBA ++ select ARM_GIC + select ARM_TIMER_SP804 + select HAVE_ARM_ARCH_TIMER + help +- This enables support for the Broadcom BCM2837 SoC. +- This SoC is used in the Raspberry Pi 3 device. ++ This enables support for the Broadcom BCM2837 and BCM2711 SoC. ++ These SoCs are used in the Raspberry Pi 3 and 4 devices. + + config ARCH_BCM_IPROC + bool "Broadcom iProc SoC Family" diff --git a/target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch deleted file mode 100644 index fb3a6a3806..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0374-ARM-dts-bcm2838-Backport-node-names-from-upstream.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 92606b5e0000c25f5daae6c17b0ab71e9fb4c3b4 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Wed, 25 Dec 2019 15:55:29 +0100 -Subject: [PATCH] ARM: dts: bcm2838: Backport node names from upstream - -According to devicetree specification the node name should describe -the general class of device like ethernet or interrupt-controller. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2838.dtsi | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -27,7 +27,7 @@ - reg = <0x40000000 0x100>; - }; - -- gicv2: gic400@40041000 { -+ gicv2: interrupt-controller@40041000 { - interrupt-controller; - #interrupt-cells = <3>; - compatible = "arm,gic-400"; -@@ -346,7 +346,7 @@ - status = "okay"; - }; - -- genet: genet@7d580000 { -+ genet: ethernet@7d580000 { - compatible = "brcm,genet-v5"; - reg = <0x0 0x7d580000 0x10000>; - status = "okay"; -@@ -362,7 +362,7 @@ - compatible = "brcm,genet-mdio-v5"; - reg = <0xe14 0x8>; - reg-names = "mdio"; -- phy1: genet-phy@0 { -+ phy1: ethernet-phy@0 { - compatible = - "ethernet-phy-ieee802.3-c22"; - /* No interrupts - use PHY_POLL */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch b/target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch deleted file mode 100644 index ef26293498..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0375-ARM-dts-bcm283x-Move-intc-label-to-bcm2835-common.dt.patch +++ /dev/null @@ -1,36 +0,0 @@ -From b124d4fdc62b91441173854872c26bea6e36d2e5 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Wed, 25 Dec 2019 18:01:57 +0100 -Subject: [PATCH] ARM: dts: bcm283x: Move intc label to - bcm2835-common.dtsi - -The intc label isn't defined in bcm283x.dtsi, so we cannot use it there. -So move it to bcm2835-common.dtsi. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2835-common.dtsi | 2 ++ - arch/arm/boot/dts/bcm283x.dtsi | 1 - - 2 files changed, 2 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2835-common.dtsi -+++ b/arch/arm/boot/dts/bcm2835-common.dtsi -@@ -5,6 +5,8 @@ - */ - - / { -+ interrupt-parent = <&intc>; -+ - soc { - intc: interrupt-controller@7e00b200 { - compatible = "brcm,bcm2835-armctrl-ic"; ---- a/arch/arm/boot/dts/bcm283x.dtsi -+++ b/arch/arm/boot/dts/bcm283x.dtsi -@@ -18,7 +18,6 @@ - / { - compatible = "brcm,bcm2835"; - model = "BCM2835"; -- interrupt-parent = <&intc>; - #address-cells = <1>; - #size-cells = <1>; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0375-hwrng-iproc-rng200-Add-support-for-BCM2711.patch b/target/linux/bcm27xx/patches-5.4/950-0375-hwrng-iproc-rng200-Add-support-for-BCM2711.patch new file mode 100644 index 0000000000..7a47128837 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0375-hwrng-iproc-rng200-Add-support-for-BCM2711.patch @@ -0,0 +1,29 @@ +From d19e54299471dbdf92a3115ec6591a81c527f786 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Fri, 27 Dec 2019 11:55:59 +0100 +Subject: [PATCH] hwrng: iproc-rng200 - Add support for BCM2711 + +commit 0f95b09a5f624964d520c8f6a2674090fb98ae25 upstream. + +BCM2711 features a RNG200 hardware random number generator block. +So make the driver available. + +Signed-off-by: Stefan Wahren +Signed-off-by: Stephen Brennan +Reviewed-by: Matthias Brugger +Reviewed-by: Florian Fainelli +Signed-off-by: Herbert Xu +--- + drivers/char/hw_random/iproc-rng200.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/char/hw_random/iproc-rng200.c ++++ b/drivers/char/hw_random/iproc-rng200.c +@@ -292,6 +292,7 @@ static int iproc_rng200_probe(struct pla + } + + static const struct of_device_id iproc_rng200_of_match[] = { ++ { .compatible = "brcm,bcm2711-rng200", }, + { .compatible = "brcm,bcm7211-rng200", }, + { .compatible = "brcm,bcm7278-rng200", }, + { .compatible = "brcm,iproc-rng200", }, diff --git a/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch b/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch new file mode 100644 index 0000000000..2feda7389e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch @@ -0,0 +1,24 @@ +From 0f4d508ca3dc0eac4ef4ac85190da58285f1580f Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Fri, 27 Dec 2019 12:01:17 +0100 +Subject: [PATCH] ARM: dts: bcm2838: Add upstream RNG compatible + +This adds the ability to use the RNG with an upstream kernel. +Keep the old one for backward compatibility. + +Signed-off-by: Stefan Wahren +--- + arch/arm/boot/dts/bcm2838.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -682,7 +682,7 @@ + }; + + &rng { +- compatible = "brcm,bcm2838-rng200"; ++ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; + }; + + &sdhost { diff --git a/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch b/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch deleted file mode 100644 index 0e2a78649f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0376-ARM-dts-bcm2838-Remove-always-on-from-armv7-timer.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 2810c8dae6aa7749bc787329d1d5841d0fdaea97 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Wed, 25 Dec 2019 18:19:28 +0100 -Subject: [PATCH] ARM: dts: bcm2838: Remove always-on from armv7-timer - -After moving bcm2835-system-timer to bcm283x.dtsi there is no need for -the always-on for armv7-timer anymore. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2838.dtsi | 1 - - 1 file changed, 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -231,7 +231,6 @@ - ; - arm,cpu-registers-not-fw-configured; -- always-on; - }; - - cpus: cpus { diff --git a/target/linux/bcm27xx/patches-5.4/950-0377-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch b/target/linux/bcm27xx/patches-5.4/950-0377-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch new file mode 100644 index 0000000000..49d885cd73 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0377-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch @@ -0,0 +1,26 @@ +From d0be0df98679b7a9a30ba74c065ed30301e2bd22 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 15 Jan 2020 13:59:57 +0000 +Subject: [PATCH] driver: char: rpivid: Destroy the legacy device on + remove + +The legacy name support created a new device that was never destroyed. +If the driver was unloaded and reloaded, it failed due to the +device already existing. + +Fixes: "75f1d14 driver: char: rpivid - also support legacy name" +Signed-off-by: Dave Stevenson +--- + drivers/char/broadcom/rpivid-mem.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/char/broadcom/rpivid-mem.c ++++ b/drivers/char/broadcom/rpivid-mem.c +@@ -233,6 +233,7 @@ static int rpivid_mem_remove(struct plat + struct device *dev = &pdev->dev; + struct rpivid_mem_priv *priv = platform_get_drvdata(pdev); + ++ device_destroy(priv->class, priv->devid + 1); + device_destroy(priv->class, priv->devid); + class_destroy(priv->class); + cdev_del(&priv->rpivid_mem_cdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0377-net-bcmgenet-Add-RGMII_RXID-support.patch b/target/linux/bcm27xx/patches-5.4/950-0377-net-bcmgenet-Add-RGMII_RXID-support.patch deleted file mode 100644 index 0e13394c7f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0377-net-bcmgenet-Add-RGMII_RXID-support.patch +++ /dev/null @@ -1,28 +0,0 @@ -From b0aff8993c458396b82ad7d0792199f971413bb8 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Wed, 25 Dec 2019 16:35:54 +0100 -Subject: [PATCH] net: bcmgenet: Add RGMII_RXID support - -This adds the missing support for the PHY mode RGMII_RXID. -It's necessary for the Raspberry Pi 4. - -Signed-off-by: Stefan Wahren ---- - drivers/net/ethernet/broadcom/genet/bcmmii.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/net/ethernet/broadcom/genet/bcmmii.c -+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c -@@ -274,10 +274,11 @@ int bcmgenet_mii_config(struct net_devic - id_mode_dis = BIT(16); - /* fall through */ - case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: - if (id_mode_dis) - phy_name = "external RGMII (no delay)"; - else -- phy_name = "external RGMII (TX delay)"; -+ phy_name = "external RGMII"; - bcmgenet_sys_writel(priv, - PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); - break; diff --git a/target/linux/bcm27xx/patches-5.4/950-0378-ARM-dts-bcm2838-Backport-genet-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0378-ARM-dts-bcm2838-Backport-genet-from-upstream.patch deleted file mode 100644 index ffd7d8e540..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0378-ARM-dts-bcm2838-Backport-genet-from-upstream.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 30bd619480b6a2b92d404a61a1e90ddb76ae4be8 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Wed, 25 Dec 2019 16:40:47 +0100 -Subject: [PATCH] ARM: dts: bcm2838: Backport genet from upstream - -This backport all genet differences (different compatible, right PHY mode, -board specific stuff) from upstream. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 14 ++++++++++++++ - arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 14 ++++++++++++++ - arch/arm/boot/dts/bcm2838.dtsi | 17 ++++------------- - 3 files changed, 32 insertions(+), 13 deletions(-) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -134,6 +134,20 @@ - vqmmc-supply = <&sd_io_1v8_reg>; - }; - -+&genet { -+ phy-handle = <&phy1>; -+ phy-mode = "rgmii-rxid"; -+ status = "okay"; -+}; -+ -+&genet_mdio { -+ phy1: ethernet-phy@1 { -+ /* No PHY interrupt */ -+ reg = <0x1>; -+ led-modes = <0x00 0x08>; /* link/activity link */ -+ }; -+}; -+ - &leds { - act_led: act { - label = "led0"; ---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2838-rpi-4-b.dts -@@ -98,6 +98,20 @@ - vqmmc-supply = <&sd_io_1v8_reg>; - }; - -+&genet { -+ phy-handle = <&phy1>; -+ phy-mode = "rgmii-rxid"; -+ status = "okay"; -+}; -+ -+&genet_mdio { -+ phy1: ethernet-phy@1 { -+ /* No PHY interrupt */ -+ reg = <0x1>; -+ led-modes = <0x00 0x08>; /* link/activity link */ -+ }; -+}; -+ - /* uart0 communicates with the BT module */ - &uart0 { - pinctrl-names = "default"; ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -346,29 +346,20 @@ - }; - - genet: ethernet@7d580000 { -- compatible = "brcm,genet-v5"; -+ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5"; - reg = <0x0 0x7d580000 0x10000>; -- status = "okay"; - #address-cells = <0x1>; - #size-cells = <0x1>; - interrupts = , - ; -- phy-handle = <&phy1>; -- phy-mode = "rgmii"; -- mdio@e14 { -+ status = "disabled"; -+ -+ genet_mdio: mdio@e14 { - #address-cells = <0x0>; - #size-cells = <0x1>; - compatible = "brcm,genet-mdio-v5"; - reg = <0xe14 0x8>; - reg-names = "mdio"; -- phy1: ethernet-phy@0 { -- compatible = -- "ethernet-phy-ieee802.3-c22"; -- /* No interrupts - use PHY_POLL */ -- max-speed = <1000>; -- reg = <0x1>; -- led-modes = <0x00 0x08>; /* link/activity link */ -- }; - }; - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0378-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch b/target/linux/bcm27xx/patches-5.4/950-0378-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch new file mode 100644 index 0000000000..b61e2c5cfe --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0378-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch @@ -0,0 +1,62 @@ +From 8b95d0d18fcfb940fb0d171663ce5c93b8fb0024 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 21 Jan 2020 16:24:45 +0000 +Subject: [PATCH] driver: char: rpivid: Clean up error handling use of + ERR_PTR/IS_ERR + +The driver used an unnecessary intermediate void* variable so it +only called ERR_PTR once to convert to the error value. + +Switch to converting as the error arises to remove these intermediate +variables. + +Signed-off-by: Dave Stevenson +--- + drivers/char/broadcom/rpivid-mem.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +--- a/drivers/char/broadcom/rpivid-mem.c ++++ b/drivers/char/broadcom/rpivid-mem.c +@@ -130,10 +130,8 @@ static const struct of_device_id rpivid_ + static int rpivid_mem_probe(struct platform_device *pdev) + { + int err; +- void *ptr_err; + const struct of_device_id *id; + struct device *dev = &pdev->dev; +- struct device *rpivid_mem_dev; + struct resource *ioresource; + struct rpivid_mem_priv *priv; + +@@ -183,16 +181,16 @@ static int rpivid_mem_probe(struct platf + /* Create sysfs entries */ + + priv->class = class_create(THIS_MODULE, priv->name); +- ptr_err = priv->class; +- if (IS_ERR(ptr_err)) ++ if (IS_ERR(priv->class)) { ++ err = PTR_ERR(priv->class); + goto failed_class_create; ++ } + +- rpivid_mem_dev = device_create(priv->class, NULL, +- priv->devid, NULL, +- priv->name); +- ptr_err = rpivid_mem_dev; +- if (IS_ERR(ptr_err)) ++ dev = device_create(priv->class, NULL, priv->devid, NULL, priv->name); ++ if (IS_ERR(dev)) { ++ err = PTR_ERR(dev); + goto failed_device_create; ++ } + + /* Legacy alias */ + { +@@ -217,7 +215,6 @@ failed_device_create: + class_destroy(priv->class); + failed_class_create: + cdev_del(&priv->rpivid_mem_cdev); +- err = PTR_ERR(ptr_err); + failed_cdev_add: + unregister_chrdev_region(priv->devid, 1); + failed_alloc_chrdev: diff --git a/target/linux/bcm27xx/patches-5.4/950-0379-ARM-bcm-Backport-BCM2711-support-from-upstream.patch b/target/linux/bcm27xx/patches-5.4/950-0379-ARM-bcm-Backport-BCM2711-support-from-upstream.patch deleted file mode 100644 index 8d16152154..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0379-ARM-bcm-Backport-BCM2711-support-from-upstream.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 88dacbcd946d2e0cd06337ab3f393064ab6aba82 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Fri, 27 Dec 2019 11:40:56 +0100 -Subject: [PATCH] ARM: bcm: Backport BCM2711 support from upstream - -Make the BCM2711 a different machine, but keep it in board_bcm2835. - -Signed-off-by: Stefan Wahren ---- - arch/arm/mach-bcm/Kconfig | 4 ++-- - arch/arm/mach-bcm/board_bcm2835.c | 17 +++++++++++++++-- - arch/arm64/Kconfig.platforms | 5 +++-- - 3 files changed, 20 insertions(+), 6 deletions(-) - ---- a/arch/arm/mach-bcm/Kconfig -+++ b/arch/arm/mach-bcm/Kconfig -@@ -161,7 +161,7 @@ config ARCH_BCM2835 - select GPIOLIB - select ARM_AMBA - select ARM_ERRATA_411920 if ARCH_MULTI_V6 -- select ARM_GIC -+ select ARM_GIC if ARCH_MULTI_V7 - select ARM_TIMER_SP804 - select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 - select TIMER_OF -@@ -175,7 +175,7 @@ config ARCH_BCM2835 - select ZONE_DMA if ARM_LPAE - select MFD_CORE - help -- This enables support for the Broadcom BCM2835 and BCM2836 SoCs. -+ This enables support for the Broadcom BCM2711 and BCM283x SoCs. - This SoC is used in the Raspberry Pi and Roku 2 devices. - - config ARCH_BCM_53573 ---- a/arch/arm/mach-bcm/board_bcm2835.c -+++ b/arch/arm/mach-bcm/board_bcm2835.c -@@ -109,17 +109,30 @@ static const char * const bcm2835_compat - #ifdef CONFIG_ARCH_MULTI_V7 - "brcm,bcm2836", - "brcm,bcm2837", -- "brcm,bcm2711", - #endif - NULL - }; - - DT_MACHINE_START(BCM2835, "BCM2835") -+ .map_io = bcm2835_map_io, -+ .init_machine = bcm2835_init, -+ .dt_compat = bcm2835_compat, -+ .smp = smp_ops(bcm2836_smp_ops), -+MACHINE_END -+ -+static const char * const bcm2711_compat[] = { -+#ifdef CONFIG_ARCH_MULTI_V7 -+ "brcm,bcm2711", -+#endif -+ NULL -+}; -+ -+DT_MACHINE_START(BCM2711, "BCM2711") - #if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE) - .dma_zone_size = SZ_1G, - #endif - .map_io = bcm2835_map_io, - .init_machine = bcm2835_init, -- .dt_compat = bcm2835_compat, -+ .dt_compat = bcm2711_compat, - .smp = smp_ops(bcm2836_smp_ops), - MACHINE_END ---- a/arch/arm64/Kconfig.platforms -+++ b/arch/arm64/Kconfig.platforms -@@ -37,11 +37,12 @@ config ARCH_BCM2835 - select PINCTRL - select PINCTRL_BCM2835 - select ARM_AMBA -+ select ARM_GIC - select ARM_TIMER_SP804 - select HAVE_ARM_ARCH_TIMER - help -- This enables support for the Broadcom BCM2837 SoC. -- This SoC is used in the Raspberry Pi 3 device. -+ This enables support for the Broadcom BCM2837 and BCM2711 SoC. -+ These SoCs are used in the Raspberry Pi 3 and 4 devices. - - config ARCH_BCM_IPROC - bool "Broadcom iProc SoC Family" diff --git a/target/linux/bcm27xx/patches-5.4/950-0379-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch b/target/linux/bcm27xx/patches-5.4/950-0379-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch new file mode 100644 index 0000000000..52aa87ed04 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0379-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch @@ -0,0 +1,42 @@ +From 7b4ea31990c1c43ad8ea86d42c1e451c85933d87 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 15 Jan 2020 14:02:43 +0000 +Subject: [PATCH] driver: char: rpivid: Add error handling to the + legacy device load + +The return value from device_create for the legacy device was never +checked or handled. Add the required error handling. + +Signed-off-by: Dave Stevenson +--- + drivers/char/broadcom/rpivid-mem.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/drivers/char/broadcom/rpivid-mem.c ++++ b/drivers/char/broadcom/rpivid-mem.c +@@ -201,9 +201,14 @@ static int rpivid_mem_probe(struct platf + oldname[3] = 'g'; + oldname[4] = 'o'; + oldname[5] = 'n'; +- (void)device_create(priv->class, NULL, priv->devid + 1, NULL, +- oldname + 1); ++ dev = device_create(priv->class, NULL, priv->devid + 1, NULL, ++ oldname + 1); + kfree(oldname); ++ ++ if (IS_ERR(dev)) { ++ err = PTR_ERR(dev); ++ goto failed_legacy_device_create; ++ } + } + + dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx", +@@ -211,6 +216,8 @@ static int rpivid_mem_probe(struct platf + + return 0; + ++failed_legacy_device_create: ++ device_destroy(priv->class, priv->devid); + failed_device_create: + class_destroy(priv->class); + failed_class_create: diff --git a/target/linux/bcm27xx/patches-5.4/950-0380-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch b/target/linux/bcm27xx/patches-5.4/950-0380-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch new file mode 100644 index 0000000000..26d0c9894b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0380-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch @@ -0,0 +1,31 @@ +From c9faef0f02397b30c389352ab9915fe529889143 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 15 Jan 2020 14:05:45 +0000 +Subject: [PATCH] driver: char: rpivid: Fix coding style whitespace + issues. + +Makes checkpatch happier. + +Signed-off-by: Dave Stevenson +--- + drivers/char/broadcom/rpivid-mem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/char/broadcom/rpivid-mem.c ++++ b/drivers/char/broadcom/rpivid-mem.c +@@ -66,6 +66,7 @@ static int rpivid_mem_open(struct inode + int dev = iminor(inode); + int ret = 0; + struct rpivid_mem_priv *priv; ++ + if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1) + ret = -ENXIO; + +@@ -135,7 +136,6 @@ static int rpivid_mem_probe(struct platf + struct resource *ioresource; + struct rpivid_mem_priv *priv; + +- + /* Allocate buffers and instance data */ + + priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL); diff --git a/target/linux/bcm27xx/patches-5.4/950-0380-hwrng-iproc-rng200-Add-support-for-BCM2711.patch b/target/linux/bcm27xx/patches-5.4/950-0380-hwrng-iproc-rng200-Add-support-for-BCM2711.patch deleted file mode 100644 index 7a47128837..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0380-hwrng-iproc-rng200-Add-support-for-BCM2711.patch +++ /dev/null @@ -1,29 +0,0 @@ -From d19e54299471dbdf92a3115ec6591a81c527f786 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Fri, 27 Dec 2019 11:55:59 +0100 -Subject: [PATCH] hwrng: iproc-rng200 - Add support for BCM2711 - -commit 0f95b09a5f624964d520c8f6a2674090fb98ae25 upstream. - -BCM2711 features a RNG200 hardware random number generator block. -So make the driver available. - -Signed-off-by: Stefan Wahren -Signed-off-by: Stephen Brennan -Reviewed-by: Matthias Brugger -Reviewed-by: Florian Fainelli -Signed-off-by: Herbert Xu ---- - drivers/char/hw_random/iproc-rng200.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/char/hw_random/iproc-rng200.c -+++ b/drivers/char/hw_random/iproc-rng200.c -@@ -292,6 +292,7 @@ static int iproc_rng200_probe(struct pla - } - - static const struct of_device_id iproc_rng200_of_match[] = { -+ { .compatible = "brcm,bcm2711-rng200", }, - { .compatible = "brcm,bcm7211-rng200", }, - { .compatible = "brcm,bcm7278-rng200", }, - { .compatible = "brcm,iproc-rng200", }, diff --git a/target/linux/bcm27xx/patches-5.4/950-0381-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch b/target/linux/bcm27xx/patches-5.4/950-0381-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch deleted file mode 100644 index 2feda7389e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0381-ARM-dts-bcm2838-Add-upstream-RNG-compatible.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0f4d508ca3dc0eac4ef4ac85190da58285f1580f Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Fri, 27 Dec 2019 12:01:17 +0100 -Subject: [PATCH] ARM: dts: bcm2838: Add upstream RNG compatible - -This adds the ability to use the RNG with an upstream kernel. -Keep the old one for backward compatibility. - -Signed-off-by: Stefan Wahren ---- - arch/arm/boot/dts/bcm2838.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -682,7 +682,7 @@ - }; - - &rng { -- compatible = "brcm,bcm2838-rng200"; -+ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; - }; - - &sdhost { diff --git a/target/linux/bcm27xx/patches-5.4/950-0381-driver-char-rpimem-Add-SPDX-licence-header.patch b/target/linux/bcm27xx/patches-5.4/950-0381-driver-char-rpimem-Add-SPDX-licence-header.patch new file mode 100644 index 0000000000..86b9400ac6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0381-driver-char-rpimem-Add-SPDX-licence-header.patch @@ -0,0 +1,19 @@ +From aa5c03a34b59ad840eeac990185c06b631a1e87e Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Wed, 15 Jan 2020 14:07:16 +0000 +Subject: [PATCH] driver: char: rpimem: Add SPDX licence header. + +Stops checkpatch complaining. + +Signed-off-by: Dave Stevenson +--- + drivers/char/broadcom/rpivid-mem.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/char/broadcom/rpivid-mem.c ++++ b/drivers/char/broadcom/rpivid-mem.c +@@ -1,3 +1,4 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + /** + * rpivid-mem.c - character device access to the RPiVid decoder registers + * diff --git a/target/linux/bcm27xx/patches-5.4/950-0382-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch b/target/linux/bcm27xx/patches-5.4/950-0382-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch deleted file mode 100644 index 49d885cd73..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0382-driver-char-rpivid-Destroy-the-legacy-device-on-remo.patch +++ /dev/null @@ -1,26 +0,0 @@ -From d0be0df98679b7a9a30ba74c065ed30301e2bd22 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 15 Jan 2020 13:59:57 +0000 -Subject: [PATCH] driver: char: rpivid: Destroy the legacy device on - remove - -The legacy name support created a new device that was never destroyed. -If the driver was unloaded and reloaded, it failed due to the -device already existing. - -Fixes: "75f1d14 driver: char: rpivid - also support legacy name" -Signed-off-by: Dave Stevenson ---- - drivers/char/broadcom/rpivid-mem.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/char/broadcom/rpivid-mem.c -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -233,6 +233,7 @@ static int rpivid_mem_remove(struct plat - struct device *dev = &pdev->dev; - struct rpivid_mem_priv *priv = platform_get_drvdata(pdev); - -+ device_destroy(priv->class, priv->devid + 1); - device_destroy(priv->class, priv->devid); - class_destroy(priv->class); - cdev_del(&priv->rpivid_mem_cdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0382-driver-char-rpivid-Fix-access-to-freed-memory.patch b/target/linux/bcm27xx/patches-5.4/950-0382-driver-char-rpivid-Fix-access-to-freed-memory.patch new file mode 100644 index 0000000000..67147fa58d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0382-driver-char-rpivid-Fix-access-to-freed-memory.patch @@ -0,0 +1,27 @@ +From be492eed9f4724798a7b85cf8779772dc901f986 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Tue, 21 Jan 2020 16:44:14 +0000 +Subject: [PATCH] driver: char: rpivid: Fix access to freed memory + +The error path during probe frees the private memory block, and +then promptly dereferences it to log an error message. + +Use the base device instead of the pointer to it in the private +structure. + +Signed-off-by: Dave Stevenson +--- + drivers/char/broadcom/rpivid-mem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/char/broadcom/rpivid-mem.c ++++ b/drivers/char/broadcom/rpivid-mem.c +@@ -229,7 +229,7 @@ failed_alloc_chrdev: + failed_get_resource: + kfree(priv); + failed_inst_alloc: +- dev_err(priv->dev, "could not load rpivid_mem"); ++ dev_err(&pdev->dev, "could not load rpivid_mem"); + return err; + } + diff --git a/target/linux/bcm27xx/patches-5.4/950-0383-add-BME680-to-i2c-sensor-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0383-add-BME680-to-i2c-sensor-overlay.patch new file mode 100644 index 0000000000..0c2fe6aa8a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0383-add-BME680-to-i2c-sensor-overlay.patch @@ -0,0 +1,67 @@ +From 13047f38ca9adef0c0a0b0afce420dc912290d35 Mon Sep 17 00:00:00 2001 +From: Willem Remie +Date: Thu, 9 Jan 2020 21:16:49 +0100 +Subject: [PATCH] add BME680 to i2c-sensor overlay + +--- + arch/arm/boot/dts/overlays/README | 7 +++++-- + .../boot/dts/overlays/i2c-sensor-overlay.dts | 19 ++++++++++++++++++- + 2 files changed, 23 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1159,12 +1159,15 @@ Name: i2c-sensor + Info: Adds support for a number of I2C barometric pressure and temperature + sensors on i2c_arm + Load: dtoverlay=i2c-sensor,= +-Params: addr Set the address for the BME280, BMP280, DS1621, +- HDC100X, LM75, SHT3x or TMP102 ++Params: addr Set the address for the BME280, BME680, BMP280, ++ DS1621, HDC100X, LM75, SHT3x or TMP102 + + bme280 Select the Bosch Sensortronic BME280 + Valid addresses 0x76-0x77, default 0x76 + ++ bme680 Select the Bosch Sensortronic BME680 ++ Valid addresses 0x76-0x77, default 0x76 ++ + bmp085 Select the Bosch Sensortronic BMP085 + + bmp180 Select the Bosch Sensortronic BMP180 +--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts +@@ -216,10 +216,26 @@ + }; + }; + ++ fragment@14 { ++ target = <&i2c_arm>; ++ __dormant__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ bme680: bme680@76 { ++ compatible = "bosch,bme680"; ++ reg = <0x76>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ + __overrides__ { + addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0", + <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0", +- <&ds1621>,"reg:0"; ++ <&ds1621>,"reg:0", <&bme680>,"reg:0"; + bme280 = <0>,"+0"; + bmp085 = <0>,"+1"; + bmp180 = <0>,"+2"; +@@ -235,5 +251,6 @@ + sht3x = <0>,"+11"; + ds1621 = <0>,"+12"; + max17040 = <0>,"+13"; ++ bme680 = <0>,"+14"; + }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0383-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch b/target/linux/bcm27xx/patches-5.4/950-0383-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch deleted file mode 100644 index b61e2c5cfe..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0383-driver-char-rpivid-Clean-up-error-handling-use-of-ER.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 8b95d0d18fcfb940fb0d171663ce5c93b8fb0024 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 21 Jan 2020 16:24:45 +0000 -Subject: [PATCH] driver: char: rpivid: Clean up error handling use of - ERR_PTR/IS_ERR - -The driver used an unnecessary intermediate void* variable so it -only called ERR_PTR once to convert to the error value. - -Switch to converting as the error arises to remove these intermediate -variables. - -Signed-off-by: Dave Stevenson ---- - drivers/char/broadcom/rpivid-mem.c | 17 +++++++---------- - 1 file changed, 7 insertions(+), 10 deletions(-) - ---- a/drivers/char/broadcom/rpivid-mem.c -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -130,10 +130,8 @@ static const struct of_device_id rpivid_ - static int rpivid_mem_probe(struct platform_device *pdev) - { - int err; -- void *ptr_err; - const struct of_device_id *id; - struct device *dev = &pdev->dev; -- struct device *rpivid_mem_dev; - struct resource *ioresource; - struct rpivid_mem_priv *priv; - -@@ -183,16 +181,16 @@ static int rpivid_mem_probe(struct platf - /* Create sysfs entries */ - - priv->class = class_create(THIS_MODULE, priv->name); -- ptr_err = priv->class; -- if (IS_ERR(ptr_err)) -+ if (IS_ERR(priv->class)) { -+ err = PTR_ERR(priv->class); - goto failed_class_create; -+ } - -- rpivid_mem_dev = device_create(priv->class, NULL, -- priv->devid, NULL, -- priv->name); -- ptr_err = rpivid_mem_dev; -- if (IS_ERR(ptr_err)) -+ dev = device_create(priv->class, NULL, priv->devid, NULL, priv->name); -+ if (IS_ERR(dev)) { -+ err = PTR_ERR(dev); - goto failed_device_create; -+ } - - /* Legacy alias */ - { -@@ -217,7 +215,6 @@ failed_device_create: - class_destroy(priv->class); - failed_class_create: - cdev_del(&priv->rpivid_mem_cdev); -- err = PTR_ERR(ptr_err); - failed_cdev_add: - unregister_chrdev_region(priv->devid, 1); - failed_alloc_chrdev: diff --git a/target/linux/bcm27xx/patches-5.4/950-0384-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch b/target/linux/bcm27xx/patches-5.4/950-0384-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch deleted file mode 100644 index 52aa87ed04..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0384-driver-char-rpivid-Add-error-handling-to-the-legacy-.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 7b4ea31990c1c43ad8ea86d42c1e451c85933d87 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 15 Jan 2020 14:02:43 +0000 -Subject: [PATCH] driver: char: rpivid: Add error handling to the - legacy device load - -The return value from device_create for the legacy device was never -checked or handled. Add the required error handling. - -Signed-off-by: Dave Stevenson ---- - drivers/char/broadcom/rpivid-mem.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - ---- a/drivers/char/broadcom/rpivid-mem.c -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -201,9 +201,14 @@ static int rpivid_mem_probe(struct platf - oldname[3] = 'g'; - oldname[4] = 'o'; - oldname[5] = 'n'; -- (void)device_create(priv->class, NULL, priv->devid + 1, NULL, -- oldname + 1); -+ dev = device_create(priv->class, NULL, priv->devid + 1, NULL, -+ oldname + 1); - kfree(oldname); -+ -+ if (IS_ERR(dev)) { -+ err = PTR_ERR(dev); -+ goto failed_legacy_device_create; -+ } - } - - dev_info(priv->dev, "%s initialised: Registers at 0x%08lx length 0x%08lx", -@@ -211,6 +216,8 @@ static int rpivid_mem_probe(struct platf - - return 0; - -+failed_legacy_device_create: -+ device_destroy(priv->class, priv->devid); - failed_device_create: - class_destroy(priv->class); - failed_class_create: diff --git a/target/linux/bcm27xx/patches-5.4/950-0384-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch b/target/linux/bcm27xx/patches-5.4/950-0384-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch new file mode 100644 index 0000000000..4de95a5449 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0384-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch @@ -0,0 +1,43 @@ +From b7944a79716c115d881898e6a95705b262e7c1c9 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Tue, 7 Jan 2020 10:08:19 +0000 +Subject: [PATCH] dwc_otg: constrain endpoint max packet and transfer + size on split IN + +The hcd would unconditionally set the transfer length to the endpoint +packet size for non-isoc IN transfers. If the remaining buffer length +was less than the length of returned data, random memory would get +scribbled over, with bad effects if it crossed a page boundary. + +Force a babble error if this happens by limiting the max transfer size +to the available buffer space. DMA will stop writing to memory on a +babble condition. + +The hardware expects xfersize to be an integer multiple of maxpacket +size, so override hcchar.b.mps as well. + +Signed-off-by: Jonathan Bell +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +@@ -1811,7 +1811,7 @@ int fiq_fsm_queue_split_transaction(dwc_ + st->nr_errors = 0; + + st->hcchar_copy.d32 = 0; +- st->hcchar_copy.b.mps = hc->max_packet; ++ st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet); + st->hcchar_copy.b.epdir = hc->ep_is_in; + st->hcchar_copy.b.devaddr = hc->dev_addr; + st->hcchar_copy.b.epnum = hc->ep_num; +@@ -1856,7 +1856,7 @@ int fiq_fsm_queue_split_transaction(dwc_ + st->hctsiz_copy.b.pid = hc->data_pid_start; + + if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) { +- hc->xfer_len = hc->max_packet; ++ hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet); + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) { + hc->xfer_len = 188; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0385-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch b/target/linux/bcm27xx/patches-5.4/950-0385-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch deleted file mode 100644 index 26d0c9894b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0385-driver-char-rpivid-Fix-coding-style-whitespace-issue.patch +++ /dev/null @@ -1,31 +0,0 @@ -From c9faef0f02397b30c389352ab9915fe529889143 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 15 Jan 2020 14:05:45 +0000 -Subject: [PATCH] driver: char: rpivid: Fix coding style whitespace - issues. - -Makes checkpatch happier. - -Signed-off-by: Dave Stevenson ---- - drivers/char/broadcom/rpivid-mem.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/char/broadcom/rpivid-mem.c -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -66,6 +66,7 @@ static int rpivid_mem_open(struct inode - int dev = iminor(inode); - int ret = 0; - struct rpivid_mem_priv *priv; -+ - if (dev != DEVICE_MINOR && dev != DEVICE_MINOR + 1) - ret = -ENXIO; - -@@ -135,7 +136,6 @@ static int rpivid_mem_probe(struct platf - struct resource *ioresource; - struct rpivid_mem_priv *priv; - -- - /* Allocate buffers and instance data */ - - priv = kzalloc(sizeof(struct rpivid_mem_priv), GFP_KERNEL); diff --git a/target/linux/bcm27xx/patches-5.4/950-0385-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch b/target/linux/bcm27xx/patches-5.4/950-0385-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch new file mode 100644 index 0000000000..0a7356ffa2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0385-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch @@ -0,0 +1,95 @@ +From 09648b92a71b03450e9482f0cc5bd22298f78d44 Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Wed, 8 Jan 2020 12:48:09 +0000 +Subject: [PATCH] dwc_otg: fiq_fsm: pause when cancelling split + transactions + +Non-periodic splits will DMA to/from the driver-provided transfer_buffer, +which may be freed immediately after the dequeue call returns. Block until +we know the transfer is complete. + +A similar delay is needed when cleaning up disconnects, as the FIQ could +have started a periodic transfer in the previous microframe to the one +that triggered a disconnect. + +Signed-off-by: Jonathan Bell +--- + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 33 +++++++++++++++++++++-- + drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 1 + + 2 files changed, 32 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +@@ -175,6 +175,7 @@ static void kill_urbs_in_qh_list(dwc_otg + dwc_list_link_t *qh_item, *qh_tmp; + dwc_otg_qh_t *qh; + dwc_otg_qtd_t *qtd, *qtd_tmp; ++ int quiesced = 0; + + DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) { + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry); +@@ -198,8 +199,17 @@ static void kill_urbs_in_qh_list(dwc_otg + qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE; + qh->channel->halt_pending = 1; + if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO || +- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) ++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) + hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED; ++ /* We're called from disconnect callback or in the middle of freeing the HCD here, ++ * so FIQ is disabled, top-level interrupts masked and we're holding the spinlock. ++ * No further URBs will be submitted, but wait 1 microframe for any previously ++ * submitted periodic DMA to finish. ++ */ ++ if (!quiesced) { ++ udelay(125); ++ quiesced = 1; ++ } + } else { + dwc_otg_hc_halt(hcd->core_if, qh->channel, + DWC_OTG_HC_XFER_URB_DEQUEUE); +@@ -600,15 +610,34 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_ + /* In FIQ FSM mode, we need to shut down carefully. + * The FIQ may attempt to restart a disabled channel */ + if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) { ++ int retries = 3; ++ int running = 0; ++ enum fiq_fsm_state state; ++ + local_fiq_disable(); + fiq_fsm_spin_lock(&hcd->fiq_state->lock); + qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE; + qh->channel->halt_pending = 1; + if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO || +- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) ++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) + hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED; + fiq_fsm_spin_unlock(&hcd->fiq_state->lock); + local_fiq_enable(); ++ ++ if (dwc_qh_is_non_per(qh)) { ++ do { ++ state = READ_ONCE(hcd->fiq_state->channel[n].fsm); ++ running = (state != FIQ_NP_SPLIT_DONE) && ++ (state != FIQ_NP_SPLIT_LS_ABORTED) && ++ (state != FIQ_NP_SPLIT_HS_ABORTED); ++ if (!running) ++ break; ++ udelay(125); ++ } while(--retries); ++ if (!retries) ++ DWC_WARN("Timed out waiting for FSM NP transfer to complete on %d", ++ qh->channel->hc_num); ++ } + } else { + dwc_otg_hc_halt(hcd->core_if, qh->channel, + DWC_OTG_HC_XFER_URB_DEQUEUE); +--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h ++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + diff --git a/target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpimem-Add-SPDX-licence-header.patch b/target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpimem-Add-SPDX-licence-header.patch deleted file mode 100644 index 86b9400ac6..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0386-driver-char-rpimem-Add-SPDX-licence-header.patch +++ /dev/null @@ -1,19 +0,0 @@ -From aa5c03a34b59ad840eeac990185c06b631a1e87e Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Wed, 15 Jan 2020 14:07:16 +0000 -Subject: [PATCH] driver: char: rpimem: Add SPDX licence header. - -Stops checkpatch complaining. - -Signed-off-by: Dave Stevenson ---- - drivers/char/broadcom/rpivid-mem.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/char/broadcom/rpivid-mem.c -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -1,3 +1,4 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause - /** - * rpivid-mem.c - character device access to the RPiVid decoder registers - * diff --git a/target/linux/bcm27xx/patches-5.4/950-0386-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch b/target/linux/bcm27xx/patches-5.4/950-0386-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch new file mode 100644 index 0000000000..e986f425ff --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0386-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch @@ -0,0 +1,49 @@ +From edbbc60ed86f4b690838e6c4b0aed48803e334cc Mon Sep 17 00:00:00 2001 +From: Jonathan Bell +Date: Mon, 13 Jan 2020 15:54:55 +0000 +Subject: [PATCH] dwc_otg: fiq_fsm: add a barrier on entry into FIQ + handler(s) + +On BCM2835, there is no hardware guarantee that multiple outstanding +reads to different peripherals will complete in-order. The FIQ code +uses peripheral reads without barriers for performance, so in the case +where a read to a slow peripheral was issued immediately prior to FIQ +entry, the first peripheral read that the FIQ did could end up with +wrong read data returned. + +Add dsb(sy) on entry so that all outstanding reads are retired. + +The FIQ only issues reads to the dwc_otg core, so per-read barriers +in the handler itself are not required. + +On BCM2836 and BCM2837 the barrier is not strictly required due to +differences in how the peripheral bus is implemented, but having +arch-specific handlers that introduce different latencies is risky. + +Signed-off-by: Jonathan Bell +--- + drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c ++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c +@@ -1259,6 +1259,9 @@ void notrace dwc_otg_fiq_fsm(struct fiq_ + haintmsk_data_t haintmsk; + int kick_irq = 0; + ++ /* Ensure peripheral reads issued prior to FIQ entry are complete */ ++ dsb(sy); ++ + gintsts_handled.d32 = 0; + haint_handled.d32 = 0; + +@@ -1379,6 +1382,9 @@ void notrace dwc_otg_fiq_nop(struct fiq_ + gintmsk_data_t gintmsk; + hfnum_data_t hfnum; + ++ /* Ensure peripheral reads issued prior to FIQ entry are complete */ ++ dsb(sy); ++ + fiq_fsm_spin_lock(&state->lock); + hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); + gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); diff --git a/target/linux/bcm27xx/patches-5.4/950-0387-Add-universal-device-tree-overlay-for-SPI-devices.patch b/target/linux/bcm27xx/patches-5.4/950-0387-Add-universal-device-tree-overlay-for-SPI-devices.patch new file mode 100644 index 0000000000..cb8fa91bef --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0387-Add-universal-device-tree-overlay-for-SPI-devices.patch @@ -0,0 +1,273 @@ +From 17159731ae064a70031d746284855b7d30f17407 Mon Sep 17 00:00:00 2001 +From: Ed Spiridonov +Date: Tue, 10 Dec 2019 22:45:04 +0300 +Subject: [PATCH] Add universal device tree overlay for SPI devices + +Just specify the SPI address and device name ("compatible" property). +This overlay lacks any device-specific parameter support! +(some of them could be added later) + +Examples: +1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz: + dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000 +2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz: + dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204" + +Signed-off-by: Ed Spiridonov +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 23 ++ + arch/arm/boot/dts/overlays/anyspi-overlay.dts | 205 ++++++++++++++++++ + 3 files changed, 229 insertions(+) + create mode 100755 arch/arm/boot/dts/overlays/anyspi-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + allo-katana-dac-audio.dtbo \ + allo-piano-dac-pcm512x-audio.dtbo \ + allo-piano-dac-plus-pcm512x-audio.dtbo \ ++ anyspi.dtbo \ + apds9960.dtbo \ + applepi-dac.dtbo \ + at86rf233.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -441,6 +441,29 @@ Params: 24db_digital_gain Allow ga + better voice quality. (default Off) + + ++Name: anyspi ++Info: Universal device tree overlay for SPI devices ++ ++ Just specify the SPI address and device name ("compatible" property). ++ This overlay lacks any device-specific parameter support! ++ ++ For devices on spi1 or spi2, the interfaces should be enabled ++ with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays. ++ ++ Examples: ++ 1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz: ++ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000 ++ 2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz: ++ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204" ++Load: dtoverlay=anyspi,= ++Params: spi- Configure device at spi, cs ++ (boolean, required) ++ dev Set device name to search compatible module ++ (string, required) ++ speed Set SPI clock frequency in Hz ++ (integer, optional, default 500000) ++ ++ + Name: apds9960 + Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and + gesture sensor +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/anyspi-overlay.dts +@@ -0,0 +1,205 @@ ++/* ++ * Universal device tree overlay for SPI devices ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&spidev0>; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&spidev1>; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "spi1/spidev@0"; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@3 { ++ target-path = "spi1/spidev@1"; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@4 { ++ target-path = "spi1/spidev@2"; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@5 { ++ target-path = "spi2/spidev@0"; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@6 { ++ target-path = "spi2/spidev@1"; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@7 { ++ target-path = "spi2/spidev@2"; ++ __dormant__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@8 { ++ target = <&spi0>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_00: anyspi@0 { ++ reg = <0>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ fragment@9 { ++ target = <&spi0>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_01: anyspi@1 { ++ reg = <1>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ fragment@10 { ++ target = <&spi1>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_10: anyspi@0 { ++ reg = <0>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ fragment@11 { ++ target = <&spi1>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_11: anyspi@1 { ++ reg = <1>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ fragment@12 { ++ target = <&spi1>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_12: anyspi@2 { ++ reg = <2>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ fragment@13 { ++ target = <&spi2>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_20: anyspi@0 { ++ reg = <0>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ fragment@14 { ++ target = <&spi2>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_21: anyspi@1 { ++ reg = <1>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ fragment@15 { ++ target = <&spi2>; ++ __dormant__ { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ anyspi_22: anyspi@2 { ++ reg = <2>; ++ spi-max-frequency = <500000>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ spi0-0 = <0>, "+0+8"; ++ spi0-1 = <0>, "+1+9"; ++ spi1-0 = <0>, "+2+10"; ++ spi1-1 = <0>, "+3+11"; ++ spi1-2 = <0>, "+4+12"; ++ spi2-0 = <0>, "+5+13"; ++ spi2-1 = <0>, "+6+14"; ++ spi2-2 = <0>, "+7+15"; ++ dev = <&anyspi_00>,"compatible", ++ <&anyspi_01>,"compatible", ++ <&anyspi_10>,"compatible", ++ <&anyspi_11>,"compatible", ++ <&anyspi_12>,"compatible", ++ <&anyspi_20>,"compatible", ++ <&anyspi_21>,"compatible", ++ <&anyspi_22>,"compatible"; ++ speed = <&anyspi_00>, "spi-max-frequency:0", ++ <&anyspi_01>, "spi-max-frequency:0", ++ <&anyspi_10>, "spi-max-frequency:0", ++ <&anyspi_11>, "spi-max-frequency:0", ++ <&anyspi_12>, "spi-max-frequency:0", ++ <&anyspi_20>, "spi-max-frequency:0", ++ <&anyspi_21>, "spi-max-frequency:0", ++ <&anyspi_22>, "spi-max-frequency:0"; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpivid-Fix-access-to-freed-memory.patch b/target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpivid-Fix-access-to-freed-memory.patch deleted file mode 100644 index 67147fa58d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0387-driver-char-rpivid-Fix-access-to-freed-memory.patch +++ /dev/null @@ -1,27 +0,0 @@ -From be492eed9f4724798a7b85cf8779772dc901f986 Mon Sep 17 00:00:00 2001 -From: Dave Stevenson -Date: Tue, 21 Jan 2020 16:44:14 +0000 -Subject: [PATCH] driver: char: rpivid: Fix access to freed memory - -The error path during probe frees the private memory block, and -then promptly dereferences it to log an error message. - -Use the base device instead of the pointer to it in the private -structure. - -Signed-off-by: Dave Stevenson ---- - drivers/char/broadcom/rpivid-mem.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/char/broadcom/rpivid-mem.c -+++ b/drivers/char/broadcom/rpivid-mem.c -@@ -229,7 +229,7 @@ failed_alloc_chrdev: - failed_get_resource: - kfree(priv); - failed_inst_alloc: -- dev_err(priv->dev, "could not load rpivid_mem"); -+ dev_err(&pdev->dev, "could not load rpivid_mem"); - return err; - } - diff --git a/target/linux/bcm27xx/patches-5.4/950-0388-add-BME680-to-i2c-sensor-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0388-add-BME680-to-i2c-sensor-overlay.patch deleted file mode 100644 index 0c2fe6aa8a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0388-add-BME680-to-i2c-sensor-overlay.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 13047f38ca9adef0c0a0b0afce420dc912290d35 Mon Sep 17 00:00:00 2001 -From: Willem Remie -Date: Thu, 9 Jan 2020 21:16:49 +0100 -Subject: [PATCH] add BME680 to i2c-sensor overlay - ---- - arch/arm/boot/dts/overlays/README | 7 +++++-- - .../boot/dts/overlays/i2c-sensor-overlay.dts | 19 ++++++++++++++++++- - 2 files changed, 23 insertions(+), 3 deletions(-) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -1159,12 +1159,15 @@ Name: i2c-sensor - Info: Adds support for a number of I2C barometric pressure and temperature - sensors on i2c_arm - Load: dtoverlay=i2c-sensor,= --Params: addr Set the address for the BME280, BMP280, DS1621, -- HDC100X, LM75, SHT3x or TMP102 -+Params: addr Set the address for the BME280, BME680, BMP280, -+ DS1621, HDC100X, LM75, SHT3x or TMP102 - - bme280 Select the Bosch Sensortronic BME280 - Valid addresses 0x76-0x77, default 0x76 - -+ bme680 Select the Bosch Sensortronic BME680 -+ Valid addresses 0x76-0x77, default 0x76 -+ - bmp085 Select the Bosch Sensortronic BMP085 - - bmp180 Select the Bosch Sensortronic BMP180 ---- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts -+++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts -@@ -216,10 +216,26 @@ - }; - }; - -+ fragment@14 { -+ target = <&i2c_arm>; -+ __dormant__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ bme680: bme680@76 { -+ compatible = "bosch,bme680"; -+ reg = <0x76>; -+ status = "okay"; -+ }; -+ }; -+ }; -+ -+ - __overrides__ { - addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0", - <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0", -- <&ds1621>,"reg:0"; -+ <&ds1621>,"reg:0", <&bme680>,"reg:0"; - bme280 = <0>,"+0"; - bmp085 = <0>,"+1"; - bmp180 = <0>,"+2"; -@@ -235,5 +251,6 @@ - sht3x = <0>,"+11"; - ds1621 = <0>,"+12"; - max17040 = <0>,"+13"; -+ bme680 = <0>,"+14"; - }; - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch b/target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch new file mode 100644 index 0000000000..6b9a6bd29c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0388-sound-Add-the-HiFiBerry-DAC-HD-version.patch @@ -0,0 +1,801 @@ +From 221b442eb7e5b4ed16151b5501f4b905a9b8455c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= + +Date: Tue, 21 Jan 2020 15:58:39 +0100 +Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version + +This adds the driver for the DAC+HD version supporting HiFiBerry's +PCM179x based DACs. It also adds PLL control for clock generation. + +Signed-off-by: Joerg Schambacher +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 + + .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++ + drivers/clk/Kconfig | 3 + + drivers/clk/Makefile | 1 + + drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++ + sound/soc/bcm/Kconfig | 9 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/hifiberry_dacplushd.c | 238 +++++++++++++ + 14 files changed, 704 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts + create mode 100644 drivers/clk/clk-hifiberry-dachd.c + create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + hifiberry-dacplusadc.dtbo \ + hifiberry-dacplusadcpro.dtbo \ + hifiberry-dacplusdsp.dtbo \ ++ hifiberry-dacplushd.dtbo \ + hifiberry-digi.dtbo \ + hifiberry-digi-pro.dtbo \ + hy28a.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp + Params: + + ++Name: hifiberry-dacplushd ++Info: Configures the HifiBerry DAC+ HD audio card ++Load: dtoverlay=hifiberry-dacplushd ++Params: ++ ++ + Name: hifiberry-digi + Info: Configures the HifiBerry Digi and Digi+ audio card + Load: dtoverlay=hifiberry-digi +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts +@@ -0,0 +1,106 @@ ++// Definitions for HiFiBerry DAC+ HD ++/dts-v1/; ++/plugin/; ++ ++#include ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target-path = "/clocks"; ++ __overlay__ { ++ dachd_osc: pll_dachd_osc { ++ compatible = "hifiberry,dachd-clk"; ++ #clock-cells = <0>; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&i2s>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ pcm1792a@4c { ++ compatible = "ti,pcm1792a"; ++ #sound-dai-cells = <0>; ++ #clock-cells = <0>; ++ clocks = <&dachd_osc>; ++ reg = <0x4c>; ++ status = "okay"; ++ }; ++ pll: pll@62 { ++ compatible = "hifiberry,dachd-clk"; ++ #clock-cells = <0>; ++ reg = <0x62>; ++ clocks = <&dachd_osc>; ++ status = "okay"; ++ common_pll_regs = [ ++ 02 53 03 00 07 20 0F 00 ++ 10 0D 11 1D 12 0D 13 8C ++ 14 8C 15 8C 16 8C 17 8C ++ 18 2A 1C 00 1D 0F 1F 00 ++ 2A 00 2C 00 2F 00 30 00 ++ 31 00 32 00 34 00 37 00 ++ 38 00 39 00 3A 00 3B 01 ++ 3E 00 3F 00 40 00 41 00 ++ 5A 00 5B 00 95 00 96 00 ++ 97 00 98 00 99 00 9A 00 ++ 9B 00 A2 00 A3 00 A4 00 ++ B7 92 ]; ++ 192k_pll_regs = [ ++ 1A 0C 1B 35 1E F0 20 09 ++ 21 50 2B 02 2D 10 2E 40 ++ 33 01 35 22 36 80 3C 22 ++ 3D 46 ]; ++ 96k_pll_regs = [ ++ 1A 0C 1B 35 1E F0 20 09 ++ 21 50 2B 02 2D 10 2E 40 ++ 33 01 35 47 36 00 3C 32 ++ 3D 46 ]; ++ 48k_pll_regs = [ ++ 1A 0C 1B 35 1E F0 20 09 ++ 21 50 2B 02 2D 10 2E 40 ++ 33 01 35 90 36 00 3C 42 ++ 3D 46 ]; ++ 176k4_pll_regs = [ ++ 1A 3D 1B 09 1E F3 20 13 ++ 21 75 2B 04 2D 11 2E E0 ++ 33 02 35 25 36 C0 3C 22 ++ 3D 7A ]; ++ 88k2_pll_regs = [ ++ 1A 3D 1B 09 1E F3 20 13 ++ 21 75 2B 04 2D 11 2E E0 ++ 33 01 35 4D 36 80 3C 32 ++ 3D 7A ]; ++ 44k1_pll_regs = [ ++ 1A 3D 1B 09 1E F3 20 13 ++ 21 75 2B 04 2D 11 2E E0 ++ 33 01 35 9D 36 00 3C 42 ++ 3D 7A ]; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&sound>; ++ __overlay__ { ++ compatible = "hifiberry,hifiberry-dacplushd"; ++ i2s-controller = <&i2s>; ++ clocks = <&pll 0>; ++ reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>; ++ status = "okay"; ++ }; ++ }; ++ ++}; +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -70,6 +70,9 @@ config COMMON_CLK_HI655X + multi-function device has one fixed-rate oscillator, clocked + at 32KHz. + ++config COMMON_CLK_HIFIBERRY_DACPLUSHD ++ tristate ++ + config COMMON_CLK_HIFIBERRY_DACPRO + tristate + +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -36,6 +36,7 @@ obj-$(CONFIG_ARCH_HIGHBANK) += clk-high + obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o + obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o + obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO) += clk-hifiberry-dacpro.o ++obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o + obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o + obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o + obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o +--- /dev/null ++++ b/drivers/clk/clk-hifiberry-dachd.c +@@ -0,0 +1,333 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Clock Driver for HiFiBerry DAC+ HD ++ * ++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry ++ * Copyright 2020 ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define NO_PLL_RESET 0 ++#define PLL_RESET 1 ++#define HIFIBERRY_PLL_MAX_REGISTER 256 ++#define DEFAULT_RATE 44100 ++ ++static struct reg_default hifiberry_pll_reg_defaults[] = { ++ {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00}, ++ {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C}, ++ {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C}, ++ {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00}, ++ {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00}, ++ {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00}, ++ {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01}, ++ {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00}, ++ {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00}, ++ {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00}, ++ {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00}, ++ {0xB7, 0x92}, ++ {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13}, ++ {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0}, ++ {0x3D, 0x7A}, ++ {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42}, ++ { 177, 0xAC}, ++}; ++static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; ++static int num_common_pll_regs; ++static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; ++static int num_dedicated_192k_pll_regs; ++static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; ++static int num_dedicated_96k_pll_regs; ++static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; ++static int num_dedicated_48k_pll_regs; ++static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; ++static int num_dedicated_176k4_pll_regs; ++static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; ++static int num_dedicated_88k2_pll_regs; ++static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; ++static int num_dedicated_44k1_pll_regs; ++ ++/** ++ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk ++ * @hw: clk_hw for the common clk framework ++ */ ++struct clk_hifiberry_drvdata { ++ struct regmap *regmap; ++ struct clk *clk; ++ struct clk_hw hw; ++ unsigned long rate; ++}; ++ ++#define to_hifiberry_clk(_hw) \ ++ container_of(_hw, struct clk_hifiberry_drvdata, hw) ++ ++static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap, ++ struct reg_default *regs, ++ int num, int do_pll_reset) ++{ ++ int i; ++ int ret = 0; ++ char pll_soft_reset[] = { 177, 0xAC, }; ++ ++ for (i = 0; i < num; i++) { ++ ret |= regmap_write(regmap, regs[i].reg, regs[i].def); ++ if (ret) ++ return ret; ++ } ++ if (do_pll_reset) { ++ ret |= regmap_write(regmap, pll_soft_reset[0], ++ pll_soft_reset[1]); ++ mdelay(10); ++ } ++ return ret; ++} ++ ++static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return to_hifiberry_clk(hw)->rate; ++} ++ ++static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long *parent_rate) ++{ ++ return rate; ++} ++ ++static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw, ++ unsigned long rate, unsigned long parent_rate) ++{ ++ int ret; ++ struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw); ++ ++ switch (rate) { ++ case 44100: ++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, ++ dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs, ++ PLL_RESET); ++ break; ++ case 88200: ++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, ++ dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs, ++ PLL_RESET); ++ break; ++ case 176400: ++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, ++ dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs, ++ PLL_RESET); ++ break; ++ case 48000: ++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, ++ dedicated_48k_pll_regs, num_dedicated_48k_pll_regs, ++ PLL_RESET); ++ break; ++ case 96000: ++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, ++ dedicated_96k_pll_regs, num_dedicated_96k_pll_regs, ++ PLL_RESET); ++ break; ++ case 192000: ++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, ++ dedicated_192k_pll_regs, num_dedicated_192k_pll_regs, ++ PLL_RESET); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ to_hifiberry_clk(hw)->rate = rate; ++ ++ return ret; ++} ++ ++const struct clk_ops clk_hifiberry_dachd_rate_ops = { ++ .recalc_rate = clk_hifiberry_dachd_recalc_rate, ++ .round_rate = clk_hifiberry_dachd_round_rate, ++ .set_rate = clk_hifiberry_dachd_set_rate, ++}; ++ ++static int clk_hifiberry_get_prop_values(struct device *dev, ++ char *prop_name, ++ struct reg_default *regs) ++{ ++ int ret; ++ int i; ++ u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER]; ++ ++ ret = of_property_read_variable_u8_array(dev->of_node, prop_name, ++ tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER); ++ if (ret < 0) ++ return ret; ++ if (ret & 1) { ++ dev_err(dev, ++ "%s <%s> -> #%i odd number of bytes for reg/val pairs!", ++ __func__, ++ prop_name, ++ ret); ++ return -EINVAL; ++ } ++ ret /= 2; ++ for (i = 0; i < ret; i++) { ++ regs[i].reg = (u32)tmp[2 * i]; ++ regs[i].def = (u32)tmp[2 * i + 1]; ++ } ++ return ret; ++} ++ ++ ++static int clk_hifiberry_dachd_dt_parse(struct device *dev) ++{ ++ num_common_pll_regs = clk_hifiberry_get_prop_values(dev, ++ "common_pll_regs", common_pll_regs); ++ num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev, ++ "44k1_pll_regs", dedicated_44k1_pll_regs); ++ num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev, ++ "88k2_pll_regs", dedicated_88k2_pll_regs); ++ num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev, ++ "176k4_pll_regs", dedicated_176k4_pll_regs); ++ num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev, ++ "48k_pll_regs", dedicated_48k_pll_regs); ++ num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev, ++ "96k_pll_regs", dedicated_96k_pll_regs); ++ num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev, ++ "192k_pll_regs", dedicated_192k_pll_regs); ++ return 0; ++} ++ ++ ++static int clk_hifiberry_dachd_remove(struct device *dev) ++{ ++ of_clk_del_provider(dev->of_node); ++ return 0; ++} ++ ++const struct regmap_config hifiberry_pll_regmap = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = HIFIBERRY_PLL_MAX_REGISTER, ++ .reg_defaults = hifiberry_pll_reg_defaults, ++ .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults), ++ .cache_type = REGCACHE_RBTREE, ++}; ++EXPORT_SYMBOL_GPL(hifiberry_pll_regmap); ++ ++ ++static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) ++{ ++ struct clk_hifiberry_drvdata *hdclk; ++ int ret = 0; ++ struct clk_init_data init; ++ struct device *dev = &i2c->dev; ++ struct device_node *dev_node = dev->of_node; ++ struct regmap_config config = hifiberry_pll_regmap; ++ ++ hdclk = devm_kzalloc(&i2c->dev, ++ sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL); ++ if (!hdclk) ++ return -ENOMEM; ++ ++ i2c_set_clientdata(i2c, hdclk); ++ ++ hdclk->regmap = devm_regmap_init_i2c(i2c, &config); ++ ++ if (IS_ERR(hdclk->regmap)) ++ return PTR_ERR(hdclk->regmap); ++ ++ /* start PLL to allow detection of DAC */ ++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, ++ hifiberry_pll_reg_defaults, ++ ARRAY_SIZE(hifiberry_pll_reg_defaults), ++ PLL_RESET); ++ if (ret) ++ return ret; ++ ++ clk_hifiberry_dachd_dt_parse(dev); ++ ++ /* restart PLL with configs from DTB */ ++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs, ++ num_common_pll_regs, PLL_RESET); ++ if (ret) ++ return ret; ++ ++ init.name = "clk-hifiberry-dachd"; ++ init.ops = &clk_hifiberry_dachd_rate_ops; ++ init.flags = 0; ++ init.parent_names = NULL; ++ init.num_parents = 0; ++ ++ hdclk->hw.init = &init; ++ ++ hdclk->clk = devm_clk_register(dev, &hdclk->hw); ++ if (IS_ERR(hdclk->clk)) { ++ dev_err(dev, "unable to register %s\n", init.name); ++ return PTR_ERR(hdclk->clk); ++ } ++ ++ ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk); ++ if (ret != 0) { ++ dev_err(dev, "Cannot of_clk_add_provider"); ++ return ret; ++ } ++ ++ ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE); ++ if (ret != 0) { ++ dev_err(dev, "Cannot set rate : %d\n", ret); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c) ++{ ++ clk_hifiberry_dachd_remove(&i2c->dev); ++ return 0; ++} ++ ++static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = { ++ { "dachd-clk", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id); ++ ++static const struct of_device_id clk_hifiberry_dachd_of_match[] = { ++ { .compatible = "hifiberry,dachd-clk", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match); ++ ++static struct i2c_driver clk_hifiberry_dachd_i2c_driver = { ++ .probe = clk_hifiberry_dachd_i2c_probe, ++ .remove = clk_hifiberry_dachd_i2c_remove, ++ .id_table = clk_hifiberry_dachd_i2c_id, ++ .driver = { ++ .name = "dachd-clk", ++ .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match), ++ }, ++}; ++ ++module_i2c_driver(clk_hifiberry_dachd_i2c_driver); ++ ++ ++MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver"); ++MODULE_AUTHOR("Joerg Schambacher "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:clk-hifiberry-dachd"); +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -42,6 +42,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + help + Say Y or M if you want to add support for HifiBerry DAC+. + ++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD ++ tristate "Support for HifiBerry DAC+ HD" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_PCM179X_I2C ++ select COMMON_CLK_HIFIBERRY_DACPLUSHD ++ help ++ Say Y or M if you want to add support for HifiBerry DAC+ HD. ++ + config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC + tristate "Support for HifiBerry DAC+ADC" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S +@@ -56,6 +64,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_PCM512x_I2C + select SND_SOC_PCM186X_I2C ++ select COMMON_CLK_HIFIBERRY_DACPRO + help + Say Y or M if you want to add support for HifiBerry DAC+ADC PRO. + +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo + + # BCM2708 Machine Support + snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o ++snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o + snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o + snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o + snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o +@@ -41,6 +42,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi + + obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o +--- /dev/null ++++ b/sound/soc/bcm/hifiberry_dacplushd.c +@@ -0,0 +1,238 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * ASoC Driver for HiFiBerry DAC+ HD ++ * ++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry ++ * Copyright 2020 ++ * ++ * 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. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/pcm179x.h" ++ ++#define DEFAULT_RATE 44100 ++ ++struct brd_drv_data { ++ struct regmap *regmap; ++ struct clk *sclk; ++}; ++ ++static struct brd_drv_data drvdata; ++static struct gpio_desc *reset_gpio; ++static const unsigned int hb_dacplushd_rates[] = { ++ 192000, 96000, 48000, 176400, 88200, 44100, ++}; ++ ++static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = { ++ .list = hb_dacplushd_rates, ++ .count = ARRAY_SIZE(hb_dacplushd_rates), ++}; ++ ++static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream) ++{ ++ /* constraints for standard sample rates */ ++ snd_pcm_hw_constraint_list(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_RATE, ++ &hb_dacplushd_constraints); ++ return 0; ++} ++ ++static void snd_rpi_hifiberry_dacplushd_set_sclk( ++ struct snd_soc_component *component, ++ int sample_rate) ++{ ++ if (!IS_ERR(drvdata.sclk)) ++ clk_set_rate(drvdata.sclk, sample_rate); ++} ++ ++static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_dai_link *dai = rtd->dai_link; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ dai->name = "HiFiBerry DAC+ HD"; ++ dai->stream_name = "HiFiBerry DAC+ HD HiFi"; ++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM; ++ ++ /* allow only fixed 32 clock counts per channel */ ++ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2); ++ ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_dacplushd_hw_params( ++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) ++{ ++ int ret = 0; ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ ++ struct snd_soc_component *component = rtd->codec_dai->component; ++ ++ snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params)); ++ return ret; ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = { ++ .startup = snd_rpi_hb_dacplushd_startup, ++ .hw_params = snd_rpi_hifiberry_dacplushd_hw_params, ++}; ++ ++SND_SOC_DAILINK_DEFS(hifi, ++ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), ++ DAILINK_COMP_ARRAY(COMP_CODEC("pcm179x.1-004c", "pcm179x-hifi")), ++ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); ++ ++ ++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = { ++{ ++ .name = "HiFiBerry DAC+ HD", ++ .stream_name = "HiFiBerry DAC+ HD HiFi", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_hifiberry_dacplushd_ops, ++ .init = snd_rpi_hifiberry_dacplushd_init, ++ SND_SOC_DAILINK_REG(hifi), ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_hifiberry_dacplushd = { ++ .name = "snd_rpi_hifiberry_dacplushd", ++ .driver_name = "HifiberryDacplusHD", ++ .owner = THIS_MODULE, ++ .dai_link = snd_rpi_hifiberry_dacplushd_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai), ++}; ++ ++static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ static int dac_reset_done; ++ struct device *dev = &pdev->dev; ++ struct device_node *dev_node = dev->of_node; ++ ++ snd_rpi_hifiberry_dacplushd.dev = &pdev->dev; ++ ++ /* get GPIO and release DAC from RESET */ ++ if (!dac_reset_done) { ++ reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW); ++ if (IS_ERR(reset_gpio)) { ++ dev_err(&pdev->dev, "gpiod_get() failed\n"); ++ return -EINVAL; ++ } ++ dac_reset_done = 1; ++ } ++ if (!IS_ERR(reset_gpio)) ++ gpiod_set_value(reset_gpio, 0); ++ msleep(1); ++ if (!IS_ERR(reset_gpio)) ++ gpiod_set_value(reset_gpio, 1); ++ msleep(1); ++ if (!IS_ERR(reset_gpio)) ++ gpiod_set_value(reset_gpio, 0); ++ ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai; ++ ++ dai = &snd_rpi_hifiberry_dacplushd_dai[0]; ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ ++ if (i2s_node) { ++ dai->cpus->of_node = i2s_node; ++ dai->platforms->of_node = i2s_node; ++ dai->cpus->dai_name = NULL; ++ dai->platforms->name = NULL; ++ } else { ++ return -EPROBE_DEFER; ++ } ++ ++ } ++ ++ ret = devm_snd_soc_register_card(&pdev->dev, ++ &snd_rpi_hifiberry_dacplushd); ++ if (ret && ret != -EPROBE_DEFER) { ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ return ret; ++ } ++ if (ret == -EPROBE_DEFER) ++ return ret; ++ ++ dev_set_drvdata(dev, &drvdata); ++ if (dev_node == NULL) { ++ dev_err(&pdev->dev, "Device tree node not found\n"); ++ return -ENODEV; ++ } ++ ++ drvdata.sclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(drvdata.sclk)) { ++ drvdata.sclk = ERR_PTR(-ENOENT); ++ return -ENODEV; ++ } ++ ++ clk_set_rate(drvdata.sclk, DEFAULT_RATE); ++ ++ return ret; ++} ++ ++static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev) ++{ ++ if (IS_ERR(reset_gpio)) ++ return -EINVAL; ++ ++ /* put DAC into RESET and release GPIO */ ++ gpiod_set_value(reset_gpio, 0); ++ gpiod_put(reset_gpio); ++ ++ return 0; ++} ++ ++static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = { ++ { .compatible = "hifiberry,hifiberry-dacplushd", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match); ++ ++static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = { ++ .driver = { ++ .name = "snd-rpi-hifiberry-dacplushd", ++ .owner = THIS_MODULE, ++ .of_match_table = snd_rpi_hifiberry_dacplushd_of_match, ++ }, ++ .probe = snd_rpi_hifiberry_dacplushd_probe, ++ .remove = snd_rpi_hifiberry_dacplushd_remove, ++}; ++ ++module_platform_driver(snd_rpi_hifiberry_dacplushd_driver); ++ ++MODULE_AUTHOR("Joerg Schambacher "); ++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0389-Initialise-rpi-firmware-before-clk-bcm2835.patch b/target/linux/bcm27xx/patches-5.4/950-0389-Initialise-rpi-firmware-before-clk-bcm2835.patch new file mode 100644 index 0000000000..cdd5e7e9ab --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0389-Initialise-rpi-firmware-before-clk-bcm2835.patch @@ -0,0 +1,47 @@ +From 2c1a5dae2fb127729773685e3cd1e48934edf1f2 Mon Sep 17 00:00:00 2001 +From: Luke Hinds <7058938+lukehinds@users.noreply.github.com> +Date: Wed, 22 Jan 2020 16:03:00 +0000 +Subject: [PATCH] Initialise rpi-firmware before clk-bcm2835 + +The IMA (Integrity Measurement Architecture) looks for a TPM (Trusted +Platform Module) having been registered when it initialises; otherwise +it assumes there is no TPM. It has been observed on BCM2835 that IMA +is initialised before TPM, and that initialising the BCM2835 clock +driver before the firmware driver has the effect of reversing this +order. + +Change the firmware driver to initialise at core_initcall, delaying the +BCM2835 clock driver to postcore_initcall. + +See: https://github.com/raspberrypi/linux/issues/3291 + https://github.com/raspberrypi/linux/pull/3297 + +Signed-off-by: Luke Hinds +Co-authored-by: Phil Elwell +--- + drivers/clk/bcm/clk-bcm2835.c | 2 +- + drivers/firmware/raspberrypi.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/clk/bcm/clk-bcm2835.c ++++ b/drivers/clk/bcm/clk-bcm2835.c +@@ -2401,7 +2401,7 @@ static int __init __bcm2835_clk_driver_i + { + return platform_driver_register(&bcm2835_clk_driver); + } +-core_initcall(__bcm2835_clk_driver_init); ++postcore_initcall(__bcm2835_clk_driver_init); + + MODULE_AUTHOR("Eric Anholt "); + MODULE_DESCRIPTION("BCM2835 clock driver"); +--- a/drivers/firmware/raspberrypi.c ++++ b/drivers/firmware/raspberrypi.c +@@ -416,7 +416,7 @@ out2: + out1: + return ret; + } +-subsys_initcall(rpi_firmware_init); ++core_initcall(rpi_firmware_init); + + static void __init rpi_firmware_exit(void) + { diff --git a/target/linux/bcm27xx/patches-5.4/950-0389-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch b/target/linux/bcm27xx/patches-5.4/950-0389-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch deleted file mode 100644 index 4de95a5449..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0389-dwc_otg-constrain-endpoint-max-packet-and-transfer-s.patch +++ /dev/null @@ -1,43 +0,0 @@ -From b7944a79716c115d881898e6a95705b262e7c1c9 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Tue, 7 Jan 2020 10:08:19 +0000 -Subject: [PATCH] dwc_otg: constrain endpoint max packet and transfer - size on split IN - -The hcd would unconditionally set the transfer length to the endpoint -packet size for non-isoc IN transfers. If the remaining buffer length -was less than the length of returned data, random memory would get -scribbled over, with bad effects if it crossed a page boundary. - -Force a babble error if this happens by limiting the max transfer size -to the available buffer space. DMA will stop writing to memory on a -babble condition. - -The hardware expects xfersize to be an integer multiple of maxpacket -size, so override hcchar.b.mps as well. - -Signed-off-by: Jonathan Bell ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -1811,7 +1811,7 @@ int fiq_fsm_queue_split_transaction(dwc_ - st->nr_errors = 0; - - st->hcchar_copy.d32 = 0; -- st->hcchar_copy.b.mps = hc->max_packet; -+ st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet); - st->hcchar_copy.b.epdir = hc->ep_is_in; - st->hcchar_copy.b.devaddr = hc->dev_addr; - st->hcchar_copy.b.epnum = hc->ep_num; -@@ -1856,7 +1856,7 @@ int fiq_fsm_queue_split_transaction(dwc_ - st->hctsiz_copy.b.pid = hc->data_pid_start; - - if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) { -- hc->xfer_len = hc->max_packet; -+ hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet); - } else if (!hc->ep_is_in && (hc->xfer_len > 188)) { - hc->xfer_len = 188; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0390-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch b/target/linux/bcm27xx/patches-5.4/950-0390-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch new file mode 100644 index 0000000000..54b366f65a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0390-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch @@ -0,0 +1,26 @@ +From fa93fc95e5fb4e75a2a5ea930509d80083dee9b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= + +Date: Thu, 23 Jan 2020 13:32:13 +0100 +Subject: [PATCH] Fix master mode settings of HiFiBerry DAC+ADC PRO + card (#3424) + +This patch fixes the board DAI setting when in master-mode. +Wrong setting could have caused random pop noise. + +Signed-off-by: Joerg Schambacher +--- + sound/soc/bcm/hifiberry_dacplusadcpro.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c ++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c +@@ -285,6 +285,8 @@ static int snd_rpi_hifiberry_dacplusadcp + + dai->name = "HiFiBerry DAC+ADC Pro"; + dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi"; ++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF ++ | SND_SOC_DAIFMT_CBM_CFM; + + // set DAC DAI configuration + ret = snd_soc_dai_set_fmt(rtd->codec_dais[0], diff --git a/target/linux/bcm27xx/patches-5.4/950-0390-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch b/target/linux/bcm27xx/patches-5.4/950-0390-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch deleted file mode 100644 index 0a7356ffa2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0390-dwc_otg-fiq_fsm-pause-when-cancelling-split-transact.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 09648b92a71b03450e9482f0cc5bd22298f78d44 Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Wed, 8 Jan 2020 12:48:09 +0000 -Subject: [PATCH] dwc_otg: fiq_fsm: pause when cancelling split - transactions - -Non-periodic splits will DMA to/from the driver-provided transfer_buffer, -which may be freed immediately after the dequeue call returns. Block until -we know the transfer is complete. - -A similar delay is needed when cleaning up disconnects, as the FIQ could -have started a periodic transfer in the previous microframe to the one -that triggered a disconnect. - -Signed-off-by: Jonathan Bell ---- - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 33 +++++++++++++++++++++-- - drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 1 + - 2 files changed, 32 insertions(+), 2 deletions(-) - ---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c -@@ -175,6 +175,7 @@ static void kill_urbs_in_qh_list(dwc_otg - dwc_list_link_t *qh_item, *qh_tmp; - dwc_otg_qh_t *qh; - dwc_otg_qtd_t *qtd, *qtd_tmp; -+ int quiesced = 0; - - DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) { - qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry); -@@ -198,8 +199,17 @@ static void kill_urbs_in_qh_list(dwc_otg - qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE; - qh->channel->halt_pending = 1; - if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO || -- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) -+ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) - hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED; -+ /* We're called from disconnect callback or in the middle of freeing the HCD here, -+ * so FIQ is disabled, top-level interrupts masked and we're holding the spinlock. -+ * No further URBs will be submitted, but wait 1 microframe for any previously -+ * submitted periodic DMA to finish. -+ */ -+ if (!quiesced) { -+ udelay(125); -+ quiesced = 1; -+ } - } else { - dwc_otg_hc_halt(hcd->core_if, qh->channel, - DWC_OTG_HC_XFER_URB_DEQUEUE); -@@ -600,15 +610,34 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_ - /* In FIQ FSM mode, we need to shut down carefully. - * The FIQ may attempt to restart a disabled channel */ - if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) { -+ int retries = 3; -+ int running = 0; -+ enum fiq_fsm_state state; -+ - local_fiq_disable(); - fiq_fsm_spin_lock(&hcd->fiq_state->lock); - qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE; - qh->channel->halt_pending = 1; - if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO || -- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) -+ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING) - hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED; - fiq_fsm_spin_unlock(&hcd->fiq_state->lock); - local_fiq_enable(); -+ -+ if (dwc_qh_is_non_per(qh)) { -+ do { -+ state = READ_ONCE(hcd->fiq_state->channel[n].fsm); -+ running = (state != FIQ_NP_SPLIT_DONE) && -+ (state != FIQ_NP_SPLIT_LS_ABORTED) && -+ (state != FIQ_NP_SPLIT_HS_ABORTED); -+ if (!running) -+ break; -+ udelay(125); -+ } while(--retries); -+ if (!retries) -+ DWC_WARN("Timed out waiting for FSM NP transfer to complete on %d", -+ qh->channel->hc_num); -+ } - } else { - dwc_otg_hc_halt(hcd->core_if, qh->channel, - DWC_OTG_HC_XFER_URB_DEQUEUE); ---- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h -+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #include - diff --git a/target/linux/bcm27xx/patches-5.4/950-0391-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch b/target/linux/bcm27xx/patches-5.4/950-0391-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch deleted file mode 100644 index e986f425ff..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0391-dwc_otg-fiq_fsm-add-a-barrier-on-entry-into-FIQ-hand.patch +++ /dev/null @@ -1,49 +0,0 @@ -From edbbc60ed86f4b690838e6c4b0aed48803e334cc Mon Sep 17 00:00:00 2001 -From: Jonathan Bell -Date: Mon, 13 Jan 2020 15:54:55 +0000 -Subject: [PATCH] dwc_otg: fiq_fsm: add a barrier on entry into FIQ - handler(s) - -On BCM2835, there is no hardware guarantee that multiple outstanding -reads to different peripherals will complete in-order. The FIQ code -uses peripheral reads without barriers for performance, so in the case -where a read to a slow peripheral was issued immediately prior to FIQ -entry, the first peripheral read that the FIQ did could end up with -wrong read data returned. - -Add dsb(sy) on entry so that all outstanding reads are retired. - -The FIQ only issues reads to the dwc_otg core, so per-read barriers -in the handler itself are not required. - -On BCM2836 and BCM2837 the barrier is not strictly required due to -differences in how the peripheral bus is implemented, but having -arch-specific handlers that introduce different latencies is risky. - -Signed-off-by: Jonathan Bell ---- - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c -@@ -1259,6 +1259,9 @@ void notrace dwc_otg_fiq_fsm(struct fiq_ - haintmsk_data_t haintmsk; - int kick_irq = 0; - -+ /* Ensure peripheral reads issued prior to FIQ entry are complete */ -+ dsb(sy); -+ - gintsts_handled.d32 = 0; - haint_handled.d32 = 0; - -@@ -1379,6 +1382,9 @@ void notrace dwc_otg_fiq_nop(struct fiq_ - gintmsk_data_t gintmsk; - hfnum_data_t hfnum; - -+ /* Ensure peripheral reads issued prior to FIQ entry are complete */ -+ dsb(sy); -+ - fiq_fsm_spin_lock(&state->lock); - hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM); - gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS); diff --git a/target/linux/bcm27xx/patches-5.4/950-0391-overlays-Use-preferred-compatible-strings.patch b/target/linux/bcm27xx/patches-5.4/950-0391-overlays-Use-preferred-compatible-strings.patch new file mode 100644 index 0000000000..6a246050cf --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0391-overlays-Use-preferred-compatible-strings.patch @@ -0,0 +1,72 @@ +From f50f0425592a8496d6d25b4936caadfe64523c91 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 24 Jan 2020 09:02:37 +0000 +Subject: [PATCH] overlays: Use preferred compatible strings + +Make sure all overlays have correct compatible strings before enabling +the automated checking. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 2 ++ + arch/arm/boot/dts/overlays/pwm-overlay.dts | 2 ++ + arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 2 ++ + 5 files changed, 8 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts +@@ -3,7 +3,7 @@ + /plugin/; + + / { +- compatible = "brcm,bcm2708"; ++ compatible = "brcm,bcm2835"; + + fragment@0 { + target-path = "/clocks"; +--- a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts ++++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts +@@ -3,7 +3,7 @@ + /plugin/; + + / { +- compatible = "brcm,bcm2708"; ++ compatible = "brcm,bcm2835"; + + fragment@0 { + target = <&i2s>; +--- a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts +@@ -17,6 +17,8 @@ N.B.: + */ + + / { ++ compatible = "brcm,bcm2835"; ++ + fragment@0 { + target = <&gpio>; + __overlay__ { +--- a/arch/arm/boot/dts/overlays/pwm-overlay.dts ++++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts +@@ -15,6 +15,8 @@ N.B.: + */ + + / { ++ compatible = "brcm,bcm2835"; ++ + fragment@0 { + target = <&gpio>; + __overlay__ { +--- a/arch/arm/boot/dts/overlays/smi-dev-overlay.dts ++++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts +@@ -5,6 +5,8 @@ + /plugin/; + + /{ ++ compatible = "brcm,bcm2835"; ++ + fragment@0 { + target = <&soc>; + __overlay__ { diff --git a/target/linux/bcm27xx/patches-5.4/950-0392-Add-universal-device-tree-overlay-for-SPI-devices.patch b/target/linux/bcm27xx/patches-5.4/950-0392-Add-universal-device-tree-overlay-for-SPI-devices.patch deleted file mode 100644 index cb8fa91bef..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0392-Add-universal-device-tree-overlay-for-SPI-devices.patch +++ /dev/null @@ -1,273 +0,0 @@ -From 17159731ae064a70031d746284855b7d30f17407 Mon Sep 17 00:00:00 2001 -From: Ed Spiridonov -Date: Tue, 10 Dec 2019 22:45:04 +0300 -Subject: [PATCH] Add universal device tree overlay for SPI devices - -Just specify the SPI address and device name ("compatible" property). -This overlay lacks any device-specific parameter support! -(some of them could be added later) - -Examples: -1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz: - dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000 -2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz: - dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204" - -Signed-off-by: Ed Spiridonov ---- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 23 ++ - arch/arm/boot/dts/overlays/anyspi-overlay.dts | 205 ++++++++++++++++++ - 3 files changed, 229 insertions(+) - create mode 100755 arch/arm/boot/dts/overlays/anyspi-overlay.dts - ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - allo-katana-dac-audio.dtbo \ - allo-piano-dac-pcm512x-audio.dtbo \ - allo-piano-dac-plus-pcm512x-audio.dtbo \ -+ anyspi.dtbo \ - apds9960.dtbo \ - applepi-dac.dtbo \ - at86rf233.dtbo \ ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -441,6 +441,29 @@ Params: 24db_digital_gain Allow ga - better voice quality. (default Off) - - -+Name: anyspi -+Info: Universal device tree overlay for SPI devices -+ -+ Just specify the SPI address and device name ("compatible" property). -+ This overlay lacks any device-specific parameter support! -+ -+ For devices on spi1 or spi2, the interfaces should be enabled -+ with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays. -+ -+ Examples: -+ 1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz: -+ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000 -+ 2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz: -+ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204" -+Load: dtoverlay=anyspi,= -+Params: spi- Configure device at spi, cs -+ (boolean, required) -+ dev Set device name to search compatible module -+ (string, required) -+ speed Set SPI clock frequency in Hz -+ (integer, optional, default 500000) -+ -+ - Name: apds9960 - Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and - gesture sensor ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/anyspi-overlay.dts -@@ -0,0 +1,205 @@ -+/* -+ * Universal device tree overlay for SPI devices -+ */ -+ -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&spidev0>; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&spidev1>; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@2 { -+ target-path = "spi1/spidev@0"; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@3 { -+ target-path = "spi1/spidev@1"; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@4 { -+ target-path = "spi1/spidev@2"; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@5 { -+ target-path = "spi2/spidev@0"; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@6 { -+ target-path = "spi2/spidev@1"; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@7 { -+ target-path = "spi2/spidev@2"; -+ __dormant__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@8 { -+ target = <&spi0>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_00: anyspi@0 { -+ reg = <0>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ fragment@9 { -+ target = <&spi0>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_01: anyspi@1 { -+ reg = <1>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ fragment@10 { -+ target = <&spi1>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_10: anyspi@0 { -+ reg = <0>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ fragment@11 { -+ target = <&spi1>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_11: anyspi@1 { -+ reg = <1>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ fragment@12 { -+ target = <&spi1>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_12: anyspi@2 { -+ reg = <2>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ fragment@13 { -+ target = <&spi2>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_20: anyspi@0 { -+ reg = <0>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ fragment@14 { -+ target = <&spi2>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_21: anyspi@1 { -+ reg = <1>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ fragment@15 { -+ target = <&spi2>; -+ __dormant__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ anyspi_22: anyspi@2 { -+ reg = <2>; -+ spi-max-frequency = <500000>; -+ }; -+ }; -+ }; -+ -+ __overrides__ { -+ spi0-0 = <0>, "+0+8"; -+ spi0-1 = <0>, "+1+9"; -+ spi1-0 = <0>, "+2+10"; -+ spi1-1 = <0>, "+3+11"; -+ spi1-2 = <0>, "+4+12"; -+ spi2-0 = <0>, "+5+13"; -+ spi2-1 = <0>, "+6+14"; -+ spi2-2 = <0>, "+7+15"; -+ dev = <&anyspi_00>,"compatible", -+ <&anyspi_01>,"compatible", -+ <&anyspi_10>,"compatible", -+ <&anyspi_11>,"compatible", -+ <&anyspi_12>,"compatible", -+ <&anyspi_20>,"compatible", -+ <&anyspi_21>,"compatible", -+ <&anyspi_22>,"compatible"; -+ speed = <&anyspi_00>, "spi-max-frequency:0", -+ <&anyspi_01>, "spi-max-frequency:0", -+ <&anyspi_10>, "spi-max-frequency:0", -+ <&anyspi_11>, "spi-max-frequency:0", -+ <&anyspi_12>, "spi-max-frequency:0", -+ <&anyspi_20>, "spi-max-frequency:0", -+ <&anyspi_21>, "spi-max-frequency:0", -+ <&anyspi_22>, "spi-max-frequency:0"; -+ }; -+}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0392-tty-amba-pl011-Add-un-throttle-support.patch b/target/linux/bcm27xx/patches-5.4/950-0392-tty-amba-pl011-Add-un-throttle-support.patch new file mode 100644 index 0000000000..ced0bf2b79 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0392-tty-amba-pl011-Add-un-throttle-support.patch @@ -0,0 +1,61 @@ +From a3749ee48539fa832b1832cdcae26d34e5d20f00 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 24 Jan 2020 11:38:28 +0000 +Subject: [PATCH] tty: amba-pl011: Add un/throttle support + +The PL011 driver lacks throttle and unthrottle methods. As a result, +sending more data to the Pi than it can immediately sink while CRTSCTS +is enabled causes a NULL pointer to be followed. + +Add a throttle handler that disables the RX interrupts, and an +unthrottle handler that reenables them. + +Signed-off-by: Phil Elwell +--- + drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -1326,6 +1326,32 @@ static void pl011_start_tx(struct uart_p + pl011_start_tx_pio(uap); + } + ++static void pl011_throttle(struct uart_port *port) ++{ ++ struct uart_amba_port *uap = ++ container_of(port, struct uart_amba_port, port); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&uap->port.lock, flags); ++ uap->im &= ~(UART011_RTIM | UART011_RXIM); ++ pl011_write(uap->im, uap, REG_IMSC); ++ spin_unlock_irqrestore(&uap->port.lock, flags); ++} ++ ++static void pl011_unthrottle(struct uart_port *port) ++{ ++ struct uart_amba_port *uap = ++ container_of(port, struct uart_amba_port, port); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&uap->port.lock, flags); ++ uap->im |= UART011_RTIM; ++ if (!pl011_dma_rx_running(uap)) ++ uap->im |= UART011_RXIM; ++ pl011_write(uap->im, uap, REG_IMSC); ++ spin_unlock_irqrestore(&uap->port.lock, flags); ++} ++ + static void pl011_stop_rx(struct uart_port *port) + { + struct uart_amba_port *uap = +@@ -2167,6 +2193,8 @@ static const struct uart_ops amba_pl011_ + .stop_tx = pl011_stop_tx, + .start_tx = pl011_start_tx, + .stop_rx = pl011_stop_rx, ++ .throttle = pl011_throttle, ++ .unthrottle = pl011_unthrottle, + .enable_ms = pl011_enable_ms, + .break_ctl = pl011_break_ctl, + .startup = pl011_startup, diff --git a/target/linux/bcm27xx/patches-5.4/950-0393-Fix-i2c-pwm-pca9685a-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0393-Fix-i2c-pwm-pca9685a-overlay.patch new file mode 100644 index 0000000000..17bdf3984e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0393-Fix-i2c-pwm-pca9685a-overlay.patch @@ -0,0 +1,20 @@ +From 1cf854cd3531b10168b8f9aeb93bb0ab4b9a9003 Mon Sep 17 00:00:00 2001 +From: MikeDK +Date: Sun, 26 Jan 2020 23:33:54 +0100 +Subject: [PATCH] Fix i2c-pwm-pca9685a overlay + +--- + arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts ++++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts +@@ -13,7 +13,7 @@ + status = "okay"; + + pca: pca@40 { +- compatible = "nxp,pca9685"; ++ compatible = "nxp,pca9685-pwm"; + #pwm-cells = <2>; + reg = <0x40>; + status = "okay"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0393-sound-Add-the-HiFiBerry-DAC-HD-version.patch b/target/linux/bcm27xx/patches-5.4/950-0393-sound-Add-the-HiFiBerry-DAC-HD-version.patch deleted file mode 100644 index 6b9a6bd29c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0393-sound-Add-the-HiFiBerry-DAC-HD-version.patch +++ /dev/null @@ -1,801 +0,0 @@ -From 221b442eb7e5b4ed16151b5501f4b905a9b8455c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= - -Date: Tue, 21 Jan 2020 15:58:39 +0100 -Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version - -This adds the driver for the DAC+HD version supporting HiFiBerry's -PCM179x based DACs. It also adds PLL control for clock generation. - -Signed-off-by: Joerg Schambacher ---- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 6 + - .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++ - drivers/clk/Kconfig | 3 + - drivers/clk/Makefile | 1 + - drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++ - sound/soc/bcm/Kconfig | 9 + - sound/soc/bcm/Makefile | 2 + - sound/soc/bcm/hifiberry_dacplushd.c | 238 +++++++++++++ - 14 files changed, 704 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts - create mode 100644 drivers/clk/clk-hifiberry-dachd.c - create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c - ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - hifiberry-dacplusadc.dtbo \ - hifiberry-dacplusadcpro.dtbo \ - hifiberry-dacplusdsp.dtbo \ -+ hifiberry-dacplushd.dtbo \ - hifiberry-digi.dtbo \ - hifiberry-digi-pro.dtbo \ - hy28a.dtbo \ ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp - Params: - - -+Name: hifiberry-dacplushd -+Info: Configures the HifiBerry DAC+ HD audio card -+Load: dtoverlay=hifiberry-dacplushd -+Params: -+ -+ - Name: hifiberry-digi - Info: Configures the HifiBerry Digi and Digi+ audio card - Load: dtoverlay=hifiberry-digi ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts -@@ -0,0 +1,106 @@ -+// Definitions for HiFiBerry DAC+ HD -+/dts-v1/; -+/plugin/; -+ -+#include -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target-path = "/clocks"; -+ __overlay__ { -+ dachd_osc: pll_dachd_osc { -+ compatible = "hifiberry,dachd-clk"; -+ #clock-cells = <0>; -+ }; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&i2s>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&i2c1>; -+ __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ pcm1792a@4c { -+ compatible = "ti,pcm1792a"; -+ #sound-dai-cells = <0>; -+ #clock-cells = <0>; -+ clocks = <&dachd_osc>; -+ reg = <0x4c>; -+ status = "okay"; -+ }; -+ pll: pll@62 { -+ compatible = "hifiberry,dachd-clk"; -+ #clock-cells = <0>; -+ reg = <0x62>; -+ clocks = <&dachd_osc>; -+ status = "okay"; -+ common_pll_regs = [ -+ 02 53 03 00 07 20 0F 00 -+ 10 0D 11 1D 12 0D 13 8C -+ 14 8C 15 8C 16 8C 17 8C -+ 18 2A 1C 00 1D 0F 1F 00 -+ 2A 00 2C 00 2F 00 30 00 -+ 31 00 32 00 34 00 37 00 -+ 38 00 39 00 3A 00 3B 01 -+ 3E 00 3F 00 40 00 41 00 -+ 5A 00 5B 00 95 00 96 00 -+ 97 00 98 00 99 00 9A 00 -+ 9B 00 A2 00 A3 00 A4 00 -+ B7 92 ]; -+ 192k_pll_regs = [ -+ 1A 0C 1B 35 1E F0 20 09 -+ 21 50 2B 02 2D 10 2E 40 -+ 33 01 35 22 36 80 3C 22 -+ 3D 46 ]; -+ 96k_pll_regs = [ -+ 1A 0C 1B 35 1E F0 20 09 -+ 21 50 2B 02 2D 10 2E 40 -+ 33 01 35 47 36 00 3C 32 -+ 3D 46 ]; -+ 48k_pll_regs = [ -+ 1A 0C 1B 35 1E F0 20 09 -+ 21 50 2B 02 2D 10 2E 40 -+ 33 01 35 90 36 00 3C 42 -+ 3D 46 ]; -+ 176k4_pll_regs = [ -+ 1A 3D 1B 09 1E F3 20 13 -+ 21 75 2B 04 2D 11 2E E0 -+ 33 02 35 25 36 C0 3C 22 -+ 3D 7A ]; -+ 88k2_pll_regs = [ -+ 1A 3D 1B 09 1E F3 20 13 -+ 21 75 2B 04 2D 11 2E E0 -+ 33 01 35 4D 36 80 3C 32 -+ 3D 7A ]; -+ 44k1_pll_regs = [ -+ 1A 3D 1B 09 1E F3 20 13 -+ 21 75 2B 04 2D 11 2E E0 -+ 33 01 35 9D 36 00 3C 42 -+ 3D 7A ]; -+ }; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&sound>; -+ __overlay__ { -+ compatible = "hifiberry,hifiberry-dacplushd"; -+ i2s-controller = <&i2s>; -+ clocks = <&pll 0>; -+ reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>; -+ status = "okay"; -+ }; -+ }; -+ -+}; ---- a/drivers/clk/Kconfig -+++ b/drivers/clk/Kconfig -@@ -70,6 +70,9 @@ config COMMON_CLK_HI655X - multi-function device has one fixed-rate oscillator, clocked - at 32KHz. - -+config COMMON_CLK_HIFIBERRY_DACPLUSHD -+ tristate -+ - config COMMON_CLK_HIFIBERRY_DACPRO - tristate - ---- a/drivers/clk/Makefile -+++ b/drivers/clk/Makefile -@@ -36,6 +36,7 @@ obj-$(CONFIG_ARCH_HIGHBANK) += clk-high - obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o - obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o - obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO) += clk-hifiberry-dacpro.o -+obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o - obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o - obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o - obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o ---- /dev/null -+++ b/drivers/clk/clk-hifiberry-dachd.c -@@ -0,0 +1,333 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Clock Driver for HiFiBerry DAC+ HD -+ * -+ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry -+ * Copyright 2020 -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define NO_PLL_RESET 0 -+#define PLL_RESET 1 -+#define HIFIBERRY_PLL_MAX_REGISTER 256 -+#define DEFAULT_RATE 44100 -+ -+static struct reg_default hifiberry_pll_reg_defaults[] = { -+ {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00}, -+ {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C}, -+ {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C}, -+ {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00}, -+ {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00}, -+ {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00}, -+ {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01}, -+ {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00}, -+ {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00}, -+ {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00}, -+ {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00}, -+ {0xB7, 0x92}, -+ {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13}, -+ {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0}, -+ {0x3D, 0x7A}, -+ {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42}, -+ { 177, 0xAC}, -+}; -+static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_common_pll_regs; -+static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_192k_pll_regs; -+static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_96k_pll_regs; -+static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_48k_pll_regs; -+static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_176k4_pll_regs; -+static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_88k2_pll_regs; -+static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER]; -+static int num_dedicated_44k1_pll_regs; -+ -+/** -+ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk -+ * @hw: clk_hw for the common clk framework -+ */ -+struct clk_hifiberry_drvdata { -+ struct regmap *regmap; -+ struct clk *clk; -+ struct clk_hw hw; -+ unsigned long rate; -+}; -+ -+#define to_hifiberry_clk(_hw) \ -+ container_of(_hw, struct clk_hifiberry_drvdata, hw) -+ -+static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap, -+ struct reg_default *regs, -+ int num, int do_pll_reset) -+{ -+ int i; -+ int ret = 0; -+ char pll_soft_reset[] = { 177, 0xAC, }; -+ -+ for (i = 0; i < num; i++) { -+ ret |= regmap_write(regmap, regs[i].reg, regs[i].def); -+ if (ret) -+ return ret; -+ } -+ if (do_pll_reset) { -+ ret |= regmap_write(regmap, pll_soft_reset[0], -+ pll_soft_reset[1]); -+ mdelay(10); -+ } -+ return ret; -+} -+ -+static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ return to_hifiberry_clk(hw)->rate; -+} -+ -+static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw, -+ unsigned long rate, unsigned long *parent_rate) -+{ -+ return rate; -+} -+ -+static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw, -+ unsigned long rate, unsigned long parent_rate) -+{ -+ int ret; -+ struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw); -+ -+ switch (rate) { -+ case 44100: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs, -+ PLL_RESET); -+ break; -+ case 88200: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs, -+ PLL_RESET); -+ break; -+ case 176400: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs, -+ PLL_RESET); -+ break; -+ case 48000: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_48k_pll_regs, num_dedicated_48k_pll_regs, -+ PLL_RESET); -+ break; -+ case 96000: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_96k_pll_regs, num_dedicated_96k_pll_regs, -+ PLL_RESET); -+ break; -+ case 192000: -+ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap, -+ dedicated_192k_pll_regs, num_dedicated_192k_pll_regs, -+ PLL_RESET); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ to_hifiberry_clk(hw)->rate = rate; -+ -+ return ret; -+} -+ -+const struct clk_ops clk_hifiberry_dachd_rate_ops = { -+ .recalc_rate = clk_hifiberry_dachd_recalc_rate, -+ .round_rate = clk_hifiberry_dachd_round_rate, -+ .set_rate = clk_hifiberry_dachd_set_rate, -+}; -+ -+static int clk_hifiberry_get_prop_values(struct device *dev, -+ char *prop_name, -+ struct reg_default *regs) -+{ -+ int ret; -+ int i; -+ u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER]; -+ -+ ret = of_property_read_variable_u8_array(dev->of_node, prop_name, -+ tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER); -+ if (ret < 0) -+ return ret; -+ if (ret & 1) { -+ dev_err(dev, -+ "%s <%s> -> #%i odd number of bytes for reg/val pairs!", -+ __func__, -+ prop_name, -+ ret); -+ return -EINVAL; -+ } -+ ret /= 2; -+ for (i = 0; i < ret; i++) { -+ regs[i].reg = (u32)tmp[2 * i]; -+ regs[i].def = (u32)tmp[2 * i + 1]; -+ } -+ return ret; -+} -+ -+ -+static int clk_hifiberry_dachd_dt_parse(struct device *dev) -+{ -+ num_common_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "common_pll_regs", common_pll_regs); -+ num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "44k1_pll_regs", dedicated_44k1_pll_regs); -+ num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "88k2_pll_regs", dedicated_88k2_pll_regs); -+ num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "176k4_pll_regs", dedicated_176k4_pll_regs); -+ num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "48k_pll_regs", dedicated_48k_pll_regs); -+ num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "96k_pll_regs", dedicated_96k_pll_regs); -+ num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev, -+ "192k_pll_regs", dedicated_192k_pll_regs); -+ return 0; -+} -+ -+ -+static int clk_hifiberry_dachd_remove(struct device *dev) -+{ -+ of_clk_del_provider(dev->of_node); -+ return 0; -+} -+ -+const struct regmap_config hifiberry_pll_regmap = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = HIFIBERRY_PLL_MAX_REGISTER, -+ .reg_defaults = hifiberry_pll_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults), -+ .cache_type = REGCACHE_RBTREE, -+}; -+EXPORT_SYMBOL_GPL(hifiberry_pll_regmap); -+ -+ -+static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) -+{ -+ struct clk_hifiberry_drvdata *hdclk; -+ int ret = 0; -+ struct clk_init_data init; -+ struct device *dev = &i2c->dev; -+ struct device_node *dev_node = dev->of_node; -+ struct regmap_config config = hifiberry_pll_regmap; -+ -+ hdclk = devm_kzalloc(&i2c->dev, -+ sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL); -+ if (!hdclk) -+ return -ENOMEM; -+ -+ i2c_set_clientdata(i2c, hdclk); -+ -+ hdclk->regmap = devm_regmap_init_i2c(i2c, &config); -+ -+ if (IS_ERR(hdclk->regmap)) -+ return PTR_ERR(hdclk->regmap); -+ -+ /* start PLL to allow detection of DAC */ -+ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, -+ hifiberry_pll_reg_defaults, -+ ARRAY_SIZE(hifiberry_pll_reg_defaults), -+ PLL_RESET); -+ if (ret) -+ return ret; -+ -+ clk_hifiberry_dachd_dt_parse(dev); -+ -+ /* restart PLL with configs from DTB */ -+ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs, -+ num_common_pll_regs, PLL_RESET); -+ if (ret) -+ return ret; -+ -+ init.name = "clk-hifiberry-dachd"; -+ init.ops = &clk_hifiberry_dachd_rate_ops; -+ init.flags = 0; -+ init.parent_names = NULL; -+ init.num_parents = 0; -+ -+ hdclk->hw.init = &init; -+ -+ hdclk->clk = devm_clk_register(dev, &hdclk->hw); -+ if (IS_ERR(hdclk->clk)) { -+ dev_err(dev, "unable to register %s\n", init.name); -+ return PTR_ERR(hdclk->clk); -+ } -+ -+ ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk); -+ if (ret != 0) { -+ dev_err(dev, "Cannot of_clk_add_provider"); -+ return ret; -+ } -+ -+ ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE); -+ if (ret != 0) { -+ dev_err(dev, "Cannot set rate : %d\n", ret); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c) -+{ -+ clk_hifiberry_dachd_remove(&i2c->dev); -+ return 0; -+} -+ -+static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = { -+ { "dachd-clk", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id); -+ -+static const struct of_device_id clk_hifiberry_dachd_of_match[] = { -+ { .compatible = "hifiberry,dachd-clk", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match); -+ -+static struct i2c_driver clk_hifiberry_dachd_i2c_driver = { -+ .probe = clk_hifiberry_dachd_i2c_probe, -+ .remove = clk_hifiberry_dachd_i2c_remove, -+ .id_table = clk_hifiberry_dachd_i2c_id, -+ .driver = { -+ .name = "dachd-clk", -+ .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match), -+ }, -+}; -+ -+module_i2c_driver(clk_hifiberry_dachd_i2c_driver); -+ -+ -+MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver"); -+MODULE_AUTHOR("Joerg Schambacher "); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:clk-hifiberry-dachd"); ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -42,6 +42,14 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - help - Say Y or M if you want to add support for HifiBerry DAC+. - -+config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD -+ tristate "Support for HifiBerry DAC+ HD" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_PCM179X_I2C -+ select COMMON_CLK_HIFIBERRY_DACPLUSHD -+ help -+ Say Y or M if you want to add support for HifiBerry DAC+ HD. -+ - config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC - tristate "Support for HifiBerry DAC+ADC" - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -@@ -56,6 +64,7 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS - depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S - select SND_SOC_PCM512x_I2C - select SND_SOC_PCM186X_I2C -+ select COMMON_CLK_HIFIBERRY_DACPRO - help - Say Y or M if you want to add support for HifiBerry DAC+ADC PRO. - ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -14,6 +14,7 @@ snd-soc-googlevoicehat-codec-objs := goo - - # BCM2708 Machine Support - snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o -+snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o - snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o - snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o - snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o -@@ -41,6 +42,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi - - obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o ---- /dev/null -+++ b/sound/soc/bcm/hifiberry_dacplushd.c -@@ -0,0 +1,238 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * ASoC Driver for HiFiBerry DAC+ HD -+ * -+ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry -+ * Copyright 2020 -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../codecs/pcm179x.h" -+ -+#define DEFAULT_RATE 44100 -+ -+struct brd_drv_data { -+ struct regmap *regmap; -+ struct clk *sclk; -+}; -+ -+static struct brd_drv_data drvdata; -+static struct gpio_desc *reset_gpio; -+static const unsigned int hb_dacplushd_rates[] = { -+ 192000, 96000, 48000, 176400, 88200, 44100, -+}; -+ -+static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = { -+ .list = hb_dacplushd_rates, -+ .count = ARRAY_SIZE(hb_dacplushd_rates), -+}; -+ -+static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream) -+{ -+ /* constraints for standard sample rates */ -+ snd_pcm_hw_constraint_list(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_RATE, -+ &hb_dacplushd_constraints); -+ return 0; -+} -+ -+static void snd_rpi_hifiberry_dacplushd_set_sclk( -+ struct snd_soc_component *component, -+ int sample_rate) -+{ -+ if (!IS_ERR(drvdata.sclk)) -+ clk_set_rate(drvdata.sclk, sample_rate); -+} -+ -+static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ struct snd_soc_dai_link *dai = rtd->dai_link; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ -+ dai->name = "HiFiBerry DAC+ HD"; -+ dai->stream_name = "HiFiBerry DAC+ HD HiFi"; -+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM; -+ -+ /* allow only fixed 32 clock counts per channel */ -+ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2); -+ -+ return 0; -+} -+ -+static int snd_rpi_hifiberry_dacplushd_hw_params( -+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) -+{ -+ int ret = 0; -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ -+ struct snd_soc_component *component = rtd->codec_dai->component; -+ -+ snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params)); -+ return ret; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = { -+ .startup = snd_rpi_hb_dacplushd_startup, -+ .hw_params = snd_rpi_hifiberry_dacplushd_hw_params, -+}; -+ -+SND_SOC_DAILINK_DEFS(hifi, -+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), -+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm179x.1-004c", "pcm179x-hifi")), -+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); -+ -+ -+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = { -+{ -+ .name = "HiFiBerry DAC+ HD", -+ .stream_name = "HiFiBerry DAC+ HD HiFi", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_hifiberry_dacplushd_ops, -+ .init = snd_rpi_hifiberry_dacplushd_init, -+ SND_SOC_DAILINK_REG(hifi), -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_hifiberry_dacplushd = { -+ .name = "snd_rpi_hifiberry_dacplushd", -+ .driver_name = "HifiberryDacplusHD", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_hifiberry_dacplushd_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai), -+}; -+ -+static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ static int dac_reset_done; -+ struct device *dev = &pdev->dev; -+ struct device_node *dev_node = dev->of_node; -+ -+ snd_rpi_hifiberry_dacplushd.dev = &pdev->dev; -+ -+ /* get GPIO and release DAC from RESET */ -+ if (!dac_reset_done) { -+ reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW); -+ if (IS_ERR(reset_gpio)) { -+ dev_err(&pdev->dev, "gpiod_get() failed\n"); -+ return -EINVAL; -+ } -+ dac_reset_done = 1; -+ } -+ if (!IS_ERR(reset_gpio)) -+ gpiod_set_value(reset_gpio, 0); -+ msleep(1); -+ if (!IS_ERR(reset_gpio)) -+ gpiod_set_value(reset_gpio, 1); -+ msleep(1); -+ if (!IS_ERR(reset_gpio)) -+ gpiod_set_value(reset_gpio, 0); -+ -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai; -+ -+ dai = &snd_rpi_hifiberry_dacplushd_dai[0]; -+ i2s_node = of_parse_phandle(pdev->dev.of_node, -+ "i2s-controller", 0); -+ -+ if (i2s_node) { -+ dai->cpus->of_node = i2s_node; -+ dai->platforms->of_node = i2s_node; -+ dai->cpus->dai_name = NULL; -+ dai->platforms->name = NULL; -+ } else { -+ return -EPROBE_DEFER; -+ } -+ -+ } -+ -+ ret = devm_snd_soc_register_card(&pdev->dev, -+ &snd_rpi_hifiberry_dacplushd); -+ if (ret && ret != -EPROBE_DEFER) { -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ return ret; -+ } -+ if (ret == -EPROBE_DEFER) -+ return ret; -+ -+ dev_set_drvdata(dev, &drvdata); -+ if (dev_node == NULL) { -+ dev_err(&pdev->dev, "Device tree node not found\n"); -+ return -ENODEV; -+ } -+ -+ drvdata.sclk = devm_clk_get(dev, NULL); -+ if (IS_ERR(drvdata.sclk)) { -+ drvdata.sclk = ERR_PTR(-ENOENT); -+ return -ENODEV; -+ } -+ -+ clk_set_rate(drvdata.sclk, DEFAULT_RATE); -+ -+ return ret; -+} -+ -+static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev) -+{ -+ if (IS_ERR(reset_gpio)) -+ return -EINVAL; -+ -+ /* put DAC into RESET and release GPIO */ -+ gpiod_set_value(reset_gpio, 0); -+ gpiod_put(reset_gpio); -+ -+ return 0; -+} -+ -+static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = { -+ { .compatible = "hifiberry,hifiberry-dacplushd", }, -+ {}, -+}; -+ -+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match); -+ -+static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = { -+ .driver = { -+ .name = "snd-rpi-hifiberry-dacplushd", -+ .owner = THIS_MODULE, -+ .of_match_table = snd_rpi_hifiberry_dacplushd_of_match, -+ }, -+ .probe = snd_rpi_hifiberry_dacplushd_probe, -+ .remove = snd_rpi_hifiberry_dacplushd_remove, -+}; -+ -+module_platform_driver(snd_rpi_hifiberry_dacplushd_driver); -+ -+MODULE_AUTHOR("Joerg Schambacher "); -+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0394-Initialise-rpi-firmware-before-clk-bcm2835.patch b/target/linux/bcm27xx/patches-5.4/950-0394-Initialise-rpi-firmware-before-clk-bcm2835.patch deleted file mode 100644 index cdd5e7e9ab..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0394-Initialise-rpi-firmware-before-clk-bcm2835.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 2c1a5dae2fb127729773685e3cd1e48934edf1f2 Mon Sep 17 00:00:00 2001 -From: Luke Hinds <7058938+lukehinds@users.noreply.github.com> -Date: Wed, 22 Jan 2020 16:03:00 +0000 -Subject: [PATCH] Initialise rpi-firmware before clk-bcm2835 - -The IMA (Integrity Measurement Architecture) looks for a TPM (Trusted -Platform Module) having been registered when it initialises; otherwise -it assumes there is no TPM. It has been observed on BCM2835 that IMA -is initialised before TPM, and that initialising the BCM2835 clock -driver before the firmware driver has the effect of reversing this -order. - -Change the firmware driver to initialise at core_initcall, delaying the -BCM2835 clock driver to postcore_initcall. - -See: https://github.com/raspberrypi/linux/issues/3291 - https://github.com/raspberrypi/linux/pull/3297 - -Signed-off-by: Luke Hinds -Co-authored-by: Phil Elwell ---- - drivers/clk/bcm/clk-bcm2835.c | 2 +- - drivers/firmware/raspberrypi.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -2401,7 +2401,7 @@ static int __init __bcm2835_clk_driver_i - { - return platform_driver_register(&bcm2835_clk_driver); - } --core_initcall(__bcm2835_clk_driver_init); -+postcore_initcall(__bcm2835_clk_driver_init); - - MODULE_AUTHOR("Eric Anholt "); - MODULE_DESCRIPTION("BCM2835 clock driver"); ---- a/drivers/firmware/raspberrypi.c -+++ b/drivers/firmware/raspberrypi.c -@@ -416,7 +416,7 @@ out2: - out1: - return ret; - } --subsys_initcall(rpi_firmware_init); -+core_initcall(rpi_firmware_init); - - static void __init rpi_firmware_exit(void) - { diff --git a/target/linux/bcm27xx/patches-5.4/950-0394-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch b/target/linux/bcm27xx/patches-5.4/950-0394-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch new file mode 100644 index 0000000000..397a2c3331 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0394-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch @@ -0,0 +1,89 @@ +From 4a773d6535c3386044490156264ebd2a3b1bc38b Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Mon, 27 Jan 2020 17:45:51 +0100 +Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC PRO sound + card + +This adds a DT overlay parameter 'leds_off' which allows +to switch off the onboard activity LEDs at all times +which has been requested by some users. + +Signed-off-by: Joerg Schambacher +--- + arch/arm/boot/dts/overlays/README | 2 ++ + .../overlays/hifiberry-dacplusadcpro-overlay.dts | 1 + + sound/soc/bcm/hifiberry_dacplusadcpro.c | 15 +++++++++++++-- + 3 files changed, 16 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -948,6 +948,8 @@ Params: 24db_digital_gain Allow ga + that does not result in clipping/distortion!) + slave Force DAC+ADC Pro into slave mode, using Pi as + master for bit clock and frame clock. ++ leds_off If set to 'true' the onboard indicator LEDs ++ are switched off at all times. + + + Name: hifiberry-dacplusdsp +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts +@@ -60,5 +60,6 @@ + 24db_digital_gain = + <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?"; + slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?"; ++ leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?"; + }; + }; +--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c ++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c +@@ -54,6 +54,7 @@ struct pcm512x_priv { + static bool slave; + static bool snd_rpi_hifiberry_is_dacpro; + static bool digital_gain_0db_limit = true; ++static bool leds_off; + + static const unsigned int pcm186x_adc_input_channel_sel_value[] = { + 0x00, 0x01, 0x02, 0x03, 0x10 +@@ -321,7 +322,10 @@ static int snd_rpi_hifiberry_dacplusadcp + + snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08); + snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); +- snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ if (leds_off) ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); ++ else ++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + + ret = pcm1863_add_controls(adc); + if (ret < 0) +@@ -331,7 +335,10 @@ static int snd_rpi_hifiberry_dacplusadcp + /* set GPIO2 to output, GPIO3 input */ + snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00); + snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04); +- snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); ++ if (leds_off) ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00); ++ else ++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); + + if (digital_gain_0db_limit) { + int ret; +@@ -417,6 +424,8 @@ static int snd_rpi_hifiberry_dacplusadcp + struct snd_soc_component *dac = rtd->codec_dais[0]->component; + struct snd_soc_component *adc = rtd->codec_dais[1]->component; + ++ if (leds_off) ++ return 0; + /* switch on respective LED */ + if (!substream->stream) + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); +@@ -500,6 +509,8 @@ static int snd_rpi_hifiberry_dacplusadcp + pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain"); + slave = of_property_read_bool(pdev->dev.of_node, + "hifiberry-dacplusadcpro,slave"); ++ leds_off = of_property_read_bool(pdev->dev.of_node, ++ "hifiberry-dacplusadcpro,leds_off"); + ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro); + if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, diff --git a/target/linux/bcm27xx/patches-5.4/950-0395-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch b/target/linux/bcm27xx/patches-5.4/950-0395-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch deleted file mode 100644 index 54b366f65a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0395-Fix-master-mode-settings-of-HiFiBerry-DAC-ADC-PRO-ca.patch +++ /dev/null @@ -1,26 +0,0 @@ -From fa93fc95e5fb4e75a2a5ea930509d80083dee9b3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B6rg=20Schambacher?= - -Date: Thu, 23 Jan 2020 13:32:13 +0100 -Subject: [PATCH] Fix master mode settings of HiFiBerry DAC+ADC PRO - card (#3424) - -This patch fixes the board DAI setting when in master-mode. -Wrong setting could have caused random pop noise. - -Signed-off-by: Joerg Schambacher ---- - sound/soc/bcm/hifiberry_dacplusadcpro.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/sound/soc/bcm/hifiberry_dacplusadcpro.c -+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c -@@ -285,6 +285,8 @@ static int snd_rpi_hifiberry_dacplusadcp - - dai->name = "HiFiBerry DAC+ADC Pro"; - dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi"; -+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM; - - // set DAC DAI configuration - ret = snd_soc_dai_set_fmt(rtd->codec_dais[0], diff --git a/target/linux/bcm27xx/patches-5.4/950-0395-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch b/target/linux/bcm27xx/patches-5.4/950-0395-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch new file mode 100644 index 0000000000..bd8f405ef8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0395-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch @@ -0,0 +1,76 @@ +From 36949b2ea78d5782faed2fb00a037f37789fa85d Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Mon, 27 Jan 2020 20:37:34 +0100 +Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC sound card + +This adds a DT overlay parameter 'leds_off' which allows +to switch off the onboard activity LEDs at all times +which has been requested by some users. + +Signed-off-by: Joerg Schambacher +--- + arch/arm/boot/dts/overlays/README | 2 ++ + .../boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 1 + + sound/soc/bcm/hifiberry_dacplusadc.c | 10 +++++++++- + 3 files changed, 12 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -927,6 +927,8 @@ Params: 24db_digital_gain Allow ga + that does not result in clipping/distortion!) + slave Force DAC+ Pro into slave mode, using Pi as + master for bit clock and frame clock. ++ leds_off If set to 'true' the onboard indicator LEDs ++ are switched off at all times. + + + Name: hifiberry-dacplusadcpro +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts +@@ -67,5 +67,6 @@ + 24db_digital_gain = + <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?"; + slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?"; ++ leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?"; + }; + }; +--- a/sound/soc/bcm/hifiberry_dacplusadc.c ++++ b/sound/soc/bcm/hifiberry_dacplusadc.c +@@ -54,6 +54,7 @@ struct pcm512x_priv { + static bool slave; + static bool snd_rpi_hifiberry_is_dacpro; + static bool digital_gain_0db_limit = true; ++static bool leds_off; + + static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component, + int clk_id) +@@ -175,7 +176,10 @@ static int snd_rpi_hifiberry_dacplusadc_ + + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08); + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); +- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ if (leds_off) ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); ++ else ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + + if (digital_gain_0db_limit) { + int ret; +@@ -254,6 +258,8 @@ static int snd_rpi_hifiberry_dacplusadc_ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = rtd->codec_dai->component; + ++ if (leds_off) ++ return 0; + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, + 0x08, 0x08); + hifiberry_dacplusadc_LED_cnt++; +@@ -330,6 +336,8 @@ static int snd_rpi_hifiberry_dacplusadc_ + pdev->dev.of_node, "hifiberry,24db_digital_gain"); + slave = of_property_read_bool(pdev->dev.of_node, + "hifiberry-dacplusadc,slave"); ++ leds_off = of_property_read_bool(pdev->dev.of_node, ++ "hifiberry-dacplusadc,leds_off"); + + ret = devm_snd_soc_register_card(&pdev->dev, + &snd_rpi_hifiberry_dacplusadc); diff --git a/target/linux/bcm27xx/patches-5.4/950-0396-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch b/target/linux/bcm27xx/patches-5.4/950-0396-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch new file mode 100644 index 0000000000..a5c3d40512 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0396-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch @@ -0,0 +1,77 @@ +From 4b3cdf84c4d8156c01fa02e4d511f7529cae488f Mon Sep 17 00:00:00 2001 +From: j-schambacher +Date: Mon, 27 Jan 2020 20:58:24 +0100 +Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+/DAC+PRO sound + cards + +This adds a DT overlay parameter 'leds_off' which allows +to switch off the onboard activity LEDs at all times +which has been requested by some users. + +Signed-off-by: Joerg Schambacher +--- + arch/arm/boot/dts/overlays/README | 2 ++ + .../boot/dts/overlays/hifiberry-dacplus-overlay.dts | 1 + + sound/soc/bcm/hifiberry_dacplus.c | 10 +++++++++- + 3 files changed, 12 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -906,6 +906,8 @@ Params: 24db_digital_gain Allow ga + that does not result in clipping/distortion!) + slave Force DAC+ Pro into slave mode, using Pi as + master for bit clock and frame clock. ++ leds_off If set to 'true' the onboard indicator LEDs ++ are switched off at all times. + + + Name: hifiberry-dacplusadc +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -55,5 +55,6 @@ + 24db_digital_gain = + <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; + slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?"; ++ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; + }; + }; +--- a/sound/soc/bcm/hifiberry_dacplus.c ++++ b/sound/soc/bcm/hifiberry_dacplus.c +@@ -50,6 +50,7 @@ struct pcm512x_priv { + static bool slave; + static bool snd_rpi_hifiberry_is_dacpro; + static bool digital_gain_0db_limit = true; ++static bool leds_off; + + static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component, + int clk_id) +@@ -171,7 +172,10 @@ static int snd_rpi_hifiberry_dacplus_ini + + snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08); + snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); +- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); ++ if (leds_off) ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); ++ else ++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + + if (digital_gain_0db_limit) + { +@@ -249,6 +253,8 @@ static int snd_rpi_hifiberry_dacplus_sta + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = rtd->codec_dai->component; + ++ if (leds_off) ++ return 0; + snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + return 0; + } +@@ -319,6 +325,8 @@ static int snd_rpi_hifiberry_dacplus_pro + pdev->dev.of_node, "hifiberry,24db_digital_gain"); + slave = of_property_read_bool(pdev->dev.of_node, + "hifiberry-dacplus,slave"); ++ leds_off = of_property_read_bool(pdev->dev.of_node, ++ "hifiberry-dacplus,leds_off"); + } + + ret = devm_snd_soc_register_card(&pdev->dev, diff --git a/target/linux/bcm27xx/patches-5.4/950-0396-overlays-Use-preferred-compatible-strings.patch b/target/linux/bcm27xx/patches-5.4/950-0396-overlays-Use-preferred-compatible-strings.patch deleted file mode 100644 index 6a246050cf..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0396-overlays-Use-preferred-compatible-strings.patch +++ /dev/null @@ -1,72 +0,0 @@ -From f50f0425592a8496d6d25b4936caadfe64523c91 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 24 Jan 2020 09:02:37 +0000 -Subject: [PATCH] overlays: Use preferred compatible strings - -Make sure all overlays have correct compatible strings before enabling -the automated checking. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 2 ++ - arch/arm/boot/dts/overlays/pwm-overlay.dts | 2 ++ - arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 2 ++ - 5 files changed, 8 insertions(+), 2 deletions(-) - ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -@@ -3,7 +3,7 @@ - /plugin/; - - / { -- compatible = "brcm,bcm2708"; -+ compatible = "brcm,bcm2835"; - - fragment@0 { - target-path = "/clocks"; ---- a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts -+++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts -@@ -3,7 +3,7 @@ - /plugin/; - - / { -- compatible = "brcm,bcm2708"; -+ compatible = "brcm,bcm2835"; - - fragment@0 { - target = <&i2s>; ---- a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts -+++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts -@@ -17,6 +17,8 @@ N.B.: - */ - - / { -+ compatible = "brcm,bcm2835"; -+ - fragment@0 { - target = <&gpio>; - __overlay__ { ---- a/arch/arm/boot/dts/overlays/pwm-overlay.dts -+++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts -@@ -15,6 +15,8 @@ N.B.: - */ - - / { -+ compatible = "brcm,bcm2835"; -+ - fragment@0 { - target = <&gpio>; - __overlay__ { ---- a/arch/arm/boot/dts/overlays/smi-dev-overlay.dts -+++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts -@@ -5,6 +5,8 @@ - /plugin/; - - /{ -+ compatible = "brcm,bcm2835"; -+ - fragment@0 { - target = <&soc>; - __overlay__ { diff --git a/target/linux/bcm27xx/patches-5.4/950-0397-pisound-Added-reading-Pisound-board-hardware-revisio.patch b/target/linux/bcm27xx/patches-5.4/950-0397-pisound-Added-reading-Pisound-board-hardware-revisio.patch new file mode 100644 index 0000000000..df6f526e2e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0397-pisound-Added-reading-Pisound-board-hardware-revisio.patch @@ -0,0 +1,201 @@ +From 21dace2c687d45819cb0dfc4f32f005da82d9197 Mon Sep 17 00:00:00 2001 +From: gtrainavicius +Date: Tue, 28 Jan 2020 14:16:37 +0200 +Subject: [PATCH] pisound: Added reading Pisound board hardware + revision and exposing it (#3425) + +pisound: Added reading Pisound board hardware revision and exposing it in kernel log and sysfs file: + +/sys/kernel/pisound/hw_version + +Signed-off-by: Giedrius +--- + sound/soc/bcm/pisound.c | 86 ++++++++++++++++++++++++++++------------- + 1 file changed, 59 insertions(+), 27 deletions(-) + +--- a/sound/soc/bcm/pisound.c ++++ b/sound/soc/bcm/pisound.c +@@ -51,7 +51,8 @@ static void pisnd_spi_set_callback(pisnd + + static const char *pisnd_spi_get_serial(void); + static const char *pisnd_spi_get_id(void); +-static const char *pisnd_spi_get_version(void); ++static const char *pisnd_spi_get_fw_version(void); ++static const char *pisnd_spi_get_hw_version(void); + + static int pisnd_midi_init(struct snd_card *card); + static void pisnd_midi_uninit(void); +@@ -222,7 +223,9 @@ static pisnd_spi_recv_cb g_recvCallback; + + static char g_serial_num[11]; + static char g_id[25]; +-static char g_version[5]; ++enum { MAX_VERSION_STR_LEN = 6 }; ++static char g_fw_version[MAX_VERSION_STR_LEN]; ++static char g_hw_version[MAX_VERSION_STR_LEN]; + + static uint8_t g_ledFlashDuration; + static bool g_ledFlashDurationChanged; +@@ -558,7 +561,8 @@ static int spi_read_info(void) + char *p; + + memset(g_serial_num, 0, sizeof(g_serial_num)); +- memset(g_version, 0, sizeof(g_version)); ++ memset(g_fw_version, 0, sizeof(g_fw_version)); ++ strcpy(g_hw_version, "1.0"); // Assume 1.0 hw version. + memset(g_id, 0, sizeof(g_id)); + + tmp = spi_transfer16(0); +@@ -581,12 +585,28 @@ static int spi_read_info(void) + return -EINVAL; + + snprintf( +- g_version, +- sizeof(g_version), ++ g_fw_version, ++ MAX_VERSION_STR_LEN, + "%x.%02x", + buffer[0], + buffer[1] + ); ++ ++ g_fw_version[MAX_VERSION_STR_LEN-1] = '\0'; ++ break; ++ case 3: ++ if (n != 2) ++ return -EINVAL; ++ ++ snprintf( ++ g_hw_version, ++ MAX_VERSION_STR_LEN, ++ "%x.%x", ++ buffer[0], ++ buffer[1] ++ ); ++ ++ g_hw_version[MAX_VERSION_STR_LEN-1] = '\0'; + break; + case 1: + if (n >= sizeof(g_serial_num)) +@@ -596,12 +616,14 @@ static int spi_read_info(void) + break; + case 2: + { +- if (n >= sizeof(g_id)) ++ if (n*2 >= sizeof(g_id)) + return -EINVAL; + + p = g_id; + for (j = 0; j < n; ++j) + p += sprintf(p, "%02x", buffer[j]); ++ ++ *p = '\0'; + } + break; + default: +@@ -619,7 +641,8 @@ static int pisnd_spi_init(struct device + + memset(g_serial_num, 0, sizeof(g_serial_num)); + memset(g_id, 0, sizeof(g_id)); +- memset(g_version, 0, sizeof(g_version)); ++ memset(g_fw_version, 0, sizeof(g_fw_version)); ++ memset(g_hw_version, 0, sizeof(g_hw_version)); + + spi = pisnd_spi_find_device(); + +@@ -729,26 +752,22 @@ static void pisnd_spi_set_callback(pisnd + + static const char *pisnd_spi_get_serial(void) + { +- if (strlen(g_serial_num)) +- return g_serial_num; +- +- return ""; ++ return g_serial_num; + } + + static const char *pisnd_spi_get_id(void) + { +- if (strlen(g_id)) +- return g_id; +- +- return ""; ++ return g_id; + } + +-static const char *pisnd_spi_get_version(void) ++static const char *pisnd_spi_get_fw_version(void) + { +- if (strlen(g_version)) +- return g_version; ++ return g_fw_version; ++} + +- return ""; ++static const char *pisnd_spi_get_hw_version(void) ++{ ++ return g_hw_version; + } + + static const struct of_device_id pisound_of_match[] = { +@@ -1056,13 +1075,22 @@ static ssize_t pisnd_id_show( + return sprintf(buf, "%s\n", pisnd_spi_get_id()); + } + +-static ssize_t pisnd_version_show( ++static ssize_t pisnd_fw_version_show( + struct kobject *kobj, + struct kobj_attribute *attr, + char *buf + ) + { +- return sprintf(buf, "%s\n", pisnd_spi_get_version()); ++ return sprintf(buf, "%s\n", pisnd_spi_get_fw_version()); ++} ++ ++static ssize_t pisnd_hw_version_show( ++ struct kobject *kobj, ++ struct kobj_attribute *attr, ++ char *buf ++) ++{ ++ return sprintf(buf, "%s\n", pisnd_spi_get_hw_version()); + } + + static ssize_t pisnd_led_store( +@@ -1087,15 +1115,18 @@ static struct kobj_attribute pisnd_seria + __ATTR(serial, 0444, pisnd_serial_show, NULL); + static struct kobj_attribute pisnd_id_attribute = + __ATTR(id, 0444, pisnd_id_show, NULL); +-static struct kobj_attribute pisnd_version_attribute = +- __ATTR(version, 0444, pisnd_version_show, NULL); ++static struct kobj_attribute pisnd_fw_version_attribute = ++ __ATTR(version, 0444, pisnd_fw_version_show, NULL); ++static struct kobj_attribute pisnd_hw_version_attribute = ++__ATTR(hw_version, 0444, pisnd_hw_version_show, NULL); + static struct kobj_attribute pisnd_led_attribute = + __ATTR(led, 0644, NULL, pisnd_led_store); + + static struct attribute *attrs[] = { + &pisnd_serial_attribute.attr, + &pisnd_id_attribute.attr, +- &pisnd_version_attribute.attr, ++ &pisnd_fw_version_attribute.attr, ++ &pisnd_hw_version_attribute.attr, + &pisnd_led_attribute.attr, + NULL + }; +@@ -1114,9 +1145,10 @@ static int pisnd_probe(struct platform_d + } + + printi("Detected Pisound card:\n"); +- printi("\tSerial: %s\n", pisnd_spi_get_serial()); +- printi("\tVersion: %s\n", pisnd_spi_get_version()); +- printi("\tId: %s\n", pisnd_spi_get_id()); ++ printi("\tSerial: %s\n", pisnd_spi_get_serial()); ++ printi("\tFirmware Version: %s\n", pisnd_spi_get_fw_version()); ++ printi("\tHardware Version: %s\n", pisnd_spi_get_hw_version()); ++ printi("\tId: %s\n", pisnd_spi_get_id()); + + pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj); + if (!pisnd_kobj) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0397-tty-amba-pl011-Add-un-throttle-support.patch b/target/linux/bcm27xx/patches-5.4/950-0397-tty-amba-pl011-Add-un-throttle-support.patch deleted file mode 100644 index ced0bf2b79..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0397-tty-amba-pl011-Add-un-throttle-support.patch +++ /dev/null @@ -1,61 +0,0 @@ -From a3749ee48539fa832b1832cdcae26d34e5d20f00 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 24 Jan 2020 11:38:28 +0000 -Subject: [PATCH] tty: amba-pl011: Add un/throttle support - -The PL011 driver lacks throttle and unthrottle methods. As a result, -sending more data to the Pi than it can immediately sink while CRTSCTS -is enabled causes a NULL pointer to be followed. - -Add a throttle handler that disables the RX interrupts, and an -unthrottle handler that reenables them. - -Signed-off-by: Phil Elwell ---- - drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -1326,6 +1326,32 @@ static void pl011_start_tx(struct uart_p - pl011_start_tx_pio(uap); - } - -+static void pl011_throttle(struct uart_port *port) -+{ -+ struct uart_amba_port *uap = -+ container_of(port, struct uart_amba_port, port); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uap->port.lock, flags); -+ uap->im &= ~(UART011_RTIM | UART011_RXIM); -+ pl011_write(uap->im, uap, REG_IMSC); -+ spin_unlock_irqrestore(&uap->port.lock, flags); -+} -+ -+static void pl011_unthrottle(struct uart_port *port) -+{ -+ struct uart_amba_port *uap = -+ container_of(port, struct uart_amba_port, port); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&uap->port.lock, flags); -+ uap->im |= UART011_RTIM; -+ if (!pl011_dma_rx_running(uap)) -+ uap->im |= UART011_RXIM; -+ pl011_write(uap->im, uap, REG_IMSC); -+ spin_unlock_irqrestore(&uap->port.lock, flags); -+} -+ - static void pl011_stop_rx(struct uart_port *port) - { - struct uart_amba_port *uap = -@@ -2167,6 +2193,8 @@ static const struct uart_ops amba_pl011_ - .stop_tx = pl011_stop_tx, - .start_tx = pl011_start_tx, - .stop_rx = pl011_stop_rx, -+ .throttle = pl011_throttle, -+ .unthrottle = pl011_unthrottle, - .enable_ms = pl011_enable_ms, - .break_ctl = pl011_break_ctl, - .startup = pl011_startup, diff --git a/target/linux/bcm27xx/patches-5.4/950-0398-Fix-i2c-pwm-pca9685a-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0398-Fix-i2c-pwm-pca9685a-overlay.patch deleted file mode 100644 index 17bdf3984e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0398-Fix-i2c-pwm-pca9685a-overlay.patch +++ /dev/null @@ -1,20 +0,0 @@ -From 1cf854cd3531b10168b8f9aeb93bb0ab4b9a9003 Mon Sep 17 00:00:00 2001 -From: MikeDK -Date: Sun, 26 Jan 2020 23:33:54 +0100 -Subject: [PATCH] Fix i2c-pwm-pca9685a overlay - ---- - arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts -+++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts -@@ -13,7 +13,7 @@ - status = "okay"; - - pca: pca@40 { -- compatible = "nxp,pca9685"; -+ compatible = "nxp,pca9685-pwm"; - #pwm-cells = <2>; - reg = <0x40>; - status = "okay"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0398-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch b/target/linux/bcm27xx/patches-5.4/950-0398-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch new file mode 100644 index 0000000000..4713dde247 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0398-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch @@ -0,0 +1,46 @@ +From 703920ad5199c46f98cf107c75a2de61608f85fd Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 2 Aug 2019 15:20:11 +0100 +Subject: [PATCH] mmc: sdhci-iproc: Fix vmmc regulators on iProc + +The Linux support for controlling card power via regulators appears to +be contentious. I would argue that the default behaviour is contrary to +the SDHCI spec - turning off the power writes a reserved value to the +SD Bus Voltage Select field of the Power Control Register, which +seems to kill the Arasan/iProc controller - but fortunately there is a +hook in sdhci_ops to override the behaviour. Borrow the implementation +from sdhci_arasan_set_power. + +Signed-off-by: Phil Elwell +--- + drivers/mmc/host/sdhci-iproc.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/mmc/host/sdhci-iproc.c ++++ b/drivers/mmc/host/sdhci-iproc.c +@@ -173,6 +173,17 @@ static unsigned int sdhci_iproc_get_max_ + return pltfm_host->clock; + } + ++static void sdhci_iproc_set_power(struct sdhci_host *host, unsigned char mode, ++ unsigned short vdd) ++{ ++ if (!IS_ERR(host->mmc->supply.vmmc)) { ++ struct mmc_host *mmc = host->mmc; ++ ++ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); ++ } ++ sdhci_set_power_noreg(host, mode, vdd); ++} ++ + static const struct sdhci_ops sdhci_iproc_ops = { + .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_iproc_get_max_clock, +@@ -190,6 +201,7 @@ static const struct sdhci_ops sdhci_ipro + .write_b = sdhci_iproc_writeb, + .set_clock = sdhci_set_clock, + .get_max_clock = sdhci_iproc_get_max_clock, ++ .set_power = sdhci_iproc_set_power, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, diff --git a/target/linux/bcm27xx/patches-5.4/950-0399-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch b/target/linux/bcm27xx/patches-5.4/950-0399-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch new file mode 100644 index 0000000000..a69feb50b4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0399-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch @@ -0,0 +1,41 @@ +From ade82688b687b3340ca5e7883646ad51291d49cd Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 30 Jul 2019 12:37:02 +0100 +Subject: [PATCH] ARM: dts: Declare RPi 4B SD card power regulator + +Later revisions of the Raspberry Pi 4B have a separate control over the +SD card power. Expose that control to Linux as a fixed regulator with +a GPIO enable. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 11 +++++++++++ + 3 files changed, 13 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -122,6 +122,16 @@ + states = <1800000 0x1 + 3300000 0x0>; + }; ++ ++ sd_vcc_reg: sd_vcc_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-sd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ enable-active-high; ++ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; ++ }; + }; + + &sdhost { +@@ -132,6 +142,7 @@ + status = "okay"; + broken-cd; + vqmmc-supply = <&sd_io_1v8_reg>; ++ vmmc-supply = <&sd_vcc_reg>; + }; + + &genet { diff --git a/target/linux/bcm27xx/patches-5.4/950-0399-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch b/target/linux/bcm27xx/patches-5.4/950-0399-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch deleted file mode 100644 index 397a2c3331..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0399-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-PRO-sound-.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 4a773d6535c3386044490156264ebd2a3b1bc38b Mon Sep 17 00:00:00 2001 -From: j-schambacher -Date: Mon, 27 Jan 2020 17:45:51 +0100 -Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC PRO sound - card - -This adds a DT overlay parameter 'leds_off' which allows -to switch off the onboard activity LEDs at all times -which has been requested by some users. - -Signed-off-by: Joerg Schambacher ---- - arch/arm/boot/dts/overlays/README | 2 ++ - .../overlays/hifiberry-dacplusadcpro-overlay.dts | 1 + - sound/soc/bcm/hifiberry_dacplusadcpro.c | 15 +++++++++++++-- - 3 files changed, 16 insertions(+), 2 deletions(-) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -948,6 +948,8 @@ Params: 24db_digital_gain Allow ga - that does not result in clipping/distortion!) - slave Force DAC+ADC Pro into slave mode, using Pi as - master for bit clock and frame clock. -+ leds_off If set to 'true' the onboard indicator LEDs -+ are switched off at all times. - - - Name: hifiberry-dacplusdsp ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -@@ -60,5 +60,6 @@ - 24db_digital_gain = - <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?"; - slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?"; -+ leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?"; - }; - }; ---- a/sound/soc/bcm/hifiberry_dacplusadcpro.c -+++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c -@@ -54,6 +54,7 @@ struct pcm512x_priv { - static bool slave; - static bool snd_rpi_hifiberry_is_dacpro; - static bool digital_gain_0db_limit = true; -+static bool leds_off; - - static const unsigned int pcm186x_adc_input_channel_sel_value[] = { - 0x00, 0x01, 0x02, 0x03, 0x10 -@@ -321,7 +322,10 @@ static int snd_rpi_hifiberry_dacplusadcp - - snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08); - snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); -- snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ if (leds_off) -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); -+ else -+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); - - ret = pcm1863_add_controls(adc); - if (ret < 0) -@@ -331,7 +335,10 @@ static int snd_rpi_hifiberry_dacplusadcp - /* set GPIO2 to output, GPIO3 input */ - snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00); - snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04); -- snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); -+ if (leds_off) -+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00); -+ else -+ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40); - - if (digital_gain_0db_limit) { - int ret; -@@ -417,6 +424,8 @@ static int snd_rpi_hifiberry_dacplusadcp - struct snd_soc_component *dac = rtd->codec_dais[0]->component; - struct snd_soc_component *adc = rtd->codec_dais[1]->component; - -+ if (leds_off) -+ return 0; - /* switch on respective LED */ - if (!substream->stream) - snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -@@ -500,6 +509,8 @@ static int snd_rpi_hifiberry_dacplusadcp - pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain"); - slave = of_property_read_bool(pdev->dev.of_node, - "hifiberry-dacplusadcpro,slave"); -+ leds_off = of_property_read_bool(pdev->dev.of_node, -+ "hifiberry-dacplusadcpro,leds_off"); - ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro); - if (ret && ret != -EPROBE_DEFER) - dev_err(&pdev->dev, diff --git a/target/linux/bcm27xx/patches-5.4/950-0400-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch b/target/linux/bcm27xx/patches-5.4/950-0400-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch deleted file mode 100644 index bd8f405ef8..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0400-adds-LED-OFF-feature-to-HiFiBerry-DAC-ADC-sound-card.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 36949b2ea78d5782faed2fb00a037f37789fa85d Mon Sep 17 00:00:00 2001 -From: j-schambacher -Date: Mon, 27 Jan 2020 20:37:34 +0100 -Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC sound card - -This adds a DT overlay parameter 'leds_off' which allows -to switch off the onboard activity LEDs at all times -which has been requested by some users. - -Signed-off-by: Joerg Schambacher ---- - arch/arm/boot/dts/overlays/README | 2 ++ - .../boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 1 + - sound/soc/bcm/hifiberry_dacplusadc.c | 10 +++++++++- - 3 files changed, 12 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -927,6 +927,8 @@ Params: 24db_digital_gain Allow ga - that does not result in clipping/distortion!) - slave Force DAC+ Pro into slave mode, using Pi as - master for bit clock and frame clock. -+ leds_off If set to 'true' the onboard indicator LEDs -+ are switched off at all times. - - - Name: hifiberry-dacplusadcpro ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts -@@ -67,5 +67,6 @@ - 24db_digital_gain = - <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?"; - slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?"; -+ leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?"; - }; - }; ---- a/sound/soc/bcm/hifiberry_dacplusadc.c -+++ b/sound/soc/bcm/hifiberry_dacplusadc.c -@@ -54,6 +54,7 @@ struct pcm512x_priv { - static bool slave; - static bool snd_rpi_hifiberry_is_dacpro; - static bool digital_gain_0db_limit = true; -+static bool leds_off; - - static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component, - int clk_id) -@@ -175,7 +176,10 @@ static int snd_rpi_hifiberry_dacplusadc_ - - snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08); - snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); -- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ if (leds_off) -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); -+ else -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); - - if (digital_gain_0db_limit) { - int ret; -@@ -254,6 +258,8 @@ static int snd_rpi_hifiberry_dacplusadc_ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = rtd->codec_dai->component; - -+ if (leds_off) -+ return 0; - snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, - 0x08, 0x08); - hifiberry_dacplusadc_LED_cnt++; -@@ -330,6 +336,8 @@ static int snd_rpi_hifiberry_dacplusadc_ - pdev->dev.of_node, "hifiberry,24db_digital_gain"); - slave = of_property_read_bool(pdev->dev.of_node, - "hifiberry-dacplusadc,slave"); -+ leds_off = of_property_read_bool(pdev->dev.of_node, -+ "hifiberry-dacplusadc,leds_off"); - - ret = devm_snd_soc_register_card(&pdev->dev, - &snd_rpi_hifiberry_dacplusadc); diff --git a/target/linux/bcm27xx/patches-5.4/950-0400-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0400-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch new file mode 100644 index 0000000000..2f5d87b004 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0400-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch @@ -0,0 +1,29 @@ +From 8be8dc74799fe7c0e09dfa53aa41e954ffba291c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 12 Jul 2019 11:43:03 +0100 +Subject: [PATCH] bcm2838.dtsi: Use BCM2711 PCIe compatible string + +The BCM2711 PCIe controller has a limited address range in the B0 +silicon, and the driver uses a compatible string to identify the +limitation. The current Pi 4 firmware will override the compatible +string if it detects a downstream DTB and it is running on a newer +revision but set the default value to enable the workaround for +backwards-compatibility with old firmware. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2838.dtsi | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ b/arch/arm/boot/dts/bcm2838.dtsi +@@ -314,7 +314,8 @@ + #interrupt-cells = <1>; + #size-cells = <2>; + bus-range = <0x0 0x01>; +- compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie", ++ compatible = "brcm,bcm2711b0-pcie", // Safe value ++ "brcm,bcm2711-pcie", + "brcm,pci-plat-dev"; + max-link-speed = <2>; + tot-num-pcie = <1>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0401-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch b/target/linux/bcm27xx/patches-5.4/950-0401-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch new file mode 100644 index 0000000000..10c5d23b46 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0401-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch @@ -0,0 +1,162 @@ +From 3c099a50b3d609206a86896405cfdc8a94cd7aa4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 29 Jan 2020 11:29:06 +0000 +Subject: [PATCH] ARM: dts: Remove bcm2838-rpi-4-b.dts + +Upstream are not going to use the bcm2838 identifier, so begin the +cleanup by removing the suggested upstream Pi 4 .dts file. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/Makefile | 1 - + arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 134 -------------------------- + 2 files changed, 135 deletions(-) + delete mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -97,7 +97,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ + bcm2837-rpi-3-b.dtb \ + bcm2837-rpi-3-b-plus.dtb \ + bcm2837-rpi-cm3-io3.dtb \ +- bcm2838-rpi-4-b.dtb \ + bcm2835-rpi-zero.dtb \ + bcm2835-rpi-zero-w.dtb + dtb-$(CONFIG_ARCH_BCM_5301X) += \ +--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts ++++ /dev/null +@@ -1,134 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/dts-v1/; +-#include "bcm2838.dtsi" +-#include "bcm2835-rpi.dtsi" +-#include "bcm2838-rpi.dtsi" +- +-/ { +- compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; +- model = "Raspberry Pi 4 Model B"; +- +- chosen { +- /* 8250 auxiliary UART instead of pl011 */ +- stdout-path = "serial1:115200n8"; +- }; +- +- memory@0 { +- device_type = "memory"; +- reg = <0x0 0x0 0x0>; +- }; +- +- leds { +- act { +- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +- }; +- +- pwr { +- label = "PWR"; +- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; +- }; +- }; +- +- wifi_pwrseq: wifi-pwrseq { +- compatible = "mmc-pwrseq-simple"; +- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; +- }; +- +- sd_io_1v8_reg: sd_io_1v8_reg { +- status = "okay"; +- compatible = "regulator-gpio"; +- vin-supply = <&vdd_5v0_reg>; +- regulator-name = "vdd-sd-io"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- regulator-boot-on; +- regulator-always-on; +- regulator-settling-time-us = <5000>; +- +- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; +- states = <1800000 0x1 +- 3300000 0x0>; +- }; +-}; +- +-&firmware { +- expgpio: gpio { +- compatible = "raspberrypi,firmware-gpio"; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-line-names = "BT_ON", +- "WL_ON", +- "PWR_LED_OFF", +- "GLOBAL_RESET", +- "VDD_SD_IO_SEL", +- "CAM_GPIO", +- "", +- ""; +- status = "okay"; +- }; +-}; +- +-&pwm1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>; +- status = "okay"; +-}; +- +-/* SDHCI is used to control the SDIO for wireless */ +-&sdhci { +- #address-cells = <1>; +- #size-cells = <0>; +- pinctrl-names = "default"; +- pinctrl-0 = <&emmc_gpio34>; +- status = "okay"; +- bus-width = <4>; +- non-removable; +- mmc-pwrseq = <&wifi_pwrseq>; +- +- brcmf: wifi@1 { +- reg = <1>; +- compatible = "brcm,bcm4329-fmac"; +- }; +-}; +- +-/* EMMC2 is used to drive the SD card */ +-&emmc2 { +- status = "okay"; +- broken-cd; +- vqmmc-supply = <&sd_io_1v8_reg>; +-}; +- +-&genet { +- phy-handle = <&phy1>; +- phy-mode = "rgmii-rxid"; +- status = "okay"; +-}; +- +-&genet_mdio { +- phy1: ethernet-phy@1 { +- /* No PHY interrupt */ +- reg = <0x1>; +- led-modes = <0x00 0x08>; /* link/activity link */ +- }; +-}; +- +-/* uart0 communicates with the BT module */ +-&uart0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; +- uart-has-rtscts; +- status = "okay"; +- +- bluetooth { +- compatible = "brcm,bcm43438-bt"; +- max-speed = <2000000>; +- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; +- }; +-}; +- +-/* uart1 is mapped to the pin header */ +-&uart1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&uart1_gpio14>; +- status = "okay"; +-}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0401-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch b/target/linux/bcm27xx/patches-5.4/950-0401-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch deleted file mode 100644 index a5c3d40512..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0401-adds-LED-OFF-feature-to-HiFiBerry-DAC-DAC-PRO-sound-.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 4b3cdf84c4d8156c01fa02e4d511f7529cae488f Mon Sep 17 00:00:00 2001 -From: j-schambacher -Date: Mon, 27 Jan 2020 20:58:24 +0100 -Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+/DAC+PRO sound - cards - -This adds a DT overlay parameter 'leds_off' which allows -to switch off the onboard activity LEDs at all times -which has been requested by some users. - -Signed-off-by: Joerg Schambacher ---- - arch/arm/boot/dts/overlays/README | 2 ++ - .../boot/dts/overlays/hifiberry-dacplus-overlay.dts | 1 + - sound/soc/bcm/hifiberry_dacplus.c | 10 +++++++++- - 3 files changed, 12 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -906,6 +906,8 @@ Params: 24db_digital_gain Allow ga - that does not result in clipping/distortion!) - slave Force DAC+ Pro into slave mode, using Pi as - master for bit clock and frame clock. -+ leds_off If set to 'true' the onboard indicator LEDs -+ are switched off at all times. - - - Name: hifiberry-dacplusadc ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts -@@ -55,5 +55,6 @@ - 24db_digital_gain = - <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; - slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?"; -+ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; - }; - }; ---- a/sound/soc/bcm/hifiberry_dacplus.c -+++ b/sound/soc/bcm/hifiberry_dacplus.c -@@ -50,6 +50,7 @@ struct pcm512x_priv { - static bool slave; - static bool snd_rpi_hifiberry_is_dacpro; - static bool digital_gain_0db_limit = true; -+static bool leds_off; - - static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component, - int clk_id) -@@ -171,7 +172,10 @@ static int snd_rpi_hifiberry_dacplus_ini - - snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08); - snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); -- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); -+ if (leds_off) -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); -+ else -+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); - - if (digital_gain_0db_limit) - { -@@ -249,6 +253,8 @@ static int snd_rpi_hifiberry_dacplus_sta - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_component *component = rtd->codec_dai->component; - -+ if (leds_off) -+ return 0; - snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); - return 0; - } -@@ -319,6 +325,8 @@ static int snd_rpi_hifiberry_dacplus_pro - pdev->dev.of_node, "hifiberry,24db_digital_gain"); - slave = of_property_read_bool(pdev->dev.of_node, - "hifiberry-dacplus,slave"); -+ leds_off = of_property_read_bool(pdev->dev.of_node, -+ "hifiberry-dacplus,leds_off"); - } - - ret = devm_snd_soc_register_card(&pdev->dev, diff --git a/target/linux/bcm27xx/patches-5.4/950-0402-pisound-Added-reading-Pisound-board-hardware-revisio.patch b/target/linux/bcm27xx/patches-5.4/950-0402-pisound-Added-reading-Pisound-board-hardware-revisio.patch deleted file mode 100644 index df6f526e2e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0402-pisound-Added-reading-Pisound-board-hardware-revisio.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 21dace2c687d45819cb0dfc4f32f005da82d9197 Mon Sep 17 00:00:00 2001 -From: gtrainavicius -Date: Tue, 28 Jan 2020 14:16:37 +0200 -Subject: [PATCH] pisound: Added reading Pisound board hardware - revision and exposing it (#3425) - -pisound: Added reading Pisound board hardware revision and exposing it in kernel log and sysfs file: - -/sys/kernel/pisound/hw_version - -Signed-off-by: Giedrius ---- - sound/soc/bcm/pisound.c | 86 ++++++++++++++++++++++++++++------------- - 1 file changed, 59 insertions(+), 27 deletions(-) - ---- a/sound/soc/bcm/pisound.c -+++ b/sound/soc/bcm/pisound.c -@@ -51,7 +51,8 @@ static void pisnd_spi_set_callback(pisnd - - static const char *pisnd_spi_get_serial(void); - static const char *pisnd_spi_get_id(void); --static const char *pisnd_spi_get_version(void); -+static const char *pisnd_spi_get_fw_version(void); -+static const char *pisnd_spi_get_hw_version(void); - - static int pisnd_midi_init(struct snd_card *card); - static void pisnd_midi_uninit(void); -@@ -222,7 +223,9 @@ static pisnd_spi_recv_cb g_recvCallback; - - static char g_serial_num[11]; - static char g_id[25]; --static char g_version[5]; -+enum { MAX_VERSION_STR_LEN = 6 }; -+static char g_fw_version[MAX_VERSION_STR_LEN]; -+static char g_hw_version[MAX_VERSION_STR_LEN]; - - static uint8_t g_ledFlashDuration; - static bool g_ledFlashDurationChanged; -@@ -558,7 +561,8 @@ static int spi_read_info(void) - char *p; - - memset(g_serial_num, 0, sizeof(g_serial_num)); -- memset(g_version, 0, sizeof(g_version)); -+ memset(g_fw_version, 0, sizeof(g_fw_version)); -+ strcpy(g_hw_version, "1.0"); // Assume 1.0 hw version. - memset(g_id, 0, sizeof(g_id)); - - tmp = spi_transfer16(0); -@@ -581,12 +585,28 @@ static int spi_read_info(void) - return -EINVAL; - - snprintf( -- g_version, -- sizeof(g_version), -+ g_fw_version, -+ MAX_VERSION_STR_LEN, - "%x.%02x", - buffer[0], - buffer[1] - ); -+ -+ g_fw_version[MAX_VERSION_STR_LEN-1] = '\0'; -+ break; -+ case 3: -+ if (n != 2) -+ return -EINVAL; -+ -+ snprintf( -+ g_hw_version, -+ MAX_VERSION_STR_LEN, -+ "%x.%x", -+ buffer[0], -+ buffer[1] -+ ); -+ -+ g_hw_version[MAX_VERSION_STR_LEN-1] = '\0'; - break; - case 1: - if (n >= sizeof(g_serial_num)) -@@ -596,12 +616,14 @@ static int spi_read_info(void) - break; - case 2: - { -- if (n >= sizeof(g_id)) -+ if (n*2 >= sizeof(g_id)) - return -EINVAL; - - p = g_id; - for (j = 0; j < n; ++j) - p += sprintf(p, "%02x", buffer[j]); -+ -+ *p = '\0'; - } - break; - default: -@@ -619,7 +641,8 @@ static int pisnd_spi_init(struct device - - memset(g_serial_num, 0, sizeof(g_serial_num)); - memset(g_id, 0, sizeof(g_id)); -- memset(g_version, 0, sizeof(g_version)); -+ memset(g_fw_version, 0, sizeof(g_fw_version)); -+ memset(g_hw_version, 0, sizeof(g_hw_version)); - - spi = pisnd_spi_find_device(); - -@@ -729,26 +752,22 @@ static void pisnd_spi_set_callback(pisnd - - static const char *pisnd_spi_get_serial(void) - { -- if (strlen(g_serial_num)) -- return g_serial_num; -- -- return ""; -+ return g_serial_num; - } - - static const char *pisnd_spi_get_id(void) - { -- if (strlen(g_id)) -- return g_id; -- -- return ""; -+ return g_id; - } - --static const char *pisnd_spi_get_version(void) -+static const char *pisnd_spi_get_fw_version(void) - { -- if (strlen(g_version)) -- return g_version; -+ return g_fw_version; -+} - -- return ""; -+static const char *pisnd_spi_get_hw_version(void) -+{ -+ return g_hw_version; - } - - static const struct of_device_id pisound_of_match[] = { -@@ -1056,13 +1075,22 @@ static ssize_t pisnd_id_show( - return sprintf(buf, "%s\n", pisnd_spi_get_id()); - } - --static ssize_t pisnd_version_show( -+static ssize_t pisnd_fw_version_show( - struct kobject *kobj, - struct kobj_attribute *attr, - char *buf - ) - { -- return sprintf(buf, "%s\n", pisnd_spi_get_version()); -+ return sprintf(buf, "%s\n", pisnd_spi_get_fw_version()); -+} -+ -+static ssize_t pisnd_hw_version_show( -+ struct kobject *kobj, -+ struct kobj_attribute *attr, -+ char *buf -+) -+{ -+ return sprintf(buf, "%s\n", pisnd_spi_get_hw_version()); - } - - static ssize_t pisnd_led_store( -@@ -1087,15 +1115,18 @@ static struct kobj_attribute pisnd_seria - __ATTR(serial, 0444, pisnd_serial_show, NULL); - static struct kobj_attribute pisnd_id_attribute = - __ATTR(id, 0444, pisnd_id_show, NULL); --static struct kobj_attribute pisnd_version_attribute = -- __ATTR(version, 0444, pisnd_version_show, NULL); -+static struct kobj_attribute pisnd_fw_version_attribute = -+ __ATTR(version, 0444, pisnd_fw_version_show, NULL); -+static struct kobj_attribute pisnd_hw_version_attribute = -+__ATTR(hw_version, 0444, pisnd_hw_version_show, NULL); - static struct kobj_attribute pisnd_led_attribute = - __ATTR(led, 0644, NULL, pisnd_led_store); - - static struct attribute *attrs[] = { - &pisnd_serial_attribute.attr, - &pisnd_id_attribute.attr, -- &pisnd_version_attribute.attr, -+ &pisnd_fw_version_attribute.attr, -+ &pisnd_hw_version_attribute.attr, - &pisnd_led_attribute.attr, - NULL - }; -@@ -1114,9 +1145,10 @@ static int pisnd_probe(struct platform_d - } - - printi("Detected Pisound card:\n"); -- printi("\tSerial: %s\n", pisnd_spi_get_serial()); -- printi("\tVersion: %s\n", pisnd_spi_get_version()); -- printi("\tId: %s\n", pisnd_spi_get_id()); -+ printi("\tSerial: %s\n", pisnd_spi_get_serial()); -+ printi("\tFirmware Version: %s\n", pisnd_spi_get_fw_version()); -+ printi("\tHardware Version: %s\n", pisnd_spi_get_hw_version()); -+ printi("\tId: %s\n", pisnd_spi_get_id()); - - pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj); - if (!pisnd_kobj) { diff --git a/target/linux/bcm27xx/patches-5.4/950-0402-tty-amba-pl011-Avoid-rare-write-when-full-error.patch b/target/linux/bcm27xx/patches-5.4/950-0402-tty-amba-pl011-Avoid-rare-write-when-full-error.patch new file mode 100644 index 0000000000..6283b83e17 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0402-tty-amba-pl011-Avoid-rare-write-when-full-error.patch @@ -0,0 +1,42 @@ +From 66ca4b2544dbd4f10d8f387782f5c7200d1e2167 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 29 Jan 2020 09:35:19 +0000 +Subject: [PATCH] tty: amba-pl011: Avoid rare write-when-full error + +Under some circumstances on BCM283x processors data loss can be +observed - a single byte missing from the TX output stream. These bytes +are always the last byte of a batch of 8 written from pl011_tx_chars +when from_irq is true, meaning that the FIFO full flag is not checked +before writing. + +The transmit optimisation relies on the FIFO being half-empty when the +TX interrupt is raised. Instrumenting the driver further showed that +the failure case correlated with the TX FIFO full flag being set at the +point where the last byte was written to the data register, which +explains the data loss but not how the FIFO appeared to be prematurely +full. A possible explanation is that a FIFO write was in flight at the +time the interrupt was raised, but as yet there is no hypothesis as to +how this might occur. + +In the absence of a clear understanding of the failure mechanism, avoid +the problem by checking the FIFO levels before writing the last byte of +the group, which will have minimal performance impact. + +Signed-off-by: Phil Elwell +--- + drivers/tty/serial/amba-pl011.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -1447,6 +1447,10 @@ static bool pl011_tx_chars(struct uart_a + if (likely(from_irq) && count-- == 0) + break; + ++ if (likely(from_irq) && count == 0 && ++ pl011_read(uap, REG_FR) & UART01x_FR_TXFF) ++ break; ++ + if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) + break; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0403-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch b/target/linux/bcm27xx/patches-5.4/950-0403-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch deleted file mode 100644 index 4713dde247..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0403-mmc-sdhci-iproc-Fix-vmmc-regulators-on-iProc.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 703920ad5199c46f98cf107c75a2de61608f85fd Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 2 Aug 2019 15:20:11 +0100 -Subject: [PATCH] mmc: sdhci-iproc: Fix vmmc regulators on iProc - -The Linux support for controlling card power via regulators appears to -be contentious. I would argue that the default behaviour is contrary to -the SDHCI spec - turning off the power writes a reserved value to the -SD Bus Voltage Select field of the Power Control Register, which -seems to kill the Arasan/iProc controller - but fortunately there is a -hook in sdhci_ops to override the behaviour. Borrow the implementation -from sdhci_arasan_set_power. - -Signed-off-by: Phil Elwell ---- - drivers/mmc/host/sdhci-iproc.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/drivers/mmc/host/sdhci-iproc.c -+++ b/drivers/mmc/host/sdhci-iproc.c -@@ -173,6 +173,17 @@ static unsigned int sdhci_iproc_get_max_ - return pltfm_host->clock; - } - -+static void sdhci_iproc_set_power(struct sdhci_host *host, unsigned char mode, -+ unsigned short vdd) -+{ -+ if (!IS_ERR(host->mmc->supply.vmmc)) { -+ struct mmc_host *mmc = host->mmc; -+ -+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); -+ } -+ sdhci_set_power_noreg(host, mode, vdd); -+} -+ - static const struct sdhci_ops sdhci_iproc_ops = { - .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_iproc_get_max_clock, -@@ -190,6 +201,7 @@ static const struct sdhci_ops sdhci_ipro - .write_b = sdhci_iproc_writeb, - .set_clock = sdhci_set_clock, - .get_max_clock = sdhci_iproc_get_max_clock, -+ .set_power = sdhci_iproc_set_power, - .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, diff --git a/target/linux/bcm27xx/patches-5.4/950-0403-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch b/target/linux/bcm27xx/patches-5.4/950-0403-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch new file mode 100644 index 0000000000..06e979a462 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0403-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch @@ -0,0 +1,84 @@ +From 333c4158645fe8aaacbd644bcdf7bc4c5b93cc26 Mon Sep 17 00:00:00 2001 +From: Tim Gover <990920+timg236@users.noreply.github.com> +Date: Wed, 15 Jan 2020 11:26:19 +0000 +Subject: [PATCH] usb: xhci: Raspberry Pi FW loader for VIA VL805 + +The VL805 FW may either be loaded from an SPI EEPROM or alternatively +loaded directly by the VideoCore firmware. A PCI reset will reset +the VL805 XHCI controller on the Raspberry Pi4 requiring the firmware +to be reloaded if an SPI EEPROM is not present. + +Use a VideoCore mailbox to trigger the loading of the VL805 +firmware (if necessary) after a PCI reset. + +Signed-off-by: Tim Gover +--- + drivers/usb/host/pci-quirks.c | 31 +++++++++++++++++++++- + include/soc/bcm2835/raspberrypi-firmware.h | 2 +- + 2 files changed, 31 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -18,7 +18,7 @@ + #include + #include "pci-quirks.h" + #include "xhci-ext-caps.h" +- ++#include + + #define UHCI_USBLEGSUP 0xc0 /* legacy support */ + #define UHCI_USBCMD 0 /* command register */ +@@ -634,6 +634,32 @@ EXPORT_SYMBOL_GPL(usb_amd_pt_check_port) + + #endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */ + ++/* The VL805 firmware may either be loaded from an EEPROM or by the BIOS into ++ * memory. If run from memory it must be reloaded after a PCI fundmental reset. ++ * The Raspberry Pi firmware acts as the BIOS in this case. ++ */ ++static void usb_vl805_init(struct pci_dev *pdev) ++{ ++#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) ++ struct rpi_firmware *fw; ++ struct { ++ u32 dev_addr; ++ } packet; ++ int ret; ++ ++ fw = rpi_firmware_get(NULL); ++ if (!fw) ++ return; ++ ++ packet.dev_addr = (pdev->bus->number << 20) | ++ (PCI_SLOT(pdev->devfn) << 15) | (PCI_FUNC(pdev->devfn) << 12); ++ ++ dev_dbg(&pdev->dev, "RPI_FIRMWARE_NOTIFY_XHCI_RESET %x", packet.dev_addr); ++ ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, ++ &packet, sizeof(packet)); ++#endif ++} ++ + #if IS_ENABLED(CONFIG_USB_UHCI_HCD) + + /* +@@ -1222,6 +1248,9 @@ hc_init: + if (pdev->vendor == PCI_VENDOR_ID_INTEL) + usb_enable_intel_xhci_ports(pdev); + ++ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) ++ usb_vl805_init(pdev); ++ + op_reg_base = base + XHCI_HC_LENGTH(readl(base)); + + /* Wait for the host controller to be ready before writing any +--- a/include/soc/bcm2835/raspberrypi-firmware.h ++++ b/include/soc/bcm2835/raspberrypi-firmware.h +@@ -95,7 +95,7 @@ enum rpi_firmware_property_tag { + RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045, + RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, + RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, +- ++ RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, + + /* Dispmanx TAGS */ + RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0404-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch b/target/linux/bcm27xx/patches-5.4/950-0404-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch deleted file mode 100644 index a69feb50b4..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0404-ARM-dts-Declare-RPi-4B-SD-card-power-regulator.patch +++ /dev/null @@ -1,41 +0,0 @@ -From ade82688b687b3340ca5e7883646ad51291d49cd Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 30 Jul 2019 12:37:02 +0100 -Subject: [PATCH] ARM: dts: Declare RPi 4B SD card power regulator - -Later revisions of the Raspberry Pi 4B have a separate control over the -SD card power. Expose that control to Linux as a fixed regulator with -a GPIO enable. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 11 +++++++++++ - 3 files changed, 13 insertions(+), 2 deletions(-) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -122,6 +122,16 @@ - states = <1800000 0x1 - 3300000 0x0>; - }; -+ -+ sd_vcc_reg: sd_vcc_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc-sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ enable-active-high; -+ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; -+ }; - }; - - &sdhost { -@@ -132,6 +142,7 @@ - status = "okay"; - broken-cd; - vqmmc-supply = <&sd_io_1v8_reg>; -+ vmmc-supply = <&sd_vcc_reg>; - }; - - &genet { diff --git a/target/linux/bcm27xx/patches-5.4/950-0404-overlays-Correct-the-eth_led-colour-assignments.patch b/target/linux/bcm27xx/patches-5.4/950-0404-overlays-Correct-the-eth_led-colour-assignments.patch new file mode 100644 index 0000000000..f1f3290bad --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0404-overlays-Correct-the-eth_led-colour-assignments.patch @@ -0,0 +1,51 @@ +From b058c3c898472ad8799bba29365c3295fdd24970 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 29 Jan 2020 14:32:51 +0000 +Subject: [PATCH] overlays: Correct the eth_led* colour assignments + +See: https://github.com/raspberrypi/firmware/issues/1311 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -109,27 +109,28 @@ Params: + Legal values are 2, 3, 4, 5 and 0, where + 0 means never downshift (default 2). Pi3B+ only. + +- eth_led0 Set mode of LED0 (usually orange). The legal +- values are: ++ eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"), ++ green on Pi4 (default "0"). ++ The legal values are: + + Pi3B+ + +- 0=link/activity 1=link1000/activity (default) ++ 0=link/activity 1=link1000/activity + 2=link100/activity 3=link10/activity + 4=link100/1000/activity 5=link10/1000/activity + 6=link10/100/activity 14=off 15=on + + Pi4 + +- 0=Speed/Activity (default) 1=Speed +- 2=Speed/Flash activity 3=FDX ++ 0=Speed/Activity 1=Speed ++ 2=Flash activity 3=FDX + 4=Off 5=On + 6=Alt 7=Speed/Flash + 8=Link 9=Activity + +- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default +- "6", Pi4 default "8"). See eth_led0 for legal +- values. ++ eth_led1 Set mode of LED1 - green on Pi3B (default "6"), ++ amber on Pi4 (default "8"). See eth_led0 for ++ legal values. + + eth_max_speed Set the maximum speed a link is allowed + to negotiate. Legal values are 10, 100 and diff --git a/target/linux/bcm27xx/patches-5.4/950-0405-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch b/target/linux/bcm27xx/patches-5.4/950-0405-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch new file mode 100644 index 0000000000..fef644e1c9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0405-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch @@ -0,0 +1,59 @@ +From 3ef2bbe381adc17d135f8f9b22a43a242eb80c63 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 30 Jan 2020 09:47:00 +0000 +Subject: [PATCH] ARM: dts: Add sd_poll_once dtparam to bcm283x/2711 + +The old sdtweak overlay allowed the SD interface to be effectively +disabled unless there was a card present at boot time, but that +overlay doesn't work on bcm2711 and has largely been replaced by +a set of sd_* dtparams (which have the advantage of being board- +specific. + +Add an sd_poll_once dtparam to allow the same functionality on +all Raspberry Pi boards. + +See: https://github.com/raspberrypi/linux/issues/3286 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 + + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 ++ + arch/arm/boot/dts/overlays/README | 7 +++++++ + 3 files changed, 10 insertions(+) + +--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi +@@ -92,6 +92,7 @@ + watchdog = <&watchdog>,"status"; + random = <&random>,"status"; + sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_poll_once = <&sdhost>,"non-removable?"; + sd_force_pio = <&sdhost>,"brcm,force-pio?"; + sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; + sd_debug = <&sdhost>,"brcm,debug"; +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -363,5 +363,7 @@ + + eth_led0 = <&phy1>,"led-modes:0"; + eth_led1 = <&phy1>,"led-modes:4"; ++ ++ sd_poll_once = <&emmc2>, "non-removable?"; + }; + }; +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -165,6 +165,13 @@ Params: + sd_overclock Clock (in MHz) to use when the MMC framework + requests 50MHz + ++ sd_poll_once Looks for a card once after booting. Useful ++ for network booting scenarios to avoid the ++ overhead of continuous polling. N.B. Using ++ this option restricts the system to using a ++ single card per boot (or none at all). ++ (default off) ++ + sd_force_pio Disable DMA support for SD driver (default off) + + sd_pio_limit Number of blocks above which to use DMA for diff --git a/target/linux/bcm27xx/patches-5.4/950-0405-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0405-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch deleted file mode 100644 index 2f5d87b004..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0405-bcm2838.dtsi-Use-BCM2711-PCIe-compatible-string.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 8be8dc74799fe7c0e09dfa53aa41e954ffba291c Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 12 Jul 2019 11:43:03 +0100 -Subject: [PATCH] bcm2838.dtsi: Use BCM2711 PCIe compatible string - -The BCM2711 PCIe controller has a limited address range in the B0 -silicon, and the driver uses a compatible string to identify the -limitation. The current Pi 4 firmware will override the compatible -string if it detects a downstream DTB and it is running on a newer -revision but set the default value to enable the workaround for -backwards-compatibility with old firmware. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2838.dtsi | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ b/arch/arm/boot/dts/bcm2838.dtsi -@@ -314,7 +314,8 @@ - #interrupt-cells = <1>; - #size-cells = <2>; - bus-range = <0x0 0x01>; -- compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie", -+ compatible = "brcm,bcm2711b0-pcie", // Safe value -+ "brcm,bcm2711-pcie", - "brcm,pci-plat-dev"; - max-link-speed = <2>; - tot-num-pcie = <1>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0406-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch b/target/linux/bcm27xx/patches-5.4/950-0406-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch deleted file mode 100644 index 10c5d23b46..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0406-ARM-dts-Remove-bcm2838-rpi-4-b.dts.patch +++ /dev/null @@ -1,162 +0,0 @@ -From 3c099a50b3d609206a86896405cfdc8a94cd7aa4 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 29 Jan 2020 11:29:06 +0000 -Subject: [PATCH] ARM: dts: Remove bcm2838-rpi-4-b.dts - -Upstream are not going to use the bcm2838 identifier, so begin the -cleanup by removing the suggested upstream Pi 4 .dts file. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/Makefile | 1 - - arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 134 -------------------------- - 2 files changed, 135 deletions(-) - delete mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts - ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -97,7 +97,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ - bcm2837-rpi-3-b.dtb \ - bcm2837-rpi-3-b-plus.dtb \ - bcm2837-rpi-cm3-io3.dtb \ -- bcm2838-rpi-4-b.dtb \ - bcm2835-rpi-zero.dtb \ - bcm2835-rpi-zero-w.dtb - dtb-$(CONFIG_ARCH_BCM_5301X) += \ ---- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts -+++ /dev/null -@@ -1,134 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/dts-v1/; --#include "bcm2838.dtsi" --#include "bcm2835-rpi.dtsi" --#include "bcm2838-rpi.dtsi" -- --/ { -- compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; -- model = "Raspberry Pi 4 Model B"; -- -- chosen { -- /* 8250 auxiliary UART instead of pl011 */ -- stdout-path = "serial1:115200n8"; -- }; -- -- memory@0 { -- device_type = "memory"; -- reg = <0x0 0x0 0x0>; -- }; -- -- leds { -- act { -- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -- }; -- -- pwr { -- label = "PWR"; -- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -- }; -- }; -- -- wifi_pwrseq: wifi-pwrseq { -- compatible = "mmc-pwrseq-simple"; -- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; -- }; -- -- sd_io_1v8_reg: sd_io_1v8_reg { -- status = "okay"; -- compatible = "regulator-gpio"; -- vin-supply = <&vdd_5v0_reg>; -- regulator-name = "vdd-sd-io"; -- regulator-min-microvolt = <1800000>; -- regulator-max-microvolt = <3300000>; -- regulator-boot-on; -- regulator-always-on; -- regulator-settling-time-us = <5000>; -- -- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; -- states = <1800000 0x1 -- 3300000 0x0>; -- }; --}; -- --&firmware { -- expgpio: gpio { -- compatible = "raspberrypi,firmware-gpio"; -- gpio-controller; -- #gpio-cells = <2>; -- gpio-line-names = "BT_ON", -- "WL_ON", -- "PWR_LED_OFF", -- "GLOBAL_RESET", -- "VDD_SD_IO_SEL", -- "CAM_GPIO", -- "", -- ""; -- status = "okay"; -- }; --}; -- --&pwm1 { -- pinctrl-names = "default"; -- pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>; -- status = "okay"; --}; -- --/* SDHCI is used to control the SDIO for wireless */ --&sdhci { -- #address-cells = <1>; -- #size-cells = <0>; -- pinctrl-names = "default"; -- pinctrl-0 = <&emmc_gpio34>; -- status = "okay"; -- bus-width = <4>; -- non-removable; -- mmc-pwrseq = <&wifi_pwrseq>; -- -- brcmf: wifi@1 { -- reg = <1>; -- compatible = "brcm,bcm4329-fmac"; -- }; --}; -- --/* EMMC2 is used to drive the SD card */ --&emmc2 { -- status = "okay"; -- broken-cd; -- vqmmc-supply = <&sd_io_1v8_reg>; --}; -- --&genet { -- phy-handle = <&phy1>; -- phy-mode = "rgmii-rxid"; -- status = "okay"; --}; -- --&genet_mdio { -- phy1: ethernet-phy@1 { -- /* No PHY interrupt */ -- reg = <0x1>; -- led-modes = <0x00 0x08>; /* link/activity link */ -- }; --}; -- --/* uart0 communicates with the BT module */ --&uart0 { -- pinctrl-names = "default"; -- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; -- uart-has-rtscts; -- status = "okay"; -- -- bluetooth { -- compatible = "brcm,bcm43438-bt"; -- max-speed = <2000000>; -- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; -- }; --}; -- --/* uart1 is mapped to the pin header */ --&uart1 { -- pinctrl-names = "default"; -- pinctrl-0 = <&uart1_gpio14>; -- status = "okay"; --}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0406-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch b/target/linux/bcm27xx/patches-5.4/950-0406-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch new file mode 100644 index 0000000000..77bf63e2e2 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0406-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch @@ -0,0 +1,353 @@ +From fe90ee51b283f7cbbce9980b76b3da8b31d39c60 Mon Sep 17 00:00:00 2001 +From: MikeDK +Date: Fri, 31 Jan 2020 10:57:21 +0100 +Subject: [PATCH] overlays: Add ssd1306-spi, ssh1106-spi, ssd-1351-spi + +Add overlays for SSD1306, SH1106 and SSD1351 based OLED displays. +SH1106 is present in many 1.3 inch OLEDs and SSD1351 is present in +1.5 inch RGB OLEDs from AliExpress. + +This will load the staging fbtft drivers. + +Signed-off-by: Michael Kaplan +--- + arch/arm/boot/dts/overlays/Makefile | 3 + + arch/arm/boot/dts/overlays/README | 35 ++++++++ + .../boot/dts/overlays/sh1106-spi-overlay.dts | 84 +++++++++++++++++++ + .../boot/dts/overlays/ssd1306-spi-overlay.dts | 84 +++++++++++++++++++ + .../boot/dts/overlays/ssd1351-spi-overlay.dts | 83 ++++++++++++++++++ + 5 files changed, 289 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts + create mode 100644 arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -145,6 +145,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + sdhost.dtbo \ + sdio.dtbo \ + sdtweak.dtbo \ ++ sh1106-spi.dtbo \ + smi.dtbo \ + smi-dev.dtbo \ + smi-nand.dtbo \ +@@ -168,6 +169,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + spi6-1cs.dtbo \ + spi6-2cs.dtbo \ + ssd1306.dtbo \ ++ ssd1306-spi.dtbo \ ++ ssd1351-spi.dtbo \ + superaudioboard.dtbo \ + sx150x.dtbo \ + tc358743.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -2145,6 +2145,18 @@ Params: overclock_50 Clock (i + (default on) + + ++Name: sh1106-spi ++Info: Overlay for SH1106 OLED via SPI using fbtft staging driver. ++Load: dtoverlay=sh1106-spi,= ++Params: speed SPI bus speed (default 4000000) ++ rotate Display rotation (0, 90, 180 or 270; default 0) ++ fps Delay between frame updates (default 25) ++ debug Debug output level (0-7; default 0) ++ dc_pin GPIO pin for D/C (default 24) ++ reset_pin GPIO pin for RESET (default 25) ++ height Display height (32 or 64; default 64) ++ ++ + Name: smi + Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! + Load: dtoverlay=smi +@@ -2428,6 +2440,29 @@ Params: address Location + https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf + + ++Name: ssd1306-spi ++Info: Overlay for SSD1306 OLED via SPI using fbtft staging driver. ++Load: dtoverlay=ssd1306-spi,= ++Params: speed SPI bus speed (default 10000000) ++ rotate Display rotation (0, 90, 180 or 270; default 0) ++ fps Delay between frame updates (default 25) ++ debug Debug output level (0-7; default 0) ++ dc_pin GPIO pin for D/C (default 24) ++ reset_pin GPIO pin for RESET (default 25) ++ height Display height (32 or 64; default 64) ++ ++ ++Name: ssd1351-spi ++Info: Overlay for SSD1351 OLED via SPI using fbtft staging driver. ++Load: dtoverlay=ssd1351-spi,= ++Params: speed SPI bus speed (default 4500000) ++ rotate Display rotation (0, 90, 180 or 270; default 0) ++ fps Delay between frame updates (default 25) ++ debug Debug output level (0-7; default 0) ++ dc_pin GPIO pin for D/C (default 24) ++ reset_pin GPIO pin for RESET (default 25) ++ ++ + Name: superaudioboard + Info: Configures the SuperAudioBoard sound card + Load: dtoverlay=superaudioboard,= +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts +@@ -0,0 +1,84 @@ ++/* ++ * Device Tree overlay for SH1106 based SPI OLED display ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&spidev0>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spidev1>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&gpio>; ++ __overlay__ { ++ sh1106_pins: sh1106_pins { ++ brcm,pins = <25 24>; ++ brcm,function = <1 1>; /* out out */ ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sh1106: sh1106@0{ ++ compatible = "sinowealth,sh1106"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sh1106_pins>; ++ ++ spi-max-frequency = <4000000>; ++ bgr = <0>; ++ bpp = <1>; ++ rotate = <0>; ++ fps = <25>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ debug = <0>; ++ ++ sinowealth,height = <64>; ++ sinowealth,width = <128>; ++ sinowealth,page-offset = <0>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&sh1106>,"spi-max-frequency:0"; ++ rotate = <&sh1106>,"rotate:0"; ++ fps = <&sh1106>,"fps:0"; ++ debug = <&sh1106>,"debug:0"; ++ dc_pin = <&sh1106>,"dc-gpios:4", ++ <&sh1106_pins>,"brcm,pins:4"; ++ reset_pin = <&sh1106>,"reset-gpios:4", ++ <&sh1106_pins>,"brcm,pins:0"; ++ height = <&sh1106>,"sinowealth,height:0"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts +@@ -0,0 +1,84 @@ ++/* ++ * Device Tree overlay for SSD1306 based SPI OLED display ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&spidev0>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spidev1>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&gpio>; ++ __overlay__ { ++ ssd1306_pins: ssd1306_pins { ++ brcm,pins = <25 24>; ++ brcm,function = <1 1>; /* out out */ ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ssd1306: ssd1306@0{ ++ compatible = "solomon,ssd1306"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ssd1306_pins>; ++ ++ spi-max-frequency = <10000000>; ++ bgr = <0>; ++ bpp = <1>; ++ rotate = <0>; ++ fps = <25>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ debug = <0>; ++ ++ solomon,height = <64>; ++ solomon,width = <128>; ++ solomon,page-offset = <0>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&ssd1306>,"spi-max-frequency:0"; ++ rotate = <&ssd1306>,"rotate:0"; ++ fps = <&ssd1306>,"fps:0"; ++ debug = <&ssd1306>,"debug:0"; ++ dc_pin = <&ssd1306>,"dc-gpios:4", ++ <&ssd1306_pins>,"brcm,pins:4"; ++ reset_pin = <&ssd1306>,"reset-gpios:4", ++ <&ssd1306_pins>,"brcm,pins:0"; ++ height = <&ssd1306>,"solomon,height:0"; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts +@@ -0,0 +1,83 @@ ++/* ++ * Device Tree overlay for SSD1351 based SPI OLED display ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&spidev0>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spidev1>; ++ __overlay__ { ++ status = "disabled"; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&gpio>; ++ __overlay__ { ++ ssd1351_pins: ssd1351_pins { ++ brcm,pins = <25 24>; ++ brcm,function = <1 1>; /* out out */ ++ }; ++ }; ++ }; ++ ++ fragment@4 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ssd1351: ssd1351@0{ ++ compatible = "solomon,ssd1351"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ssd1351_pins>; ++ ++ spi-max-frequency = <4500000>; ++ bgr = <0>; ++ bpp = <16>; ++ rotate = <0>; ++ fps = <25>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ debug = <0>; ++ ++ solomon,height = <128>; ++ solomon,width = <128>; ++ solomon,page-offset = <0>; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&ssd1351>,"spi-max-frequency:0"; ++ rotate = <&ssd1351>,"rotate:0"; ++ fps = <&ssd1351>,"fps:0"; ++ debug = <&ssd1351>,"debug:0"; ++ dc_pin = <&ssd1351>,"dc-gpios:4", ++ <&ssd1351_pins>,"brcm,pins:4"; ++ reset_pin = <&ssd1351>,"reset-gpios:4", ++ <&ssd1351_pins>,"brcm,pins:0"; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0407-overlays-dwc2-Increase-RX-FIFO-size.patch b/target/linux/bcm27xx/patches-5.4/950-0407-overlays-dwc2-Increase-RX-FIFO-size.patch new file mode 100644 index 0000000000..23bc39b3d8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0407-overlays-dwc2-Increase-RX-FIFO-size.patch @@ -0,0 +1,46 @@ +From 1257716d9bae9730c43c636046983f5d80c4efc8 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 4 Feb 2020 13:03:21 +0000 +Subject: [PATCH] overlays: dwc2: Increase RX FIFO size + +The previous version of the dwc2 overlay set the RX FIFO size to +256 4-byte words. This sounds large enough for a 1024 byte packet (the +largest isochronous high speed packet allowed), but it doesn't take +into account some extra space needed by the hardware. + +Minas Harutyunyan at Synopsys (the source of the DWC OTG design) +came up with a more correct value, 301, but since there is spare packet +RAM this can be increased to 558 to allow two packets per frame. + +Also update the upstream overlay to match. + +See: https://github.com/raspberrypi/linux/issues/3447 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts ++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts +@@ -12,7 +12,7 @@ + compatible = "brcm,bcm2835-usb"; + dr_mode = "otg"; + g-np-tx-fifo-size = <32>; +- g-rx-fifo-size = <256>; ++ g-rx-fifo-size = <558>; + g-tx-fifo-size = <512 512 512 512 512 256 256>; + status = "okay"; + }; +--- a/arch/arm/boot/dts/overlays/upstream-overlay.dts ++++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts +@@ -123,7 +123,7 @@ + compatible = "brcm,bcm2835-usb"; + dr_mode = "otg"; + g-np-tx-fifo-size = <32>; +- g-rx-fifo-size = <256>; ++ g-rx-fifo-size = <558>; + g-tx-fifo-size = <512 512 512 512 512 256 256>; + status = "okay"; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0407-tty-amba-pl011-Avoid-rare-write-when-full-error.patch b/target/linux/bcm27xx/patches-5.4/950-0407-tty-amba-pl011-Avoid-rare-write-when-full-error.patch deleted file mode 100644 index 6283b83e17..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0407-tty-amba-pl011-Avoid-rare-write-when-full-error.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 66ca4b2544dbd4f10d8f387782f5c7200d1e2167 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 29 Jan 2020 09:35:19 +0000 -Subject: [PATCH] tty: amba-pl011: Avoid rare write-when-full error - -Under some circumstances on BCM283x processors data loss can be -observed - a single byte missing from the TX output stream. These bytes -are always the last byte of a batch of 8 written from pl011_tx_chars -when from_irq is true, meaning that the FIFO full flag is not checked -before writing. - -The transmit optimisation relies on the FIFO being half-empty when the -TX interrupt is raised. Instrumenting the driver further showed that -the failure case correlated with the TX FIFO full flag being set at the -point where the last byte was written to the data register, which -explains the data loss but not how the FIFO appeared to be prematurely -full. A possible explanation is that a FIFO write was in flight at the -time the interrupt was raised, but as yet there is no hypothesis as to -how this might occur. - -In the absence of a clear understanding of the failure mechanism, avoid -the problem by checking the FIFO levels before writing the last byte of -the group, which will have minimal performance impact. - -Signed-off-by: Phil Elwell ---- - drivers/tty/serial/amba-pl011.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -1447,6 +1447,10 @@ static bool pl011_tx_chars(struct uart_a - if (likely(from_irq) && count-- == 0) - break; - -+ if (likely(from_irq) && count == 0 && -+ pl011_read(uap, REG_FR) & UART01x_FR_TXFF) -+ break; -+ - if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) - break; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0408-overlays-Fix-mcp23017-s-addr-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0408-overlays-Fix-mcp23017-s-addr-parameter.patch new file mode 100644 index 0000000000..29ad87227d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0408-overlays-Fix-mcp23017-s-addr-parameter.patch @@ -0,0 +1,46 @@ +From 9fa750db2d682fa2c124dae609d05d15f93a5e52 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 4 Feb 2020 15:22:55 +0000 +Subject: [PATCH] overlays: Fix mcp23017's addr parameter + +The addr parameter of the mcp23017 overlay was broken by the addition +of the noints parameter; splitting the mcp node in two without also +modifying the second half from the addr parameter would cause the two +halves to separate. Change the implementation strategy to patch +fragment 2 (as was originally proposed). This will prevent the +overlay from being applied at runtime until the "dtoverlay" command +is improved, but the overlay already has this restriction due to +fragment 3 so this isn't a step backwards. + +See: https://github.com/raspberrypi/linux/issues/3449 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts ++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts +@@ -48,15 +48,13 @@ + }; + + fragment@4 { +- target = <&i2c1>; +- __overlay__ { +- mcp23017_irq: mcp@20 { +- #interrupt-cells=<2>; +- interrupt-parent = <&gpio>; +- interrupts = <4 2>; +- interrupt-controller; +- microchip,irq-mirror; +- }; ++ target = <&mcp23017>; ++ mcp23017_irq: __overlay__ { ++ #interrupt-cells=<2>; ++ interrupt-parent = <&gpio>; ++ interrupts = <4 2>; ++ interrupt-controller; ++ microchip,irq-mirror; + }; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0408-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch b/target/linux/bcm27xx/patches-5.4/950-0408-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch deleted file mode 100644 index 06e979a462..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0408-usb-xhci-Raspberry-Pi-FW-loader-for-VIA-VL805.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 333c4158645fe8aaacbd644bcdf7bc4c5b93cc26 Mon Sep 17 00:00:00 2001 -From: Tim Gover <990920+timg236@users.noreply.github.com> -Date: Wed, 15 Jan 2020 11:26:19 +0000 -Subject: [PATCH] usb: xhci: Raspberry Pi FW loader for VIA VL805 - -The VL805 FW may either be loaded from an SPI EEPROM or alternatively -loaded directly by the VideoCore firmware. A PCI reset will reset -the VL805 XHCI controller on the Raspberry Pi4 requiring the firmware -to be reloaded if an SPI EEPROM is not present. - -Use a VideoCore mailbox to trigger the loading of the VL805 -firmware (if necessary) after a PCI reset. - -Signed-off-by: Tim Gover ---- - drivers/usb/host/pci-quirks.c | 31 +++++++++++++++++++++- - include/soc/bcm2835/raspberrypi-firmware.h | 2 +- - 2 files changed, 31 insertions(+), 2 deletions(-) - ---- a/drivers/usb/host/pci-quirks.c -+++ b/drivers/usb/host/pci-quirks.c -@@ -18,7 +18,7 @@ - #include - #include "pci-quirks.h" - #include "xhci-ext-caps.h" -- -+#include - - #define UHCI_USBLEGSUP 0xc0 /* legacy support */ - #define UHCI_USBCMD 0 /* command register */ -@@ -634,6 +634,32 @@ EXPORT_SYMBOL_GPL(usb_amd_pt_check_port) - - #endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */ - -+/* The VL805 firmware may either be loaded from an EEPROM or by the BIOS into -+ * memory. If run from memory it must be reloaded after a PCI fundmental reset. -+ * The Raspberry Pi firmware acts as the BIOS in this case. -+ */ -+static void usb_vl805_init(struct pci_dev *pdev) -+{ -+#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) -+ struct rpi_firmware *fw; -+ struct { -+ u32 dev_addr; -+ } packet; -+ int ret; -+ -+ fw = rpi_firmware_get(NULL); -+ if (!fw) -+ return; -+ -+ packet.dev_addr = (pdev->bus->number << 20) | -+ (PCI_SLOT(pdev->devfn) << 15) | (PCI_FUNC(pdev->devfn) << 12); -+ -+ dev_dbg(&pdev->dev, "RPI_FIRMWARE_NOTIFY_XHCI_RESET %x", packet.dev_addr); -+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, -+ &packet, sizeof(packet)); -+#endif -+} -+ - #if IS_ENABLED(CONFIG_USB_UHCI_HCD) - - /* -@@ -1222,6 +1248,9 @@ hc_init: - if (pdev->vendor == PCI_VENDOR_ID_INTEL) - usb_enable_intel_xhci_ports(pdev); - -+ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) -+ usb_vl805_init(pdev); -+ - op_reg_base = base + XHCI_HC_LENGTH(readl(base)); - - /* Wait for the host controller to be ready before writing any ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -95,7 +95,7 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045, - RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, - RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, -- -+ RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, - - /* Dispmanx TAGS */ - RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, diff --git a/target/linux/bcm27xx/patches-5.4/950-0409-SQUASH-Fix-spi-driver-compiler-warnings.patch b/target/linux/bcm27xx/patches-5.4/950-0409-SQUASH-Fix-spi-driver-compiler-warnings.patch new file mode 100644 index 0000000000..4413439101 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0409-SQUASH-Fix-spi-driver-compiler-warnings.patch @@ -0,0 +1,22 @@ +From 69811ede9ad350beb531082177bdc6da92c7fdb9 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 4 Feb 2020 16:35:12 +0000 +Subject: [PATCH] SQUASH: Fix spi driver compiler warnings + +Squash with "spi: spi-bcm2835: Disable forced software CS" + +Signed-off-by: Phil Elwell +--- + drivers/spi/spi-bcm2835.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/spi/spi-bcm2835.c ++++ b/drivers/spi/spi-bcm2835.c +@@ -1182,7 +1182,6 @@ static int bcm2835_spi_setup(struct spi_ + { + struct spi_controller *ctlr = spi->controller; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); +- struct gpio_chip *chip; + u32 cs; + + /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0409-overlays-Correct-the-eth_led-colour-assignments.patch b/target/linux/bcm27xx/patches-5.4/950-0409-overlays-Correct-the-eth_led-colour-assignments.patch deleted file mode 100644 index f1f3290bad..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0409-overlays-Correct-the-eth_led-colour-assignments.patch +++ /dev/null @@ -1,51 +0,0 @@ -From b058c3c898472ad8799bba29365c3295fdd24970 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Wed, 29 Jan 2020 14:32:51 +0000 -Subject: [PATCH] overlays: Correct the eth_led* colour assignments - -See: https://github.com/raspberrypi/firmware/issues/1311 - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/README | 17 +++++++++-------- - 1 file changed, 9 insertions(+), 8 deletions(-) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -109,27 +109,28 @@ Params: - Legal values are 2, 3, 4, 5 and 0, where - 0 means never downshift (default 2). Pi3B+ only. - -- eth_led0 Set mode of LED0 (usually orange). The legal -- values are: -+ eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"), -+ green on Pi4 (default "0"). -+ The legal values are: - - Pi3B+ - -- 0=link/activity 1=link1000/activity (default) -+ 0=link/activity 1=link1000/activity - 2=link100/activity 3=link10/activity - 4=link100/1000/activity 5=link10/1000/activity - 6=link10/100/activity 14=off 15=on - - Pi4 - -- 0=Speed/Activity (default) 1=Speed -- 2=Speed/Flash activity 3=FDX -+ 0=Speed/Activity 1=Speed -+ 2=Flash activity 3=FDX - 4=Off 5=On - 6=Alt 7=Speed/Flash - 8=Link 9=Activity - -- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default -- "6", Pi4 default "8"). See eth_led0 for legal -- values. -+ eth_led1 Set mode of LED1 - green on Pi3B (default "6"), -+ amber on Pi4 (default "8"). See eth_led0 for -+ legal values. - - eth_max_speed Set the maximum speed a link is allowed - to negotiate. Legal values are 10, 100 and diff --git a/target/linux/bcm27xx/patches-5.4/950-0410-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch b/target/linux/bcm27xx/patches-5.4/950-0410-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch deleted file mode 100644 index fef644e1c9..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0410-ARM-dts-Add-sd_poll_once-dtparam-to-bcm283x-2711.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 3ef2bbe381adc17d135f8f9b22a43a242eb80c63 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 30 Jan 2020 09:47:00 +0000 -Subject: [PATCH] ARM: dts: Add sd_poll_once dtparam to bcm283x/2711 - -The old sdtweak overlay allowed the SD interface to be effectively -disabled unless there was a card present at boot time, but that -overlay doesn't work on bcm2711 and has largely been replaced by -a set of sd_* dtparams (which have the advantage of being board- -specific. - -Add an sd_poll_once dtparam to allow the same functionality on -all Raspberry Pi boards. - -See: https://github.com/raspberrypi/linux/issues/3286 - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 + - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 ++ - arch/arm/boot/dts/overlays/README | 7 +++++++ - 3 files changed, 10 insertions(+) - ---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi -@@ -92,6 +92,7 @@ - watchdog = <&watchdog>,"status"; - random = <&random>,"status"; - sd_overclock = <&sdhost>,"brcm,overclock-50:0"; -+ sd_poll_once = <&sdhost>,"non-removable?"; - sd_force_pio = <&sdhost>,"brcm,force-pio?"; - sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; - sd_debug = <&sdhost>,"brcm,debug"; ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -363,5 +363,7 @@ - - eth_led0 = <&phy1>,"led-modes:0"; - eth_led1 = <&phy1>,"led-modes:4"; -+ -+ sd_poll_once = <&emmc2>, "non-removable?"; - }; - }; ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -165,6 +165,13 @@ Params: - sd_overclock Clock (in MHz) to use when the MMC framework - requests 50MHz - -+ sd_poll_once Looks for a card once after booting. Useful -+ for network booting scenarios to avoid the -+ overhead of continuous polling. N.B. Using -+ this option restricts the system to using a -+ single card per boot (or none at all). -+ (default off) -+ - sd_force_pio Disable DMA support for SD driver (default off) - - sd_pio_limit Number of blocks above which to use DMA for diff --git a/target/linux/bcm27xx/patches-5.4/950-0410-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0410-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch new file mode 100644 index 0000000000..e94f15196b --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0410-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch @@ -0,0 +1,106 @@ +From c6e4343e441558f45df2685b9ed7c13daf7988be Mon Sep 17 00:00:00 2001 +From: Michael Kaplan +Date: Wed, 5 Feb 2020 10:27:23 +0100 +Subject: [PATCH] overlays: add hdmi-backlight-hwhack-gpio-overlay + +This is a Devicetree overlay for GPIO based backlight on/off capability. + +Use this if you have one of those HDMI displays whose backlight cannot be controlled via DPMS over HDMI and plan to do a little soldering to use an RPi gpio pin for on/off switching. + +See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control + +This was tested with a clone of the Waveshare "7 inch HDMI Touch LCD C" where I soldered two mosfets to override the backlight dip-switch. +When the overlay is loaded, a sysfs backlight node appears which can be used to modify the brightness value (0 or 1), and is even used by DPMS to switch the display backlight off after the configured timeout. +(On current Raspbian Buster Desktop, it's also possible to wakeup the display via a tap on the touch display :-) ) + +Signed-off-by: Michael Kaplan +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 14 ++++++ + .../hdmi-backlight-hwhack-gpio-overlay.dts | 47 +++++++++++++++++++ + 3 files changed, 62 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts + +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -51,6 +51,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + gpio-poweroff.dtbo \ + gpio-shutdown.dtbo \ + hd44780-lcd.dtbo \ ++ hdmi-backlight-hwhack-gpio.dtbo \ + hifiberry-amp.dtbo \ + hifiberry-dac.dtbo \ + hifiberry-dacplus.dtbo \ +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -883,6 +883,20 @@ Params: pin_d4 GPIO pin + display_width Width of the display in characters + + ++Name: hdmi-backlight-hwhack-gpio ++Info: Devicetree overlay for GPIO based backlight on/off capability. ++ Use this if you have one of those HDMI displays whose backlight cannot ++ be controlled via DPMS over HDMI and plan to do a little soldering to ++ use an RPi gpio pin for on/off switching. See: ++ https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control ++Load: dtoverlay=hdmi-backlight-hwhack-gpio,= ++Params: gpio_pin GPIO pin used (default 17) ++ active_low Set this to 1 if the display backlight is ++ switched on when the wire goes low. ++ Leave the default (value 0) if the backlight ++ expects a high to switch it on. ++ ++ + Name: hifiberry-amp + Info: Configures the HifiBerry Amp and Amp+ audio cards + Load: dtoverlay=hifiberry-amp +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts +@@ -0,0 +1,47 @@ ++/* ++ * Devicetree overlay for GPIO based backlight on/off capability. ++ * ++ * Use this if you have one of those HDMI displays whose backlight cannot be ++ * controlled via DPMS over HDMI and plan to do a little soldering to use an ++ * RPi gpio pin for on/off switching. ++ * ++ * See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control ++ * ++ */ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835"; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ hdmi_backlight_hwhack_gpio_pins: hdmi_backlight_hwhack_gpio_pins { ++ brcm,pins = <17>; ++ brcm,function = <1>; /* out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target-path = "/"; ++ __overlay__ { ++ hdmi_backlight_hwhack_gpio: hdmi_backlight_hwhack_gpio { ++ compatible = "gpio-backlight"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_backlight_hwhack_gpio_pins>; ++ ++ gpios = <&gpio 17 0>; ++ default-on; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ gpio_pin = <&hdmi_backlight_hwhack_gpio>,"gpios:4", ++ <&hdmi_backlight_hwhack_gpio_pins>,"brcm,pins:0"; ++ active_low = <&hdmi_backlight_hwhack_gpio>,"gpios:8"; ++ }; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0411-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch b/target/linux/bcm27xx/patches-5.4/950-0411-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch new file mode 100644 index 0000000000..403f534baf --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0411-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch @@ -0,0 +1,1929 @@ +From e90536d721612de6a2619ae6727ee12b56bb2660 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 30 Jan 2020 11:39:39 +0000 +Subject: [PATCH] ARM: dts: Revert all changes to upstream dts files + +With the possible exception of bcm2711* files where there is a name +clash, we should not be modifying upstream DTS files. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 348 ++------ + arch/arm/boot/dts/bcm2711.dtsi | 888 ++++++++++++++++++++- + arch/arm/boot/dts/bcm2835-common.dtsi | 131 +++ + arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 1 - + arch/arm/boot/dts/bcm2835-rpi-a.dts | 1 - + arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 1 - + arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 1 - + arch/arm/boot/dts/bcm2835-rpi-b.dts | 1 - + arch/arm/boot/dts/bcm2835-rpi-zero.dts | 1 - + arch/arm/boot/dts/bcm2835-rpi.dtsi | 37 - + arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 1 - + arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 1 - + arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi | 15 - + arch/arm/boot/dts/bcm283x.dtsi | 152 +--- + 14 files changed, 1068 insertions(+), 511 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -1,54 +1,57 @@ ++// SPDX-License-Identifier: GPL-2.0 + /dts-v1/; +- + #include "bcm2711.dtsi" +-#include "bcm2711-rpi.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" ++#include "bcm2835-rpi.dtsi" ++#include "bcm283x-rpi-usb-peripheral.dtsi" + + / { + compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; + model = "Raspberry Pi 4 Model B"; + +- memory@0 { +- device_type = "memory"; +- reg = <0x0 0x0 0x0>; ++ chosen { ++ /* 8250 auxiliary UART instead of pl011 */ ++ stdout-path = "serial1:115200n8"; + }; + +- chosen { +- bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M"; ++ /* Will be filled by the bootloader */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0 0 0>; + }; + + aliases { +- serial0 = &uart1; +- serial1 = &uart0; +- mmc0 = &emmc2; +- mmc1 = &mmcnr; +- mmc2 = &sdhost; +- i2c3 = &i2c3; +- i2c4 = &i2c4; +- i2c5 = &i2c5; +- i2c6 = &i2c6; +- /delete-property/ ethernet; +- /delete-property/ intc; + ethernet0 = &genet; +- pcie0 = &pcie_0; + }; +-}; + +-&soc { +- virtgpio: virtgpio { +- compatible = "brcm,bcm2835-virtgpio"; +- gpio-controller; +- #gpio-cells = <2>; +- firmware = <&firmware>; +- status = "okay"; ++ leds { ++ act { ++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ pwr { ++ label = "PWR"; ++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; ++ }; + }; +-}; + +-&mmcnr { +- pinctrl-names = "default"; +- pinctrl-0 = <&sdio_pins>; +- bus-width = <4>; +- status = "okay"; ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; ++ }; ++ ++ sd_io_1v8_reg: sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-name = "vdd-sd-io"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-settling-time-us = <5000>; ++ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++ status = "okay"; ++ }; + }; + + &firmware { +@@ -68,81 +71,34 @@ + }; + }; + +-&uart0 { ++&pwm1 { + pinctrl-names = "default"; +- pinctrl-0 = <&uart0_pins &bt_pins>; ++ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; + status = "okay"; + }; + +-&uart1 { ++/* SDHCI is used to control the SDIO for wireless */ ++&sdhci { ++ #address-cells = <1>; ++ #size-cells = <0>; + pinctrl-names = "default"; +- pinctrl-0 = <&uart1_pins>; ++ pinctrl-0 = <&emmc_gpio34>; ++ bus-width = <4>; ++ non-removable; ++ mmc-pwrseq = <&wifi_pwrseq>; + status = "okay"; +-}; + +-&spi0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&spi0_pins &spi0_cs_pins>; +- cs-gpios = <&gpio 8 1>, <&gpio 7 1>; +- +- spidev0: spidev@0{ +- compatible = "spidev"; +- reg = <0>; /* CE0 */ +- #address-cells = <1>; +- #size-cells = <0>; +- spi-max-frequency = <125000000>; +- }; +- +- spidev1: spidev@1{ +- compatible = "spidev"; +- reg = <1>; /* CE1 */ +- #address-cells = <1>; +- #size-cells = <0>; +- spi-max-frequency = <125000000>; +- }; +-}; +- +-// ============================================= +-// Board specific stuff here +- +-/ { +- +- sd_io_1v8_reg: sd_io_1v8_reg { +- status = "okay"; +- compatible = "regulator-gpio"; +- vin-supply = <&vdd_5v0_reg>; +- regulator-name = "vdd-sd-io"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- regulator-boot-on; +- regulator-always-on; +- regulator-settling-time-us = <5000>; +- +- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; +- states = <1800000 0x1 +- 3300000 0x0>; ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; + }; +- +- sd_vcc_reg: sd_vcc_reg { +- compatible = "regulator-fixed"; +- regulator-name = "vcc-sd"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-boot-on; +- enable-active-high; +- gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; +- }; +-}; +- +-&sdhost { +- status = "disabled"; + }; + ++/* EMMC2 is used to drive the SD card */ + &emmc2 { +- status = "okay"; +- broken-cd; + vqmmc-supply = <&sd_io_1v8_reg>; +- vmmc-supply = <&sd_vcc_reg>; ++ broken-cd; ++ status = "okay"; + }; + + &genet { +@@ -155,200 +111,32 @@ + phy1: ethernet-phy@1 { + /* No PHY interrupt */ + reg = <0x1>; +- led-modes = <0x00 0x08>; /* link/activity link */ + }; + }; + +-&leds { +- act_led: act { +- label = "led0"; +- linux,default-trigger = "mmc0"; +- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +- }; +- +- pwr_led: pwr { +- label = "led1"; +- linux,default-trigger = "default-on"; +- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; +- }; +-}; +- +-&audio { ++/* uart0 communicates with the BT module */ ++&uart0 { + pinctrl-names = "default"; +- pinctrl-0 = <&audio_pins>; +-}; +- +-&sdhost_gpio48 { +- brcm,pins = <22 23 24 25 26 27>; +- brcm,function = ; +-}; +- +-&gpio { +- spi0_pins: spi0_pins { +- brcm,pins = <9 10 11>; +- brcm,function = ; +- }; +- +- spi0_cs_pins: spi0_cs_pins { +- brcm,pins = <8 7>; +- brcm,function = ; +- }; +- +- spi3_pins: spi3_pins { +- brcm,pins = <1 2 3>; +- brcm,function = ; +- }; +- +- spi3_cs_pins: spi3_cs_pins { +- brcm,pins = <0 24>; +- brcm,function = ; +- }; +- +- spi4_pins: spi4_pins { +- brcm,pins = <5 6 7>; +- brcm,function = ; +- }; +- +- spi4_cs_pins: spi4_cs_pins { +- brcm,pins = <4 25>; +- brcm,function = ; +- }; +- +- spi5_pins: spi5_pins { +- brcm,pins = <13 14 15>; +- brcm,function = ; +- }; +- +- spi5_cs_pins: spi5_cs_pins { +- brcm,pins = <12 26>; +- brcm,function = ; +- }; +- +- spi6_pins: spi6_pins { +- brcm,pins = <19 20 21>; +- brcm,function = ; +- }; +- +- spi6_cs_pins: spi6_cs_pins { +- brcm,pins = <18 27>; +- brcm,function = ; +- }; +- +- i2c0_pins: i2c0 { +- brcm,pins = <0 1>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2c1_pins: i2c1 { +- brcm,pins = <2 3>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2c3_pins: i2c3 { +- brcm,pins = <4 5>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2c4_pins: i2c4 { +- brcm,pins = <8 9>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2c5_pins: i2c5 { +- brcm,pins = <12 13>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2c6_pins: i2c6 { +- brcm,pins = <22 23>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2s_pins: i2s { +- brcm,pins = <18 19 20 21>; +- brcm,function = ; +- }; +- +- sdio_pins: sdio_pins { +- brcm,pins = <34 35 36 37 38 39>; +- brcm,function = ; // alt3 = SD1 +- brcm,pull = <0 2 2 2 2 2>; +- }; +- +- bt_pins: bt_pins { +- brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0 +- // to fool pinctrl +- brcm,function = <0>; +- brcm,pull = <2>; +- }; +- +- uart0_pins: uart0_pins { +- brcm,pins = <32 33>; +- brcm,function = ; +- brcm,pull = <0 2>; +- }; +- +- uart1_pins: uart1_pins { +- brcm,pins; +- brcm,function; +- brcm,pull; +- }; +- +- uart2_pins: uart2_pins { +- brcm,pins = <0 1>; +- brcm,function = ; +- brcm,pull = <0 2>; +- }; +- +- uart3_pins: uart3_pins { +- brcm,pins = <4 5>; +- brcm,function = ; +- brcm,pull = <0 2>; +- }; +- +- uart4_pins: uart4_pins { +- brcm,pins = <8 9>; +- brcm,function = ; +- brcm,pull = <0 2>; +- }; +- +- uart5_pins: uart5_pins { +- brcm,pins = <12 13>; +- brcm,function = ; +- brcm,pull = <0 2>; +- }; ++ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; ++ uart-has-rtscts; ++ status = "okay"; + +- audio_pins: audio_pins { +- brcm,pins = <40 41>; +- brcm,function = <4>; ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <2000000>; ++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; + }; + }; + +-&i2c0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2c0_pins>; +- clock-frequency = <100000>; +-}; +- +-&i2c1 { ++/* uart1 is mapped to the pin header */ ++&uart1 { + pinctrl-names = "default"; +- pinctrl-0 = <&i2c1_pins>; +- clock-frequency = <100000>; +-}; +- +-&i2c2 { +- clock-frequency = <100000>; ++ pinctrl-0 = <&uart1_gpio14>; ++ status = "okay"; + }; + +-&i2s { +- pinctrl-names = "default"; +- pinctrl-0 = <&i2s_pins>; ++&vchiq { ++ interrupts = ; + }; + + / { +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -1,44 +1,890 @@ +-#include "bcm2838.dtsi" +-#include "bcm270x.dtsi" ++// SPDX-License-Identifier: GPL-2.0 ++#include "bcm283x.dtsi" ++ ++#include ++#include + + / { ++ compatible = "brcm,bcm2711"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ interrupt-parent = <&gicv2>; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges; ++ ++ /* ++ * arm64 reserves the CMA by default somewhere in ZONE_DMA32, ++ * that's not good enough for the BCM2711 as some devices can ++ * only address the lower 1G of memory (ZONE_DMA). ++ */ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ size = <0x2000000>; /* 32MB */ ++ alloc-ranges = <0x0 0x00000000 0x40000000>; ++ reusable; ++ linux,cma-default; ++ }; ++ }; ++ ++ + soc { +- /delete-node/ v3d@7ec00000; ++ /* ++ * Defined ranges: ++ * Common BCM283x peripherals ++ * BCM2711-specific peripherals ++ * ARM-local peripherals ++ */ ++ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, ++ <0x7c000000 0x0 0xfc000000 0x02000000>, ++ <0x40000000 0x0 0xff800000 0x00800000>; ++ /* Emulate a contiguous 30-bit address range for DMA */ ++ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>; ++ ++ /* ++ * This node is the provider for the enable-method for ++ * bringing up secondary cores. ++ */ ++ local_intc: local_intc@40000000 { ++ compatible = "brcm,bcm2836-l1-intc"; ++ reg = <0x40000000 0x100>; ++ }; ++ ++ gicv2: interrupt-controller@40041000 { ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ compatible = "arm,gic-400"; ++ reg = <0x40041000 0x1000>, ++ <0x40042000 0x2000>, ++ <0x40044000 0x2000>, ++ <0x40046000 0x2000>; ++ interrupts = ; ++ }; ++ ++ dma: dma@7e007000 { ++ compatible = "brcm,bcm2835-dma"; ++ reg = <0x7e007000 0xb00>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ /* DMA lite 7 - 10 */ ++ , ++ , ++ , ++ ; ++ interrupt-names = "dma0", ++ "dma1", ++ "dma2", ++ "dma3", ++ "dma4", ++ "dma5", ++ "dma6", ++ "dma7", ++ "dma8", ++ "dma9", ++ "dma10"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x07f5>; ++ }; ++ ++ pm: watchdog@7e100000 { ++ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; ++ #power-domain-cells = <1>; ++ #reset-cells = <1>; ++ reg = <0x7e100000 0x114>, ++ <0x7e00a000 0x24>, ++ <0x7ec11000 0x20>; ++ clocks = <&clocks BCM2835_CLOCK_V3D>, ++ <&clocks BCM2835_CLOCK_PERI_IMAGE>, ++ <&clocks BCM2835_CLOCK_H264>, ++ <&clocks BCM2835_CLOCK_ISP>; ++ clock-names = "v3d", "peri_image", "h264", "isp"; ++ system-power-controller; ++ }; ++ ++ rng@7e104000 { ++ interrupts = ; ++ ++ /* RNG is incompatible with brcm,bcm2835-rng */ ++ status = "disabled"; ++ }; ++ ++ uart2: serial@7e201400 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201400 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@7e201600 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201600 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@7e201800 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201800 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@7e201a00 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201a00 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ spi3: spi@7e204600 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204600 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi4: spi@7e204800 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204800 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi5: spi@7e204a00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204a00 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi6: spi@7e204c00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204c00 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@7e205600 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205600 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@7e205800 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205800 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@7e205a00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205a00 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c6: i2c@7e205c00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205c00 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm1: pwm@7e20c800 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7e20c800 0x28>; ++ clocks = <&clocks BCM2835_CLOCK_PWM>; ++ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; ++ assigned-clock-rates = <10000000>; ++ #pwm-cells = <2>; ++ status = "disabled"; ++ }; ++ ++ emmc2: emmc2@7e340000 { ++ compatible = "brcm,bcm2711-emmc2"; ++ reg = <0x7e340000 0x100>; ++ interrupts = ; ++ clocks = <&clocks BCM2711_CLOCK_EMMC2>; ++ status = "disabled"; ++ }; ++ ++ hvs@7e400000 { ++ interrupts = ; ++ }; ++ }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3"; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ /* This only applies to the ARMv7 stub */ ++ arm,cpu-registers-not-fw-configured; ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000d8>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <1>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000e0>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <2>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000e8>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <3>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000f0>; ++ }; + }; + +- __overrides__ { +- arm_freq; ++ scb { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; ++ ++ genet: ethernet@7d580000 { ++ compatible = "brcm,bcm2711-genet-v5"; ++ reg = <0x0 0x7d580000 0x10000>; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ interrupts = , ++ ; ++ status = "disabled"; ++ ++ genet_mdio: mdio@e14 { ++ compatible = "brcm,genet-mdio-v5"; ++ reg = <0xe14 0x8>; ++ reg-names = "mdio"; ++ #address-cells = <0x0>; ++ #size-cells = <0x1>; ++ }; ++ }; + }; + }; + +-&v3d { +- status = "disabled"; ++&clk_osc { ++ clock-frequency = <54000000>; + }; + +-&firmwarekms { +- interrupts = ; ++&clocks { ++ compatible = "brcm,bcm2711-cprman"; + }; + +-&smi { +- interrupts = ; ++&cpu_thermal { ++ coefficients = <(-487) 410040>; + }; + +-&mmc { +- interrupts = ; ++&dsi0 { ++ interrupts = ; ++}; ++ ++&dsi1 { ++ interrupts = ; ++}; ++ ++&gpio { ++ compatible = "brcm,bcm2711-gpio"; ++ interrupts = , ++ , ++ , ++ ; ++ ++ gpclk0_gpio49: gpclk0_gpio49 { ++ pin-gpclk { ++ pins = "gpio49"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ gpclk1_gpio50: gpclk1_gpio50 { ++ pin-gpclk { ++ pins = "gpio50"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ gpclk2_gpio51: gpclk2_gpio51 { ++ pin-gpclk { ++ pins = "gpio51"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ ++ i2c0_gpio46: i2c0_gpio46 { ++ pin-sda { ++ function = "alt0"; ++ pins = "gpio46"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt0"; ++ pins = "gpio47"; ++ bias-disable; ++ }; ++ }; ++ i2c1_gpio46: i2c1_gpio46 { ++ pin-sda { ++ function = "alt1"; ++ pins = "gpio46"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt1"; ++ pins = "gpio47"; ++ bias-disable; ++ }; ++ }; ++ i2c3_gpio2: i2c3_gpio2 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio2"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio3"; ++ bias-disable; ++ }; ++ }; ++ i2c3_gpio4: i2c3_gpio4 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio4"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio5"; ++ bias-disable; ++ }; ++ }; ++ i2c4_gpio6: i2c4_gpio6 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio6"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio7"; ++ bias-disable; ++ }; ++ }; ++ i2c4_gpio8: i2c4_gpio8 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio8"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio9"; ++ bias-disable; ++ }; ++ }; ++ i2c5_gpio10: i2c5_gpio10 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio10"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio11"; ++ bias-disable; ++ }; ++ }; ++ i2c5_gpio12: i2c5_gpio12 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio12"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio13"; ++ bias-disable; ++ }; ++ }; ++ i2c6_gpio0: i2c6_gpio0 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio0"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio1"; ++ bias-disable; ++ }; ++ }; ++ i2c6_gpio22: i2c6_gpio22 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio22"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio23"; ++ bias-disable; ++ }; ++ }; ++ i2c_slave_gpio8: i2c_slave_gpio8 { ++ pins-i2c-slave { ++ pins = "gpio8", ++ "gpio9", ++ "gpio10", ++ "gpio11"; ++ function = "alt3"; ++ }; ++ }; ++ ++ jtag_gpio48: jtag_gpio48 { ++ pins-jtag { ++ pins = "gpio48", ++ "gpio49", ++ "gpio50", ++ "gpio51", ++ "gpio52", ++ "gpio53"; ++ function = "alt4"; ++ }; ++ }; ++ ++ mii_gpio28: mii_gpio28 { ++ pins-mii { ++ pins = "gpio28", ++ "gpio29", ++ "gpio30", ++ "gpio31"; ++ function = "alt4"; ++ }; ++ }; ++ mii_gpio36: mii_gpio36 { ++ pins-mii { ++ pins = "gpio36", ++ "gpio37", ++ "gpio38", ++ "gpio39"; ++ function = "alt5"; ++ }; ++ }; ++ ++ pcm_gpio50: pcm_gpio50 { ++ pins-pcm { ++ pins = "gpio50", ++ "gpio51", ++ "gpio52", ++ "gpio53"; ++ function = "alt2"; ++ }; ++ }; ++ ++ pwm0_0_gpio12: pwm0_0_gpio12 { ++ pin-pwm { ++ pins = "gpio12"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_0_gpio18: pwm0_0_gpio18 { ++ pin-pwm { ++ pins = "gpio18"; ++ function = "alt5"; ++ bias-disable; ++ }; ++ }; ++ pwm1_0_gpio40: pwm1_0_gpio40 { ++ pin-pwm { ++ pins = "gpio40"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio13: pwm0_1_gpio13 { ++ pin-pwm { ++ pins = "gpio13"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio19: pwm0_1_gpio19 { ++ pin-pwm { ++ pins = "gpio19"; ++ function = "alt5"; ++ bias-disable; ++ }; ++ }; ++ pwm1_1_gpio41: pwm1_1_gpio41 { ++ pin-pwm { ++ pins = "gpio41"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio45: pwm0_1_gpio45 { ++ pin-pwm { ++ pins = "gpio45"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_0_gpio52: pwm0_0_gpio52 { ++ pin-pwm { ++ pins = "gpio52"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio53: pwm0_1_gpio53 { ++ pin-pwm { ++ pins = "gpio53"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ ++ rgmii_gpio35: rgmii_gpio35 { ++ pin-start-stop { ++ pins = "gpio35"; ++ function = "alt4"; ++ }; ++ pin-rx-ok { ++ pins = "gpio36"; ++ function = "alt4"; ++ }; ++ }; ++ rgmii_irq_gpio34: rgmii_irq_gpio34 { ++ pin-irq { ++ pins = "gpio34"; ++ function = "alt5"; ++ }; ++ }; ++ rgmii_irq_gpio39: rgmii_irq_gpio39 { ++ pin-irq { ++ pins = "gpio39"; ++ function = "alt4"; ++ }; ++ }; ++ rgmii_mdio_gpio28: rgmii_mdio_gpio28 { ++ pins-mdio { ++ pins = "gpio28", ++ "gpio29"; ++ function = "alt5"; ++ }; ++ }; ++ rgmii_mdio_gpio37: rgmii_mdio_gpio37 { ++ pins-mdio { ++ pins = "gpio37", ++ "gpio38"; ++ function = "alt4"; ++ }; ++ }; ++ ++ spi0_gpio46: spi0_gpio46 { ++ pins-spi { ++ pins = "gpio46", ++ "gpio47", ++ "gpio48", ++ "gpio49"; ++ function = "alt2"; ++ }; ++ }; ++ spi2_gpio46: spi2_gpio46 { ++ pins-spi { ++ pins = "gpio46", ++ "gpio47", ++ "gpio48", ++ "gpio49", ++ "gpio50"; ++ function = "alt5"; ++ }; ++ }; ++ spi3_gpio0: spi3_gpio0 { ++ pins-spi { ++ pins = "gpio0", ++ "gpio1", ++ "gpio2", ++ "gpio3"; ++ function = "alt3"; ++ }; ++ }; ++ spi4_gpio4: spi4_gpio4 { ++ pins-spi { ++ pins = "gpio4", ++ "gpio5", ++ "gpio6", ++ "gpio7"; ++ function = "alt3"; ++ }; ++ }; ++ spi5_gpio12: spi5_gpio12 { ++ pins-spi { ++ pins = "gpio12", ++ "gpio13", ++ "gpio14", ++ "gpio15"; ++ function = "alt3"; ++ }; ++ }; ++ spi6_gpio18: spi6_gpio18 { ++ pins-spi { ++ pins = "gpio18", ++ "gpio19", ++ "gpio20", ++ "gpio21"; ++ function = "alt3"; ++ }; ++ }; ++ ++ uart2_gpio0: uart2_gpio0 { ++ pin-tx { ++ pins = "gpio0"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio1"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { ++ pin-cts { ++ pins = "gpio2"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio3"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; ++ uart3_gpio4: uart3_gpio4 { ++ pin-tx { ++ pins = "gpio4"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio5"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { ++ pin-cts { ++ pins = "gpio6"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio7"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; ++ uart4_gpio8: uart4_gpio8 { ++ pin-tx { ++ pins = "gpio8"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio9"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { ++ pin-cts { ++ pins = "gpio10"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio11"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; ++ uart5_gpio12: uart5_gpio12 { ++ pin-tx { ++ pins = "gpio12"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio13"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { ++ pin-cts { ++ pins = "gpio14"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio15"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; + }; + +-&mmcnr { ++&i2c0 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ interrupts = ; ++}; ++ ++&i2c1 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ interrupts = ; ++}; ++ ++&mailbox { ++ interrupts = ; ++}; ++ ++&sdhci { + interrupts = ; + }; + ++&sdhost { ++ interrupts = ; ++}; ++ ++&spi { ++ interrupts = ; ++}; ++ ++&spi1 { ++ interrupts = ; ++}; ++ ++&spi2 { ++ interrupts = ; ++}; ++ ++&system_timer { ++ interrupts = , ++ , ++ , ++ ; ++}; ++ ++&txp { ++ interrupts = ; ++}; ++ ++&uart0 { ++ interrupts = ; ++}; ++ ++&uart1 { ++ interrupts = ; ++}; ++ + &usb { +- reg = <0x7e980000 0x10000>, +- <0x7e00b200 0x200>; +- interrupts = , +- ; ++ interrupts = ; + }; + +-&gpio { +- interrupts = , +- ; ++&vec { ++ interrupts = ; + }; +--- a/arch/arm/boot/dts/bcm2835-common.dtsi ++++ b/arch/arm/boot/dts/bcm2835-common.dtsi +@@ -8,6 +8,47 @@ + interrupt-parent = <&intc>; + + soc { ++ dma: dma@7e007000 { ++ compatible = "brcm,bcm2835-dma"; ++ reg = <0x7e007000 0xf00>; ++ interrupts = <1 16>, ++ <1 17>, ++ <1 18>, ++ <1 19>, ++ <1 20>, ++ <1 21>, ++ <1 22>, ++ <1 23>, ++ <1 24>, ++ <1 25>, ++ <1 26>, ++ /* dma channel 11-14 share one irq */ ++ <1 27>, ++ <1 27>, ++ <1 27>, ++ <1 27>, ++ /* unused shared irq for all channels */ ++ <1 28>; ++ interrupt-names = "dma0", ++ "dma1", ++ "dma2", ++ "dma3", ++ "dma4", ++ "dma5", ++ "dma6", ++ "dma7", ++ "dma8", ++ "dma9", ++ "dma10", ++ "dma11", ++ "dma12", ++ "dma13", ++ "dma14", ++ "dma-shared-all"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x7f35>; ++ }; ++ + intc: interrupt-controller@7e00b200 { + compatible = "brcm,bcm2835-armctrl-ic"; + reg = <0x7e00b200 0x200>; +@@ -15,6 +56,20 @@ + #interrupt-cells = <2>; + }; + ++ pm: watchdog@7e100000 { ++ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; ++ #power-domain-cells = <1>; ++ #reset-cells = <1>; ++ reg = <0x7e100000 0x114>, ++ <0x7e00a000 0x24>; ++ clocks = <&clocks BCM2835_CLOCK_V3D>, ++ <&clocks BCM2835_CLOCK_PERI_IMAGE>, ++ <&clocks BCM2835_CLOCK_H264>, ++ <&clocks BCM2835_CLOCK_ISP>; ++ clock-names = "v3d", "peri_image", "h264", "isp"; ++ system-power-controller; ++ }; ++ + pixelvalve@7e206000 { + compatible = "brcm,bcm2835-pixelvalve0"; + reg = <0x7e206000 0x100>; +@@ -35,21 +90,53 @@ + status = "disabled"; + }; + ++ i2c2: i2c@7e805000 { ++ compatible = "brcm,bcm2835-i2c"; ++ reg = <0x7e805000 0x1000>; ++ interrupts = <2 21>; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ }; ++ + pixelvalve@7e807000 { + compatible = "brcm,bcm2835-pixelvalve2"; + reg = <0x7e807000 0x100>; + interrupts = <2 10>; /* pixelvalve */ + }; + ++ hdmi: hdmi@7e902000 { ++ compatible = "brcm,bcm2835-hdmi"; ++ reg = <0x7e902000 0x600>, ++ <0x7e808000 0x100>; ++ interrupts = <2 8>, <2 9>; ++ ddc = <&i2c2>; ++ clocks = <&clocks BCM2835_PLLH_PIX>, ++ <&clocks BCM2835_CLOCK_HSM>; ++ clock-names = "pixel", "hdmi"; ++ dmas = <&dma 17>; ++ dma-names = "audio-rx"; ++ status = "disabled"; ++ }; ++ + v3d: v3d@7ec00000 { + compatible = "brcm,bcm2835-v3d"; + reg = <0x7ec00000 0x1000>; + interrupts = <1 10>; + power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; + }; ++ ++ vc4: gpu { ++ compatible = "brcm,bcm2835-vc4"; ++ }; + }; + }; + ++&cpu_thermal { ++ thermal-sensors = <&thermal>; ++}; ++ + &gpio { + i2c_slave_gpio18: i2c_slave_gpio18 { + brcm,pins = <18 19 20 21>; +@@ -60,4 +147,48 @@ + brcm,pins = <4 5 6 12 13>; + brcm,function = ; + }; ++ ++ pwm0_gpio12: pwm0_gpio12 { ++ brcm,pins = <12>; ++ brcm,function = ; ++ }; ++ pwm0_gpio18: pwm0_gpio18 { ++ brcm,pins = <18>; ++ brcm,function = ; ++ }; ++ pwm0_gpio40: pwm0_gpio40 { ++ brcm,pins = <40>; ++ brcm,function = ; ++ }; ++ pwm1_gpio13: pwm1_gpio13 { ++ brcm,pins = <13>; ++ brcm,function = ; ++ }; ++ pwm1_gpio19: pwm1_gpio19 { ++ brcm,pins = <19>; ++ brcm,function = ; ++ }; ++ pwm1_gpio41: pwm1_gpio41 { ++ brcm,pins = <41>; ++ brcm,function = ; ++ }; ++ pwm1_gpio45: pwm1_gpio45 { ++ brcm,pins = <45>; ++ brcm,function = ; ++ }; ++}; ++ ++&i2s { ++ dmas = <&dma 2>, <&dma 3>; ++ dma-names = "tx", "rx"; ++}; ++ ++&sdhost { ++ dmas = <&dma 13>; ++ dma-names = "rx-tx"; ++}; ++ ++&spi { ++ dmas = <&dma 6>, <&dma 7>; ++ dma-names = "tx", "rx"; + }; +--- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts +@@ -3,7 +3,6 @@ + #include "bcm2835.dtsi" + #include "bcm2835-rpi.dtsi" + #include "bcm283x-rpi-usb-host.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,model-a-plus", "brcm,bcm2835"; +--- a/arch/arm/boot/dts/bcm2835-rpi-a.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts +@@ -3,7 +3,6 @@ + #include "bcm2835.dtsi" + #include "bcm2835-rpi.dtsi" + #include "bcm283x-rpi-usb-host.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,model-a", "brcm,bcm2835"; +--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts +@@ -4,7 +4,6 @@ + #include "bcm2835-rpi.dtsi" + #include "bcm283x-rpi-smsc9514.dtsi" + #include "bcm283x-rpi-usb-host.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,model-b-plus", "brcm,bcm2835"; +--- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts +@@ -4,7 +4,6 @@ + #include "bcm2835-rpi.dtsi" + #include "bcm283x-rpi-smsc9512.dtsi" + #include "bcm283x-rpi-usb-host.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835"; +--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts +@@ -4,7 +4,6 @@ + #include "bcm2835-rpi.dtsi" + #include "bcm283x-rpi-smsc9512.dtsi" + #include "bcm283x-rpi-usb-host.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,model-b", "brcm,bcm2835"; +--- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts ++++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts +@@ -7,7 +7,6 @@ + #include "bcm2835.dtsi" + #include "bcm2835-rpi.dtsi" + #include "bcm283x-rpi-usb-otg.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,model-zero", "brcm,bcm2835"; +--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi +@@ -29,22 +29,6 @@ + interrupts = <0 2>; + }; + }; +- +- vdd_3v3_reg: fixedregulator_3v3 { +- compatible = "regulator-fixed"; +- regulator-name = "3v3"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-always-on; +- }; +- +- vdd_5v0_reg: fixedregulator_5v0 { +- compatible = "regulator-fixed"; +- regulator-name = "5v0"; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- regulator-always-on; +- }; + }; + + &gpio { +@@ -75,23 +59,10 @@ + clock-frequency = <100000>; + }; + +-&i2c2 { +- status = "okay"; +-}; +- + &usb { + power-domains = <&power RPI_POWER_DOMAIN_USB>; + }; + +-&hdmi { +- power-domains = <&power RPI_POWER_DOMAIN_HDMI>; +- status = "okay"; +-}; +- +-&v3d { +- power-domains = <&power RPI_POWER_DOMAIN_V3D>; +-}; +- + &vec { + power-domains = <&power RPI_POWER_DOMAIN_VEC>; + status = "okay"; +@@ -104,11 +75,3 @@ + &dsi1 { + power-domains = <&power RPI_POWER_DOMAIN_DSI1>; + }; +- +-&csi0 { +- power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>; +-}; +- +-&csi1 { +- power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>; +-}; +--- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts ++++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +@@ -4,7 +4,6 @@ + #include "bcm2836-rpi.dtsi" + #include "bcm283x-rpi-smsc9514.dtsi" + #include "bcm283x-rpi-usb-host.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; +--- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts ++++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts +@@ -4,7 +4,6 @@ + #include "bcm2836-rpi.dtsi" + #include "bcm283x-rpi-smsc9514.dtsi" + #include "bcm283x-rpi-usb-host.dtsi" +-#include "bcm283x-rpi-csi1-2lane.dtsi" + + / { + compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; +--- a/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi ++++ b/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi +@@ -29,9 +29,6 @@ + #size-cells = <0x0>; + eth_phy: ethernet-phy@1 { + reg = <1>; +- microchip,eee-enabled; +- microchip,tx-lpi-timer = <600>; /* non-aggressive*/ +- microchip,downshift-after = <2>; + microchip,led-modes = < + LAN78XX_LINK_1000_ACTIVITY + LAN78XX_LINK_10_100_ACTIVITY +@@ -42,15 +39,3 @@ + }; + }; + }; +- +- +-/ { +- __overrides__ { +- eee = <ð_phy>,"microchip,eee-enabled?"; +- tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0"; +- eth_led0 = <ð_phy>,"microchip,led-modes:0"; +- eth_led1 = <ð_phy>,"microchip,led-modes:4"; +- eth_downshift_after = <ð_phy>,"microchip,downshift-after:0"; +- eth_max_speed = <ð_phy>,"max-speed:0"; +- }; +-}; +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -35,8 +35,6 @@ + polling-delay-passive = <0>; + polling-delay = <1000>; + +- thermal-sensors = <&thermal>; +- + trips { + cpu-crit { + temperature = <90000>; +@@ -72,61 +70,6 @@ + interrupts = <1 11>; + }; + +- dma: dma@7e007000 { +- compatible = "brcm,bcm2835-dma"; +- reg = <0x7e007000 0xf00>; +- interrupts = <1 16>, +- <1 17>, +- <1 18>, +- <1 19>, +- <1 20>, +- <1 21>, +- <1 22>, +- <1 23>, +- <1 24>, +- <1 25>, +- <1 26>, +- /* dma channel 11-14 share one irq */ +- <1 27>, +- <1 27>, +- <1 27>, +- <1 27>, +- /* unused shared irq for all channels */ +- <1 28>; +- interrupt-names = "dma0", +- "dma1", +- "dma2", +- "dma3", +- "dma4", +- "dma5", +- "dma6", +- "dma7", +- "dma8", +- "dma9", +- "dma10", +- "dma11", +- "dma12", +- "dma13", +- "dma14", +- "dma-shared-all"; +- #dma-cells = <1>; +- brcm,dma-channel-mask = <0x7f35>; +- }; +- +- pm: watchdog@7e100000 { +- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; +- #power-domain-cells = <1>; +- #reset-cells = <1>; +- reg = <0x7e100000 0x114>, +- <0x7e00a000 0x24>; +- clocks = <&clocks BCM2835_CLOCK_V3D>, +- <&clocks BCM2835_CLOCK_PERI_IMAGE>, +- <&clocks BCM2835_CLOCK_H264>, +- <&clocks BCM2835_CLOCK_ISP>; +- clock-names = "v3d", "peri_image", "h264", "isp"; +- system-power-controller; +- }; +- + clocks: cprman@7e101000 { + compatible = "brcm,bcm2835-cprman"; + #clock-cells = <1>; +@@ -141,7 +84,7 @@ + <&dsi1 0>, <&dsi1 1>, <&dsi1 2>; + }; + +- rng: rng@7e104000 { ++ rng@7e104000 { + compatible = "brcm,bcm2835-rng"; + reg = <0x7e104000 0x10>; + interrupts = <2 29>; +@@ -269,35 +212,6 @@ + brcm,function = ; + }; + +- pwm0_gpio12: pwm0_gpio12 { +- brcm,pins = <12>; +- brcm,function = ; +- }; +- pwm0_gpio18: pwm0_gpio18 { +- brcm,pins = <18>; +- brcm,function = ; +- }; +- pwm0_gpio40: pwm0_gpio40 { +- brcm,pins = <40>; +- brcm,function = ; +- }; +- pwm1_gpio13: pwm1_gpio13 { +- brcm,pins = <13>; +- brcm,function = ; +- }; +- pwm1_gpio19: pwm1_gpio19 { +- brcm,pins = <19>; +- brcm,function = ; +- }; +- pwm1_gpio41: pwm1_gpio41 { +- brcm,pins = <41>; +- brcm,function = ; +- }; +- pwm1_gpio45: pwm1_gpio45 { +- brcm,pins = <45>; +- brcm,function = ; +- }; +- + sdhost_gpio48: sdhost_gpio48 { + brcm,pins = <48 49 50 51 52 53>; + brcm,function = ; +@@ -379,7 +293,7 @@ + }; + + uart0: serial@7e201000 { +- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; ++ compatible = "arm,pl011", "arm,primecell"; + reg = <0x7e201000 0x200>; + interrupts = <2 25>; + clocks = <&clocks BCM2835_CLOCK_UART>, +@@ -393,8 +307,6 @@ + reg = <0x7e202000 0x100>; + interrupts = <2 24>; + clocks = <&clocks BCM2835_CLOCK_VPU>; +- dmas = <&dma (13|(1<<29))>; +- dma-names = "rx-tx"; + status = "disabled"; + }; + +@@ -402,10 +314,6 @@ + compatible = "brcm,bcm2835-i2s"; + reg = <0x7e203000 0x24>; + clocks = <&clocks BCM2835_CLOCK_PCM>; +- +- dmas = <&dma 2>, +- <&dma 3>; +- dma-names = "tx", "rx"; + status = "disabled"; + }; + +@@ -414,8 +322,6 @@ + reg = <0x7e204000 0x200>; + interrupts = <2 22>; + clocks = <&clocks BCM2835_CLOCK_VPU>; +- dmas = <&dma 6>, <&dma 7>; +- dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +@@ -541,32 +447,6 @@ + status = "disabled"; + }; + +- csi0: csi@7e800000 { +- compatible = "brcm,bcm2835-unicam"; +- reg = <0x7e800000 0x800>, +- <0x7e802000 0x4>; +- interrupts = <2 6>; +- clocks = <&clocks BCM2835_CLOCK_CAM0>; +- clock-names = "lp"; +- #address-cells = <1>; +- #size-cells = <0>; +- #clock-cells = <1>; +- status = "disabled"; +- }; +- +- csi1: csi@7e801000 { +- compatible = "brcm,bcm2835-unicam"; +- reg = <0x7e801000 0x800>, +- <0x7e802004 0x4>; +- interrupts = <2 7>; +- clocks = <&clocks BCM2835_CLOCK_CAM1>; +- clock-names = "lp"; +- #address-cells = <1>; +- #size-cells = <0>; +- #clock-cells = <1>; +- status = "disabled"; +- }; +- + i2c1: i2c@7e804000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e804000 0x1000>; +@@ -577,16 +457,6 @@ + status = "disabled"; + }; + +- i2c2: i2c@7e805000 { +- compatible = "brcm,bcm2835-i2c"; +- reg = <0x7e805000 0x1000>; +- interrupts = <2 21>; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- + vec: vec@7e806000 { + compatible = "brcm,bcm2835-vec"; + reg = <0x7e806000 0x1000>; +@@ -595,20 +465,6 @@ + status = "disabled"; + }; + +- hdmi: hdmi@7e902000 { +- compatible = "brcm,bcm2835-hdmi"; +- reg = <0x7e902000 0x600>, +- <0x7e808000 0x100>; +- interrupts = <2 8>, <2 9>; +- ddc = <&i2c2>; +- clocks = <&clocks BCM2835_PLLH_PIX>, +- <&clocks BCM2835_CLOCK_HSM>; +- clock-names = "pixel", "hdmi"; +- dmas = <&dma 17>; +- dma-names = "audio-rx"; +- status = "disabled"; +- }; +- + usb: usb@7e980000 { + compatible = "brcm,bcm2835-usb"; + reg = <0x7e980000 0x10000>; +@@ -620,10 +476,6 @@ + phys = <&usbphy>; + phy-names = "usb2-phy"; + }; +- +- vc4: gpu { +- compatible = "brcm,bcm2835-vc4"; +- }; + }; + + clocks { diff --git a/target/linux/bcm27xx/patches-5.4/950-0411-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch b/target/linux/bcm27xx/patches-5.4/950-0411-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch deleted file mode 100644 index 77bf63e2e2..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0411-overlays-Add-ssd1306-spi-ssh1106-spi-ssd-1351-spi.patch +++ /dev/null @@ -1,353 +0,0 @@ -From fe90ee51b283f7cbbce9980b76b3da8b31d39c60 Mon Sep 17 00:00:00 2001 -From: MikeDK -Date: Fri, 31 Jan 2020 10:57:21 +0100 -Subject: [PATCH] overlays: Add ssd1306-spi, ssh1106-spi, ssd-1351-spi - -Add overlays for SSD1306, SH1106 and SSD1351 based OLED displays. -SH1106 is present in many 1.3 inch OLEDs and SSD1351 is present in -1.5 inch RGB OLEDs from AliExpress. - -This will load the staging fbtft drivers. - -Signed-off-by: Michael Kaplan ---- - arch/arm/boot/dts/overlays/Makefile | 3 + - arch/arm/boot/dts/overlays/README | 35 ++++++++ - .../boot/dts/overlays/sh1106-spi-overlay.dts | 84 +++++++++++++++++++ - .../boot/dts/overlays/ssd1306-spi-overlay.dts | 84 +++++++++++++++++++ - .../boot/dts/overlays/ssd1351-spi-overlay.dts | 83 ++++++++++++++++++ - 5 files changed, 289 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts - create mode 100644 arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts - ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -145,6 +145,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - sdhost.dtbo \ - sdio.dtbo \ - sdtweak.dtbo \ -+ sh1106-spi.dtbo \ - smi.dtbo \ - smi-dev.dtbo \ - smi-nand.dtbo \ -@@ -168,6 +169,8 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - spi6-1cs.dtbo \ - spi6-2cs.dtbo \ - ssd1306.dtbo \ -+ ssd1306-spi.dtbo \ -+ ssd1351-spi.dtbo \ - superaudioboard.dtbo \ - sx150x.dtbo \ - tc358743.dtbo \ ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -2145,6 +2145,18 @@ Params: overclock_50 Clock (i - (default on) - - -+Name: sh1106-spi -+Info: Overlay for SH1106 OLED via SPI using fbtft staging driver. -+Load: dtoverlay=sh1106-spi,= -+Params: speed SPI bus speed (default 4000000) -+ rotate Display rotation (0, 90, 180 or 270; default 0) -+ fps Delay between frame updates (default 25) -+ debug Debug output level (0-7; default 0) -+ dc_pin GPIO pin for D/C (default 24) -+ reset_pin GPIO pin for RESET (default 25) -+ height Display height (32 or 64; default 64) -+ -+ - Name: smi - Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25! - Load: dtoverlay=smi -@@ -2428,6 +2440,29 @@ Params: address Location - https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf - - -+Name: ssd1306-spi -+Info: Overlay for SSD1306 OLED via SPI using fbtft staging driver. -+Load: dtoverlay=ssd1306-spi,= -+Params: speed SPI bus speed (default 10000000) -+ rotate Display rotation (0, 90, 180 or 270; default 0) -+ fps Delay between frame updates (default 25) -+ debug Debug output level (0-7; default 0) -+ dc_pin GPIO pin for D/C (default 24) -+ reset_pin GPIO pin for RESET (default 25) -+ height Display height (32 or 64; default 64) -+ -+ -+Name: ssd1351-spi -+Info: Overlay for SSD1351 OLED via SPI using fbtft staging driver. -+Load: dtoverlay=ssd1351-spi,= -+Params: speed SPI bus speed (default 4500000) -+ rotate Display rotation (0, 90, 180 or 270; default 0) -+ fps Delay between frame updates (default 25) -+ debug Debug output level (0-7; default 0) -+ dc_pin GPIO pin for D/C (default 24) -+ reset_pin GPIO pin for RESET (default 25) -+ -+ - Name: superaudioboard - Info: Configures the SuperAudioBoard sound card - Load: dtoverlay=superaudioboard,= ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts -@@ -0,0 +1,84 @@ -+/* -+ * Device Tree overlay for SH1106 based SPI OLED display -+ * -+ */ -+ -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&spidev0>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&spidev1>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&gpio>; -+ __overlay__ { -+ sh1106_pins: sh1106_pins { -+ brcm,pins = <25 24>; -+ brcm,function = <1 1>; /* out out */ -+ }; -+ }; -+ }; -+ -+ fragment@4 { -+ target = <&spi0>; -+ __overlay__ { -+ /* needed to avoid dtc warning */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ sh1106: sh1106@0{ -+ compatible = "sinowealth,sh1106"; -+ reg = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sh1106_pins>; -+ -+ spi-max-frequency = <4000000>; -+ bgr = <0>; -+ bpp = <1>; -+ rotate = <0>; -+ fps = <25>; -+ buswidth = <8>; -+ reset-gpios = <&gpio 25 0>; -+ dc-gpios = <&gpio 24 0>; -+ debug = <0>; -+ -+ sinowealth,height = <64>; -+ sinowealth,width = <128>; -+ sinowealth,page-offset = <0>; -+ }; -+ }; -+ }; -+ -+ __overrides__ { -+ speed = <&sh1106>,"spi-max-frequency:0"; -+ rotate = <&sh1106>,"rotate:0"; -+ fps = <&sh1106>,"fps:0"; -+ debug = <&sh1106>,"debug:0"; -+ dc_pin = <&sh1106>,"dc-gpios:4", -+ <&sh1106_pins>,"brcm,pins:4"; -+ reset_pin = <&sh1106>,"reset-gpios:4", -+ <&sh1106_pins>,"brcm,pins:0"; -+ height = <&sh1106>,"sinowealth,height:0"; -+ }; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts -@@ -0,0 +1,84 @@ -+/* -+ * Device Tree overlay for SSD1306 based SPI OLED display -+ * -+ */ -+ -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&spidev0>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&spidev1>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&gpio>; -+ __overlay__ { -+ ssd1306_pins: ssd1306_pins { -+ brcm,pins = <25 24>; -+ brcm,function = <1 1>; /* out out */ -+ }; -+ }; -+ }; -+ -+ fragment@4 { -+ target = <&spi0>; -+ __overlay__ { -+ /* needed to avoid dtc warning */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ssd1306: ssd1306@0{ -+ compatible = "solomon,ssd1306"; -+ reg = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&ssd1306_pins>; -+ -+ spi-max-frequency = <10000000>; -+ bgr = <0>; -+ bpp = <1>; -+ rotate = <0>; -+ fps = <25>; -+ buswidth = <8>; -+ reset-gpios = <&gpio 25 0>; -+ dc-gpios = <&gpio 24 0>; -+ debug = <0>; -+ -+ solomon,height = <64>; -+ solomon,width = <128>; -+ solomon,page-offset = <0>; -+ }; -+ }; -+ }; -+ -+ __overrides__ { -+ speed = <&ssd1306>,"spi-max-frequency:0"; -+ rotate = <&ssd1306>,"rotate:0"; -+ fps = <&ssd1306>,"fps:0"; -+ debug = <&ssd1306>,"debug:0"; -+ dc_pin = <&ssd1306>,"dc-gpios:4", -+ <&ssd1306_pins>,"brcm,pins:4"; -+ reset_pin = <&ssd1306>,"reset-gpios:4", -+ <&ssd1306_pins>,"brcm,pins:0"; -+ height = <&ssd1306>,"solomon,height:0"; -+ }; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts -@@ -0,0 +1,83 @@ -+/* -+ * Device Tree overlay for SSD1351 based SPI OLED display -+ * -+ */ -+ -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@0 { -+ target = <&spi0>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&spidev0>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&spidev1>; -+ __overlay__ { -+ status = "disabled"; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&gpio>; -+ __overlay__ { -+ ssd1351_pins: ssd1351_pins { -+ brcm,pins = <25 24>; -+ brcm,function = <1 1>; /* out out */ -+ }; -+ }; -+ }; -+ -+ fragment@4 { -+ target = <&spi0>; -+ __overlay__ { -+ /* needed to avoid dtc warning */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ssd1351: ssd1351@0{ -+ compatible = "solomon,ssd1351"; -+ reg = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&ssd1351_pins>; -+ -+ spi-max-frequency = <4500000>; -+ bgr = <0>; -+ bpp = <16>; -+ rotate = <0>; -+ fps = <25>; -+ buswidth = <8>; -+ reset-gpios = <&gpio 25 0>; -+ dc-gpios = <&gpio 24 0>; -+ debug = <0>; -+ -+ solomon,height = <128>; -+ solomon,width = <128>; -+ solomon,page-offset = <0>; -+ }; -+ }; -+ }; -+ -+ __overrides__ { -+ speed = <&ssd1351>,"spi-max-frequency:0"; -+ rotate = <&ssd1351>,"rotate:0"; -+ fps = <&ssd1351>,"fps:0"; -+ debug = <&ssd1351>,"debug:0"; -+ dc_pin = <&ssd1351>,"dc-gpios:4", -+ <&ssd1351_pins>,"brcm,pins:4"; -+ reset_pin = <&ssd1351>,"reset-gpios:4", -+ <&ssd1351_pins>,"brcm,pins:0"; -+ }; -+}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0412-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch b/target/linux/bcm27xx/patches-5.4/950-0412-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch new file mode 100644 index 0000000000..a66202a2c9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0412-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch @@ -0,0 +1,1846 @@ +From 134e06abd2d002edfdac3561656ab9e8161b29a3 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 31 Jan 2020 16:53:13 +0000 +Subject: [PATCH] ARM: dts: Clean out downstream BCM2711/2838 files + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 157 ----- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 7 - + arch/arm/boot/dts/bcm2711.dtsi | 890 -------------------------- + arch/arm/boot/dts/bcm2838-rpi.dtsi | 25 - + arch/arm/boot/dts/bcm2838.dtsi | 733 --------------------- + 5 files changed, 1812 deletions(-) + delete mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts + delete mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi + delete mode 100644 arch/arm/boot/dts/bcm2711.dtsi + delete mode 100644 arch/arm/boot/dts/bcm2838-rpi.dtsi + delete mode 100644 arch/arm/boot/dts/bcm2838.dtsi + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ /dev/null +@@ -1,157 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/dts-v1/; +-#include "bcm2711.dtsi" +-#include "bcm2835-rpi.dtsi" +-#include "bcm283x-rpi-usb-peripheral.dtsi" +- +-/ { +- compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; +- model = "Raspberry Pi 4 Model B"; +- +- chosen { +- /* 8250 auxiliary UART instead of pl011 */ +- stdout-path = "serial1:115200n8"; +- }; +- +- /* Will be filled by the bootloader */ +- memory@0 { +- device_type = "memory"; +- reg = <0 0 0>; +- }; +- +- aliases { +- ethernet0 = &genet; +- }; +- +- leds { +- act { +- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +- }; +- +- pwr { +- label = "PWR"; +- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; +- }; +- }; +- +- wifi_pwrseq: wifi-pwrseq { +- compatible = "mmc-pwrseq-simple"; +- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; +- }; +- +- sd_io_1v8_reg: sd_io_1v8_reg { +- compatible = "regulator-gpio"; +- regulator-name = "vdd-sd-io"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <3300000>; +- regulator-boot-on; +- regulator-always-on; +- regulator-settling-time-us = <5000>; +- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; +- states = <1800000 0x1 +- 3300000 0x0>; +- status = "okay"; +- }; +-}; +- +-&firmware { +- expgpio: gpio { +- compatible = "raspberrypi,firmware-gpio"; +- gpio-controller; +- #gpio-cells = <2>; +- gpio-line-names = "BT_ON", +- "WL_ON", +- "PWR_LED_OFF", +- "GLOBAL_RESET", +- "VDD_SD_IO_SEL", +- "CAM_GPIO", +- "", +- ""; +- status = "okay"; +- }; +-}; +- +-&pwm1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; +- status = "okay"; +-}; +- +-/* SDHCI is used to control the SDIO for wireless */ +-&sdhci { +- #address-cells = <1>; +- #size-cells = <0>; +- pinctrl-names = "default"; +- pinctrl-0 = <&emmc_gpio34>; +- bus-width = <4>; +- non-removable; +- mmc-pwrseq = <&wifi_pwrseq>; +- status = "okay"; +- +- brcmf: wifi@1 { +- reg = <1>; +- compatible = "brcm,bcm4329-fmac"; +- }; +-}; +- +-/* EMMC2 is used to drive the SD card */ +-&emmc2 { +- vqmmc-supply = <&sd_io_1v8_reg>; +- broken-cd; +- status = "okay"; +-}; +- +-&genet { +- phy-handle = <&phy1>; +- phy-mode = "rgmii-rxid"; +- status = "okay"; +-}; +- +-&genet_mdio { +- phy1: ethernet-phy@1 { +- /* No PHY interrupt */ +- reg = <0x1>; +- }; +-}; +- +-/* uart0 communicates with the BT module */ +-&uart0 { +- pinctrl-names = "default"; +- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; +- uart-has-rtscts; +- status = "okay"; +- +- bluetooth { +- compatible = "brcm,bcm43438-bt"; +- max-speed = <2000000>; +- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; +- }; +-}; +- +-/* uart1 is mapped to the pin header */ +-&uart1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&uart1_gpio14>; +- status = "okay"; +-}; +- +-&vchiq { +- interrupts = ; +-}; +- +-/ { +- __overrides__ { +- act_led_gpio = <&act_led>,"gpios:4"; +- act_led_activelow = <&act_led>,"gpios:8"; +- act_led_trigger = <&act_led>,"linux,default-trigger"; +- +- pwr_led_gpio = <&pwr_led>,"gpios:4"; +- pwr_led_activelow = <&pwr_led>,"gpios:8"; +- pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; +- +- eth_led0 = <&phy1>,"led-modes:0"; +- eth_led1 = <&phy1>,"led-modes:4"; +- +- sd_poll_once = <&emmc2>, "non-removable?"; +- }; +-}; +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ /dev/null +@@ -1,7 +0,0 @@ +-#include "bcm2708-rpi.dtsi" +-#include "bcm2838-rpi.dtsi" +- +-&v3d { +- /* Undo the overwriting by bcm270x.dtsi */ +- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; +-}; +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ /dev/null +@@ -1,890 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include "bcm283x.dtsi" +- +-#include +-#include +- +-/ { +- compatible = "brcm,bcm2711"; +- +- #address-cells = <2>; +- #size-cells = <1>; +- +- interrupt-parent = <&gicv2>; +- +- reserved-memory { +- #address-cells = <2>; +- #size-cells = <1>; +- ranges; +- +- /* +- * arm64 reserves the CMA by default somewhere in ZONE_DMA32, +- * that's not good enough for the BCM2711 as some devices can +- * only address the lower 1G of memory (ZONE_DMA). +- */ +- linux,cma { +- compatible = "shared-dma-pool"; +- size = <0x2000000>; /* 32MB */ +- alloc-ranges = <0x0 0x00000000 0x40000000>; +- reusable; +- linux,cma-default; +- }; +- }; +- +- +- soc { +- /* +- * Defined ranges: +- * Common BCM283x peripherals +- * BCM2711-specific peripherals +- * ARM-local peripherals +- */ +- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, +- <0x7c000000 0x0 0xfc000000 0x02000000>, +- <0x40000000 0x0 0xff800000 0x00800000>; +- /* Emulate a contiguous 30-bit address range for DMA */ +- dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>; +- +- /* +- * This node is the provider for the enable-method for +- * bringing up secondary cores. +- */ +- local_intc: local_intc@40000000 { +- compatible = "brcm,bcm2836-l1-intc"; +- reg = <0x40000000 0x100>; +- }; +- +- gicv2: interrupt-controller@40041000 { +- interrupt-controller; +- #interrupt-cells = <3>; +- compatible = "arm,gic-400"; +- reg = <0x40041000 0x1000>, +- <0x40042000 0x2000>, +- <0x40044000 0x2000>, +- <0x40046000 0x2000>; +- interrupts = ; +- }; +- +- dma: dma@7e007000 { +- compatible = "brcm,bcm2835-dma"; +- reg = <0x7e007000 0xb00>; +- interrupts = , +- , +- , +- , +- , +- , +- , +- /* DMA lite 7 - 10 */ +- , +- , +- , +- ; +- interrupt-names = "dma0", +- "dma1", +- "dma2", +- "dma3", +- "dma4", +- "dma5", +- "dma6", +- "dma7", +- "dma8", +- "dma9", +- "dma10"; +- #dma-cells = <1>; +- brcm,dma-channel-mask = <0x07f5>; +- }; +- +- pm: watchdog@7e100000 { +- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; +- #power-domain-cells = <1>; +- #reset-cells = <1>; +- reg = <0x7e100000 0x114>, +- <0x7e00a000 0x24>, +- <0x7ec11000 0x20>; +- clocks = <&clocks BCM2835_CLOCK_V3D>, +- <&clocks BCM2835_CLOCK_PERI_IMAGE>, +- <&clocks BCM2835_CLOCK_H264>, +- <&clocks BCM2835_CLOCK_ISP>; +- clock-names = "v3d", "peri_image", "h264", "isp"; +- system-power-controller; +- }; +- +- rng@7e104000 { +- interrupts = ; +- +- /* RNG is incompatible with brcm,bcm2835-rng */ +- status = "disabled"; +- }; +- +- uart2: serial@7e201400 { +- compatible = "arm,pl011", "arm,primecell"; +- reg = <0x7e201400 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- uart3: serial@7e201600 { +- compatible = "arm,pl011", "arm,primecell"; +- reg = <0x7e201600 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- uart4: serial@7e201800 { +- compatible = "arm,pl011", "arm,primecell"; +- reg = <0x7e201800 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- uart5: serial@7e201a00 { +- compatible = "arm,pl011", "arm,primecell"; +- reg = <0x7e201a00 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- spi3: spi@7e204600 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204600 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi4: spi@7e204800 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204800 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi5: spi@7e204a00 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204a00 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi6: spi@7e204c00 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204c00 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c3: i2c@7e205600 { +- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; +- reg = <0x7e205600 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c4: i2c@7e205800 { +- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; +- reg = <0x7e205800 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c5: i2c@7e205a00 { +- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; +- reg = <0x7e205a00 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c6: i2c@7e205c00 { +- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; +- reg = <0x7e205c00 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- pwm1: pwm@7e20c800 { +- compatible = "brcm,bcm2835-pwm"; +- reg = <0x7e20c800 0x28>; +- clocks = <&clocks BCM2835_CLOCK_PWM>; +- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; +- assigned-clock-rates = <10000000>; +- #pwm-cells = <2>; +- status = "disabled"; +- }; +- +- emmc2: emmc2@7e340000 { +- compatible = "brcm,bcm2711-emmc2"; +- reg = <0x7e340000 0x100>; +- interrupts = ; +- clocks = <&clocks BCM2711_CLOCK_EMMC2>; +- status = "disabled"; +- }; +- +- hvs@7e400000 { +- interrupts = ; +- }; +- }; +- +- arm-pmu { +- compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3"; +- interrupts = , +- , +- , +- ; +- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; +- }; +- +- timer { +- compatible = "arm,armv8-timer"; +- interrupts = , +- , +- , +- ; +- /* This only applies to the ARMv7 stub */ +- arm,cpu-registers-not-fw-configured; +- }; +- +- cpus: cpus { +- #address-cells = <1>; +- #size-cells = <0>; +- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit +- +- cpu0: cpu@0 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <0>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000d8>; +- }; +- +- cpu1: cpu@1 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <1>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000e0>; +- }; +- +- cpu2: cpu@2 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <2>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000e8>; +- }; +- +- cpu3: cpu@3 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <3>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000f0>; +- }; +- }; +- +- scb { +- compatible = "simple-bus"; +- #address-cells = <2>; +- #size-cells = <1>; +- +- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; +- +- genet: ethernet@7d580000 { +- compatible = "brcm,bcm2711-genet-v5"; +- reg = <0x0 0x7d580000 0x10000>; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupts = , +- ; +- status = "disabled"; +- +- genet_mdio: mdio@e14 { +- compatible = "brcm,genet-mdio-v5"; +- reg = <0xe14 0x8>; +- reg-names = "mdio"; +- #address-cells = <0x0>; +- #size-cells = <0x1>; +- }; +- }; +- }; +-}; +- +-&clk_osc { +- clock-frequency = <54000000>; +-}; +- +-&clocks { +- compatible = "brcm,bcm2711-cprman"; +-}; +- +-&cpu_thermal { +- coefficients = <(-487) 410040>; +-}; +- +-&dsi0 { +- interrupts = ; +-}; +- +-&dsi1 { +- interrupts = ; +-}; +- +-&gpio { +- compatible = "brcm,bcm2711-gpio"; +- interrupts = , +- , +- , +- ; +- +- gpclk0_gpio49: gpclk0_gpio49 { +- pin-gpclk { +- pins = "gpio49"; +- function = "alt1"; +- bias-disable; +- }; +- }; +- gpclk1_gpio50: gpclk1_gpio50 { +- pin-gpclk { +- pins = "gpio50"; +- function = "alt1"; +- bias-disable; +- }; +- }; +- gpclk2_gpio51: gpclk2_gpio51 { +- pin-gpclk { +- pins = "gpio51"; +- function = "alt1"; +- bias-disable; +- }; +- }; +- +- i2c0_gpio46: i2c0_gpio46 { +- pin-sda { +- function = "alt0"; +- pins = "gpio46"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt0"; +- pins = "gpio47"; +- bias-disable; +- }; +- }; +- i2c1_gpio46: i2c1_gpio46 { +- pin-sda { +- function = "alt1"; +- pins = "gpio46"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt1"; +- pins = "gpio47"; +- bias-disable; +- }; +- }; +- i2c3_gpio2: i2c3_gpio2 { +- pin-sda { +- function = "alt5"; +- pins = "gpio2"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio3"; +- bias-disable; +- }; +- }; +- i2c3_gpio4: i2c3_gpio4 { +- pin-sda { +- function = "alt5"; +- pins = "gpio4"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio5"; +- bias-disable; +- }; +- }; +- i2c4_gpio6: i2c4_gpio6 { +- pin-sda { +- function = "alt5"; +- pins = "gpio6"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio7"; +- bias-disable; +- }; +- }; +- i2c4_gpio8: i2c4_gpio8 { +- pin-sda { +- function = "alt5"; +- pins = "gpio8"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio9"; +- bias-disable; +- }; +- }; +- i2c5_gpio10: i2c5_gpio10 { +- pin-sda { +- function = "alt5"; +- pins = "gpio10"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio11"; +- bias-disable; +- }; +- }; +- i2c5_gpio12: i2c5_gpio12 { +- pin-sda { +- function = "alt5"; +- pins = "gpio12"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio13"; +- bias-disable; +- }; +- }; +- i2c6_gpio0: i2c6_gpio0 { +- pin-sda { +- function = "alt5"; +- pins = "gpio0"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio1"; +- bias-disable; +- }; +- }; +- i2c6_gpio22: i2c6_gpio22 { +- pin-sda { +- function = "alt5"; +- pins = "gpio22"; +- bias-pull-up; +- }; +- pin-scl { +- function = "alt5"; +- pins = "gpio23"; +- bias-disable; +- }; +- }; +- i2c_slave_gpio8: i2c_slave_gpio8 { +- pins-i2c-slave { +- pins = "gpio8", +- "gpio9", +- "gpio10", +- "gpio11"; +- function = "alt3"; +- }; +- }; +- +- jtag_gpio48: jtag_gpio48 { +- pins-jtag { +- pins = "gpio48", +- "gpio49", +- "gpio50", +- "gpio51", +- "gpio52", +- "gpio53"; +- function = "alt4"; +- }; +- }; +- +- mii_gpio28: mii_gpio28 { +- pins-mii { +- pins = "gpio28", +- "gpio29", +- "gpio30", +- "gpio31"; +- function = "alt4"; +- }; +- }; +- mii_gpio36: mii_gpio36 { +- pins-mii { +- pins = "gpio36", +- "gpio37", +- "gpio38", +- "gpio39"; +- function = "alt5"; +- }; +- }; +- +- pcm_gpio50: pcm_gpio50 { +- pins-pcm { +- pins = "gpio50", +- "gpio51", +- "gpio52", +- "gpio53"; +- function = "alt2"; +- }; +- }; +- +- pwm0_0_gpio12: pwm0_0_gpio12 { +- pin-pwm { +- pins = "gpio12"; +- function = "alt0"; +- bias-disable; +- }; +- }; +- pwm0_0_gpio18: pwm0_0_gpio18 { +- pin-pwm { +- pins = "gpio18"; +- function = "alt5"; +- bias-disable; +- }; +- }; +- pwm1_0_gpio40: pwm1_0_gpio40 { +- pin-pwm { +- pins = "gpio40"; +- function = "alt0"; +- bias-disable; +- }; +- }; +- pwm0_1_gpio13: pwm0_1_gpio13 { +- pin-pwm { +- pins = "gpio13"; +- function = "alt0"; +- bias-disable; +- }; +- }; +- pwm0_1_gpio19: pwm0_1_gpio19 { +- pin-pwm { +- pins = "gpio19"; +- function = "alt5"; +- bias-disable; +- }; +- }; +- pwm1_1_gpio41: pwm1_1_gpio41 { +- pin-pwm { +- pins = "gpio41"; +- function = "alt0"; +- bias-disable; +- }; +- }; +- pwm0_1_gpio45: pwm0_1_gpio45 { +- pin-pwm { +- pins = "gpio45"; +- function = "alt0"; +- bias-disable; +- }; +- }; +- pwm0_0_gpio52: pwm0_0_gpio52 { +- pin-pwm { +- pins = "gpio52"; +- function = "alt1"; +- bias-disable; +- }; +- }; +- pwm0_1_gpio53: pwm0_1_gpio53 { +- pin-pwm { +- pins = "gpio53"; +- function = "alt1"; +- bias-disable; +- }; +- }; +- +- rgmii_gpio35: rgmii_gpio35 { +- pin-start-stop { +- pins = "gpio35"; +- function = "alt4"; +- }; +- pin-rx-ok { +- pins = "gpio36"; +- function = "alt4"; +- }; +- }; +- rgmii_irq_gpio34: rgmii_irq_gpio34 { +- pin-irq { +- pins = "gpio34"; +- function = "alt5"; +- }; +- }; +- rgmii_irq_gpio39: rgmii_irq_gpio39 { +- pin-irq { +- pins = "gpio39"; +- function = "alt4"; +- }; +- }; +- rgmii_mdio_gpio28: rgmii_mdio_gpio28 { +- pins-mdio { +- pins = "gpio28", +- "gpio29"; +- function = "alt5"; +- }; +- }; +- rgmii_mdio_gpio37: rgmii_mdio_gpio37 { +- pins-mdio { +- pins = "gpio37", +- "gpio38"; +- function = "alt4"; +- }; +- }; +- +- spi0_gpio46: spi0_gpio46 { +- pins-spi { +- pins = "gpio46", +- "gpio47", +- "gpio48", +- "gpio49"; +- function = "alt2"; +- }; +- }; +- spi2_gpio46: spi2_gpio46 { +- pins-spi { +- pins = "gpio46", +- "gpio47", +- "gpio48", +- "gpio49", +- "gpio50"; +- function = "alt5"; +- }; +- }; +- spi3_gpio0: spi3_gpio0 { +- pins-spi { +- pins = "gpio0", +- "gpio1", +- "gpio2", +- "gpio3"; +- function = "alt3"; +- }; +- }; +- spi4_gpio4: spi4_gpio4 { +- pins-spi { +- pins = "gpio4", +- "gpio5", +- "gpio6", +- "gpio7"; +- function = "alt3"; +- }; +- }; +- spi5_gpio12: spi5_gpio12 { +- pins-spi { +- pins = "gpio12", +- "gpio13", +- "gpio14", +- "gpio15"; +- function = "alt3"; +- }; +- }; +- spi6_gpio18: spi6_gpio18 { +- pins-spi { +- pins = "gpio18", +- "gpio19", +- "gpio20", +- "gpio21"; +- function = "alt3"; +- }; +- }; +- +- uart2_gpio0: uart2_gpio0 { +- pin-tx { +- pins = "gpio0"; +- function = "alt4"; +- bias-disable; +- }; +- pin-rx { +- pins = "gpio1"; +- function = "alt4"; +- bias-pull-up; +- }; +- }; +- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { +- pin-cts { +- pins = "gpio2"; +- function = "alt4"; +- bias-pull-up; +- }; +- pin-rts { +- pins = "gpio3"; +- function = "alt4"; +- bias-disable; +- }; +- }; +- uart3_gpio4: uart3_gpio4 { +- pin-tx { +- pins = "gpio4"; +- function = "alt4"; +- bias-disable; +- }; +- pin-rx { +- pins = "gpio5"; +- function = "alt4"; +- bias-pull-up; +- }; +- }; +- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { +- pin-cts { +- pins = "gpio6"; +- function = "alt4"; +- bias-pull-up; +- }; +- pin-rts { +- pins = "gpio7"; +- function = "alt4"; +- bias-disable; +- }; +- }; +- uart4_gpio8: uart4_gpio8 { +- pin-tx { +- pins = "gpio8"; +- function = "alt4"; +- bias-disable; +- }; +- pin-rx { +- pins = "gpio9"; +- function = "alt4"; +- bias-pull-up; +- }; +- }; +- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { +- pin-cts { +- pins = "gpio10"; +- function = "alt4"; +- bias-pull-up; +- }; +- pin-rts { +- pins = "gpio11"; +- function = "alt4"; +- bias-disable; +- }; +- }; +- uart5_gpio12: uart5_gpio12 { +- pin-tx { +- pins = "gpio12"; +- function = "alt4"; +- bias-disable; +- }; +- pin-rx { +- pins = "gpio13"; +- function = "alt4"; +- bias-pull-up; +- }; +- }; +- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { +- pin-cts { +- pins = "gpio14"; +- function = "alt4"; +- bias-pull-up; +- }; +- pin-rts { +- pins = "gpio15"; +- function = "alt4"; +- bias-disable; +- }; +- }; +-}; +- +-&i2c0 { +- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; +- interrupts = ; +-}; +- +-&i2c1 { +- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; +- interrupts = ; +-}; +- +-&mailbox { +- interrupts = ; +-}; +- +-&sdhci { +- interrupts = ; +-}; +- +-&sdhost { +- interrupts = ; +-}; +- +-&spi { +- interrupts = ; +-}; +- +-&spi1 { +- interrupts = ; +-}; +- +-&spi2 { +- interrupts = ; +-}; +- +-&system_timer { +- interrupts = , +- , +- , +- ; +-}; +- +-&txp { +- interrupts = ; +-}; +- +-&uart0 { +- interrupts = ; +-}; +- +-&uart1 { +- interrupts = ; +-}; +- +-&usb { +- interrupts = ; +-}; +- +-&vec { +- interrupts = ; +-}; +--- a/arch/arm/boot/dts/bcm2838-rpi.dtsi ++++ /dev/null +@@ -1,25 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +- +-/ { +- soc { +- /delete-node/ mailbox@7e00b840; +- }; +-}; +- +-&scb { +- vchiq: mailbox@7e00b840 { +- compatible = "brcm,bcm2838-vchiq"; +- reg = <0 0x7e00b840 0x3c>; +- interrupts = ; +- }; +-}; +- +-&dma { +- /* The VPU firmware uses DMA channel 11 for VCHIQ */ +- brcm,dma-channel-mask = <0x1f5>; +-}; +- +-&dma40 { +- /* The VPU firmware DMA channel 11 for VCHIQ */ +- brcm,dma-channel-mask = <0x7000>; +-}; +--- a/arch/arm/boot/dts/bcm2838.dtsi ++++ /dev/null +@@ -1,733 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include "bcm283x.dtsi" +- +-#include +-#include +- +-/ { +- compatible = "brcm,bcm2838"; +- +- #address-cells = <2>; +- #size-cells = <1>; +- +- interrupt-parent = <&gicv2>; +- +- soc { +- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, +- <0x7c000000 0x0 0xfc000000 0x02000000>, +- <0x40000000 0x0 0xff800000 0x00800000>; +- /* Emulate a contiguous 30-bit address range for DMA */ +- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>; +- +- /delete-node/ interrupt-controller@7e00f300; +- /delete-node/ v3d@7ec00000; +- +- local_intc: local_intc@40000000 { +- compatible = "brcm,bcm2836-l1-intc"; +- reg = <0x40000000 0x100>; +- }; +- +- gicv2: interrupt-controller@40041000 { +- interrupt-controller; +- #interrupt-cells = <3>; +- compatible = "arm,gic-400"; +- reg = <0x40041000 0x1000>, +- <0x40042000 0x2000>, +- <0x40044000 0x2000>, +- <0x40046000 0x2000>; +- interrupts = ; +- }; +- +- thermal: thermal@7d5d2200 { +- compatible = "brcm,avs-tmon-bcm2838"; +- reg = <0x7d5d2200 0x2c>; +- interrupts = ; +- interrupt-names = "tmon"; +- clocks = <&clocks BCM2835_CLOCK_TSENS>; +- #thermal-sensor-cells = <0>; +- status = "okay"; +- }; +- +- pm: watchdog@7e100000 { +- reg = <0x7e100000 0x114>, +- <0x7e00a000 0x24>, +- <0x7ec11000 0x20>; +- }; +- +- rng@7e104000 { +- interrupts = ; +- }; +- +- uart2: serial@7e201400 { +- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; +- reg = <0x7e201400 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- uart3: serial@7e201600 { +- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; +- reg = <0x7e201600 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- uart4: serial@7e201800 { +- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; +- reg = <0x7e201800 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- uart5: serial@7e201a00 { +- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; +- reg = <0x7e201a00 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_UART>, +- <&clocks BCM2835_CLOCK_VPU>; +- clock-names = "uartclk", "apb_pclk"; +- arm,primecell-periphid = <0x00241011>; +- status = "disabled"; +- }; +- +- spi@7e204000 { +- reg = <0x7e204000 0x0200>; +- interrupts = ; +- }; +- +- spi3: spi@7e204600 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204600 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi4: spi@7e204800 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204800 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi5: spi@7e204a00 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204a00 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- spi6: spi@7e204c00 { +- compatible = "brcm,bcm2835-spi"; +- reg = <0x7e204c00 0x0200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c3: i2c@7e205600 { +- compatible = "brcm,bcm2835-i2c"; +- reg = <0x7e205600 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c4: i2c@7e205800 { +- compatible = "brcm,bcm2835-i2c"; +- reg = <0x7e205800 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c5: i2c@7e205a00 { +- compatible = "brcm,bcm2835-i2c"; +- reg = <0x7e205a00 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- i2c6: i2c@7e205c00 { +- compatible = "brcm,bcm2835-i2c"; +- reg = <0x7e205c00 0x200>; +- interrupts = ; +- clocks = <&clocks BCM2835_CLOCK_VPU>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- +- pwm1: pwm@7e20c800 { +- compatible = "brcm,bcm2835-pwm"; +- reg = <0x7e20c800 0x28>; +- clocks = <&clocks BCM2835_CLOCK_PWM>; +- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; +- assigned-clock-rates = <10000000>; +- #pwm-cells = <2>; +- status = "disabled"; +- }; +- +- emmc2: emmc2@7e340000 { +- compatible = "brcm,bcm2711-emmc2"; +- status = "okay"; +- interrupts = ; +- clocks = <&clocks BCM2711_CLOCK_EMMC2>; +- reg = <0x7e340000 0x100>; +- }; +- +- hvs@7e400000 { +- interrupts = ; +- }; +- }; +- +- arm-pmu { +- compatible = "arm,cortex-a72-pmu"; +- interrupts = , +- , +- , +- ; +- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; +- }; +- +- timer { +- compatible = "arm,armv7-timer"; +- interrupts = , +- , +- , +- ; +- arm,cpu-registers-not-fw-configured; +- }; +- +- cpus: cpus { +- #address-cells = <1>; +- #size-cells = <0>; +- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit +- +- cpu0: cpu@0 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <0>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000d8>; +- }; +- +- cpu1: cpu@1 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <1>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000e0>; +- }; +- +- cpu2: cpu@2 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <2>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000e8>; +- }; +- +- cpu3: cpu@3 { +- device_type = "cpu"; +- compatible = "arm,cortex-a72"; +- reg = <3>; +- enable-method = "spin-table"; +- cpu-release-addr = <0x0 0x000000f0>; +- }; +- }; +- +- v3dbus { +- compatible = "simple-bus"; +- #address-cells = <1>; +- #size-cells = <2>; +- ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>, +- <0x40000000 0x0 0xff800000 0x0 0x00800000>; +- dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>; +- +- v3d: v3d@7ec04000 { +- compatible = "brcm,2711-v3d"; +- reg = +- <0x7ec00000 0x0 0x4000>, +- <0x7ec04000 0x0 0x4000>; +- reg-names = "hub", "core0"; +- +- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; +- resets = <&pm BCM2835_RESET_V3D>; +- clocks = <&clocks BCM2835_CLOCK_V3D>; +- interrupts = ; +- status = "okay"; +- }; +- }; +- +- scb: scb { +- compatible = "simple-bus"; +- #address-cells = <2>; +- #size-cells = <1>; +- +- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, +- <0x0 0x40000000 0x0 0xff800000 0x00800000>, +- <0x6 0x00000000 0x6 0x00000000 0x40000000>, +- <0x0 0x00000000 0x0 0x00000000 0xfc000000>; +- dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; +- +- pcie_0: pcie@7d500000 { +- reg = <0x0 0x7d500000 0x9310>, +- <0x0 0x7e00f300 0x20>; +- msi-controller; +- msi-parent = <&pcie_0>; +- #address-cells = <3>; +- #interrupt-cells = <1>; +- #size-cells = <2>; +- bus-range = <0x0 0x01>; +- compatible = "brcm,bcm2711b0-pcie", // Safe value +- "brcm,bcm2711-pcie", +- "brcm,pci-plat-dev"; +- max-link-speed = <2>; +- tot-num-pcie = <1>; +- linux,pci-domain = <0>; +- interrupts = , +- ; +- interrupt-names = "pcie", "msi"; +- interrupt-map-mask = <0x0 0x0 0x0 0x7>; +- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 2 &gicv2 GIC_SPI 144 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 3 &gicv2 GIC_SPI 145 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 4 &gicv2 GIC_SPI 146 +- IRQ_TYPE_LEVEL_HIGH>; +- +- /* Map outbound accesses from scb:0x6_00000000-03ffffff +- * to pci:0x0_f8000000-fbffffff +- */ +- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 +- 0x0 0x04000000>; +- /* Map inbound accesses from pci:0x0_00000000..ffffffff +- * to scb:0x0_00000000-ffffffff +- */ +- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 +- 0x1 0x00000000>; +- status = "okay"; +- }; +- +- genet: ethernet@7d580000 { +- compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5"; +- reg = <0x0 0x7d580000 0x10000>; +- #address-cells = <0x1>; +- #size-cells = <0x1>; +- interrupts = , +- ; +- status = "disabled"; +- +- genet_mdio: mdio@e14 { +- #address-cells = <0x0>; +- #size-cells = <0x1>; +- compatible = "brcm,genet-mdio-v5"; +- reg = <0xe14 0x8>; +- reg-names = "mdio"; +- }; +- }; +- +- dma40: dma@7e007b00 { +- compatible = "brcm,bcm2838-dma"; +- reg = <0x0 0x7e007b00 0x400>; +- interrupts = +- , /* dma4 11 */ +- , /* dma4 12 */ +- , /* dma4 13 */ +- ; /* dma4 14 */ +- interrupt-names = "dma11", +- "dma12", +- "dma13", +- "dma14"; +- #dma-cells = <1>; +- brcm,dma-channel-mask = <0x7800>; +- }; +- /* DMA4 - 40 bit DMA engines */ +- +- xhci: xhci@7e9c0000 { +- compatible = "generic-xhci"; +- status = "disabled"; +- reg = <0x0 0x7e9c0000 0x100000>; +- interrupts = ; +- }; +- +- hevc-decoder@7eb00000 { +- compatible = "raspberrypi,rpivid-hevc-decoder"; +- reg = <0x0 0x7eb00000 0x10000>; +- status = "okay"; +- }; +- +- rpivid-local-intc@7eb10000 { +- compatible = "raspberrypi,rpivid-local-intc"; +- reg = <0x0 0x7eb10000 0x1000>; +- status = "okay"; +- interrupts = ; +- }; +- +- h264-decoder@7eb20000 { +- compatible = "raspberrypi,rpivid-h264-decoder"; +- reg = <0x0 0x7eb20000 0x10000>; +- status = "okay"; +- }; +- +- vp9-decoder@7eb30000 { +- compatible = "raspberrypi,rpivid-vp9-decoder"; +- reg = <0x0 0x7eb30000 0x10000>; +- status = "okay"; +- }; +- }; +-}; +- +-&clk_osc { +- clock-frequency = <54000000>; +-}; +- +-&clocks { +- compatible = "brcm,bcm2711-cprman"; +-}; +- +-&cpu_thermal { +- coefficients = <(-487) 410040>; +-}; +- +-&dsi0 { +- interrupts = ; +-}; +- +-&dsi1 { +- interrupts = ; +-}; +- +-&gpio { +- compatible = "brcm,bcm2711-gpio", "brcm,bcm2835-gpio"; +- +- gpclk0_gpio49: gpclk0_gpio49 { +- brcm,pins = <49>; +- brcm,function = ; +- brcm,pull = ; +- }; +- gpclk1_gpio50: gpclk1_gpio50 { +- brcm,pins = <50>; +- brcm,function = ; +- brcm,pull = ; +- }; +- gpclk2_gpio51: gpclk2_gpio51 { +- brcm,pins = <51>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- i2c0_gpio46: i2c0_gpio46 { +- brcm,pins = <46 47>; +- brcm,function = ; +- }; +- i2c1_gpio46: i2c1_gpio46 { +- brcm,pins = <46 47>; +- brcm,function = ; +- }; +- i2c3_gpio2: i2c3_gpio2 { +- brcm,pins = <2 3>; +- brcm,function = ; +- }; +- i2c3_gpio4: i2c3_gpio4 { +- brcm,pins = <4 5>; +- brcm,function = ; +- }; +- i2c4_gpio6: i2c4_gpio6 { +- brcm,pins = <6 7>; +- brcm,function = ; +- }; +- i2c4_gpio8: i2c4_gpio8 { +- brcm,pins = <8 9>; +- brcm,function = ; +- }; +- i2c5_gpio10: i2c5_gpio10 { +- brcm,pins = <10 11>; +- brcm,function = ; +- }; +- i2c5_gpio12: i2c5_gpio12 { +- brcm,pins = <12 13>; +- brcm,function = ; +- }; +- i2c6_gpio0: i2c6_gpio0 { +- brcm,pins = <0 1>; +- brcm,function = ; +- }; +- i2c6_gpio22: i2c6_gpio22 { +- brcm,pins = <22 23>; +- brcm,function = ; +- }; +- i2c_slave_gpio8: i2c_slave_gpio8 { +- brcm,pins = <8 9 10 11>; +- brcm,function = ; +- }; +- +- jtag_gpio48: jtag_gpio48 { +- brcm,pins = <48 49 50 51 52 53>; +- brcm,function = ; +- }; +- +- mii_gpio28: mii_gpio28 { +- brcm,pins = <28 29 30 31>; +- brcm,function = ; +- }; +- mii_gpio36: mii_gpio36 { +- brcm,pins = <36 37 38 39>; +- brcm,function = ; +- }; +- +- pcm_gpio50: pcm_gpio50 { +- brcm,pins = <50 51 52 53>; +- brcm,function = ; +- }; +- +- pwm0_gpio52: pwm0_gpio52 { +- brcm,pins = <52>; +- brcm,function = ; +- brcm,pull = ; +- }; +- pwm1_gpio53: pwm1_gpio53 { +- brcm,pins = <53>; +- brcm,function = ; +- brcm,pull = ; +- }; +- +- /* The following group consists of: +- * RGMII_START_STOP +- * RGMII_RX_OK +- */ +- rgmii_gpio35: rgmii_gpio35 { +- brcm,pins = <35 36>; +- brcm,function = ; +- }; +- rgmii_irq_gpio34: rgmii_irq_gpio34 { +- brcm,pins = <34>; +- brcm,function = ; +- }; +- rgmii_irq_gpio39: rgmii_irq_gpio39 { +- brcm,pins = <39>; +- brcm,function = ; +- }; +- rgmii_mdio_gpio28: rgmii_mdio_gpio28 { +- brcm,pins = <28 29>; +- brcm,function = ; +- }; +- rgmii_mdio_gpio37: rgmii_mdio_gpio37 { +- brcm,pins = <37 38>; +- brcm,function = ; +- }; +- +- spi0_gpio46: spi0_gpio46 { +- brcm,pins = <46 47 48 49>; +- brcm,function = ; +- }; +- spi2_gpio46: spi2_gpio46 { +- brcm,pins = <46 47 48 49 50>; +- brcm,function = ; +- }; +- spi3_gpio0: spi3_gpio0 { +- brcm,pins = <0 1 2 3>; +- brcm,function = ; +- }; +- spi4_gpio4: spi4_gpio4 { +- brcm,pins = <4 5 6 7>; +- brcm,function = ; +- }; +- spi5_gpio12: spi5_gpio12 { +- brcm,pins = <12 13 14 15>; +- brcm,function = ; +- }; +- spi6_gpio18: spi6_gpio18 { +- brcm,pins = <18 19 20 21>; +- brcm,function = ; +- }; +- +- uart2_gpio0: uart2_gpio0 { +- brcm,pins = <0 1>; +- brcm,function = ; +- brcm,pull = ; +- }; +- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { +- brcm,pins = <2 3>; +- brcm,function = ; +- brcm,pull = ; +- }; +- uart3_gpio4: uart3_gpio4 { +- brcm,pins = <4 5>; +- brcm,function = ; +- brcm,pull = ; +- }; +- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { +- brcm,pins = <6 7>; +- brcm,function = ; +- brcm,pull = ; +- }; +- uart4_gpio8: uart4_gpio8 { +- brcm,pins = <8 9>; +- brcm,function = ; +- brcm,pull = ; +- }; +- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { +- brcm,pins = <10 11>; +- brcm,function = ; +- brcm,pull = ; +- }; +- uart5_gpio12: uart5_gpio12 { +- brcm,pins = <12 13>; +- brcm,function = ; +- brcm,pull = ; +- }; +- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { +- brcm,pins = <14 15>; +- brcm,function = ; +- brcm,pull = ; +- }; +-}; +- +-&vec { +- interrupts = ; +-}; +- +-&usb { +- interrupts = ; +- status = "disabled"; +-}; +- +-&hdmi { +- interrupts = , +- ; +-}; +- +-&uart1 { +- interrupts = ; +-}; +- +-&spi1 { +- interrupts = ; +-}; +- +-&spi2 { +- interrupts = ; +-}; +- +-&csi0 { +- interrupts = ; +-}; +- +-&csi1 { +- interrupts = ; +-}; +- +-&sdhci { +- interrupts = ; +-}; +- +-&i2c0 { +- interrupts = ; +-}; +- +-&i2c1 { +- interrupts = ; +-}; +- +-&i2c2 { +- interrupts = ; +-}; +- +-&gpio { +- interrupts = , +- , +- , +- ; +-}; +- +-&mailbox { +- interrupts = ; +-}; +- +-&rng { +- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; +-}; +- +-&sdhost { +- interrupts = ; +-}; +- +-&system_timer { +- interrupts = , +- , +- , +- ; +-}; +- +-&uart0 { +- interrupts = ; +-}; +- +-&dma { +- reg = <0x7e007000 0xb00>; +- interrupts = , +- , +- , +- , +- , +- , +- , +- , /* dmalite 7 */ +- , /* dmalite 8 */ +- , /* dmalite 9 */ +- ; /* dmalite 10 */ +- interrupt-names = "dma0", +- "dma1", +- "dma2", +- "dma3", +- "dma4", +- "dma5", +- "dma6", +- "dma7", +- "dma8", +- "dma9", +- "dma10"; +- brcm,dma-channel-mask = <0x07f5>; +-}; +- +-&txp { +- interrupts = ; +-}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0412-overlays-dwc2-Increase-RX-FIFO-size.patch b/target/linux/bcm27xx/patches-5.4/950-0412-overlays-dwc2-Increase-RX-FIFO-size.patch deleted file mode 100644 index 23bc39b3d8..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0412-overlays-dwc2-Increase-RX-FIFO-size.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 1257716d9bae9730c43c636046983f5d80c4efc8 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 4 Feb 2020 13:03:21 +0000 -Subject: [PATCH] overlays: dwc2: Increase RX FIFO size - -The previous version of the dwc2 overlay set the RX FIFO size to -256 4-byte words. This sounds large enough for a 1024 byte packet (the -largest isochronous high speed packet allowed), but it doesn't take -into account some extra space needed by the hardware. - -Minas Harutyunyan at Synopsys (the source of the DWC OTG design) -came up with a more correct value, 301, but since there is spare packet -RAM this can be increased to 558 to allow two packets per frame. - -Also update the upstream overlay to match. - -See: https://github.com/raspberrypi/linux/issues/3447 - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/upstream-overlay.dts | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - ---- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts -+++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts -@@ -12,7 +12,7 @@ - compatible = "brcm,bcm2835-usb"; - dr_mode = "otg"; - g-np-tx-fifo-size = <32>; -- g-rx-fifo-size = <256>; -+ g-rx-fifo-size = <558>; - g-tx-fifo-size = <512 512 512 512 512 256 256>; - status = "okay"; - }; ---- a/arch/arm/boot/dts/overlays/upstream-overlay.dts -+++ b/arch/arm/boot/dts/overlays/upstream-overlay.dts -@@ -123,7 +123,7 @@ - compatible = "brcm,bcm2835-usb"; - dr_mode = "otg"; - g-np-tx-fifo-size = <32>; -- g-rx-fifo-size = <256>; -+ g-rx-fifo-size = <558>; - g-tx-fifo-size = <512 512 512 512 512 256 256>; - status = "okay"; - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0413-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch b/target/linux/bcm27xx/patches-5.4/950-0413-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch new file mode 100644 index 0000000000..15e4f53a0a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0413-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch @@ -0,0 +1,1024 @@ +From 19a0ac654994661f63f7c9e099ed91a1210af161 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Sun, 6 Oct 2019 15:41:25 +0200 +Subject: [PATCH] ARM: dts: Add minimal Raspberry Pi 4 support + +This adds minimal support for the new Raspberry Pi 4 without the +fancy stuff like GENET, PCIe, xHCI, 40 bit DMA and V3D. The RPi 4 is +available in 3 different variants (1, 2 and 4 GB RAM), so leave the memory +size to zero and let the bootloader take care of it. The DWC2 is still +usable as peripheral via the USB-C port. + +Other differences to the Raspberry Pi 3: +- additional GIC 400 Interrupt controller +- new thermal IP and HWRNG +- additional MMC interface (emmc2) +- additional UART, I2C, SPI and PWM interfaces +- clock stretching bug in I2C IP has been fixed + +Signed-off-by: Stefan Wahren +Acked-by: Eric Anholt +Acked-by: Florian Fanelli +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 123 +++ + arch/arm/boot/dts/bcm2711.dtsi | 844 ++++++++++++++++++ + .../boot/dts/bcm283x-rpi-usb-peripheral.dtsi | 7 + + 4 files changed, 975 insertions(+) + create mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts + create mode 100644 arch/arm/boot/dts/bcm2711.dtsi + create mode 100644 arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -97,6 +97,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ + bcm2837-rpi-3-b.dtb \ + bcm2837-rpi-3-b-plus.dtb \ + bcm2837-rpi-cm3-io3.dtb \ ++ bcm2711-rpi-4-b.dtb \ + bcm2835-rpi-zero.dtb \ + bcm2835-rpi-zero-w.dtb + dtb-$(CONFIG_ARCH_BCM_5301X) += \ +--- /dev/null ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -0,0 +1,123 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/dts-v1/; ++#include "bcm2711.dtsi" ++#include "bcm2835-rpi.dtsi" ++#include "bcm283x-rpi-usb-peripheral.dtsi" ++ ++/ { ++ compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; ++ model = "Raspberry Pi 4 Model B"; ++ ++ chosen { ++ /* 8250 auxiliary UART instead of pl011 */ ++ stdout-path = "serial1:115200n8"; ++ }; ++ ++ /* Will be filled by the bootloader */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0 0 0>; ++ }; ++ ++ leds { ++ act { ++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ pwr { ++ label = "PWR"; ++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ wifi_pwrseq: wifi-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; ++ }; ++ ++ sd_io_1v8_reg: sd_io_1v8_reg { ++ compatible = "regulator-gpio"; ++ regulator-name = "vdd-sd-io"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-settling-time-us = <5000>; ++ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; ++ states = <1800000 0x1 ++ 3300000 0x0>; ++ status = "okay"; ++ }; ++}; ++ ++&firmware { ++ expgpio: gpio { ++ compatible = "raspberrypi,firmware-gpio"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-line-names = "BT_ON", ++ "WL_ON", ++ "PWR_LED_OFF", ++ "GLOBAL_RESET", ++ "VDD_SD_IO_SEL", ++ "CAM_GPIO", ++ "", ++ ""; ++ status = "okay"; ++ }; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; ++ status = "okay"; ++}; ++ ++/* SDHCI is used to control the SDIO for wireless */ ++&sdhci { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_gpio34>; ++ bus-width = <4>; ++ non-removable; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ status = "okay"; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; ++}; ++ ++/* EMMC2 is used to drive the SD card */ ++&emmc2 { ++ vqmmc-supply = <&sd_io_1v8_reg>; ++ broken-cd; ++ status = "okay"; ++}; ++ ++/* uart0 communicates with the BT module */ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; ++ uart-has-rtscts; ++ status = "okay"; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ max-speed = <2000000>; ++ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++/* uart1 is mapped to the pin header */ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1_gpio14>; ++ status = "okay"; ++}; ++ ++&vchiq { ++ interrupts = ; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -0,0 +1,844 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "bcm283x.dtsi" ++ ++#include ++#include ++ ++/ { ++ compatible = "brcm,bcm2711"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ interrupt-parent = <&gicv2>; ++ ++ soc { ++ /* ++ * Defined ranges: ++ * Common BCM283x peripherals ++ * BCM2711-specific peripherals ++ * ARM-local peripherals ++ */ ++ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, ++ <0x7c000000 0x0 0xfc000000 0x02000000>, ++ <0x40000000 0x0 0xff800000 0x00800000>; ++ /* Emulate a contiguous 30-bit address range for DMA */ ++ dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>; ++ ++ /* ++ * This node is the provider for the enable-method for ++ * bringing up secondary cores. ++ */ ++ local_intc: local_intc@40000000 { ++ compatible = "brcm,bcm2836-l1-intc"; ++ reg = <0x40000000 0x100>; ++ }; ++ ++ gicv2: interrupt-controller@40041000 { ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ compatible = "arm,gic-400"; ++ reg = <0x40041000 0x1000>, ++ <0x40042000 0x2000>, ++ <0x40044000 0x2000>, ++ <0x40046000 0x2000>; ++ interrupts = ; ++ }; ++ ++ dma: dma@7e007000 { ++ compatible = "brcm,bcm2835-dma"; ++ reg = <0x7e007000 0xb00>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ /* DMA lite 7 - 10 */ ++ , ++ , ++ , ++ ; ++ interrupt-names = "dma0", ++ "dma1", ++ "dma2", ++ "dma3", ++ "dma4", ++ "dma5", ++ "dma6", ++ "dma7", ++ "dma8", ++ "dma9", ++ "dma10"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x07f5>; ++ }; ++ ++ pm: watchdog@7e100000 { ++ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; ++ #power-domain-cells = <1>; ++ #reset-cells = <1>; ++ reg = <0x7e100000 0x114>, ++ <0x7e00a000 0x24>, ++ <0x7ec11000 0x20>; ++ clocks = <&clocks BCM2835_CLOCK_V3D>, ++ <&clocks BCM2835_CLOCK_PERI_IMAGE>, ++ <&clocks BCM2835_CLOCK_H264>, ++ <&clocks BCM2835_CLOCK_ISP>; ++ clock-names = "v3d", "peri_image", "h264", "isp"; ++ system-power-controller; ++ }; ++ ++ rng@7e104000 { ++ interrupts = ; ++ ++ /* RNG is incompatible with brcm,bcm2835-rng */ ++ status = "disabled"; ++ }; ++ ++ uart2: serial@7e201400 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201400 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@7e201600 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201600 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@7e201800 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201800 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@7e201a00 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x7e201a00 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_UART>, ++ <&clocks BCM2835_CLOCK_VPU>; ++ clock-names = "uartclk", "apb_pclk"; ++ arm,primecell-periphid = <0x00241011>; ++ status = "disabled"; ++ }; ++ ++ spi3: spi@7e204600 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204600 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi4: spi@7e204800 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204800 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi5: spi@7e204a00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204a00 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ spi6: spi@7e204c00 { ++ compatible = "brcm,bcm2835-spi"; ++ reg = <0x7e204c00 0x0200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@7e205600 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205600 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@7e205800 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205800 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@7e205a00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205a00 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c6: i2c@7e205c00 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ reg = <0x7e205c00 0x200>; ++ interrupts = ; ++ clocks = <&clocks BCM2835_CLOCK_VPU>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm1: pwm@7e20c800 { ++ compatible = "brcm,bcm2835-pwm"; ++ reg = <0x7e20c800 0x28>; ++ clocks = <&clocks BCM2835_CLOCK_PWM>; ++ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; ++ assigned-clock-rates = <10000000>; ++ #pwm-cells = <2>; ++ status = "disabled"; ++ }; ++ ++ emmc2: emmc2@7e340000 { ++ compatible = "brcm,bcm2711-emmc2"; ++ reg = <0x7e340000 0x100>; ++ interrupts = ; ++ clocks = <&clocks BCM2711_CLOCK_EMMC2>; ++ status = "disabled"; ++ }; ++ ++ hvs@7e400000 { ++ interrupts = ; ++ }; ++ }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3"; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ /* This only applies to the ARMv7 stub */ ++ arm,cpu-registers-not-fw-configured; ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000d8>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <1>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000e0>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <2>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000e8>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <3>; ++ enable-method = "spin-table"; ++ cpu-release-addr = <0x0 0x000000f0>; ++ }; ++ }; ++}; ++ ++&clk_osc { ++ clock-frequency = <54000000>; ++}; ++ ++&clocks { ++ compatible = "brcm,bcm2711-cprman"; ++}; ++ ++&cpu_thermal { ++ coefficients = <(-487) 410040>; ++}; ++ ++&dsi0 { ++ interrupts = ; ++}; ++ ++&dsi1 { ++ interrupts = ; ++}; ++ ++&gpio { ++ compatible = "brcm,bcm2711-gpio"; ++ interrupts = , ++ , ++ , ++ ; ++ ++ gpclk0_gpio49: gpclk0_gpio49 { ++ pin-gpclk { ++ pins = "gpio49"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ gpclk1_gpio50: gpclk1_gpio50 { ++ pin-gpclk { ++ pins = "gpio50"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ gpclk2_gpio51: gpclk2_gpio51 { ++ pin-gpclk { ++ pins = "gpio51"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ ++ i2c0_gpio46: i2c0_gpio46 { ++ pin-sda { ++ function = "alt0"; ++ pins = "gpio46"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt0"; ++ pins = "gpio47"; ++ bias-disable; ++ }; ++ }; ++ i2c1_gpio46: i2c1_gpio46 { ++ pin-sda { ++ function = "alt1"; ++ pins = "gpio46"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt1"; ++ pins = "gpio47"; ++ bias-disable; ++ }; ++ }; ++ i2c3_gpio2: i2c3_gpio2 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio2"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio3"; ++ bias-disable; ++ }; ++ }; ++ i2c3_gpio4: i2c3_gpio4 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio4"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio5"; ++ bias-disable; ++ }; ++ }; ++ i2c4_gpio6: i2c4_gpio6 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio6"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio7"; ++ bias-disable; ++ }; ++ }; ++ i2c4_gpio8: i2c4_gpio8 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio8"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio9"; ++ bias-disable; ++ }; ++ }; ++ i2c5_gpio10: i2c5_gpio10 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio10"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio11"; ++ bias-disable; ++ }; ++ }; ++ i2c5_gpio12: i2c5_gpio12 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio12"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio13"; ++ bias-disable; ++ }; ++ }; ++ i2c6_gpio0: i2c6_gpio0 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio0"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio1"; ++ bias-disable; ++ }; ++ }; ++ i2c6_gpio22: i2c6_gpio22 { ++ pin-sda { ++ function = "alt5"; ++ pins = "gpio22"; ++ bias-pull-up; ++ }; ++ pin-scl { ++ function = "alt5"; ++ pins = "gpio23"; ++ bias-disable; ++ }; ++ }; ++ i2c_slave_gpio8: i2c_slave_gpio8 { ++ pins-i2c-slave { ++ pins = "gpio8", ++ "gpio9", ++ "gpio10", ++ "gpio11"; ++ function = "alt3"; ++ }; ++ }; ++ ++ jtag_gpio48: jtag_gpio48 { ++ pins-jtag { ++ pins = "gpio48", ++ "gpio49", ++ "gpio50", ++ "gpio51", ++ "gpio52", ++ "gpio53"; ++ function = "alt4"; ++ }; ++ }; ++ ++ mii_gpio28: mii_gpio28 { ++ pins-mii { ++ pins = "gpio28", ++ "gpio29", ++ "gpio30", ++ "gpio31"; ++ function = "alt4"; ++ }; ++ }; ++ mii_gpio36: mii_gpio36 { ++ pins-mii { ++ pins = "gpio36", ++ "gpio37", ++ "gpio38", ++ "gpio39"; ++ function = "alt5"; ++ }; ++ }; ++ ++ pcm_gpio50: pcm_gpio50 { ++ pins-pcm { ++ pins = "gpio50", ++ "gpio51", ++ "gpio52", ++ "gpio53"; ++ function = "alt2"; ++ }; ++ }; ++ ++ pwm0_0_gpio12: pwm0_0_gpio12 { ++ pin-pwm { ++ pins = "gpio12"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_0_gpio18: pwm0_0_gpio18 { ++ pin-pwm { ++ pins = "gpio18"; ++ function = "alt5"; ++ bias-disable; ++ }; ++ }; ++ pwm1_0_gpio40: pwm1_0_gpio40 { ++ pin-pwm { ++ pins = "gpio40"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio13: pwm0_1_gpio13 { ++ pin-pwm { ++ pins = "gpio13"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio19: pwm0_1_gpio19 { ++ pin-pwm { ++ pins = "gpio19"; ++ function = "alt5"; ++ bias-disable; ++ }; ++ }; ++ pwm1_1_gpio41: pwm1_1_gpio41 { ++ pin-pwm { ++ pins = "gpio41"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio45: pwm0_1_gpio45 { ++ pin-pwm { ++ pins = "gpio45"; ++ function = "alt0"; ++ bias-disable; ++ }; ++ }; ++ pwm0_0_gpio52: pwm0_0_gpio52 { ++ pin-pwm { ++ pins = "gpio52"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ pwm0_1_gpio53: pwm0_1_gpio53 { ++ pin-pwm { ++ pins = "gpio53"; ++ function = "alt1"; ++ bias-disable; ++ }; ++ }; ++ ++ rgmii_gpio35: rgmii_gpio35 { ++ pin-start-stop { ++ pins = "gpio35"; ++ function = "alt4"; ++ }; ++ pin-rx-ok { ++ pins = "gpio36"; ++ function = "alt4"; ++ }; ++ }; ++ rgmii_irq_gpio34: rgmii_irq_gpio34 { ++ pin-irq { ++ pins = "gpio34"; ++ function = "alt5"; ++ }; ++ }; ++ rgmii_irq_gpio39: rgmii_irq_gpio39 { ++ pin-irq { ++ pins = "gpio39"; ++ function = "alt4"; ++ }; ++ }; ++ rgmii_mdio_gpio28: rgmii_mdio_gpio28 { ++ pins-mdio { ++ pins = "gpio28", ++ "gpio29"; ++ function = "alt5"; ++ }; ++ }; ++ rgmii_mdio_gpio37: rgmii_mdio_gpio37 { ++ pins-mdio { ++ pins = "gpio37", ++ "gpio38"; ++ function = "alt4"; ++ }; ++ }; ++ ++ spi0_gpio46: spi0_gpio46 { ++ pins-spi { ++ pins = "gpio46", ++ "gpio47", ++ "gpio48", ++ "gpio49"; ++ function = "alt2"; ++ }; ++ }; ++ spi2_gpio46: spi2_gpio46 { ++ pins-spi { ++ pins = "gpio46", ++ "gpio47", ++ "gpio48", ++ "gpio49", ++ "gpio50"; ++ function = "alt5"; ++ }; ++ }; ++ spi3_gpio0: spi3_gpio0 { ++ pins-spi { ++ pins = "gpio0", ++ "gpio1", ++ "gpio2", ++ "gpio3"; ++ function = "alt3"; ++ }; ++ }; ++ spi4_gpio4: spi4_gpio4 { ++ pins-spi { ++ pins = "gpio4", ++ "gpio5", ++ "gpio6", ++ "gpio7"; ++ function = "alt3"; ++ }; ++ }; ++ spi5_gpio12: spi5_gpio12 { ++ pins-spi { ++ pins = "gpio12", ++ "gpio13", ++ "gpio14", ++ "gpio15"; ++ function = "alt3"; ++ }; ++ }; ++ spi6_gpio18: spi6_gpio18 { ++ pins-spi { ++ pins = "gpio18", ++ "gpio19", ++ "gpio20", ++ "gpio21"; ++ function = "alt3"; ++ }; ++ }; ++ ++ uart2_gpio0: uart2_gpio0 { ++ pin-tx { ++ pins = "gpio0"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio1"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { ++ pin-cts { ++ pins = "gpio2"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio3"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; ++ uart3_gpio4: uart3_gpio4 { ++ pin-tx { ++ pins = "gpio4"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio5"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { ++ pin-cts { ++ pins = "gpio6"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio7"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; ++ uart4_gpio8: uart4_gpio8 { ++ pin-tx { ++ pins = "gpio8"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio9"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { ++ pin-cts { ++ pins = "gpio10"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio11"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; ++ uart5_gpio12: uart5_gpio12 { ++ pin-tx { ++ pins = "gpio12"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ pin-rx { ++ pins = "gpio13"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ }; ++ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { ++ pin-cts { ++ pins = "gpio14"; ++ function = "alt4"; ++ bias-pull-up; ++ }; ++ pin-rts { ++ pins = "gpio15"; ++ function = "alt4"; ++ bias-disable; ++ }; ++ }; ++}; ++ ++&i2c0 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ interrupts = ; ++}; ++ ++&i2c1 { ++ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; ++ interrupts = ; ++}; ++ ++&mailbox { ++ interrupts = ; ++}; ++ ++&sdhci { ++ interrupts = ; ++}; ++ ++&sdhost { ++ interrupts = ; ++}; ++ ++&spi { ++ interrupts = ; ++}; ++ ++&spi1 { ++ interrupts = ; ++}; ++ ++&spi2 { ++ interrupts = ; ++}; ++ ++&system_timer { ++ interrupts = , ++ , ++ , ++ ; ++}; ++ ++&txp { ++ interrupts = ; ++}; ++ ++&uart0 { ++ interrupts = ; ++}; ++ ++&uart1 { ++ interrupts = ; ++}; ++ ++&usb { ++ interrupts = ; ++}; ++ ++&vec { ++ interrupts = ; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi +@@ -0,0 +1,7 @@ ++// SPDX-License-Identifier: GPL-2.0 ++&usb { ++ dr_mode = "peripheral"; ++ g-rx-fifo-size = <256>; ++ g-np-tx-fifo-size = <32>; ++ g-tx-fifo-size = <256 256 512 512 512 768 768>; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0413-overlays-Fix-mcp23017-s-addr-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0413-overlays-Fix-mcp23017-s-addr-parameter.patch deleted file mode 100644 index 29ad87227d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0413-overlays-Fix-mcp23017-s-addr-parameter.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 9fa750db2d682fa2c124dae609d05d15f93a5e52 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 4 Feb 2020 15:22:55 +0000 -Subject: [PATCH] overlays: Fix mcp23017's addr parameter - -The addr parameter of the mcp23017 overlay was broken by the addition -of the noints parameter; splitting the mcp node in two without also -modifying the second half from the addr parameter would cause the two -halves to separate. Change the implementation strategy to patch -fragment 2 (as was originally proposed). This will prevent the -overlay from being applied at runtime until the "dtoverlay" command -is improved, but the overlay already has this restriction due to -fragment 3 so this isn't a step backwards. - -See: https://github.com/raspberrypi/linux/issues/3449 - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 16 +++++++--------- - 1 file changed, 7 insertions(+), 9 deletions(-) - ---- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts -+++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts -@@ -48,15 +48,13 @@ - }; - - fragment@4 { -- target = <&i2c1>; -- __overlay__ { -- mcp23017_irq: mcp@20 { -- #interrupt-cells=<2>; -- interrupt-parent = <&gpio>; -- interrupts = <4 2>; -- interrupt-controller; -- microchip,irq-mirror; -- }; -+ target = <&mcp23017>; -+ mcp23017_irq: __overlay__ { -+ #interrupt-cells=<2>; -+ interrupt-parent = <&gpio>; -+ interrupts = <4 2>; -+ interrupt-controller; -+ microchip,irq-mirror; - }; - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0414-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch b/target/linux/bcm27xx/patches-5.4/950-0414-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch new file mode 100644 index 0000000000..44f60d610f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0414-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch @@ -0,0 +1,45 @@ +From 4bcb99a967998d255ef009bb0b6880ae99c6f6bf Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 6 Nov 2019 10:59:44 +0100 +Subject: [PATCH] ARM: dts: bcm2711: force CMA into first GB of memory + +arm64 places the CMA in ZONE_DMA32, which is not good enough for the +Raspberry Pi 4 since it contains peripherals that can only address the +first GB of memory. Explicitly place the CMA into that area. + +Signed-off-by: Nicolas Saenz Julienne +Acked-by: Stefan Wahren +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm2711.dtsi | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -12,6 +12,26 @@ + + interrupt-parent = <&gicv2>; + ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges; ++ ++ /* ++ * arm64 reserves the CMA by default somewhere in ZONE_DMA32, ++ * that's not good enough for the BCM2711 as some devices can ++ * only address the lower 1G of memory (ZONE_DMA). ++ */ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ size = <0x2000000>; /* 32MB */ ++ alloc-ranges = <0x0 0x00000000 0x40000000>; ++ reusable; ++ linux,cma-default; ++ }; ++ }; ++ ++ + soc { + /* + * Defined ranges: diff --git a/target/linux/bcm27xx/patches-5.4/950-0414-SQUASH-Fix-spi-driver-compiler-warnings.patch b/target/linux/bcm27xx/patches-5.4/950-0414-SQUASH-Fix-spi-driver-compiler-warnings.patch deleted file mode 100644 index f233c4aedc..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0414-SQUASH-Fix-spi-driver-compiler-warnings.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 69811ede9ad350beb531082177bdc6da92c7fdb9 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 4 Feb 2020 16:35:12 +0000 -Subject: [PATCH] SQUASH: Fix spi driver compiler warnings - -Squash with "spi: spi-bcm2835: Disable forced software CS" - -Signed-off-by: Phil Elwell ---- - drivers/spi/spi-bcm2835.c | 2 -- - 1 file changed, 2 deletions(-) - ---- a/drivers/spi/spi-bcm2835.c -+++ b/drivers/spi/spi-bcm2835.c -@@ -1230,7 +1230,6 @@ static int bcm2835_spi_setup(struct spi_ - { - struct spi_controller *ctlr = spi->controller; - struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); -- struct gpio_chip *chip; - u32 cs; - - /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0415-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch b/target/linux/bcm27xx/patches-5.4/950-0415-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch new file mode 100644 index 0000000000..e204859fbd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0415-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch @@ -0,0 +1,86 @@ +From 32847947e1d1e1ac2a73c7ea8ad47cca49aef5d4 Mon Sep 17 00:00:00 2001 +From: Stefan Wahren +Date: Mon, 11 Nov 2019 20:49:26 +0100 +Subject: [PATCH] ARM: dts: bcm2711-rpi-4: Enable GENET support + +This enables the Gigabit Ethernet support on the Raspberry Pi 4. +The defined PHY mode is equivalent to the default register settings +in the downstream tree. + +Signed-off-by: Matthias Brugger +Signed-off-by: Stefan Wahren +Reviewed-by: Florian Fainelli +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 17 +++++++++++++++++ + arch/arm/boot/dts/bcm2711.dtsi | 26 ++++++++++++++++++++++++++ + 2 files changed, 43 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -19,6 +19,10 @@ + reg = <0 0 0>; + }; + ++ aliases { ++ ethernet0 = &genet; ++ }; ++ + leds { + act { + gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; +@@ -97,6 +101,19 @@ + status = "okay"; + }; + ++&genet { ++ phy-handle = <&phy1>; ++ phy-mode = "rgmii-rxid"; ++ status = "okay"; ++}; ++ ++&genet_mdio { ++ phy1: ethernet-phy@1 { ++ /* No PHY interrupt */ ++ reg = <0x1>; ++ }; ++}; ++ + /* uart0 communicates with the BT module */ + &uart0 { + pinctrl-names = "default"; +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -325,6 +325,32 @@ + cpu-release-addr = <0x0 0x000000f0>; + }; + }; ++ ++ scb { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; ++ ++ genet: ethernet@7d580000 { ++ compatible = "brcm,bcm2711-genet-v5"; ++ reg = <0x0 0x7d580000 0x10000>; ++ #address-cells = <0x1>; ++ #size-cells = <0x1>; ++ interrupts = , ++ ; ++ status = "disabled"; ++ ++ genet_mdio: mdio@e14 { ++ compatible = "brcm,genet-mdio-v5"; ++ reg = <0xe14 0x8>; ++ reg-names = "mdio"; ++ #address-cells = <0x0>; ++ #size-cells = <0x1>; ++ }; ++ }; ++ }; + }; + + &clk_osc { diff --git a/target/linux/bcm27xx/patches-5.4/950-0415-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch b/target/linux/bcm27xx/patches-5.4/950-0415-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch deleted file mode 100644 index e94f15196b..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0415-overlays-add-hdmi-backlight-hwhack-gpio-overlay.patch +++ /dev/null @@ -1,106 +0,0 @@ -From c6e4343e441558f45df2685b9ed7c13daf7988be Mon Sep 17 00:00:00 2001 -From: Michael Kaplan -Date: Wed, 5 Feb 2020 10:27:23 +0100 -Subject: [PATCH] overlays: add hdmi-backlight-hwhack-gpio-overlay - -This is a Devicetree overlay for GPIO based backlight on/off capability. - -Use this if you have one of those HDMI displays whose backlight cannot be controlled via DPMS over HDMI and plan to do a little soldering to use an RPi gpio pin for on/off switching. - -See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control - -This was tested with a clone of the Waveshare "7 inch HDMI Touch LCD C" where I soldered two mosfets to override the backlight dip-switch. -When the overlay is loaded, a sysfs backlight node appears which can be used to modify the brightness value (0 or 1), and is even used by DPMS to switch the display backlight off after the configured timeout. -(On current Raspbian Buster Desktop, it's also possible to wakeup the display via a tap on the touch display :-) ) - -Signed-off-by: Michael Kaplan ---- - arch/arm/boot/dts/overlays/Makefile | 1 + - arch/arm/boot/dts/overlays/README | 14 ++++++ - .../hdmi-backlight-hwhack-gpio-overlay.dts | 47 +++++++++++++++++++ - 3 files changed, 62 insertions(+) - create mode 100644 arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts - ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -51,6 +51,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ - gpio-poweroff.dtbo \ - gpio-shutdown.dtbo \ - hd44780-lcd.dtbo \ -+ hdmi-backlight-hwhack-gpio.dtbo \ - hifiberry-amp.dtbo \ - hifiberry-dac.dtbo \ - hifiberry-dacplus.dtbo \ ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -883,6 +883,20 @@ Params: pin_d4 GPIO pin - display_width Width of the display in characters - - -+Name: hdmi-backlight-hwhack-gpio -+Info: Devicetree overlay for GPIO based backlight on/off capability. -+ Use this if you have one of those HDMI displays whose backlight cannot -+ be controlled via DPMS over HDMI and plan to do a little soldering to -+ use an RPi gpio pin for on/off switching. See: -+ https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control -+Load: dtoverlay=hdmi-backlight-hwhack-gpio,= -+Params: gpio_pin GPIO pin used (default 17) -+ active_low Set this to 1 if the display backlight is -+ switched on when the wire goes low. -+ Leave the default (value 0) if the backlight -+ expects a high to switch it on. -+ -+ - Name: hifiberry-amp - Info: Configures the HifiBerry Amp and Amp+ audio cards - Load: dtoverlay=hifiberry-amp ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/hdmi-backlight-hwhack-gpio-overlay.dts -@@ -0,0 +1,47 @@ -+/* -+ * Devicetree overlay for GPIO based backlight on/off capability. -+ * -+ * Use this if you have one of those HDMI displays whose backlight cannot be -+ * controlled via DPMS over HDMI and plan to do a little soldering to use an -+ * RPi gpio pin for on/off switching. -+ * -+ * See: https://www.waveshare.com/wiki/7inch_HDMI_LCD_(C)#Backlight_Control -+ * -+ */ -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2835"; -+ -+ fragment@1 { -+ target = <&gpio>; -+ __overlay__ { -+ hdmi_backlight_hwhack_gpio_pins: hdmi_backlight_hwhack_gpio_pins { -+ brcm,pins = <17>; -+ brcm,function = <1>; /* out */ -+ }; -+ }; -+ }; -+ -+ fragment@2 { -+ target-path = "/"; -+ __overlay__ { -+ hdmi_backlight_hwhack_gpio: hdmi_backlight_hwhack_gpio { -+ compatible = "gpio-backlight"; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&hdmi_backlight_hwhack_gpio_pins>; -+ -+ gpios = <&gpio 17 0>; -+ default-on; -+ }; -+ }; -+ }; -+ -+ __overrides__ { -+ gpio_pin = <&hdmi_backlight_hwhack_gpio>,"gpios:4", -+ <&hdmi_backlight_hwhack_gpio_pins>,"brcm,pins:0"; -+ active_low = <&hdmi_backlight_hwhack_gpio>,"gpios:8"; -+ }; -+}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0416-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch b/target/linux/bcm27xx/patches-5.4/950-0416-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch deleted file mode 100644 index 403f534baf..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0416-ARM-dts-Revert-all-changes-to-upstream-dts-files.patch +++ /dev/null @@ -1,1929 +0,0 @@ -From e90536d721612de6a2619ae6727ee12b56bb2660 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 30 Jan 2020 11:39:39 +0000 -Subject: [PATCH] ARM: dts: Revert all changes to upstream dts files - -With the possible exception of bcm2711* files where there is a name -clash, we should not be modifying upstream DTS files. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 348 ++------ - arch/arm/boot/dts/bcm2711.dtsi | 888 ++++++++++++++++++++- - arch/arm/boot/dts/bcm2835-common.dtsi | 131 +++ - arch/arm/boot/dts/bcm2835-rpi-a-plus.dts | 1 - - arch/arm/boot/dts/bcm2835-rpi-a.dts | 1 - - arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 1 - - arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts | 1 - - arch/arm/boot/dts/bcm2835-rpi-b.dts | 1 - - arch/arm/boot/dts/bcm2835-rpi-zero.dts | 1 - - arch/arm/boot/dts/bcm2835-rpi.dtsi | 37 - - arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 1 - - arch/arm/boot/dts/bcm2837-rpi-3-b.dts | 1 - - arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi | 15 - - arch/arm/boot/dts/bcm283x.dtsi | 152 +--- - 14 files changed, 1068 insertions(+), 511 deletions(-) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -1,54 +1,57 @@ -+// SPDX-License-Identifier: GPL-2.0 - /dts-v1/; -- - #include "bcm2711.dtsi" --#include "bcm2711-rpi.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" -+#include "bcm2835-rpi.dtsi" -+#include "bcm283x-rpi-usb-peripheral.dtsi" - - / { - compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; - model = "Raspberry Pi 4 Model B"; - -- memory@0 { -- device_type = "memory"; -- reg = <0x0 0x0 0x0>; -+ chosen { -+ /* 8250 auxiliary UART instead of pl011 */ -+ stdout-path = "serial1:115200n8"; - }; - -- chosen { -- bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M"; -+ /* Will be filled by the bootloader */ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0 0 0>; - }; - - aliases { -- serial0 = &uart1; -- serial1 = &uart0; -- mmc0 = &emmc2; -- mmc1 = &mmcnr; -- mmc2 = &sdhost; -- i2c3 = &i2c3; -- i2c4 = &i2c4; -- i2c5 = &i2c5; -- i2c6 = &i2c6; -- /delete-property/ ethernet; -- /delete-property/ intc; - ethernet0 = &genet; -- pcie0 = &pcie_0; - }; --}; - --&soc { -- virtgpio: virtgpio { -- compatible = "brcm,bcm2835-virtgpio"; -- gpio-controller; -- #gpio-cells = <2>; -- firmware = <&firmware>; -- status = "okay"; -+ leds { -+ act { -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ pwr { -+ label = "PWR"; -+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -+ }; - }; --}; - --&mmcnr { -- pinctrl-names = "default"; -- pinctrl-0 = <&sdio_pins>; -- bus-width = <4>; -- status = "okay"; -+ wifi_pwrseq: wifi-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ -+ sd_io_1v8_reg: sd_io_1v8_reg { -+ compatible = "regulator-gpio"; -+ regulator-name = "vdd-sd-io"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ regulator-settling-time-us = <5000>; -+ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; -+ states = <1800000 0x1 -+ 3300000 0x0>; -+ status = "okay"; -+ }; - }; - - &firmware { -@@ -68,81 +71,34 @@ - }; - }; - --&uart0 { -+&pwm1 { - pinctrl-names = "default"; -- pinctrl-0 = <&uart0_pins &bt_pins>; -+ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; - status = "okay"; - }; - --&uart1 { -+/* SDHCI is used to control the SDIO for wireless */ -+&sdhci { -+ #address-cells = <1>; -+ #size-cells = <0>; - pinctrl-names = "default"; -- pinctrl-0 = <&uart1_pins>; -+ pinctrl-0 = <&emmc_gpio34>; -+ bus-width = <4>; -+ non-removable; -+ mmc-pwrseq = <&wifi_pwrseq>; - status = "okay"; --}; - --&spi0 { -- pinctrl-names = "default"; -- pinctrl-0 = <&spi0_pins &spi0_cs_pins>; -- cs-gpios = <&gpio 8 1>, <&gpio 7 1>; -- -- spidev0: spidev@0{ -- compatible = "spidev"; -- reg = <0>; /* CE0 */ -- #address-cells = <1>; -- #size-cells = <0>; -- spi-max-frequency = <125000000>; -- }; -- -- spidev1: spidev@1{ -- compatible = "spidev"; -- reg = <1>; /* CE1 */ -- #address-cells = <1>; -- #size-cells = <0>; -- spi-max-frequency = <125000000>; -- }; --}; -- --// ============================================= --// Board specific stuff here -- --/ { -- -- sd_io_1v8_reg: sd_io_1v8_reg { -- status = "okay"; -- compatible = "regulator-gpio"; -- vin-supply = <&vdd_5v0_reg>; -- regulator-name = "vdd-sd-io"; -- regulator-min-microvolt = <1800000>; -- regulator-max-microvolt = <3300000>; -- regulator-boot-on; -- regulator-always-on; -- regulator-settling-time-us = <5000>; -- -- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; -- states = <1800000 0x1 -- 3300000 0x0>; -+ brcmf: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; - }; -- -- sd_vcc_reg: sd_vcc_reg { -- compatible = "regulator-fixed"; -- regulator-name = "vcc-sd"; -- regulator-min-microvolt = <3300000>; -- regulator-max-microvolt = <3300000>; -- regulator-boot-on; -- enable-active-high; -- gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; -- }; --}; -- --&sdhost { -- status = "disabled"; - }; - -+/* EMMC2 is used to drive the SD card */ - &emmc2 { -- status = "okay"; -- broken-cd; - vqmmc-supply = <&sd_io_1v8_reg>; -- vmmc-supply = <&sd_vcc_reg>; -+ broken-cd; -+ status = "okay"; - }; - - &genet { -@@ -155,200 +111,32 @@ - phy1: ethernet-phy@1 { - /* No PHY interrupt */ - reg = <0x1>; -- led-modes = <0x00 0x08>; /* link/activity link */ - }; - }; - --&leds { -- act_led: act { -- label = "led0"; -- linux,default-trigger = "mmc0"; -- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -- }; -- -- pwr_led: pwr { -- label = "led1"; -- linux,default-trigger = "default-on"; -- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -- }; --}; -- --&audio { -+/* uart0 communicates with the BT module */ -+&uart0 { - pinctrl-names = "default"; -- pinctrl-0 = <&audio_pins>; --}; -- --&sdhost_gpio48 { -- brcm,pins = <22 23 24 25 26 27>; -- brcm,function = ; --}; -- --&gpio { -- spi0_pins: spi0_pins { -- brcm,pins = <9 10 11>; -- brcm,function = ; -- }; -- -- spi0_cs_pins: spi0_cs_pins { -- brcm,pins = <8 7>; -- brcm,function = ; -- }; -- -- spi3_pins: spi3_pins { -- brcm,pins = <1 2 3>; -- brcm,function = ; -- }; -- -- spi3_cs_pins: spi3_cs_pins { -- brcm,pins = <0 24>; -- brcm,function = ; -- }; -- -- spi4_pins: spi4_pins { -- brcm,pins = <5 6 7>; -- brcm,function = ; -- }; -- -- spi4_cs_pins: spi4_cs_pins { -- brcm,pins = <4 25>; -- brcm,function = ; -- }; -- -- spi5_pins: spi5_pins { -- brcm,pins = <13 14 15>; -- brcm,function = ; -- }; -- -- spi5_cs_pins: spi5_cs_pins { -- brcm,pins = <12 26>; -- brcm,function = ; -- }; -- -- spi6_pins: spi6_pins { -- brcm,pins = <19 20 21>; -- brcm,function = ; -- }; -- -- spi6_cs_pins: spi6_cs_pins { -- brcm,pins = <18 27>; -- brcm,function = ; -- }; -- -- i2c0_pins: i2c0 { -- brcm,pins = <0 1>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- i2c1_pins: i2c1 { -- brcm,pins = <2 3>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- i2c3_pins: i2c3 { -- brcm,pins = <4 5>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- i2c4_pins: i2c4 { -- brcm,pins = <8 9>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- i2c5_pins: i2c5 { -- brcm,pins = <12 13>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- i2c6_pins: i2c6 { -- brcm,pins = <22 23>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- i2s_pins: i2s { -- brcm,pins = <18 19 20 21>; -- brcm,function = ; -- }; -- -- sdio_pins: sdio_pins { -- brcm,pins = <34 35 36 37 38 39>; -- brcm,function = ; // alt3 = SD1 -- brcm,pull = <0 2 2 2 2 2>; -- }; -- -- bt_pins: bt_pins { -- brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0 -- // to fool pinctrl -- brcm,function = <0>; -- brcm,pull = <2>; -- }; -- -- uart0_pins: uart0_pins { -- brcm,pins = <32 33>; -- brcm,function = ; -- brcm,pull = <0 2>; -- }; -- -- uart1_pins: uart1_pins { -- brcm,pins; -- brcm,function; -- brcm,pull; -- }; -- -- uart2_pins: uart2_pins { -- brcm,pins = <0 1>; -- brcm,function = ; -- brcm,pull = <0 2>; -- }; -- -- uart3_pins: uart3_pins { -- brcm,pins = <4 5>; -- brcm,function = ; -- brcm,pull = <0 2>; -- }; -- -- uart4_pins: uart4_pins { -- brcm,pins = <8 9>; -- brcm,function = ; -- brcm,pull = <0 2>; -- }; -- -- uart5_pins: uart5_pins { -- brcm,pins = <12 13>; -- brcm,function = ; -- brcm,pull = <0 2>; -- }; -+ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; -+ uart-has-rtscts; -+ status = "okay"; - -- audio_pins: audio_pins { -- brcm,pins = <40 41>; -- brcm,function = <4>; -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <2000000>; -+ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; - }; - }; - --&i2c0 { -- pinctrl-names = "default"; -- pinctrl-0 = <&i2c0_pins>; -- clock-frequency = <100000>; --}; -- --&i2c1 { -+/* uart1 is mapped to the pin header */ -+&uart1 { - pinctrl-names = "default"; -- pinctrl-0 = <&i2c1_pins>; -- clock-frequency = <100000>; --}; -- --&i2c2 { -- clock-frequency = <100000>; -+ pinctrl-0 = <&uart1_gpio14>; -+ status = "okay"; - }; - --&i2s { -- pinctrl-names = "default"; -- pinctrl-0 = <&i2s_pins>; -+&vchiq { -+ interrupts = ; - }; - - / { ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -1,44 +1,890 @@ --#include "bcm2838.dtsi" --#include "bcm270x.dtsi" -+// SPDX-License-Identifier: GPL-2.0 -+#include "bcm283x.dtsi" -+ -+#include -+#include - - / { -+ compatible = "brcm,bcm2711"; -+ -+ #address-cells = <2>; -+ #size-cells = <1>; -+ -+ interrupt-parent = <&gicv2>; -+ -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <1>; -+ ranges; -+ -+ /* -+ * arm64 reserves the CMA by default somewhere in ZONE_DMA32, -+ * that's not good enough for the BCM2711 as some devices can -+ * only address the lower 1G of memory (ZONE_DMA). -+ */ -+ linux,cma { -+ compatible = "shared-dma-pool"; -+ size = <0x2000000>; /* 32MB */ -+ alloc-ranges = <0x0 0x00000000 0x40000000>; -+ reusable; -+ linux,cma-default; -+ }; -+ }; -+ -+ - soc { -- /delete-node/ v3d@7ec00000; -+ /* -+ * Defined ranges: -+ * Common BCM283x peripherals -+ * BCM2711-specific peripherals -+ * ARM-local peripherals -+ */ -+ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, -+ <0x7c000000 0x0 0xfc000000 0x02000000>, -+ <0x40000000 0x0 0xff800000 0x00800000>; -+ /* Emulate a contiguous 30-bit address range for DMA */ -+ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>; -+ -+ /* -+ * This node is the provider for the enable-method for -+ * bringing up secondary cores. -+ */ -+ local_intc: local_intc@40000000 { -+ compatible = "brcm,bcm2836-l1-intc"; -+ reg = <0x40000000 0x100>; -+ }; -+ -+ gicv2: interrupt-controller@40041000 { -+ interrupt-controller; -+ #interrupt-cells = <3>; -+ compatible = "arm,gic-400"; -+ reg = <0x40041000 0x1000>, -+ <0x40042000 0x2000>, -+ <0x40044000 0x2000>, -+ <0x40046000 0x2000>; -+ interrupts = ; -+ }; -+ -+ dma: dma@7e007000 { -+ compatible = "brcm,bcm2835-dma"; -+ reg = <0x7e007000 0xb00>; -+ interrupts = , -+ , -+ , -+ , -+ , -+ , -+ , -+ /* DMA lite 7 - 10 */ -+ , -+ , -+ , -+ ; -+ interrupt-names = "dma0", -+ "dma1", -+ "dma2", -+ "dma3", -+ "dma4", -+ "dma5", -+ "dma6", -+ "dma7", -+ "dma8", -+ "dma9", -+ "dma10"; -+ #dma-cells = <1>; -+ brcm,dma-channel-mask = <0x07f5>; -+ }; -+ -+ pm: watchdog@7e100000 { -+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; -+ #power-domain-cells = <1>; -+ #reset-cells = <1>; -+ reg = <0x7e100000 0x114>, -+ <0x7e00a000 0x24>, -+ <0x7ec11000 0x20>; -+ clocks = <&clocks BCM2835_CLOCK_V3D>, -+ <&clocks BCM2835_CLOCK_PERI_IMAGE>, -+ <&clocks BCM2835_CLOCK_H264>, -+ <&clocks BCM2835_CLOCK_ISP>; -+ clock-names = "v3d", "peri_image", "h264", "isp"; -+ system-power-controller; -+ }; -+ -+ rng@7e104000 { -+ interrupts = ; -+ -+ /* RNG is incompatible with brcm,bcm2835-rng */ -+ status = "disabled"; -+ }; -+ -+ uart2: serial@7e201400 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201400 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart3: serial@7e201600 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201600 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart4: serial@7e201800 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201800 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart5: serial@7e201a00 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201a00 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ spi3: spi@7e204600 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204600 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi4: spi@7e204800 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204800 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi5: spi@7e204a00 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204a00 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi6: spi@7e204c00 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204c00 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c3: i2c@7e205600 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205600 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c4: i2c@7e205800 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205800 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c5: i2c@7e205a00 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205a00 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c6: i2c@7e205c00 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205c00 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ pwm1: pwm@7e20c800 { -+ compatible = "brcm,bcm2835-pwm"; -+ reg = <0x7e20c800 0x28>; -+ clocks = <&clocks BCM2835_CLOCK_PWM>; -+ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; -+ assigned-clock-rates = <10000000>; -+ #pwm-cells = <2>; -+ status = "disabled"; -+ }; -+ -+ emmc2: emmc2@7e340000 { -+ compatible = "brcm,bcm2711-emmc2"; -+ reg = <0x7e340000 0x100>; -+ interrupts = ; -+ clocks = <&clocks BCM2711_CLOCK_EMMC2>; -+ status = "disabled"; -+ }; -+ -+ hvs@7e400000 { -+ interrupts = ; -+ }; -+ }; -+ -+ arm-pmu { -+ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3"; -+ interrupts = , -+ , -+ , -+ ; -+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; -+ }; -+ -+ timer { -+ compatible = "arm,armv8-timer"; -+ interrupts = , -+ , -+ , -+ ; -+ /* This only applies to the ARMv7 stub */ -+ arm,cpu-registers-not-fw-configured; -+ }; -+ -+ cpus: cpus { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit -+ -+ cpu0: cpu@0 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <0>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000d8>; -+ }; -+ -+ cpu1: cpu@1 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <1>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000e0>; -+ }; -+ -+ cpu2: cpu@2 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <2>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000e8>; -+ }; -+ -+ cpu3: cpu@3 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <3>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000f0>; -+ }; - }; - -- __overrides__ { -- arm_freq; -+ scb { -+ compatible = "simple-bus"; -+ #address-cells = <2>; -+ #size-cells = <1>; -+ -+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; -+ -+ genet: ethernet@7d580000 { -+ compatible = "brcm,bcm2711-genet-v5"; -+ reg = <0x0 0x7d580000 0x10000>; -+ #address-cells = <0x1>; -+ #size-cells = <0x1>; -+ interrupts = , -+ ; -+ status = "disabled"; -+ -+ genet_mdio: mdio@e14 { -+ compatible = "brcm,genet-mdio-v5"; -+ reg = <0xe14 0x8>; -+ reg-names = "mdio"; -+ #address-cells = <0x0>; -+ #size-cells = <0x1>; -+ }; -+ }; - }; - }; - --&v3d { -- status = "disabled"; -+&clk_osc { -+ clock-frequency = <54000000>; - }; - --&firmwarekms { -- interrupts = ; -+&clocks { -+ compatible = "brcm,bcm2711-cprman"; - }; - --&smi { -- interrupts = ; -+&cpu_thermal { -+ coefficients = <(-487) 410040>; - }; - --&mmc { -- interrupts = ; -+&dsi0 { -+ interrupts = ; -+}; -+ -+&dsi1 { -+ interrupts = ; -+}; -+ -+&gpio { -+ compatible = "brcm,bcm2711-gpio"; -+ interrupts = , -+ , -+ , -+ ; -+ -+ gpclk0_gpio49: gpclk0_gpio49 { -+ pin-gpclk { -+ pins = "gpio49"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ gpclk1_gpio50: gpclk1_gpio50 { -+ pin-gpclk { -+ pins = "gpio50"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ gpclk2_gpio51: gpclk2_gpio51 { -+ pin-gpclk { -+ pins = "gpio51"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ -+ i2c0_gpio46: i2c0_gpio46 { -+ pin-sda { -+ function = "alt0"; -+ pins = "gpio46"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt0"; -+ pins = "gpio47"; -+ bias-disable; -+ }; -+ }; -+ i2c1_gpio46: i2c1_gpio46 { -+ pin-sda { -+ function = "alt1"; -+ pins = "gpio46"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt1"; -+ pins = "gpio47"; -+ bias-disable; -+ }; -+ }; -+ i2c3_gpio2: i2c3_gpio2 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio2"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio3"; -+ bias-disable; -+ }; -+ }; -+ i2c3_gpio4: i2c3_gpio4 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio4"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio5"; -+ bias-disable; -+ }; -+ }; -+ i2c4_gpio6: i2c4_gpio6 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio6"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio7"; -+ bias-disable; -+ }; -+ }; -+ i2c4_gpio8: i2c4_gpio8 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio8"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio9"; -+ bias-disable; -+ }; -+ }; -+ i2c5_gpio10: i2c5_gpio10 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio10"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio11"; -+ bias-disable; -+ }; -+ }; -+ i2c5_gpio12: i2c5_gpio12 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio12"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio13"; -+ bias-disable; -+ }; -+ }; -+ i2c6_gpio0: i2c6_gpio0 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio0"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio1"; -+ bias-disable; -+ }; -+ }; -+ i2c6_gpio22: i2c6_gpio22 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio22"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio23"; -+ bias-disable; -+ }; -+ }; -+ i2c_slave_gpio8: i2c_slave_gpio8 { -+ pins-i2c-slave { -+ pins = "gpio8", -+ "gpio9", -+ "gpio10", -+ "gpio11"; -+ function = "alt3"; -+ }; -+ }; -+ -+ jtag_gpio48: jtag_gpio48 { -+ pins-jtag { -+ pins = "gpio48", -+ "gpio49", -+ "gpio50", -+ "gpio51", -+ "gpio52", -+ "gpio53"; -+ function = "alt4"; -+ }; -+ }; -+ -+ mii_gpio28: mii_gpio28 { -+ pins-mii { -+ pins = "gpio28", -+ "gpio29", -+ "gpio30", -+ "gpio31"; -+ function = "alt4"; -+ }; -+ }; -+ mii_gpio36: mii_gpio36 { -+ pins-mii { -+ pins = "gpio36", -+ "gpio37", -+ "gpio38", -+ "gpio39"; -+ function = "alt5"; -+ }; -+ }; -+ -+ pcm_gpio50: pcm_gpio50 { -+ pins-pcm { -+ pins = "gpio50", -+ "gpio51", -+ "gpio52", -+ "gpio53"; -+ function = "alt2"; -+ }; -+ }; -+ -+ pwm0_0_gpio12: pwm0_0_gpio12 { -+ pin-pwm { -+ pins = "gpio12"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_0_gpio18: pwm0_0_gpio18 { -+ pin-pwm { -+ pins = "gpio18"; -+ function = "alt5"; -+ bias-disable; -+ }; -+ }; -+ pwm1_0_gpio40: pwm1_0_gpio40 { -+ pin-pwm { -+ pins = "gpio40"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio13: pwm0_1_gpio13 { -+ pin-pwm { -+ pins = "gpio13"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio19: pwm0_1_gpio19 { -+ pin-pwm { -+ pins = "gpio19"; -+ function = "alt5"; -+ bias-disable; -+ }; -+ }; -+ pwm1_1_gpio41: pwm1_1_gpio41 { -+ pin-pwm { -+ pins = "gpio41"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio45: pwm0_1_gpio45 { -+ pin-pwm { -+ pins = "gpio45"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_0_gpio52: pwm0_0_gpio52 { -+ pin-pwm { -+ pins = "gpio52"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio53: pwm0_1_gpio53 { -+ pin-pwm { -+ pins = "gpio53"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ -+ rgmii_gpio35: rgmii_gpio35 { -+ pin-start-stop { -+ pins = "gpio35"; -+ function = "alt4"; -+ }; -+ pin-rx-ok { -+ pins = "gpio36"; -+ function = "alt4"; -+ }; -+ }; -+ rgmii_irq_gpio34: rgmii_irq_gpio34 { -+ pin-irq { -+ pins = "gpio34"; -+ function = "alt5"; -+ }; -+ }; -+ rgmii_irq_gpio39: rgmii_irq_gpio39 { -+ pin-irq { -+ pins = "gpio39"; -+ function = "alt4"; -+ }; -+ }; -+ rgmii_mdio_gpio28: rgmii_mdio_gpio28 { -+ pins-mdio { -+ pins = "gpio28", -+ "gpio29"; -+ function = "alt5"; -+ }; -+ }; -+ rgmii_mdio_gpio37: rgmii_mdio_gpio37 { -+ pins-mdio { -+ pins = "gpio37", -+ "gpio38"; -+ function = "alt4"; -+ }; -+ }; -+ -+ spi0_gpio46: spi0_gpio46 { -+ pins-spi { -+ pins = "gpio46", -+ "gpio47", -+ "gpio48", -+ "gpio49"; -+ function = "alt2"; -+ }; -+ }; -+ spi2_gpio46: spi2_gpio46 { -+ pins-spi { -+ pins = "gpio46", -+ "gpio47", -+ "gpio48", -+ "gpio49", -+ "gpio50"; -+ function = "alt5"; -+ }; -+ }; -+ spi3_gpio0: spi3_gpio0 { -+ pins-spi { -+ pins = "gpio0", -+ "gpio1", -+ "gpio2", -+ "gpio3"; -+ function = "alt3"; -+ }; -+ }; -+ spi4_gpio4: spi4_gpio4 { -+ pins-spi { -+ pins = "gpio4", -+ "gpio5", -+ "gpio6", -+ "gpio7"; -+ function = "alt3"; -+ }; -+ }; -+ spi5_gpio12: spi5_gpio12 { -+ pins-spi { -+ pins = "gpio12", -+ "gpio13", -+ "gpio14", -+ "gpio15"; -+ function = "alt3"; -+ }; -+ }; -+ spi6_gpio18: spi6_gpio18 { -+ pins-spi { -+ pins = "gpio18", -+ "gpio19", -+ "gpio20", -+ "gpio21"; -+ function = "alt3"; -+ }; -+ }; -+ -+ uart2_gpio0: uart2_gpio0 { -+ pin-tx { -+ pins = "gpio0"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio1"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { -+ pin-cts { -+ pins = "gpio2"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio3"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; -+ uart3_gpio4: uart3_gpio4 { -+ pin-tx { -+ pins = "gpio4"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio5"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { -+ pin-cts { -+ pins = "gpio6"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio7"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; -+ uart4_gpio8: uart4_gpio8 { -+ pin-tx { -+ pins = "gpio8"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio9"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { -+ pin-cts { -+ pins = "gpio10"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio11"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; -+ uart5_gpio12: uart5_gpio12 { -+ pin-tx { -+ pins = "gpio12"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio13"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { -+ pin-cts { -+ pins = "gpio14"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio15"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; - }; - --&mmcnr { -+&i2c0 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ interrupts = ; -+}; -+ -+&i2c1 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ interrupts = ; -+}; -+ -+&mailbox { -+ interrupts = ; -+}; -+ -+&sdhci { - interrupts = ; - }; - -+&sdhost { -+ interrupts = ; -+}; -+ -+&spi { -+ interrupts = ; -+}; -+ -+&spi1 { -+ interrupts = ; -+}; -+ -+&spi2 { -+ interrupts = ; -+}; -+ -+&system_timer { -+ interrupts = , -+ , -+ , -+ ; -+}; -+ -+&txp { -+ interrupts = ; -+}; -+ -+&uart0 { -+ interrupts = ; -+}; -+ -+&uart1 { -+ interrupts = ; -+}; -+ - &usb { -- reg = <0x7e980000 0x10000>, -- <0x7e00b200 0x200>; -- interrupts = , -- ; -+ interrupts = ; - }; - --&gpio { -- interrupts = , -- ; -+&vec { -+ interrupts = ; - }; ---- a/arch/arm/boot/dts/bcm2835-common.dtsi -+++ b/arch/arm/boot/dts/bcm2835-common.dtsi -@@ -8,6 +8,47 @@ - interrupt-parent = <&intc>; - - soc { -+ dma: dma@7e007000 { -+ compatible = "brcm,bcm2835-dma"; -+ reg = <0x7e007000 0xf00>; -+ interrupts = <1 16>, -+ <1 17>, -+ <1 18>, -+ <1 19>, -+ <1 20>, -+ <1 21>, -+ <1 22>, -+ <1 23>, -+ <1 24>, -+ <1 25>, -+ <1 26>, -+ /* dma channel 11-14 share one irq */ -+ <1 27>, -+ <1 27>, -+ <1 27>, -+ <1 27>, -+ /* unused shared irq for all channels */ -+ <1 28>; -+ interrupt-names = "dma0", -+ "dma1", -+ "dma2", -+ "dma3", -+ "dma4", -+ "dma5", -+ "dma6", -+ "dma7", -+ "dma8", -+ "dma9", -+ "dma10", -+ "dma11", -+ "dma12", -+ "dma13", -+ "dma14", -+ "dma-shared-all"; -+ #dma-cells = <1>; -+ brcm,dma-channel-mask = <0x7f35>; -+ }; -+ - intc: interrupt-controller@7e00b200 { - compatible = "brcm,bcm2835-armctrl-ic"; - reg = <0x7e00b200 0x200>; -@@ -15,6 +56,20 @@ - #interrupt-cells = <2>; - }; - -+ pm: watchdog@7e100000 { -+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; -+ #power-domain-cells = <1>; -+ #reset-cells = <1>; -+ reg = <0x7e100000 0x114>, -+ <0x7e00a000 0x24>; -+ clocks = <&clocks BCM2835_CLOCK_V3D>, -+ <&clocks BCM2835_CLOCK_PERI_IMAGE>, -+ <&clocks BCM2835_CLOCK_H264>, -+ <&clocks BCM2835_CLOCK_ISP>; -+ clock-names = "v3d", "peri_image", "h264", "isp"; -+ system-power-controller; -+ }; -+ - pixelvalve@7e206000 { - compatible = "brcm,bcm2835-pixelvalve0"; - reg = <0x7e206000 0x100>; -@@ -35,21 +90,53 @@ - status = "disabled"; - }; - -+ i2c2: i2c@7e805000 { -+ compatible = "brcm,bcm2835-i2c"; -+ reg = <0x7e805000 0x1000>; -+ interrupts = <2 21>; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ }; -+ - pixelvalve@7e807000 { - compatible = "brcm,bcm2835-pixelvalve2"; - reg = <0x7e807000 0x100>; - interrupts = <2 10>; /* pixelvalve */ - }; - -+ hdmi: hdmi@7e902000 { -+ compatible = "brcm,bcm2835-hdmi"; -+ reg = <0x7e902000 0x600>, -+ <0x7e808000 0x100>; -+ interrupts = <2 8>, <2 9>; -+ ddc = <&i2c2>; -+ clocks = <&clocks BCM2835_PLLH_PIX>, -+ <&clocks BCM2835_CLOCK_HSM>; -+ clock-names = "pixel", "hdmi"; -+ dmas = <&dma 17>; -+ dma-names = "audio-rx"; -+ status = "disabled"; -+ }; -+ - v3d: v3d@7ec00000 { - compatible = "brcm,bcm2835-v3d"; - reg = <0x7ec00000 0x1000>; - interrupts = <1 10>; - power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; - }; -+ -+ vc4: gpu { -+ compatible = "brcm,bcm2835-vc4"; -+ }; - }; - }; - -+&cpu_thermal { -+ thermal-sensors = <&thermal>; -+}; -+ - &gpio { - i2c_slave_gpio18: i2c_slave_gpio18 { - brcm,pins = <18 19 20 21>; -@@ -60,4 +147,48 @@ - brcm,pins = <4 5 6 12 13>; - brcm,function = ; - }; -+ -+ pwm0_gpio12: pwm0_gpio12 { -+ brcm,pins = <12>; -+ brcm,function = ; -+ }; -+ pwm0_gpio18: pwm0_gpio18 { -+ brcm,pins = <18>; -+ brcm,function = ; -+ }; -+ pwm0_gpio40: pwm0_gpio40 { -+ brcm,pins = <40>; -+ brcm,function = ; -+ }; -+ pwm1_gpio13: pwm1_gpio13 { -+ brcm,pins = <13>; -+ brcm,function = ; -+ }; -+ pwm1_gpio19: pwm1_gpio19 { -+ brcm,pins = <19>; -+ brcm,function = ; -+ }; -+ pwm1_gpio41: pwm1_gpio41 { -+ brcm,pins = <41>; -+ brcm,function = ; -+ }; -+ pwm1_gpio45: pwm1_gpio45 { -+ brcm,pins = <45>; -+ brcm,function = ; -+ }; -+}; -+ -+&i2s { -+ dmas = <&dma 2>, <&dma 3>; -+ dma-names = "tx", "rx"; -+}; -+ -+&sdhost { -+ dmas = <&dma 13>; -+ dma-names = "rx-tx"; -+}; -+ -+&spi { -+ dmas = <&dma 6>, <&dma 7>; -+ dma-names = "tx", "rx"; - }; ---- a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts -@@ -3,7 +3,6 @@ - #include "bcm2835.dtsi" - #include "bcm2835-rpi.dtsi" - #include "bcm283x-rpi-usb-host.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,model-a-plus", "brcm,bcm2835"; ---- a/arch/arm/boot/dts/bcm2835-rpi-a.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-a.dts -@@ -3,7 +3,6 @@ - #include "bcm2835.dtsi" - #include "bcm2835-rpi.dtsi" - #include "bcm283x-rpi-usb-host.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,model-a", "brcm,bcm2835"; ---- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts -@@ -4,7 +4,6 @@ - #include "bcm2835-rpi.dtsi" - #include "bcm283x-rpi-smsc9514.dtsi" - #include "bcm283x-rpi-usb-host.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,model-b-plus", "brcm,bcm2835"; ---- a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts -@@ -4,7 +4,6 @@ - #include "bcm2835-rpi.dtsi" - #include "bcm283x-rpi-smsc9512.dtsi" - #include "bcm283x-rpi-usb-host.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835"; ---- a/arch/arm/boot/dts/bcm2835-rpi-b.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts -@@ -4,7 +4,6 @@ - #include "bcm2835-rpi.dtsi" - #include "bcm283x-rpi-smsc9512.dtsi" - #include "bcm283x-rpi-usb-host.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,model-b", "brcm,bcm2835"; ---- a/arch/arm/boot/dts/bcm2835-rpi-zero.dts -+++ b/arch/arm/boot/dts/bcm2835-rpi-zero.dts -@@ -7,7 +7,6 @@ - #include "bcm2835.dtsi" - #include "bcm2835-rpi.dtsi" - #include "bcm283x-rpi-usb-otg.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,model-zero", "brcm,bcm2835"; ---- a/arch/arm/boot/dts/bcm2835-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi -@@ -29,22 +29,6 @@ - interrupts = <0 2>; - }; - }; -- -- vdd_3v3_reg: fixedregulator_3v3 { -- compatible = "regulator-fixed"; -- regulator-name = "3v3"; -- regulator-min-microvolt = <3300000>; -- regulator-max-microvolt = <3300000>; -- regulator-always-on; -- }; -- -- vdd_5v0_reg: fixedregulator_5v0 { -- compatible = "regulator-fixed"; -- regulator-name = "5v0"; -- regulator-min-microvolt = <5000000>; -- regulator-max-microvolt = <5000000>; -- regulator-always-on; -- }; - }; - - &gpio { -@@ -75,23 +59,10 @@ - clock-frequency = <100000>; - }; - --&i2c2 { -- status = "okay"; --}; -- - &usb { - power-domains = <&power RPI_POWER_DOMAIN_USB>; - }; - --&hdmi { -- power-domains = <&power RPI_POWER_DOMAIN_HDMI>; -- status = "okay"; --}; -- --&v3d { -- power-domains = <&power RPI_POWER_DOMAIN_V3D>; --}; -- - &vec { - power-domains = <&power RPI_POWER_DOMAIN_VEC>; - status = "okay"; -@@ -104,11 +75,3 @@ - &dsi1 { - power-domains = <&power RPI_POWER_DOMAIN_DSI1>; - }; -- --&csi0 { -- power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>; --}; -- --&csi1 { -- power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>; --}; ---- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts -+++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts -@@ -4,7 +4,6 @@ - #include "bcm2836-rpi.dtsi" - #include "bcm283x-rpi-smsc9514.dtsi" - #include "bcm283x-rpi-usb-host.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; ---- a/arch/arm/boot/dts/bcm2837-rpi-3-b.dts -+++ b/arch/arm/boot/dts/bcm2837-rpi-3-b.dts -@@ -4,7 +4,6 @@ - #include "bcm2836-rpi.dtsi" - #include "bcm283x-rpi-smsc9514.dtsi" - #include "bcm283x-rpi-usb-host.dtsi" --#include "bcm283x-rpi-csi1-2lane.dtsi" - - / { - compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; ---- a/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi -+++ b/arch/arm/boot/dts/bcm283x-rpi-lan7515.dtsi -@@ -29,9 +29,6 @@ - #size-cells = <0x0>; - eth_phy: ethernet-phy@1 { - reg = <1>; -- microchip,eee-enabled; -- microchip,tx-lpi-timer = <600>; /* non-aggressive*/ -- microchip,downshift-after = <2>; - microchip,led-modes = < - LAN78XX_LINK_1000_ACTIVITY - LAN78XX_LINK_10_100_ACTIVITY -@@ -42,15 +39,3 @@ - }; - }; - }; -- -- --/ { -- __overrides__ { -- eee = <ð_phy>,"microchip,eee-enabled?"; -- tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0"; -- eth_led0 = <ð_phy>,"microchip,led-modes:0"; -- eth_led1 = <ð_phy>,"microchip,led-modes:4"; -- eth_downshift_after = <ð_phy>,"microchip,downshift-after:0"; -- eth_max_speed = <ð_phy>,"max-speed:0"; -- }; --}; ---- a/arch/arm/boot/dts/bcm283x.dtsi -+++ b/arch/arm/boot/dts/bcm283x.dtsi -@@ -35,8 +35,6 @@ - polling-delay-passive = <0>; - polling-delay = <1000>; - -- thermal-sensors = <&thermal>; -- - trips { - cpu-crit { - temperature = <90000>; -@@ -72,61 +70,6 @@ - interrupts = <1 11>; - }; - -- dma: dma@7e007000 { -- compatible = "brcm,bcm2835-dma"; -- reg = <0x7e007000 0xf00>; -- interrupts = <1 16>, -- <1 17>, -- <1 18>, -- <1 19>, -- <1 20>, -- <1 21>, -- <1 22>, -- <1 23>, -- <1 24>, -- <1 25>, -- <1 26>, -- /* dma channel 11-14 share one irq */ -- <1 27>, -- <1 27>, -- <1 27>, -- <1 27>, -- /* unused shared irq for all channels */ -- <1 28>; -- interrupt-names = "dma0", -- "dma1", -- "dma2", -- "dma3", -- "dma4", -- "dma5", -- "dma6", -- "dma7", -- "dma8", -- "dma9", -- "dma10", -- "dma11", -- "dma12", -- "dma13", -- "dma14", -- "dma-shared-all"; -- #dma-cells = <1>; -- brcm,dma-channel-mask = <0x7f35>; -- }; -- -- pm: watchdog@7e100000 { -- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; -- #power-domain-cells = <1>; -- #reset-cells = <1>; -- reg = <0x7e100000 0x114>, -- <0x7e00a000 0x24>; -- clocks = <&clocks BCM2835_CLOCK_V3D>, -- <&clocks BCM2835_CLOCK_PERI_IMAGE>, -- <&clocks BCM2835_CLOCK_H264>, -- <&clocks BCM2835_CLOCK_ISP>; -- clock-names = "v3d", "peri_image", "h264", "isp"; -- system-power-controller; -- }; -- - clocks: cprman@7e101000 { - compatible = "brcm,bcm2835-cprman"; - #clock-cells = <1>; -@@ -141,7 +84,7 @@ - <&dsi1 0>, <&dsi1 1>, <&dsi1 2>; - }; - -- rng: rng@7e104000 { -+ rng@7e104000 { - compatible = "brcm,bcm2835-rng"; - reg = <0x7e104000 0x10>; - interrupts = <2 29>; -@@ -269,35 +212,6 @@ - brcm,function = ; - }; - -- pwm0_gpio12: pwm0_gpio12 { -- brcm,pins = <12>; -- brcm,function = ; -- }; -- pwm0_gpio18: pwm0_gpio18 { -- brcm,pins = <18>; -- brcm,function = ; -- }; -- pwm0_gpio40: pwm0_gpio40 { -- brcm,pins = <40>; -- brcm,function = ; -- }; -- pwm1_gpio13: pwm1_gpio13 { -- brcm,pins = <13>; -- brcm,function = ; -- }; -- pwm1_gpio19: pwm1_gpio19 { -- brcm,pins = <19>; -- brcm,function = ; -- }; -- pwm1_gpio41: pwm1_gpio41 { -- brcm,pins = <41>; -- brcm,function = ; -- }; -- pwm1_gpio45: pwm1_gpio45 { -- brcm,pins = <45>; -- brcm,function = ; -- }; -- - sdhost_gpio48: sdhost_gpio48 { - brcm,pins = <48 49 50 51 52 53>; - brcm,function = ; -@@ -379,7 +293,7 @@ - }; - - uart0: serial@7e201000 { -- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; -+ compatible = "arm,pl011", "arm,primecell"; - reg = <0x7e201000 0x200>; - interrupts = <2 25>; - clocks = <&clocks BCM2835_CLOCK_UART>, -@@ -393,8 +307,6 @@ - reg = <0x7e202000 0x100>; - interrupts = <2 24>; - clocks = <&clocks BCM2835_CLOCK_VPU>; -- dmas = <&dma (13|(1<<29))>; -- dma-names = "rx-tx"; - status = "disabled"; - }; - -@@ -402,10 +314,6 @@ - compatible = "brcm,bcm2835-i2s"; - reg = <0x7e203000 0x24>; - clocks = <&clocks BCM2835_CLOCK_PCM>; -- -- dmas = <&dma 2>, -- <&dma 3>; -- dma-names = "tx", "rx"; - status = "disabled"; - }; - -@@ -414,8 +322,6 @@ - reg = <0x7e204000 0x200>; - interrupts = <2 22>; - clocks = <&clocks BCM2835_CLOCK_VPU>; -- dmas = <&dma 6>, <&dma 7>; -- dma-names = "tx", "rx"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; -@@ -541,32 +447,6 @@ - status = "disabled"; - }; - -- csi0: csi@7e800000 { -- compatible = "brcm,bcm2835-unicam"; -- reg = <0x7e800000 0x800>, -- <0x7e802000 0x4>; -- interrupts = <2 6>; -- clocks = <&clocks BCM2835_CLOCK_CAM0>; -- clock-names = "lp"; -- #address-cells = <1>; -- #size-cells = <0>; -- #clock-cells = <1>; -- status = "disabled"; -- }; -- -- csi1: csi@7e801000 { -- compatible = "brcm,bcm2835-unicam"; -- reg = <0x7e801000 0x800>, -- <0x7e802004 0x4>; -- interrupts = <2 7>; -- clocks = <&clocks BCM2835_CLOCK_CAM1>; -- clock-names = "lp"; -- #address-cells = <1>; -- #size-cells = <0>; -- #clock-cells = <1>; -- status = "disabled"; -- }; -- - i2c1: i2c@7e804000 { - compatible = "brcm,bcm2835-i2c"; - reg = <0x7e804000 0x1000>; -@@ -577,16 +457,6 @@ - status = "disabled"; - }; - -- i2c2: i2c@7e805000 { -- compatible = "brcm,bcm2835-i2c"; -- reg = <0x7e805000 0x1000>; -- interrupts = <2 21>; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- - vec: vec@7e806000 { - compatible = "brcm,bcm2835-vec"; - reg = <0x7e806000 0x1000>; -@@ -595,20 +465,6 @@ - status = "disabled"; - }; - -- hdmi: hdmi@7e902000 { -- compatible = "brcm,bcm2835-hdmi"; -- reg = <0x7e902000 0x600>, -- <0x7e808000 0x100>; -- interrupts = <2 8>, <2 9>; -- ddc = <&i2c2>; -- clocks = <&clocks BCM2835_PLLH_PIX>, -- <&clocks BCM2835_CLOCK_HSM>; -- clock-names = "pixel", "hdmi"; -- dmas = <&dma 17>; -- dma-names = "audio-rx"; -- status = "disabled"; -- }; -- - usb: usb@7e980000 { - compatible = "brcm,bcm2835-usb"; - reg = <0x7e980000 0x10000>; -@@ -620,10 +476,6 @@ - phys = <&usbphy>; - phy-names = "usb2-phy"; - }; -- -- vc4: gpu { -- compatible = "brcm,bcm2835-vc4"; -- }; - }; - - clocks { diff --git a/target/linux/bcm27xx/patches-5.4/950-0416-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch b/target/linux/bcm27xx/patches-5.4/950-0416-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch new file mode 100644 index 0000000000..ed0be9b9a3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0416-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch @@ -0,0 +1,40 @@ +From 44d7ee4730fbe3c00aba0457489acd0b6e2937c9 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 4 Dec 2019 13:56:33 +0100 +Subject: [PATCH] ARM: dts: bcm2711: fix soc's node dma-ranges + +Raspberry Pi's firmware has a feature to select how much memory to +reserve for its GPU called 'gpu_mem'. The possible values go from 16MB +to 944MB, with a default of 64MB. This memory resides in the topmost +part of the lower 1GB memory area and grows bigger expanding towards the +begging of memory. + +It turns out that with low 'gpu_mem' values (16MB and 32MB) the size of +the memory available to the system in the lower 1GB area can outgrow the +interconnect's dma-range as its size was selected based on the maximum +system memory available given the default gpu_mem configuration. This +makes that memory slice unavailable for DMA. And may cause nasty kernel +warnings if CMA happens to include it. + +Change soc's dma-ranges to really reflect it's HW limitation, which is +being able to only DMA to the lower 1GB area. + +Fixes: 7dbe8c62ceeb ("ARM: dts: Add minimal Raspberry Pi 4 support") +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Phil Elwell +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm2711.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -43,7 +43,7 @@ + <0x7c000000 0x0 0xfc000000 0x02000000>, + <0x40000000 0x0 0xff800000 0x00800000>; + /* Emulate a contiguous 30-bit address range for DMA */ +- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>; ++ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>; + + /* + * This node is the provider for the enable-method for diff --git a/target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch b/target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch deleted file mode 100644 index a66202a2c9..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Clean-out-downstream-BCM2711-2838-files.patch +++ /dev/null @@ -1,1846 +0,0 @@ -From 134e06abd2d002edfdac3561656ab9e8161b29a3 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 31 Jan 2020 16:53:13 +0000 -Subject: [PATCH] ARM: dts: Clean out downstream BCM2711/2838 files - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 157 ----- - arch/arm/boot/dts/bcm2711-rpi.dtsi | 7 - - arch/arm/boot/dts/bcm2711.dtsi | 890 -------------------------- - arch/arm/boot/dts/bcm2838-rpi.dtsi | 25 - - arch/arm/boot/dts/bcm2838.dtsi | 733 --------------------- - 5 files changed, 1812 deletions(-) - delete mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts - delete mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi - delete mode 100644 arch/arm/boot/dts/bcm2711.dtsi - delete mode 100644 arch/arm/boot/dts/bcm2838-rpi.dtsi - delete mode 100644 arch/arm/boot/dts/bcm2838.dtsi - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ /dev/null -@@ -1,157 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/dts-v1/; --#include "bcm2711.dtsi" --#include "bcm2835-rpi.dtsi" --#include "bcm283x-rpi-usb-peripheral.dtsi" -- --/ { -- compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; -- model = "Raspberry Pi 4 Model B"; -- -- chosen { -- /* 8250 auxiliary UART instead of pl011 */ -- stdout-path = "serial1:115200n8"; -- }; -- -- /* Will be filled by the bootloader */ -- memory@0 { -- device_type = "memory"; -- reg = <0 0 0>; -- }; -- -- aliases { -- ethernet0 = &genet; -- }; -- -- leds { -- act { -- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -- }; -- -- pwr { -- label = "PWR"; -- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -- }; -- }; -- -- wifi_pwrseq: wifi-pwrseq { -- compatible = "mmc-pwrseq-simple"; -- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; -- }; -- -- sd_io_1v8_reg: sd_io_1v8_reg { -- compatible = "regulator-gpio"; -- regulator-name = "vdd-sd-io"; -- regulator-min-microvolt = <1800000>; -- regulator-max-microvolt = <3300000>; -- regulator-boot-on; -- regulator-always-on; -- regulator-settling-time-us = <5000>; -- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; -- states = <1800000 0x1 -- 3300000 0x0>; -- status = "okay"; -- }; --}; -- --&firmware { -- expgpio: gpio { -- compatible = "raspberrypi,firmware-gpio"; -- gpio-controller; -- #gpio-cells = <2>; -- gpio-line-names = "BT_ON", -- "WL_ON", -- "PWR_LED_OFF", -- "GLOBAL_RESET", -- "VDD_SD_IO_SEL", -- "CAM_GPIO", -- "", -- ""; -- status = "okay"; -- }; --}; -- --&pwm1 { -- pinctrl-names = "default"; -- pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; -- status = "okay"; --}; -- --/* SDHCI is used to control the SDIO for wireless */ --&sdhci { -- #address-cells = <1>; -- #size-cells = <0>; -- pinctrl-names = "default"; -- pinctrl-0 = <&emmc_gpio34>; -- bus-width = <4>; -- non-removable; -- mmc-pwrseq = <&wifi_pwrseq>; -- status = "okay"; -- -- brcmf: wifi@1 { -- reg = <1>; -- compatible = "brcm,bcm4329-fmac"; -- }; --}; -- --/* EMMC2 is used to drive the SD card */ --&emmc2 { -- vqmmc-supply = <&sd_io_1v8_reg>; -- broken-cd; -- status = "okay"; --}; -- --&genet { -- phy-handle = <&phy1>; -- phy-mode = "rgmii-rxid"; -- status = "okay"; --}; -- --&genet_mdio { -- phy1: ethernet-phy@1 { -- /* No PHY interrupt */ -- reg = <0x1>; -- }; --}; -- --/* uart0 communicates with the BT module */ --&uart0 { -- pinctrl-names = "default"; -- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; -- uart-has-rtscts; -- status = "okay"; -- -- bluetooth { -- compatible = "brcm,bcm43438-bt"; -- max-speed = <2000000>; -- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; -- }; --}; -- --/* uart1 is mapped to the pin header */ --&uart1 { -- pinctrl-names = "default"; -- pinctrl-0 = <&uart1_gpio14>; -- status = "okay"; --}; -- --&vchiq { -- interrupts = ; --}; -- --/ { -- __overrides__ { -- act_led_gpio = <&act_led>,"gpios:4"; -- act_led_activelow = <&act_led>,"gpios:8"; -- act_led_trigger = <&act_led>,"linux,default-trigger"; -- -- pwr_led_gpio = <&pwr_led>,"gpios:4"; -- pwr_led_activelow = <&pwr_led>,"gpios:8"; -- pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; -- -- eth_led0 = <&phy1>,"led-modes:0"; -- eth_led1 = <&phy1>,"led-modes:4"; -- -- sd_poll_once = <&emmc2>, "non-removable?"; -- }; --}; ---- a/arch/arm/boot/dts/bcm2711-rpi.dtsi -+++ /dev/null -@@ -1,7 +0,0 @@ --#include "bcm2708-rpi.dtsi" --#include "bcm2838-rpi.dtsi" -- --&v3d { -- /* Undo the overwriting by bcm270x.dtsi */ -- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; --}; ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ /dev/null -@@ -1,890 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --#include "bcm283x.dtsi" -- --#include --#include -- --/ { -- compatible = "brcm,bcm2711"; -- -- #address-cells = <2>; -- #size-cells = <1>; -- -- interrupt-parent = <&gicv2>; -- -- reserved-memory { -- #address-cells = <2>; -- #size-cells = <1>; -- ranges; -- -- /* -- * arm64 reserves the CMA by default somewhere in ZONE_DMA32, -- * that's not good enough for the BCM2711 as some devices can -- * only address the lower 1G of memory (ZONE_DMA). -- */ -- linux,cma { -- compatible = "shared-dma-pool"; -- size = <0x2000000>; /* 32MB */ -- alloc-ranges = <0x0 0x00000000 0x40000000>; -- reusable; -- linux,cma-default; -- }; -- }; -- -- -- soc { -- /* -- * Defined ranges: -- * Common BCM283x peripherals -- * BCM2711-specific peripherals -- * ARM-local peripherals -- */ -- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, -- <0x7c000000 0x0 0xfc000000 0x02000000>, -- <0x40000000 0x0 0xff800000 0x00800000>; -- /* Emulate a contiguous 30-bit address range for DMA */ -- dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>; -- -- /* -- * This node is the provider for the enable-method for -- * bringing up secondary cores. -- */ -- local_intc: local_intc@40000000 { -- compatible = "brcm,bcm2836-l1-intc"; -- reg = <0x40000000 0x100>; -- }; -- -- gicv2: interrupt-controller@40041000 { -- interrupt-controller; -- #interrupt-cells = <3>; -- compatible = "arm,gic-400"; -- reg = <0x40041000 0x1000>, -- <0x40042000 0x2000>, -- <0x40044000 0x2000>, -- <0x40046000 0x2000>; -- interrupts = ; -- }; -- -- dma: dma@7e007000 { -- compatible = "brcm,bcm2835-dma"; -- reg = <0x7e007000 0xb00>; -- interrupts = , -- , -- , -- , -- , -- , -- , -- /* DMA lite 7 - 10 */ -- , -- , -- , -- ; -- interrupt-names = "dma0", -- "dma1", -- "dma2", -- "dma3", -- "dma4", -- "dma5", -- "dma6", -- "dma7", -- "dma8", -- "dma9", -- "dma10"; -- #dma-cells = <1>; -- brcm,dma-channel-mask = <0x07f5>; -- }; -- -- pm: watchdog@7e100000 { -- compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; -- #power-domain-cells = <1>; -- #reset-cells = <1>; -- reg = <0x7e100000 0x114>, -- <0x7e00a000 0x24>, -- <0x7ec11000 0x20>; -- clocks = <&clocks BCM2835_CLOCK_V3D>, -- <&clocks BCM2835_CLOCK_PERI_IMAGE>, -- <&clocks BCM2835_CLOCK_H264>, -- <&clocks BCM2835_CLOCK_ISP>; -- clock-names = "v3d", "peri_image", "h264", "isp"; -- system-power-controller; -- }; -- -- rng@7e104000 { -- interrupts = ; -- -- /* RNG is incompatible with brcm,bcm2835-rng */ -- status = "disabled"; -- }; -- -- uart2: serial@7e201400 { -- compatible = "arm,pl011", "arm,primecell"; -- reg = <0x7e201400 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- uart3: serial@7e201600 { -- compatible = "arm,pl011", "arm,primecell"; -- reg = <0x7e201600 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- uart4: serial@7e201800 { -- compatible = "arm,pl011", "arm,primecell"; -- reg = <0x7e201800 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- uart5: serial@7e201a00 { -- compatible = "arm,pl011", "arm,primecell"; -- reg = <0x7e201a00 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- spi3: spi@7e204600 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204600 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- spi4: spi@7e204800 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204800 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- spi5: spi@7e204a00 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204a00 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- spi6: spi@7e204c00 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204c00 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c3: i2c@7e205600 { -- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -- reg = <0x7e205600 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c4: i2c@7e205800 { -- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -- reg = <0x7e205800 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c5: i2c@7e205a00 { -- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -- reg = <0x7e205a00 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c6: i2c@7e205c00 { -- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -- reg = <0x7e205c00 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- pwm1: pwm@7e20c800 { -- compatible = "brcm,bcm2835-pwm"; -- reg = <0x7e20c800 0x28>; -- clocks = <&clocks BCM2835_CLOCK_PWM>; -- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; -- assigned-clock-rates = <10000000>; -- #pwm-cells = <2>; -- status = "disabled"; -- }; -- -- emmc2: emmc2@7e340000 { -- compatible = "brcm,bcm2711-emmc2"; -- reg = <0x7e340000 0x100>; -- interrupts = ; -- clocks = <&clocks BCM2711_CLOCK_EMMC2>; -- status = "disabled"; -- }; -- -- hvs@7e400000 { -- interrupts = ; -- }; -- }; -- -- arm-pmu { -- compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3"; -- interrupts = , -- , -- , -- ; -- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; -- }; -- -- timer { -- compatible = "arm,armv8-timer"; -- interrupts = , -- , -- , -- ; -- /* This only applies to the ARMv7 stub */ -- arm,cpu-registers-not-fw-configured; -- }; -- -- cpus: cpus { -- #address-cells = <1>; -- #size-cells = <0>; -- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit -- -- cpu0: cpu@0 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <0>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000d8>; -- }; -- -- cpu1: cpu@1 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <1>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000e0>; -- }; -- -- cpu2: cpu@2 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <2>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000e8>; -- }; -- -- cpu3: cpu@3 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <3>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000f0>; -- }; -- }; -- -- scb { -- compatible = "simple-bus"; -- #address-cells = <2>; -- #size-cells = <1>; -- -- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; -- -- genet: ethernet@7d580000 { -- compatible = "brcm,bcm2711-genet-v5"; -- reg = <0x0 0x7d580000 0x10000>; -- #address-cells = <0x1>; -- #size-cells = <0x1>; -- interrupts = , -- ; -- status = "disabled"; -- -- genet_mdio: mdio@e14 { -- compatible = "brcm,genet-mdio-v5"; -- reg = <0xe14 0x8>; -- reg-names = "mdio"; -- #address-cells = <0x0>; -- #size-cells = <0x1>; -- }; -- }; -- }; --}; -- --&clk_osc { -- clock-frequency = <54000000>; --}; -- --&clocks { -- compatible = "brcm,bcm2711-cprman"; --}; -- --&cpu_thermal { -- coefficients = <(-487) 410040>; --}; -- --&dsi0 { -- interrupts = ; --}; -- --&dsi1 { -- interrupts = ; --}; -- --&gpio { -- compatible = "brcm,bcm2711-gpio"; -- interrupts = , -- , -- , -- ; -- -- gpclk0_gpio49: gpclk0_gpio49 { -- pin-gpclk { -- pins = "gpio49"; -- function = "alt1"; -- bias-disable; -- }; -- }; -- gpclk1_gpio50: gpclk1_gpio50 { -- pin-gpclk { -- pins = "gpio50"; -- function = "alt1"; -- bias-disable; -- }; -- }; -- gpclk2_gpio51: gpclk2_gpio51 { -- pin-gpclk { -- pins = "gpio51"; -- function = "alt1"; -- bias-disable; -- }; -- }; -- -- i2c0_gpio46: i2c0_gpio46 { -- pin-sda { -- function = "alt0"; -- pins = "gpio46"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt0"; -- pins = "gpio47"; -- bias-disable; -- }; -- }; -- i2c1_gpio46: i2c1_gpio46 { -- pin-sda { -- function = "alt1"; -- pins = "gpio46"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt1"; -- pins = "gpio47"; -- bias-disable; -- }; -- }; -- i2c3_gpio2: i2c3_gpio2 { -- pin-sda { -- function = "alt5"; -- pins = "gpio2"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio3"; -- bias-disable; -- }; -- }; -- i2c3_gpio4: i2c3_gpio4 { -- pin-sda { -- function = "alt5"; -- pins = "gpio4"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio5"; -- bias-disable; -- }; -- }; -- i2c4_gpio6: i2c4_gpio6 { -- pin-sda { -- function = "alt5"; -- pins = "gpio6"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio7"; -- bias-disable; -- }; -- }; -- i2c4_gpio8: i2c4_gpio8 { -- pin-sda { -- function = "alt5"; -- pins = "gpio8"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio9"; -- bias-disable; -- }; -- }; -- i2c5_gpio10: i2c5_gpio10 { -- pin-sda { -- function = "alt5"; -- pins = "gpio10"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio11"; -- bias-disable; -- }; -- }; -- i2c5_gpio12: i2c5_gpio12 { -- pin-sda { -- function = "alt5"; -- pins = "gpio12"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio13"; -- bias-disable; -- }; -- }; -- i2c6_gpio0: i2c6_gpio0 { -- pin-sda { -- function = "alt5"; -- pins = "gpio0"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio1"; -- bias-disable; -- }; -- }; -- i2c6_gpio22: i2c6_gpio22 { -- pin-sda { -- function = "alt5"; -- pins = "gpio22"; -- bias-pull-up; -- }; -- pin-scl { -- function = "alt5"; -- pins = "gpio23"; -- bias-disable; -- }; -- }; -- i2c_slave_gpio8: i2c_slave_gpio8 { -- pins-i2c-slave { -- pins = "gpio8", -- "gpio9", -- "gpio10", -- "gpio11"; -- function = "alt3"; -- }; -- }; -- -- jtag_gpio48: jtag_gpio48 { -- pins-jtag { -- pins = "gpio48", -- "gpio49", -- "gpio50", -- "gpio51", -- "gpio52", -- "gpio53"; -- function = "alt4"; -- }; -- }; -- -- mii_gpio28: mii_gpio28 { -- pins-mii { -- pins = "gpio28", -- "gpio29", -- "gpio30", -- "gpio31"; -- function = "alt4"; -- }; -- }; -- mii_gpio36: mii_gpio36 { -- pins-mii { -- pins = "gpio36", -- "gpio37", -- "gpio38", -- "gpio39"; -- function = "alt5"; -- }; -- }; -- -- pcm_gpio50: pcm_gpio50 { -- pins-pcm { -- pins = "gpio50", -- "gpio51", -- "gpio52", -- "gpio53"; -- function = "alt2"; -- }; -- }; -- -- pwm0_0_gpio12: pwm0_0_gpio12 { -- pin-pwm { -- pins = "gpio12"; -- function = "alt0"; -- bias-disable; -- }; -- }; -- pwm0_0_gpio18: pwm0_0_gpio18 { -- pin-pwm { -- pins = "gpio18"; -- function = "alt5"; -- bias-disable; -- }; -- }; -- pwm1_0_gpio40: pwm1_0_gpio40 { -- pin-pwm { -- pins = "gpio40"; -- function = "alt0"; -- bias-disable; -- }; -- }; -- pwm0_1_gpio13: pwm0_1_gpio13 { -- pin-pwm { -- pins = "gpio13"; -- function = "alt0"; -- bias-disable; -- }; -- }; -- pwm0_1_gpio19: pwm0_1_gpio19 { -- pin-pwm { -- pins = "gpio19"; -- function = "alt5"; -- bias-disable; -- }; -- }; -- pwm1_1_gpio41: pwm1_1_gpio41 { -- pin-pwm { -- pins = "gpio41"; -- function = "alt0"; -- bias-disable; -- }; -- }; -- pwm0_1_gpio45: pwm0_1_gpio45 { -- pin-pwm { -- pins = "gpio45"; -- function = "alt0"; -- bias-disable; -- }; -- }; -- pwm0_0_gpio52: pwm0_0_gpio52 { -- pin-pwm { -- pins = "gpio52"; -- function = "alt1"; -- bias-disable; -- }; -- }; -- pwm0_1_gpio53: pwm0_1_gpio53 { -- pin-pwm { -- pins = "gpio53"; -- function = "alt1"; -- bias-disable; -- }; -- }; -- -- rgmii_gpio35: rgmii_gpio35 { -- pin-start-stop { -- pins = "gpio35"; -- function = "alt4"; -- }; -- pin-rx-ok { -- pins = "gpio36"; -- function = "alt4"; -- }; -- }; -- rgmii_irq_gpio34: rgmii_irq_gpio34 { -- pin-irq { -- pins = "gpio34"; -- function = "alt5"; -- }; -- }; -- rgmii_irq_gpio39: rgmii_irq_gpio39 { -- pin-irq { -- pins = "gpio39"; -- function = "alt4"; -- }; -- }; -- rgmii_mdio_gpio28: rgmii_mdio_gpio28 { -- pins-mdio { -- pins = "gpio28", -- "gpio29"; -- function = "alt5"; -- }; -- }; -- rgmii_mdio_gpio37: rgmii_mdio_gpio37 { -- pins-mdio { -- pins = "gpio37", -- "gpio38"; -- function = "alt4"; -- }; -- }; -- -- spi0_gpio46: spi0_gpio46 { -- pins-spi { -- pins = "gpio46", -- "gpio47", -- "gpio48", -- "gpio49"; -- function = "alt2"; -- }; -- }; -- spi2_gpio46: spi2_gpio46 { -- pins-spi { -- pins = "gpio46", -- "gpio47", -- "gpio48", -- "gpio49", -- "gpio50"; -- function = "alt5"; -- }; -- }; -- spi3_gpio0: spi3_gpio0 { -- pins-spi { -- pins = "gpio0", -- "gpio1", -- "gpio2", -- "gpio3"; -- function = "alt3"; -- }; -- }; -- spi4_gpio4: spi4_gpio4 { -- pins-spi { -- pins = "gpio4", -- "gpio5", -- "gpio6", -- "gpio7"; -- function = "alt3"; -- }; -- }; -- spi5_gpio12: spi5_gpio12 { -- pins-spi { -- pins = "gpio12", -- "gpio13", -- "gpio14", -- "gpio15"; -- function = "alt3"; -- }; -- }; -- spi6_gpio18: spi6_gpio18 { -- pins-spi { -- pins = "gpio18", -- "gpio19", -- "gpio20", -- "gpio21"; -- function = "alt3"; -- }; -- }; -- -- uart2_gpio0: uart2_gpio0 { -- pin-tx { -- pins = "gpio0"; -- function = "alt4"; -- bias-disable; -- }; -- pin-rx { -- pins = "gpio1"; -- function = "alt4"; -- bias-pull-up; -- }; -- }; -- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { -- pin-cts { -- pins = "gpio2"; -- function = "alt4"; -- bias-pull-up; -- }; -- pin-rts { -- pins = "gpio3"; -- function = "alt4"; -- bias-disable; -- }; -- }; -- uart3_gpio4: uart3_gpio4 { -- pin-tx { -- pins = "gpio4"; -- function = "alt4"; -- bias-disable; -- }; -- pin-rx { -- pins = "gpio5"; -- function = "alt4"; -- bias-pull-up; -- }; -- }; -- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { -- pin-cts { -- pins = "gpio6"; -- function = "alt4"; -- bias-pull-up; -- }; -- pin-rts { -- pins = "gpio7"; -- function = "alt4"; -- bias-disable; -- }; -- }; -- uart4_gpio8: uart4_gpio8 { -- pin-tx { -- pins = "gpio8"; -- function = "alt4"; -- bias-disable; -- }; -- pin-rx { -- pins = "gpio9"; -- function = "alt4"; -- bias-pull-up; -- }; -- }; -- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { -- pin-cts { -- pins = "gpio10"; -- function = "alt4"; -- bias-pull-up; -- }; -- pin-rts { -- pins = "gpio11"; -- function = "alt4"; -- bias-disable; -- }; -- }; -- uart5_gpio12: uart5_gpio12 { -- pin-tx { -- pins = "gpio12"; -- function = "alt4"; -- bias-disable; -- }; -- pin-rx { -- pins = "gpio13"; -- function = "alt4"; -- bias-pull-up; -- }; -- }; -- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { -- pin-cts { -- pins = "gpio14"; -- function = "alt4"; -- bias-pull-up; -- }; -- pin-rts { -- pins = "gpio15"; -- function = "alt4"; -- bias-disable; -- }; -- }; --}; -- --&i2c0 { -- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -- interrupts = ; --}; -- --&i2c1 { -- compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -- interrupts = ; --}; -- --&mailbox { -- interrupts = ; --}; -- --&sdhci { -- interrupts = ; --}; -- --&sdhost { -- interrupts = ; --}; -- --&spi { -- interrupts = ; --}; -- --&spi1 { -- interrupts = ; --}; -- --&spi2 { -- interrupts = ; --}; -- --&system_timer { -- interrupts = , -- , -- , -- ; --}; -- --&txp { -- interrupts = ; --}; -- --&uart0 { -- interrupts = ; --}; -- --&uart1 { -- interrupts = ; --}; -- --&usb { -- interrupts = ; --}; -- --&vec { -- interrupts = ; --}; ---- a/arch/arm/boot/dts/bcm2838-rpi.dtsi -+++ /dev/null -@@ -1,25 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 -- --/ { -- soc { -- /delete-node/ mailbox@7e00b840; -- }; --}; -- --&scb { -- vchiq: mailbox@7e00b840 { -- compatible = "brcm,bcm2838-vchiq"; -- reg = <0 0x7e00b840 0x3c>; -- interrupts = ; -- }; --}; -- --&dma { -- /* The VPU firmware uses DMA channel 11 for VCHIQ */ -- brcm,dma-channel-mask = <0x1f5>; --}; -- --&dma40 { -- /* The VPU firmware DMA channel 11 for VCHIQ */ -- brcm,dma-channel-mask = <0x7000>; --}; ---- a/arch/arm/boot/dts/bcm2838.dtsi -+++ /dev/null -@@ -1,733 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --#include "bcm283x.dtsi" -- --#include --#include -- --/ { -- compatible = "brcm,bcm2838"; -- -- #address-cells = <2>; -- #size-cells = <1>; -- -- interrupt-parent = <&gicv2>; -- -- soc { -- ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, -- <0x7c000000 0x0 0xfc000000 0x02000000>, -- <0x40000000 0x0 0xff800000 0x00800000>; -- /* Emulate a contiguous 30-bit address range for DMA */ -- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>; -- -- /delete-node/ interrupt-controller@7e00f300; -- /delete-node/ v3d@7ec00000; -- -- local_intc: local_intc@40000000 { -- compatible = "brcm,bcm2836-l1-intc"; -- reg = <0x40000000 0x100>; -- }; -- -- gicv2: interrupt-controller@40041000 { -- interrupt-controller; -- #interrupt-cells = <3>; -- compatible = "arm,gic-400"; -- reg = <0x40041000 0x1000>, -- <0x40042000 0x2000>, -- <0x40044000 0x2000>, -- <0x40046000 0x2000>; -- interrupts = ; -- }; -- -- thermal: thermal@7d5d2200 { -- compatible = "brcm,avs-tmon-bcm2838"; -- reg = <0x7d5d2200 0x2c>; -- interrupts = ; -- interrupt-names = "tmon"; -- clocks = <&clocks BCM2835_CLOCK_TSENS>; -- #thermal-sensor-cells = <0>; -- status = "okay"; -- }; -- -- pm: watchdog@7e100000 { -- reg = <0x7e100000 0x114>, -- <0x7e00a000 0x24>, -- <0x7ec11000 0x20>; -- }; -- -- rng@7e104000 { -- interrupts = ; -- }; -- -- uart2: serial@7e201400 { -- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; -- reg = <0x7e201400 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- uart3: serial@7e201600 { -- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; -- reg = <0x7e201600 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- uart4: serial@7e201800 { -- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; -- reg = <0x7e201800 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- uart5: serial@7e201a00 { -- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; -- reg = <0x7e201a00 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_UART>, -- <&clocks BCM2835_CLOCK_VPU>; -- clock-names = "uartclk", "apb_pclk"; -- arm,primecell-periphid = <0x00241011>; -- status = "disabled"; -- }; -- -- spi@7e204000 { -- reg = <0x7e204000 0x0200>; -- interrupts = ; -- }; -- -- spi3: spi@7e204600 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204600 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- spi4: spi@7e204800 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204800 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- spi5: spi@7e204a00 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204a00 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- spi6: spi@7e204c00 { -- compatible = "brcm,bcm2835-spi"; -- reg = <0x7e204c00 0x0200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c3: i2c@7e205600 { -- compatible = "brcm,bcm2835-i2c"; -- reg = <0x7e205600 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c4: i2c@7e205800 { -- compatible = "brcm,bcm2835-i2c"; -- reg = <0x7e205800 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c5: i2c@7e205a00 { -- compatible = "brcm,bcm2835-i2c"; -- reg = <0x7e205a00 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- i2c6: i2c@7e205c00 { -- compatible = "brcm,bcm2835-i2c"; -- reg = <0x7e205c00 0x200>; -- interrupts = ; -- clocks = <&clocks BCM2835_CLOCK_VPU>; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- -- pwm1: pwm@7e20c800 { -- compatible = "brcm,bcm2835-pwm"; -- reg = <0x7e20c800 0x28>; -- clocks = <&clocks BCM2835_CLOCK_PWM>; -- assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; -- assigned-clock-rates = <10000000>; -- #pwm-cells = <2>; -- status = "disabled"; -- }; -- -- emmc2: emmc2@7e340000 { -- compatible = "brcm,bcm2711-emmc2"; -- status = "okay"; -- interrupts = ; -- clocks = <&clocks BCM2711_CLOCK_EMMC2>; -- reg = <0x7e340000 0x100>; -- }; -- -- hvs@7e400000 { -- interrupts = ; -- }; -- }; -- -- arm-pmu { -- compatible = "arm,cortex-a72-pmu"; -- interrupts = , -- , -- , -- ; -- interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; -- }; -- -- timer { -- compatible = "arm,armv7-timer"; -- interrupts = , -- , -- , -- ; -- arm,cpu-registers-not-fw-configured; -- }; -- -- cpus: cpus { -- #address-cells = <1>; -- #size-cells = <0>; -- enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit -- -- cpu0: cpu@0 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <0>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000d8>; -- }; -- -- cpu1: cpu@1 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <1>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000e0>; -- }; -- -- cpu2: cpu@2 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <2>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000e8>; -- }; -- -- cpu3: cpu@3 { -- device_type = "cpu"; -- compatible = "arm,cortex-a72"; -- reg = <3>; -- enable-method = "spin-table"; -- cpu-release-addr = <0x0 0x000000f0>; -- }; -- }; -- -- v3dbus { -- compatible = "simple-bus"; -- #address-cells = <1>; -- #size-cells = <2>; -- ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>, -- <0x40000000 0x0 0xff800000 0x0 0x00800000>; -- dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>; -- -- v3d: v3d@7ec04000 { -- compatible = "brcm,2711-v3d"; -- reg = -- <0x7ec00000 0x0 0x4000>, -- <0x7ec04000 0x0 0x4000>; -- reg-names = "hub", "core0"; -- -- power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; -- resets = <&pm BCM2835_RESET_V3D>; -- clocks = <&clocks BCM2835_CLOCK_V3D>; -- interrupts = ; -- status = "okay"; -- }; -- }; -- -- scb: scb { -- compatible = "simple-bus"; -- #address-cells = <2>; -- #size-cells = <1>; -- -- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, -- <0x0 0x40000000 0x0 0xff800000 0x00800000>, -- <0x6 0x00000000 0x6 0x00000000 0x40000000>, -- <0x0 0x00000000 0x0 0x00000000 0xfc000000>; -- dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; -- -- pcie_0: pcie@7d500000 { -- reg = <0x0 0x7d500000 0x9310>, -- <0x0 0x7e00f300 0x20>; -- msi-controller; -- msi-parent = <&pcie_0>; -- #address-cells = <3>; -- #interrupt-cells = <1>; -- #size-cells = <2>; -- bus-range = <0x0 0x01>; -- compatible = "brcm,bcm2711b0-pcie", // Safe value -- "brcm,bcm2711-pcie", -- "brcm,pci-plat-dev"; -- max-link-speed = <2>; -- tot-num-pcie = <1>; -- linux,pci-domain = <0>; -- interrupts = , -- ; -- interrupt-names = "pcie", "msi"; -- interrupt-map-mask = <0x0 0x0 0x0 0x7>; -- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 -- IRQ_TYPE_LEVEL_HIGH -- 0 0 0 2 &gicv2 GIC_SPI 144 -- IRQ_TYPE_LEVEL_HIGH -- 0 0 0 3 &gicv2 GIC_SPI 145 -- IRQ_TYPE_LEVEL_HIGH -- 0 0 0 4 &gicv2 GIC_SPI 146 -- IRQ_TYPE_LEVEL_HIGH>; -- -- /* Map outbound accesses from scb:0x6_00000000-03ffffff -- * to pci:0x0_f8000000-fbffffff -- */ -- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 -- 0x0 0x04000000>; -- /* Map inbound accesses from pci:0x0_00000000..ffffffff -- * to scb:0x0_00000000-ffffffff -- */ -- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 -- 0x1 0x00000000>; -- status = "okay"; -- }; -- -- genet: ethernet@7d580000 { -- compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5"; -- reg = <0x0 0x7d580000 0x10000>; -- #address-cells = <0x1>; -- #size-cells = <0x1>; -- interrupts = , -- ; -- status = "disabled"; -- -- genet_mdio: mdio@e14 { -- #address-cells = <0x0>; -- #size-cells = <0x1>; -- compatible = "brcm,genet-mdio-v5"; -- reg = <0xe14 0x8>; -- reg-names = "mdio"; -- }; -- }; -- -- dma40: dma@7e007b00 { -- compatible = "brcm,bcm2838-dma"; -- reg = <0x0 0x7e007b00 0x400>; -- interrupts = -- , /* dma4 11 */ -- , /* dma4 12 */ -- , /* dma4 13 */ -- ; /* dma4 14 */ -- interrupt-names = "dma11", -- "dma12", -- "dma13", -- "dma14"; -- #dma-cells = <1>; -- brcm,dma-channel-mask = <0x7800>; -- }; -- /* DMA4 - 40 bit DMA engines */ -- -- xhci: xhci@7e9c0000 { -- compatible = "generic-xhci"; -- status = "disabled"; -- reg = <0x0 0x7e9c0000 0x100000>; -- interrupts = ; -- }; -- -- hevc-decoder@7eb00000 { -- compatible = "raspberrypi,rpivid-hevc-decoder"; -- reg = <0x0 0x7eb00000 0x10000>; -- status = "okay"; -- }; -- -- rpivid-local-intc@7eb10000 { -- compatible = "raspberrypi,rpivid-local-intc"; -- reg = <0x0 0x7eb10000 0x1000>; -- status = "okay"; -- interrupts = ; -- }; -- -- h264-decoder@7eb20000 { -- compatible = "raspberrypi,rpivid-h264-decoder"; -- reg = <0x0 0x7eb20000 0x10000>; -- status = "okay"; -- }; -- -- vp9-decoder@7eb30000 { -- compatible = "raspberrypi,rpivid-vp9-decoder"; -- reg = <0x0 0x7eb30000 0x10000>; -- status = "okay"; -- }; -- }; --}; -- --&clk_osc { -- clock-frequency = <54000000>; --}; -- --&clocks { -- compatible = "brcm,bcm2711-cprman"; --}; -- --&cpu_thermal { -- coefficients = <(-487) 410040>; --}; -- --&dsi0 { -- interrupts = ; --}; -- --&dsi1 { -- interrupts = ; --}; -- --&gpio { -- compatible = "brcm,bcm2711-gpio", "brcm,bcm2835-gpio"; -- -- gpclk0_gpio49: gpclk0_gpio49 { -- brcm,pins = <49>; -- brcm,function = ; -- brcm,pull = ; -- }; -- gpclk1_gpio50: gpclk1_gpio50 { -- brcm,pins = <50>; -- brcm,function = ; -- brcm,pull = ; -- }; -- gpclk2_gpio51: gpclk2_gpio51 { -- brcm,pins = <51>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- i2c0_gpio46: i2c0_gpio46 { -- brcm,pins = <46 47>; -- brcm,function = ; -- }; -- i2c1_gpio46: i2c1_gpio46 { -- brcm,pins = <46 47>; -- brcm,function = ; -- }; -- i2c3_gpio2: i2c3_gpio2 { -- brcm,pins = <2 3>; -- brcm,function = ; -- }; -- i2c3_gpio4: i2c3_gpio4 { -- brcm,pins = <4 5>; -- brcm,function = ; -- }; -- i2c4_gpio6: i2c4_gpio6 { -- brcm,pins = <6 7>; -- brcm,function = ; -- }; -- i2c4_gpio8: i2c4_gpio8 { -- brcm,pins = <8 9>; -- brcm,function = ; -- }; -- i2c5_gpio10: i2c5_gpio10 { -- brcm,pins = <10 11>; -- brcm,function = ; -- }; -- i2c5_gpio12: i2c5_gpio12 { -- brcm,pins = <12 13>; -- brcm,function = ; -- }; -- i2c6_gpio0: i2c6_gpio0 { -- brcm,pins = <0 1>; -- brcm,function = ; -- }; -- i2c6_gpio22: i2c6_gpio22 { -- brcm,pins = <22 23>; -- brcm,function = ; -- }; -- i2c_slave_gpio8: i2c_slave_gpio8 { -- brcm,pins = <8 9 10 11>; -- brcm,function = ; -- }; -- -- jtag_gpio48: jtag_gpio48 { -- brcm,pins = <48 49 50 51 52 53>; -- brcm,function = ; -- }; -- -- mii_gpio28: mii_gpio28 { -- brcm,pins = <28 29 30 31>; -- brcm,function = ; -- }; -- mii_gpio36: mii_gpio36 { -- brcm,pins = <36 37 38 39>; -- brcm,function = ; -- }; -- -- pcm_gpio50: pcm_gpio50 { -- brcm,pins = <50 51 52 53>; -- brcm,function = ; -- }; -- -- pwm0_gpio52: pwm0_gpio52 { -- brcm,pins = <52>; -- brcm,function = ; -- brcm,pull = ; -- }; -- pwm1_gpio53: pwm1_gpio53 { -- brcm,pins = <53>; -- brcm,function = ; -- brcm,pull = ; -- }; -- -- /* The following group consists of: -- * RGMII_START_STOP -- * RGMII_RX_OK -- */ -- rgmii_gpio35: rgmii_gpio35 { -- brcm,pins = <35 36>; -- brcm,function = ; -- }; -- rgmii_irq_gpio34: rgmii_irq_gpio34 { -- brcm,pins = <34>; -- brcm,function = ; -- }; -- rgmii_irq_gpio39: rgmii_irq_gpio39 { -- brcm,pins = <39>; -- brcm,function = ; -- }; -- rgmii_mdio_gpio28: rgmii_mdio_gpio28 { -- brcm,pins = <28 29>; -- brcm,function = ; -- }; -- rgmii_mdio_gpio37: rgmii_mdio_gpio37 { -- brcm,pins = <37 38>; -- brcm,function = ; -- }; -- -- spi0_gpio46: spi0_gpio46 { -- brcm,pins = <46 47 48 49>; -- brcm,function = ; -- }; -- spi2_gpio46: spi2_gpio46 { -- brcm,pins = <46 47 48 49 50>; -- brcm,function = ; -- }; -- spi3_gpio0: spi3_gpio0 { -- brcm,pins = <0 1 2 3>; -- brcm,function = ; -- }; -- spi4_gpio4: spi4_gpio4 { -- brcm,pins = <4 5 6 7>; -- brcm,function = ; -- }; -- spi5_gpio12: spi5_gpio12 { -- brcm,pins = <12 13 14 15>; -- brcm,function = ; -- }; -- spi6_gpio18: spi6_gpio18 { -- brcm,pins = <18 19 20 21>; -- brcm,function = ; -- }; -- -- uart2_gpio0: uart2_gpio0 { -- brcm,pins = <0 1>; -- brcm,function = ; -- brcm,pull = ; -- }; -- uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { -- brcm,pins = <2 3>; -- brcm,function = ; -- brcm,pull = ; -- }; -- uart3_gpio4: uart3_gpio4 { -- brcm,pins = <4 5>; -- brcm,function = ; -- brcm,pull = ; -- }; -- uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { -- brcm,pins = <6 7>; -- brcm,function = ; -- brcm,pull = ; -- }; -- uart4_gpio8: uart4_gpio8 { -- brcm,pins = <8 9>; -- brcm,function = ; -- brcm,pull = ; -- }; -- uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { -- brcm,pins = <10 11>; -- brcm,function = ; -- brcm,pull = ; -- }; -- uart5_gpio12: uart5_gpio12 { -- brcm,pins = <12 13>; -- brcm,function = ; -- brcm,pull = ; -- }; -- uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { -- brcm,pins = <14 15>; -- brcm,function = ; -- brcm,pull = ; -- }; --}; -- --&vec { -- interrupts = ; --}; -- --&usb { -- interrupts = ; -- status = "disabled"; --}; -- --&hdmi { -- interrupts = , -- ; --}; -- --&uart1 { -- interrupts = ; --}; -- --&spi1 { -- interrupts = ; --}; -- --&spi2 { -- interrupts = ; --}; -- --&csi0 { -- interrupts = ; --}; -- --&csi1 { -- interrupts = ; --}; -- --&sdhci { -- interrupts = ; --}; -- --&i2c0 { -- interrupts = ; --}; -- --&i2c1 { -- interrupts = ; --}; -- --&i2c2 { -- interrupts = ; --}; -- --&gpio { -- interrupts = , -- , -- , -- ; --}; -- --&mailbox { -- interrupts = ; --}; -- --&rng { -- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; --}; -- --&sdhost { -- interrupts = ; --}; -- --&system_timer { -- interrupts = , -- , -- , -- ; --}; -- --&uart0 { -- interrupts = ; --}; -- --&dma { -- reg = <0x7e007000 0xb00>; -- interrupts = , -- , -- , -- , -- , -- , -- , -- , /* dmalite 7 */ -- , /* dmalite 8 */ -- , /* dmalite 9 */ -- ; /* dmalite 10 */ -- interrupt-names = "dma0", -- "dma1", -- "dma2", -- "dma3", -- "dma4", -- "dma5", -- "dma6", -- "dma7", -- "dma8", -- "dma9", -- "dma10"; -- brcm,dma-channel-mask = <0x07f5>; --}; -- --&txp { -- interrupts = ; --}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Rebuild-downstream-DTS-files.patch b/target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Rebuild-downstream-DTS-files.patch new file mode 100644 index 0000000000..8d230d0edb --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0417-ARM-dts-Rebuild-downstream-DTS-files.patch @@ -0,0 +1,1076 @@ +From b229e7f5a6d21d1b52f3f19fed58bba638714884 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 30 Jan 2020 15:48:00 +0000 +Subject: [PATCH] ARM: dts: Rebuild downstream DTS files + +Refactor the tree of downstream DTS files to achieve approximately the +same end result but wihout modifying upstream files (except for +bcm2711-rpi-4-b.dts). + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2708-rpi.dtsi | 133 +-------- + arch/arm/boot/dts/bcm2708.dtsi | 4 + + arch/arm/boot/dts/bcm2709.dtsi | 4 + + arch/arm/boot/dts/bcm270x-rpi.dtsi | 139 +++++++++ + arch/arm/boot/dts/bcm270x.dtsi | 98 ++++--- + arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 13 + + arch/arm/boot/dts/bcm2710.dtsi | 4 + + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 315 ++++++++++++++++++++- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 222 +++++++++++++++ + 9 files changed, 766 insertions(+), 166 deletions(-) + create mode 100644 arch/arm/boot/dts/bcm270x-rpi.dtsi + create mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi + +--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi +@@ -1,6 +1,7 @@ +-/* Downstream modifications to bcm2835-rpi.dtsi */ ++/* Downstream modifications common to bcm2835, bcm2836, bcm2837 */ + + #include "bcm2835-rpi.dtsi" ++#include "bcm270x-rpi.dtsi" + + / { + memory@0 { +@@ -9,147 +10,27 @@ + }; + + aliases { +- audio = &audio; +- aux = &aux; +- sound = &sound; +- soc = &soc; +- dma = &dma; +- intc = &intc; +- watchdog = &watchdog; +- random = &random; +- mailbox = &mailbox; +- gpio = &gpio; +- uart0 = &uart0; +- sdhost = &sdhost; +- mmc0 = &sdhost; +- i2s = &i2s; +- spi0 = &spi0; +- i2c0 = &i2c0; +- uart1 = &uart1; +- spi1 = &spi1; +- spi2 = &spi2; +- mmc = &mmc; +- mmc1 = &mmc; +- i2c1 = &i2c1; + i2c2 = &i2c2; +- usb = &usb; +- leds = &leds; +- fb = &fb; +- thermal = &thermal; +- axiperf = &axiperf; +- }; +- +- leds: leds { +- compatible = "gpio-leds"; +- }; +- +- soc { +- gpiomem { +- compatible = "brcm,bcm2835-gpiomem"; +- reg = <0x7e200000 0x1000>; +- }; +- +- fb: fb { +- compatible = "brcm,bcm2708-fb"; +- firmware = <&firmware>; +- status = "okay"; +- }; +- +- vcsm: vcsm { +- compatible = "raspberrypi,bcm2835-vcsm"; +- firmware = <&firmware>; +- status = "okay"; +- }; +- +- /* Onboard audio */ +- audio: audio { +- compatible = "brcm,bcm2835-audio"; +- brcm,pwm-channels = <8>; +- status = "disabled"; +- }; +- +- /* External sound card */ +- sound: sound { +- status = "disabled"; +- }; + }; + + __overrides__ { +- cache_line_size; +- +- uart0 = <&uart0>,"status"; +- uart1 = <&uart1>,"status"; +- i2s = <&i2s>,"status"; +- spi = <&spi0>,"status"; +- i2c0 = <&i2c0>,"status"; +- i2c1 = <&i2c1>,"status"; + i2c2_iknowwhatimdoing = <&i2c2>,"status"; +- i2c0_baudrate = <&i2c0>,"clock-frequency:0"; +- i2c1_baudrate = <&i2c1>,"clock-frequency:0"; + i2c2_baudrate = <&i2c2>,"clock-frequency:0"; +- +- audio = <&audio>,"status"; +- watchdog = <&watchdog>,"status"; +- random = <&random>,"status"; +- sd_overclock = <&sdhost>,"brcm,overclock-50:0"; +- sd_poll_once = <&sdhost>,"non-removable?"; +- sd_force_pio = <&sdhost>,"brcm,force-pio?"; +- sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; +- sd_debug = <&sdhost>,"brcm,debug"; +- sdio_overclock = <&mmc>,"brcm,overclock-50:0", +- <&mmcnr>,"brcm,overclock-50:0"; +- axiperf = <&axiperf>,"status"; ++ sd_poll_once = <&sdhost>, "non-removable?"; + }; + }; + +-&hdmi { +- power-domains = <&power RPI_POWER_DOMAIN_HDMI>; +- status = "disabled"; +-}; +- +-&txp { +- status = "disabled"; +-}; +- +-&i2c0 { +- status = "disabled"; +-}; +- +-&i2c1 { +- status = "disabled"; +-}; +- +-&i2c2 { +- status = "disabled"; +-}; +- +-&clocks { +- firmware = <&firmware>; +-}; +- +-&sdhci { +- pinctrl-names = "default"; +- pinctrl-0 = <&emmc_gpio48>; +- bus-width = <4>; +-}; +- +-sdhost_pins: &sdhost_gpio48 { +- /* Add alias */ +-}; +- + &sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; +- bus-width = <4>; +- brcm,overclock-50 = <0>; +- brcm,pio-limit = <1>; + status = "okay"; + }; + +-&cpu_thermal { +- /delete-node/ trips; ++&hdmi { ++ power-domains = <&power RPI_POWER_DOMAIN_HDMI>; ++ status = "disabled"; + }; + +-&vec { ++&i2c2 { + status = "disabled"; + }; +--- a/arch/arm/boot/dts/bcm2708.dtsi ++++ b/arch/arm/boot/dts/bcm2708.dtsi +@@ -8,3 +8,7 @@ + arm_freq; + }; + }; ++ ++&vc4 { ++ status = "disabled"; ++}; +--- a/arch/arm/boot/dts/bcm2709.dtsi ++++ b/arch/arm/boot/dts/bcm2709.dtsi +@@ -16,3 +16,7 @@ + <&v7_cpu3>, "clock-frequency:0"; + }; + }; ++ ++&vc4 { ++ status = "disabled"; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi +@@ -0,0 +1,139 @@ ++/* Downstream modifications to bcm2835-rpi.dtsi */ ++ ++/ { ++ aliases { ++ audio = &audio; ++ aux = &aux; ++ sound = &sound; ++ soc = &soc; ++ dma = &dma; ++ intc = &intc; ++ watchdog = &watchdog; ++ random = &random; ++ mailbox = &mailbox; ++ gpio = &gpio; ++ uart0 = &uart0; ++ uart1 = &uart1; ++ sdhost = &sdhost; ++ mmc = &mmc; ++ mmc1 = &mmc; ++ mmc0 = &sdhost; ++ i2s = &i2s; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ spi0 = &spi0; ++ spi1 = &spi1; ++ spi2 = &spi2; ++ usb = &usb; ++ leds = &leds; ++ fb = &fb; ++ thermal = &thermal; ++ axiperf = &axiperf; ++ }; ++ ++ /* Define these notional regulators for use by overlays */ ++ vdd_3v3_reg: fixedregulator_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <3300000>; ++ regulator-min-microvolt = <3300000>; ++ regulator-name = "3v3"; ++ }; ++ ++ vdd_5v0_reg: fixedregulator_5v0 { ++ compatible = "regulator-fixed"; ++ regulator-always-on; ++ regulator-max-microvolt = <5000000>; ++ regulator-min-microvolt = <5000000>; ++ regulator-name = "5v0"; ++ }; ++ ++ leds: leds { ++ compatible = "gpio-leds"; ++ }; ++ ++ soc { ++ gpiomem { ++ compatible = "brcm,bcm2835-gpiomem"; ++ reg = <0x7e200000 0x1000>; ++ }; ++ ++ fb: fb { ++ compatible = "brcm,bcm2708-fb"; ++ firmware = <&firmware>; ++ status = "okay"; ++ }; ++ ++ vcsm: vcsm { ++ compatible = "raspberrypi,bcm2835-vcsm"; ++ firmware = <&firmware>; ++ status = "okay"; ++ }; ++ ++ /* Onboard audio */ ++ audio: audio { ++ compatible = "brcm,bcm2835-audio"; ++ brcm,pwm-channels = <8>; ++ status = "disabled"; ++ }; ++ ++ /* External sound card */ ++ sound: sound { ++ status = "disabled"; ++ }; ++ }; ++ ++ __overrides__ { ++ cache_line_size; ++ ++ uart0 = <&uart0>,"status"; ++ uart1 = <&uart1>,"status"; ++ i2s = <&i2s>,"status"; ++ spi = <&spi0>,"status"; ++ i2c0 = <&i2c0>,"status"; ++ i2c1 = <&i2c1>,"status"; ++ i2c0_baudrate = <&i2c0>,"clock-frequency:0"; ++ i2c1_baudrate = <&i2c1>,"clock-frequency:0"; ++ ++ audio = <&audio>,"status"; ++ watchdog = <&watchdog>,"status"; ++ random = <&random>,"status"; ++ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; ++ sd_force_pio = <&sdhost>,"brcm,force-pio?"; ++ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; ++ sd_debug = <&sdhost>,"brcm,debug"; ++ sdio_overclock = <&mmc>,"brcm,overclock-50:0", ++ <&mmcnr>,"brcm,overclock-50:0"; ++ axiperf = <&axiperf>,"status"; ++ }; ++}; ++ ++&txp { ++ status = "disabled"; ++}; ++ ++&i2c0 { ++ status = "disabled"; ++}; ++ ++&i2c1 { ++ status = "disabled"; ++}; ++ ++&clocks { ++ firmware = <&firmware>; ++}; ++ ++&sdhci { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_gpio48>; ++ bus-width = <4>; ++}; ++ ++&cpu_thermal { ++ /delete-node/ trips; ++}; ++ ++&vec { ++ status = "disabled"; ++}; +--- a/arch/arm/boot/dts/bcm270x.dtsi ++++ b/arch/arm/boot/dts/bcm270x.dtsi +@@ -17,32 +17,8 @@ + /* Add label */ + }; + +- gpio@7e200000 { /* gpio */ +- interrupts = <2 17>, <2 18>; +- +- dpi_18bit_gpio0: dpi_18bit_gpio0 { +- brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11 +- 12 13 14 15 16 17 18 19 +- 20 21>; +- brcm,function = ; +- }; +- }; +- +- serial@7e201000 { /* uart0 */ +- /* Enable CTS bug workaround */ +- cts-event-workaround; +- }; +- +- i2s@7e203000 { /* i2s */ +- #sound-dai-cells = <0>; +- reg = <0x7e203000 0x24>; +- clocks = <&clocks BCM2835_CLOCK_PCM>; +- }; +- + spi0: spi@7e204000 { + /* Add label */ +- dmas = <&dma 6>, <&dma 7>; +- dma-names = "tx", "rx"; + }; + + pixelvalve0: pixelvalve@7e206000 { +@@ -55,17 +31,6 @@ + status = "disabled"; + }; + +- dpi: dpi@7e208000 { +- compatible = "brcm,bcm2835-dpi"; +- reg = <0x7e208000 0x8c>; +- clocks = <&clocks BCM2835_CLOCK_VPU>, +- <&clocks BCM2835_CLOCK_DPI>; +- clock-names = "core", "pixel"; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- + /delete-node/ sdhci@7e300000; + + sdhci: mmc: mmc@7e300000 { +@@ -118,6 +83,34 @@ + status = "disabled"; + }; + ++ csi0: csi@7e800000 { ++ compatible = "brcm,bcm2835-unicam"; ++ reg = <0x7e800000 0x800>, ++ <0x7e802000 0x4>; ++ interrupts = <2 6>; ++ clocks = <&clocks BCM2835_CLOCK_CAM0>; ++ clock-names = "lp"; ++ power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #clock-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ csi1: csi@7e801000 { ++ compatible = "brcm,bcm2835-unicam"; ++ reg = <0x7e801000 0x800>, ++ <0x7e802004 0x4>; ++ interrupts = <2 7>; ++ clocks = <&clocks BCM2835_CLOCK_CAM1>; ++ clock-names = "lp"; ++ power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ #clock-cells = <1>; ++ status = "disabled"; ++ }; ++ + pixelvalve2: pixelvalve@7e807000 { + /* Add label */ + status = "disabled"; +@@ -160,6 +153,37 @@ + }; + }; + +-&vc4 { +- status = "disabled"; ++&gpio { ++ interrupts = <2 17>, <2 18>; ++ ++ dpi_18bit_gpio0: dpi_18bit_gpio0 { ++ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11 ++ 12 13 14 15 16 17 18 19 ++ 20 21>; ++ brcm,function = ; ++ }; ++}; ++ ++&uart0 { ++ /* Enable CTS bug workaround */ ++ cts-event-workaround; ++}; ++ ++&i2s { ++ #sound-dai-cells = <0>; ++ dmas = <&dma 2>, <&dma 3>; ++ dma-names = "tx", "rx"; ++}; ++ ++&sdhost { ++ dmas = <&dma (13|(1<<29))>; ++ dma-names = "rx-tx"; ++ bus-width = <4>; ++ brcm,overclock-50 = <0>; ++ brcm,pio-limit = <1>; ++}; ++ ++&spi0 { ++ dmas = <&dma 6>, <&dma 7>; ++ dma-names = "tx", "rx"; + }; +--- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts ++++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts +@@ -170,6 +170,12 @@ + pinctrl-0 = <&audio_pins>; + }; + ++ð_phy { ++ microchip,eee-enabled; ++ microchip,tx-lpi-timer = <600>; /* non-aggressive*/ ++ microchip,downshift-after = <2>; ++}; ++ + / { + __overrides__ { + act_led_gpio = <&act_led>,"gpios:4"; +@@ -179,5 +185,12 @@ + pwr_led_gpio = <&pwr_led>,"gpios:4"; + pwr_led_activelow = <&pwr_led>,"gpios:8"; + pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; ++ ++ eee = <ð_phy>,"microchip,eee-enabled?"; ++ tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0"; ++ eth_led0 = <ð_phy>,"microchip,led-modes:0"; ++ eth_led1 = <ð_phy>,"microchip,led-modes:4"; ++ eth_downshift_after = <ð_phy>,"microchip,downshift-after:0"; ++ eth_max_speed = <ð_phy>,"max-speed:0"; + }; + }; +--- a/arch/arm/boot/dts/bcm2710.dtsi ++++ b/arch/arm/boot/dts/bcm2710.dtsi +@@ -23,3 +23,7 @@ + <&cpu3>, "clock-frequency:0"; + }; + }; ++ ++&vc4 { ++ status = "disabled"; ++}; +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -2,7 +2,6 @@ + /dts-v1/; + #include "bcm2711.dtsi" + #include "bcm2835-rpi.dtsi" +-#include "bcm283x-rpi-usb-peripheral.dtsi" + + / { + compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; +@@ -65,8 +64,8 @@ + "GLOBAL_RESET", + "VDD_SD_IO_SEL", + "CAM_GPIO", +- "", +- ""; ++ "SD_PWR_ON", ++ "SD_OC_N"; + status = "okay"; + }; + }; +@@ -138,3 +137,313 @@ + &vchiq { + interrupts = ; + }; ++ ++// ============================================= ++// Downstream rpi- changes ++ ++#include "bcm270x.dtsi" ++#include "bcm2711-rpi.dtsi" ++#include "bcm283x-rpi-csi1-2lane.dtsi" ++ ++/ { ++ chosen { ++ bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M"; ++ }; ++ ++ aliases { ++ serial0 = &uart1; ++ serial1 = &uart0; ++ mmc0 = &emmc2; ++ mmc1 = &mmcnr; ++ mmc2 = &sdhost; ++ /delete-property/ i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ i2c5 = &i2c5; ++ i2c6 = &i2c6; ++ /delete-property/ ethernet; ++ /delete-property/ intc; ++ pcie0 = &pcie_0; ++ }; ++ ++ /delete-node/ wifi-pwrseq; ++}; ++ ++&mmcnr { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio_pins>; ++ bus-width = <4>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-0 = <&uart0_pins &bt_pins>; ++ status = "okay"; ++ ++ /delete-node/ bluetooth; ++}; ++ ++&uart1 { ++ pinctrl-0 = <&uart1_pins>; ++}; ++ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_pins &spi0_cs_pins>; ++ cs-gpios = <&gpio 8 1>, <&gpio 7 1>; ++ ++ spidev0: spidev@0{ ++ compatible = "spidev"; ++ reg = <0>; /* CE0 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++ ++ spidev1: spidev@1{ ++ compatible = "spidev"; ++ reg = <1>; /* CE1 */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ spi-max-frequency = <125000000>; ++ }; ++}; ++ ++&gpio { ++ spi0_pins: spi0_pins { ++ brcm,pins = <9 10 11>; ++ brcm,function = ; ++ }; ++ ++ spi0_cs_pins: spi0_cs_pins { ++ brcm,pins = <8 7>; ++ brcm,function = ; ++ }; ++ ++ spi3_pins: spi3_pins { ++ brcm,pins = <1 2 3>; ++ brcm,function = ; ++ }; ++ ++ spi3_cs_pins: spi3_cs_pins { ++ brcm,pins = <0 24>; ++ brcm,function = ; ++ }; ++ ++ spi4_pins: spi4_pins { ++ brcm,pins = <5 6 7>; ++ brcm,function = ; ++ }; ++ ++ spi4_cs_pins: spi4_cs_pins { ++ brcm,pins = <4 25>; ++ brcm,function = ; ++ }; ++ ++ spi5_pins: spi5_pins { ++ brcm,pins = <13 14 15>; ++ brcm,function = ; ++ }; ++ ++ spi5_cs_pins: spi5_cs_pins { ++ brcm,pins = <12 26>; ++ brcm,function = ; ++ }; ++ ++ spi6_pins: spi6_pins { ++ brcm,pins = <19 20 21>; ++ brcm,function = ; ++ }; ++ ++ spi6_cs_pins: spi6_cs_pins { ++ brcm,pins = <18 27>; ++ brcm,function = ; ++ }; ++ ++ i2c0_pins: i2c0 { ++ brcm,pins = <0 1>; ++ brcm,function = ; ++ brcm,pull = ; ++ }; ++ ++ i2c1_pins: i2c1 { ++ brcm,pins = <2 3>; ++ brcm,function = ; ++ brcm,pull = ; ++ }; ++ ++ i2c3_pins: i2c3 { ++ brcm,pins = <4 5>; ++ brcm,function = ; ++ brcm,pull = ; ++ }; ++ ++ i2c4_pins: i2c4 { ++ brcm,pins = <8 9>; ++ brcm,function = ; ++ brcm,pull = ; ++ }; ++ ++ i2c5_pins: i2c5 { ++ brcm,pins = <12 13>; ++ brcm,function = ; ++ brcm,pull = ; ++ }; ++ ++ i2c6_pins: i2c6 { ++ brcm,pins = <22 23>; ++ brcm,function = ; ++ brcm,pull = ; ++ }; ++ ++ i2s_pins: i2s { ++ brcm,pins = <18 19 20 21>; ++ brcm,function = ; ++ }; ++ ++ sdio_pins: sdio_pins { ++ brcm,pins = <34 35 36 37 38 39>; ++ brcm,function = ; // alt3 = SD1 ++ brcm,pull = <0 2 2 2 2 2>; ++ }; ++ ++ bt_pins: bt_pins { ++ brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0 ++ // to fool pinctrl ++ brcm,function = <0>; ++ brcm,pull = <2>; ++ }; ++ ++ uart0_pins: uart0_pins { ++ brcm,pins = <32 33>; ++ brcm,function = ; ++ brcm,pull = <0 2>; ++ }; ++ ++ uart1_pins: uart1_pins { ++ brcm,pins; ++ brcm,function; ++ brcm,pull; ++ }; ++ ++ uart2_pins: uart2_pins { ++ brcm,pins = <0 1>; ++ brcm,function = ; ++ brcm,pull = <0 2>; ++ }; ++ ++ uart3_pins: uart3_pins { ++ brcm,pins = <4 5>; ++ brcm,function = ; ++ brcm,pull = <0 2>; ++ }; ++ ++ uart4_pins: uart4_pins { ++ brcm,pins = <8 9>; ++ brcm,function = ; ++ brcm,pull = <0 2>; ++ }; ++ ++ uart5_pins: uart5_pins { ++ brcm,pins = <12 13>; ++ brcm,function = ; ++ brcm,pull = <0 2>; ++ }; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ clock-frequency = <100000>; ++}; ++ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; ++ clock-frequency = <100000>; ++}; ++ ++&i2s { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2s_pins>; ++}; ++ ++/ { ++ __overrides__ { ++ /delete-property/ i2c2_baudrate; ++ /delete-property/ i2c2_iknowwhatimdoing; ++ }; ++}; ++ ++// ============================================= ++// Board specific stuff here ++ ++/ { ++ sd_vcc_reg: sd_vcc_reg { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-sd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ enable-active-high; ++ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&sdhost { ++ status = "disabled"; ++}; ++ ++&emmc2 { ++ vmmc-supply = <&sd_vcc_reg>; ++}; ++ ++&phy1 { ++ led-modes = <0x00 0x08>; /* link/activity link */ ++}; ++ ++&gpio { ++ audio_pins: audio_pins { ++ brcm,pins = <40 41>; ++ brcm,function = <4>; ++ }; ++}; ++ ++&leds { ++ act_led: act { ++ label = "led0"; ++ linux,default-trigger = "mmc0"; ++ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ pwr_led: pwr { ++ label = "led1"; ++ linux,default-trigger = "default-on"; ++ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; ++ }; ++}; ++ ++&pwm1 { ++ status = "disabled"; ++}; ++ ++&audio { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&audio_pins>; ++}; ++ ++/ { ++ __overrides__ { ++ act_led_gpio = <&act_led>,"gpios:4"; ++ act_led_activelow = <&act_led>,"gpios:8"; ++ act_led_trigger = <&act_led>,"linux,default-trigger"; ++ ++ pwr_led_gpio = <&pwr_led>,"gpios:4"; ++ pwr_led_activelow = <&pwr_led>,"gpios:8"; ++ pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; ++ ++ eth_led0 = <&phy1>,"led-modes:0"; ++ eth_led1 = <&phy1>,"led-modes:4"; ++ ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -0,0 +1,222 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include "bcm270x-rpi.dtsi" ++ ++/ { ++ soc { ++ /delete-node/ v3d@7ec00000; ++ /delete-node/ mailbox@7e00b840; ++ }; ++ ++ __overrides__ { ++ arm_freq; ++ sd_poll_once = <&emmc2>, "non-removable?"; ++ }; ++ ++ v3dbus { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <2>; ++ ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>, ++ <0x40000000 0x0 0xff800000 0x0 0x00800000>; ++ dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>; ++ ++ v3d: v3d@7ec04000 { ++ compatible = "brcm,2711-v3d"; ++ reg = ++ <0x7ec00000 0x0 0x4000>, ++ <0x7ec04000 0x0 0x4000>; ++ reg-names = "hub", "core0"; ++ ++ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; ++ resets = <&pm BCM2835_RESET_V3D>; ++ clocks = <&clocks BCM2835_CLOCK_V3D>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ }; ++ ++ scb: scb { ++ /* Add a label */ ++ }; ++}; ++ ++&soc { ++ thermal: thermal@7d5d2200 { ++ compatible = "brcm,avs-tmon-bcm2838"; ++ reg = <0x7d5d2200 0x2c>; ++ interrupts = ; ++ interrupt-names = "tmon"; ++ clocks = <&clocks BCM2835_CLOCK_TSENS>; ++ #thermal-sensor-cells = <0>; ++ status = "okay"; ++ }; ++ ++ vc4: gpu { ++ compatible = "brcm,bcm2835-vc4"; ++ status = "disabled"; ++ }; ++}; ++ ++&scb { ++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, ++ <0x0 0x40000000 0x0 0xff800000 0x00800000>, ++ <0x6 0x00000000 0x6 0x00000000 0x40000000>, ++ <0x0 0x00000000 0x0 0x00000000 0xfc000000>; ++ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; ++ ++ pcie_0: pcie@7d500000 { ++ reg = <0x0 0x7d500000 0x9310>, ++ <0x0 0x7e00f300 0x20>; ++ msi-controller; ++ msi-parent = <&pcie_0>; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ bus-range = <0x0 0x01>; ++ compatible = "brcm,bcm2711b0-pcie", // Safe value ++ "brcm,bcm2711-pcie", ++ "brcm,pci-plat-dev"; ++ max-link-speed = <2>; ++ tot-num-pcie = <1>; ++ linux,pci-domain = <0>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 ++ IRQ_TYPE_LEVEL_HIGH ++ 0 0 0 2 &gicv2 GIC_SPI 144 ++ IRQ_TYPE_LEVEL_HIGH ++ 0 0 0 3 &gicv2 GIC_SPI 145 ++ IRQ_TYPE_LEVEL_HIGH ++ 0 0 0 4 &gicv2 GIC_SPI 146 ++ IRQ_TYPE_LEVEL_HIGH>; ++ ++ /* Map outbound accesses from scb:0x6_00000000-03ffffff ++ * to pci:0x0_f8000000-fbffffff ++ */ ++ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 ++ 0x0 0x04000000>; ++ /* Map inbound accesses from pci:0x0_00000000..ffffffff ++ * to scb:0x0_00000000-ffffffff ++ */ ++ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 ++ 0x1 0x00000000>; ++ status = "okay"; ++ }; ++ ++ dma40: dma@7e007b00 { ++ compatible = "brcm,bcm2838-dma"; ++ reg = <0x0 0x7e007b00 0x400>; ++ interrupts = ++ , /* dma4 11 */ ++ , /* dma4 12 */ ++ , /* dma4 13 */ ++ ; /* dma4 14 */ ++ interrupt-names = "dma11", ++ "dma12", ++ "dma13", ++ "dma14"; ++ #dma-cells = <1>; ++ brcm,dma-channel-mask = <0x7800>; ++ }; ++ ++ vchiq: mailbox@7e00b840 { ++ compatible = "brcm,bcm2838-vchiq"; ++ reg = <0 0x7e00b840 0x3c>; ++ interrupts = ; ++ }; ++ ++ xhci: xhci@7e9c0000 { ++ compatible = "generic-xhci"; ++ status = "disabled"; ++ reg = <0x0 0x7e9c0000 0x100000>; ++ interrupts = ; ++ }; ++ ++ hevc-decoder@7eb00000 { ++ compatible = "raspberrypi,rpivid-hevc-decoder"; ++ reg = <0x0 0x7eb00000 0x10000>; ++ status = "okay"; ++ }; ++ ++ rpivid-local-intc@7eb10000 { ++ compatible = "raspberrypi,rpivid-local-intc"; ++ reg = <0x0 0x7eb10000 0x1000>; ++ status = "okay"; ++ interrupts = ; ++ }; ++ ++ h264-decoder@7eb20000 { ++ compatible = "raspberrypi,rpivid-h264-decoder"; ++ reg = <0x0 0x7eb20000 0x10000>; ++ status = "okay"; ++ }; ++ ++ vp9-decoder@7eb30000 { ++ compatible = "raspberrypi,rpivid-vp9-decoder"; ++ reg = <0x0 0x7eb30000 0x10000>; ++ status = "okay"; ++ }; ++}; ++ ++&dma { ++ /* The VPU firmware uses DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x1f5>; ++}; ++ ++&dma40 { ++ /* The VPU firmware DMA channel 11 for VCHIQ */ ++ brcm,dma-channel-mask = <0x7000>; ++}; ++ ++&firmwarekms { ++ interrupts = ; ++}; ++ ++&smi { ++ interrupts = ; ++}; ++ ++&mmc { ++ interrupts = ; ++}; ++ ++&mmcnr { ++ interrupts = ; ++}; ++ ++&csi0 { ++ interrupts = ; ++}; ++ ++&csi1 { ++ interrupts = ; ++}; ++ ++&random { ++ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; ++ status = "okay"; ++}; ++ ++&usb { ++ /* Enable the FIQ support */ ++ reg = <0x7e980000 0x10000>, ++ <0x7e00b200 0x200>; ++ interrupts = , ++ ; ++ status = "disabled"; ++}; ++ ++&gpio { ++ interrupts = , ++ ; ++}; ++ ++&cpu_thermal { ++ thermal-sensors = <&thermal>; ++}; ++ ++&genet { ++ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5"; ++}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0418-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch b/target/linux/bcm27xx/patches-5.4/950-0418-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch deleted file mode 100644 index 15e4f53a0a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0418-ARM-dts-Add-minimal-Raspberry-Pi-4-support.patch +++ /dev/null @@ -1,1024 +0,0 @@ -From 19a0ac654994661f63f7c9e099ed91a1210af161 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Sun, 6 Oct 2019 15:41:25 +0200 -Subject: [PATCH] ARM: dts: Add minimal Raspberry Pi 4 support - -This adds minimal support for the new Raspberry Pi 4 without the -fancy stuff like GENET, PCIe, xHCI, 40 bit DMA and V3D. The RPi 4 is -available in 3 different variants (1, 2 and 4 GB RAM), so leave the memory -size to zero and let the bootloader take care of it. The DWC2 is still -usable as peripheral via the USB-C port. - -Other differences to the Raspberry Pi 3: -- additional GIC 400 Interrupt controller -- new thermal IP and HWRNG -- additional MMC interface (emmc2) -- additional UART, I2C, SPI and PWM interfaces -- clock stretching bug in I2C IP has been fixed - -Signed-off-by: Stefan Wahren -Acked-by: Eric Anholt -Acked-by: Florian Fanelli ---- - arch/arm/boot/dts/Makefile | 1 + - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 123 +++ - arch/arm/boot/dts/bcm2711.dtsi | 844 ++++++++++++++++++ - .../boot/dts/bcm283x-rpi-usb-peripheral.dtsi | 7 + - 4 files changed, 975 insertions(+) - create mode 100644 arch/arm/boot/dts/bcm2711-rpi-4-b.dts - create mode 100644 arch/arm/boot/dts/bcm2711.dtsi - create mode 100644 arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi - ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -97,6 +97,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ - bcm2837-rpi-3-b.dtb \ - bcm2837-rpi-3-b-plus.dtb \ - bcm2837-rpi-cm3-io3.dtb \ -+ bcm2711-rpi-4-b.dtb \ - bcm2835-rpi-zero.dtb \ - bcm2835-rpi-zero-w.dtb - dtb-$(CONFIG_ARCH_BCM_5301X) += \ ---- /dev/null -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -0,0 +1,123 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/dts-v1/; -+#include "bcm2711.dtsi" -+#include "bcm2835-rpi.dtsi" -+#include "bcm283x-rpi-usb-peripheral.dtsi" -+ -+/ { -+ compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; -+ model = "Raspberry Pi 4 Model B"; -+ -+ chosen { -+ /* 8250 auxiliary UART instead of pl011 */ -+ stdout-path = "serial1:115200n8"; -+ }; -+ -+ /* Will be filled by the bootloader */ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0 0 0>; -+ }; -+ -+ leds { -+ act { -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ pwr { -+ label = "PWR"; -+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -+ }; -+ }; -+ -+ wifi_pwrseq: wifi-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>; -+ }; -+ -+ sd_io_1v8_reg: sd_io_1v8_reg { -+ compatible = "regulator-gpio"; -+ regulator-name = "vdd-sd-io"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ regulator-settling-time-us = <5000>; -+ gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>; -+ states = <1800000 0x1 -+ 3300000 0x0>; -+ status = "okay"; -+ }; -+}; -+ -+&firmware { -+ expgpio: gpio { -+ compatible = "raspberrypi,firmware-gpio"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ gpio-line-names = "BT_ON", -+ "WL_ON", -+ "PWR_LED_OFF", -+ "GLOBAL_RESET", -+ "VDD_SD_IO_SEL", -+ "CAM_GPIO", -+ "", -+ ""; -+ status = "okay"; -+ }; -+}; -+ -+&pwm1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm1_0_gpio40 &pwm1_1_gpio41>; -+ status = "okay"; -+}; -+ -+/* SDHCI is used to control the SDIO for wireless */ -+&sdhci { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_gpio34>; -+ bus-width = <4>; -+ non-removable; -+ mmc-pwrseq = <&wifi_pwrseq>; -+ status = "okay"; -+ -+ brcmf: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ }; -+}; -+ -+/* EMMC2 is used to drive the SD card */ -+&emmc2 { -+ vqmmc-supply = <&sd_io_1v8_reg>; -+ broken-cd; -+ status = "okay"; -+}; -+ -+/* uart0 communicates with the BT module */ -+&uart0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>; -+ uart-has-rtscts; -+ status = "okay"; -+ -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <2000000>; -+ shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>; -+ }; -+}; -+ -+/* uart1 is mapped to the pin header */ -+&uart1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart1_gpio14>; -+ status = "okay"; -+}; -+ -+&vchiq { -+ interrupts = ; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -0,0 +1,844 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include "bcm283x.dtsi" -+ -+#include -+#include -+ -+/ { -+ compatible = "brcm,bcm2711"; -+ -+ #address-cells = <2>; -+ #size-cells = <1>; -+ -+ interrupt-parent = <&gicv2>; -+ -+ soc { -+ /* -+ * Defined ranges: -+ * Common BCM283x peripherals -+ * BCM2711-specific peripherals -+ * ARM-local peripherals -+ */ -+ ranges = <0x7e000000 0x0 0xfe000000 0x01800000>, -+ <0x7c000000 0x0 0xfc000000 0x02000000>, -+ <0x40000000 0x0 0xff800000 0x00800000>; -+ /* Emulate a contiguous 30-bit address range for DMA */ -+ dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>; -+ -+ /* -+ * This node is the provider for the enable-method for -+ * bringing up secondary cores. -+ */ -+ local_intc: local_intc@40000000 { -+ compatible = "brcm,bcm2836-l1-intc"; -+ reg = <0x40000000 0x100>; -+ }; -+ -+ gicv2: interrupt-controller@40041000 { -+ interrupt-controller; -+ #interrupt-cells = <3>; -+ compatible = "arm,gic-400"; -+ reg = <0x40041000 0x1000>, -+ <0x40042000 0x2000>, -+ <0x40044000 0x2000>, -+ <0x40046000 0x2000>; -+ interrupts = ; -+ }; -+ -+ dma: dma@7e007000 { -+ compatible = "brcm,bcm2835-dma"; -+ reg = <0x7e007000 0xb00>; -+ interrupts = , -+ , -+ , -+ , -+ , -+ , -+ , -+ /* DMA lite 7 - 10 */ -+ , -+ , -+ , -+ ; -+ interrupt-names = "dma0", -+ "dma1", -+ "dma2", -+ "dma3", -+ "dma4", -+ "dma5", -+ "dma6", -+ "dma7", -+ "dma8", -+ "dma9", -+ "dma10"; -+ #dma-cells = <1>; -+ brcm,dma-channel-mask = <0x07f5>; -+ }; -+ -+ pm: watchdog@7e100000 { -+ compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt"; -+ #power-domain-cells = <1>; -+ #reset-cells = <1>; -+ reg = <0x7e100000 0x114>, -+ <0x7e00a000 0x24>, -+ <0x7ec11000 0x20>; -+ clocks = <&clocks BCM2835_CLOCK_V3D>, -+ <&clocks BCM2835_CLOCK_PERI_IMAGE>, -+ <&clocks BCM2835_CLOCK_H264>, -+ <&clocks BCM2835_CLOCK_ISP>; -+ clock-names = "v3d", "peri_image", "h264", "isp"; -+ system-power-controller; -+ }; -+ -+ rng@7e104000 { -+ interrupts = ; -+ -+ /* RNG is incompatible with brcm,bcm2835-rng */ -+ status = "disabled"; -+ }; -+ -+ uart2: serial@7e201400 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201400 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart3: serial@7e201600 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201600 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart4: serial@7e201800 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201800 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ uart5: serial@7e201a00 { -+ compatible = "arm,pl011", "arm,primecell"; -+ reg = <0x7e201a00 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_UART>, -+ <&clocks BCM2835_CLOCK_VPU>; -+ clock-names = "uartclk", "apb_pclk"; -+ arm,primecell-periphid = <0x00241011>; -+ status = "disabled"; -+ }; -+ -+ spi3: spi@7e204600 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204600 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi4: spi@7e204800 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204800 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi5: spi@7e204a00 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204a00 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ spi6: spi@7e204c00 { -+ compatible = "brcm,bcm2835-spi"; -+ reg = <0x7e204c00 0x0200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c3: i2c@7e205600 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205600 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c4: i2c@7e205800 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205800 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c5: i2c@7e205a00 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205a00 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c6: i2c@7e205c00 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ reg = <0x7e205c00 0x200>; -+ interrupts = ; -+ clocks = <&clocks BCM2835_CLOCK_VPU>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ pwm1: pwm@7e20c800 { -+ compatible = "brcm,bcm2835-pwm"; -+ reg = <0x7e20c800 0x28>; -+ clocks = <&clocks BCM2835_CLOCK_PWM>; -+ assigned-clocks = <&clocks BCM2835_CLOCK_PWM>; -+ assigned-clock-rates = <10000000>; -+ #pwm-cells = <2>; -+ status = "disabled"; -+ }; -+ -+ emmc2: emmc2@7e340000 { -+ compatible = "brcm,bcm2711-emmc2"; -+ reg = <0x7e340000 0x100>; -+ interrupts = ; -+ clocks = <&clocks BCM2711_CLOCK_EMMC2>; -+ status = "disabled"; -+ }; -+ -+ hvs@7e400000 { -+ interrupts = ; -+ }; -+ }; -+ -+ arm-pmu { -+ compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3"; -+ interrupts = , -+ , -+ , -+ ; -+ interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; -+ }; -+ -+ timer { -+ compatible = "arm,armv8-timer"; -+ interrupts = , -+ , -+ , -+ ; -+ /* This only applies to the ARMv7 stub */ -+ arm,cpu-registers-not-fw-configured; -+ }; -+ -+ cpus: cpus { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ enable-method = "brcm,bcm2836-smp"; // for ARM 32-bit -+ -+ cpu0: cpu@0 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <0>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000d8>; -+ }; -+ -+ cpu1: cpu@1 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <1>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000e0>; -+ }; -+ -+ cpu2: cpu@2 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <2>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000e8>; -+ }; -+ -+ cpu3: cpu@3 { -+ device_type = "cpu"; -+ compatible = "arm,cortex-a72"; -+ reg = <3>; -+ enable-method = "spin-table"; -+ cpu-release-addr = <0x0 0x000000f0>; -+ }; -+ }; -+}; -+ -+&clk_osc { -+ clock-frequency = <54000000>; -+}; -+ -+&clocks { -+ compatible = "brcm,bcm2711-cprman"; -+}; -+ -+&cpu_thermal { -+ coefficients = <(-487) 410040>; -+}; -+ -+&dsi0 { -+ interrupts = ; -+}; -+ -+&dsi1 { -+ interrupts = ; -+}; -+ -+&gpio { -+ compatible = "brcm,bcm2711-gpio"; -+ interrupts = , -+ , -+ , -+ ; -+ -+ gpclk0_gpio49: gpclk0_gpio49 { -+ pin-gpclk { -+ pins = "gpio49"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ gpclk1_gpio50: gpclk1_gpio50 { -+ pin-gpclk { -+ pins = "gpio50"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ gpclk2_gpio51: gpclk2_gpio51 { -+ pin-gpclk { -+ pins = "gpio51"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ -+ i2c0_gpio46: i2c0_gpio46 { -+ pin-sda { -+ function = "alt0"; -+ pins = "gpio46"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt0"; -+ pins = "gpio47"; -+ bias-disable; -+ }; -+ }; -+ i2c1_gpio46: i2c1_gpio46 { -+ pin-sda { -+ function = "alt1"; -+ pins = "gpio46"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt1"; -+ pins = "gpio47"; -+ bias-disable; -+ }; -+ }; -+ i2c3_gpio2: i2c3_gpio2 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio2"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio3"; -+ bias-disable; -+ }; -+ }; -+ i2c3_gpio4: i2c3_gpio4 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio4"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio5"; -+ bias-disable; -+ }; -+ }; -+ i2c4_gpio6: i2c4_gpio6 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio6"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio7"; -+ bias-disable; -+ }; -+ }; -+ i2c4_gpio8: i2c4_gpio8 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio8"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio9"; -+ bias-disable; -+ }; -+ }; -+ i2c5_gpio10: i2c5_gpio10 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio10"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio11"; -+ bias-disable; -+ }; -+ }; -+ i2c5_gpio12: i2c5_gpio12 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio12"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio13"; -+ bias-disable; -+ }; -+ }; -+ i2c6_gpio0: i2c6_gpio0 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio0"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio1"; -+ bias-disable; -+ }; -+ }; -+ i2c6_gpio22: i2c6_gpio22 { -+ pin-sda { -+ function = "alt5"; -+ pins = "gpio22"; -+ bias-pull-up; -+ }; -+ pin-scl { -+ function = "alt5"; -+ pins = "gpio23"; -+ bias-disable; -+ }; -+ }; -+ i2c_slave_gpio8: i2c_slave_gpio8 { -+ pins-i2c-slave { -+ pins = "gpio8", -+ "gpio9", -+ "gpio10", -+ "gpio11"; -+ function = "alt3"; -+ }; -+ }; -+ -+ jtag_gpio48: jtag_gpio48 { -+ pins-jtag { -+ pins = "gpio48", -+ "gpio49", -+ "gpio50", -+ "gpio51", -+ "gpio52", -+ "gpio53"; -+ function = "alt4"; -+ }; -+ }; -+ -+ mii_gpio28: mii_gpio28 { -+ pins-mii { -+ pins = "gpio28", -+ "gpio29", -+ "gpio30", -+ "gpio31"; -+ function = "alt4"; -+ }; -+ }; -+ mii_gpio36: mii_gpio36 { -+ pins-mii { -+ pins = "gpio36", -+ "gpio37", -+ "gpio38", -+ "gpio39"; -+ function = "alt5"; -+ }; -+ }; -+ -+ pcm_gpio50: pcm_gpio50 { -+ pins-pcm { -+ pins = "gpio50", -+ "gpio51", -+ "gpio52", -+ "gpio53"; -+ function = "alt2"; -+ }; -+ }; -+ -+ pwm0_0_gpio12: pwm0_0_gpio12 { -+ pin-pwm { -+ pins = "gpio12"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_0_gpio18: pwm0_0_gpio18 { -+ pin-pwm { -+ pins = "gpio18"; -+ function = "alt5"; -+ bias-disable; -+ }; -+ }; -+ pwm1_0_gpio40: pwm1_0_gpio40 { -+ pin-pwm { -+ pins = "gpio40"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio13: pwm0_1_gpio13 { -+ pin-pwm { -+ pins = "gpio13"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio19: pwm0_1_gpio19 { -+ pin-pwm { -+ pins = "gpio19"; -+ function = "alt5"; -+ bias-disable; -+ }; -+ }; -+ pwm1_1_gpio41: pwm1_1_gpio41 { -+ pin-pwm { -+ pins = "gpio41"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio45: pwm0_1_gpio45 { -+ pin-pwm { -+ pins = "gpio45"; -+ function = "alt0"; -+ bias-disable; -+ }; -+ }; -+ pwm0_0_gpio52: pwm0_0_gpio52 { -+ pin-pwm { -+ pins = "gpio52"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ pwm0_1_gpio53: pwm0_1_gpio53 { -+ pin-pwm { -+ pins = "gpio53"; -+ function = "alt1"; -+ bias-disable; -+ }; -+ }; -+ -+ rgmii_gpio35: rgmii_gpio35 { -+ pin-start-stop { -+ pins = "gpio35"; -+ function = "alt4"; -+ }; -+ pin-rx-ok { -+ pins = "gpio36"; -+ function = "alt4"; -+ }; -+ }; -+ rgmii_irq_gpio34: rgmii_irq_gpio34 { -+ pin-irq { -+ pins = "gpio34"; -+ function = "alt5"; -+ }; -+ }; -+ rgmii_irq_gpio39: rgmii_irq_gpio39 { -+ pin-irq { -+ pins = "gpio39"; -+ function = "alt4"; -+ }; -+ }; -+ rgmii_mdio_gpio28: rgmii_mdio_gpio28 { -+ pins-mdio { -+ pins = "gpio28", -+ "gpio29"; -+ function = "alt5"; -+ }; -+ }; -+ rgmii_mdio_gpio37: rgmii_mdio_gpio37 { -+ pins-mdio { -+ pins = "gpio37", -+ "gpio38"; -+ function = "alt4"; -+ }; -+ }; -+ -+ spi0_gpio46: spi0_gpio46 { -+ pins-spi { -+ pins = "gpio46", -+ "gpio47", -+ "gpio48", -+ "gpio49"; -+ function = "alt2"; -+ }; -+ }; -+ spi2_gpio46: spi2_gpio46 { -+ pins-spi { -+ pins = "gpio46", -+ "gpio47", -+ "gpio48", -+ "gpio49", -+ "gpio50"; -+ function = "alt5"; -+ }; -+ }; -+ spi3_gpio0: spi3_gpio0 { -+ pins-spi { -+ pins = "gpio0", -+ "gpio1", -+ "gpio2", -+ "gpio3"; -+ function = "alt3"; -+ }; -+ }; -+ spi4_gpio4: spi4_gpio4 { -+ pins-spi { -+ pins = "gpio4", -+ "gpio5", -+ "gpio6", -+ "gpio7"; -+ function = "alt3"; -+ }; -+ }; -+ spi5_gpio12: spi5_gpio12 { -+ pins-spi { -+ pins = "gpio12", -+ "gpio13", -+ "gpio14", -+ "gpio15"; -+ function = "alt3"; -+ }; -+ }; -+ spi6_gpio18: spi6_gpio18 { -+ pins-spi { -+ pins = "gpio18", -+ "gpio19", -+ "gpio20", -+ "gpio21"; -+ function = "alt3"; -+ }; -+ }; -+ -+ uart2_gpio0: uart2_gpio0 { -+ pin-tx { -+ pins = "gpio0"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio1"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart2_ctsrts_gpio2: uart2_ctsrts_gpio2 { -+ pin-cts { -+ pins = "gpio2"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio3"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; -+ uart3_gpio4: uart3_gpio4 { -+ pin-tx { -+ pins = "gpio4"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio5"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart3_ctsrts_gpio6: uart3_ctsrts_gpio6 { -+ pin-cts { -+ pins = "gpio6"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio7"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; -+ uart4_gpio8: uart4_gpio8 { -+ pin-tx { -+ pins = "gpio8"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio9"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart4_ctsrts_gpio10: uart4_ctsrts_gpio10 { -+ pin-cts { -+ pins = "gpio10"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio11"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; -+ uart5_gpio12: uart5_gpio12 { -+ pin-tx { -+ pins = "gpio12"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ pin-rx { -+ pins = "gpio13"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ }; -+ uart5_ctsrts_gpio14: uart5_ctsrts_gpio14 { -+ pin-cts { -+ pins = "gpio14"; -+ function = "alt4"; -+ bias-pull-up; -+ }; -+ pin-rts { -+ pins = "gpio15"; -+ function = "alt4"; -+ bias-disable; -+ }; -+ }; -+}; -+ -+&i2c0 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ interrupts = ; -+}; -+ -+&i2c1 { -+ compatible = "brcm,bcm2711-i2c", "brcm,bcm2835-i2c"; -+ interrupts = ; -+}; -+ -+&mailbox { -+ interrupts = ; -+}; -+ -+&sdhci { -+ interrupts = ; -+}; -+ -+&sdhost { -+ interrupts = ; -+}; -+ -+&spi { -+ interrupts = ; -+}; -+ -+&spi1 { -+ interrupts = ; -+}; -+ -+&spi2 { -+ interrupts = ; -+}; -+ -+&system_timer { -+ interrupts = , -+ , -+ , -+ ; -+}; -+ -+&txp { -+ interrupts = ; -+}; -+ -+&uart0 { -+ interrupts = ; -+}; -+ -+&uart1 { -+ interrupts = ; -+}; -+ -+&usb { -+ interrupts = ; -+}; -+ -+&vec { -+ interrupts = ; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/bcm283x-rpi-usb-peripheral.dtsi -@@ -0,0 +1,7 @@ -+// SPDX-License-Identifier: GPL-2.0 -+&usb { -+ dr_mode = "peripheral"; -+ g-rx-fifo-size = <256>; -+ g-np-tx-fifo-size = <32>; -+ g-tx-fifo-size = <256 256 512 512 512 768 768>; -+}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0418-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0418-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch new file mode 100644 index 0000000000..4436c0a39d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0418-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch @@ -0,0 +1,32 @@ +From 871370c31c23fcd07ec375a088bd09a0a5a31126 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 31 Jan 2020 09:26:18 +0000 +Subject: [PATCH] staging/vchiq_arm: Fix bcm2711 compatible string + +Fixes: "vchiq: Add 36-bit address support" + +Signed-off-by: Phil Elwell +--- + drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -151,7 +151,7 @@ static struct vchiq_drvdata bcm2836_drvd + .cache_line_size = 64, + }; + +-static struct vchiq_drvdata bcm2838_drvdata = { ++static struct vchiq_drvdata bcm2711_drvdata = { + .cache_line_size = 64, + .use_36bit_addrs = true, + }; +@@ -3171,7 +3171,7 @@ void vchiq_platform_conn_state_changed(s + static const struct of_device_id vchiq_of_match[] = { + { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata }, + { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata }, +- { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata }, ++ { .compatible = "brcm,bcm2711-vchiq", .data = &bcm2711_drvdata }, + {}, + }; + MODULE_DEVICE_TABLE(of, vchiq_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0419-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch b/target/linux/bcm27xx/patches-5.4/950-0419-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch deleted file mode 100644 index 44f60d610f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0419-ARM-dts-bcm2711-force-CMA-into-first-GB-of-memory.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 4bcb99a967998d255ef009bb0b6880ae99c6f6bf Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 6 Nov 2019 10:59:44 +0100 -Subject: [PATCH] ARM: dts: bcm2711: force CMA into first GB of memory - -arm64 places the CMA in ZONE_DMA32, which is not good enough for the -Raspberry Pi 4 since it contains peripherals that can only address the -first GB of memory. Explicitly place the CMA into that area. - -Signed-off-by: Nicolas Saenz Julienne -Acked-by: Stefan Wahren -Signed-off-by: Florian Fainelli ---- - arch/arm/boot/dts/bcm2711.dtsi | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -12,6 +12,26 @@ - - interrupt-parent = <&gicv2>; - -+ reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <1>; -+ ranges; -+ -+ /* -+ * arm64 reserves the CMA by default somewhere in ZONE_DMA32, -+ * that's not good enough for the BCM2711 as some devices can -+ * only address the lower 1G of memory (ZONE_DMA). -+ */ -+ linux,cma { -+ compatible = "shared-dma-pool"; -+ size = <0x2000000>; /* 32MB */ -+ alloc-ranges = <0x0 0x00000000 0x40000000>; -+ reusable; -+ linux,cma-default; -+ }; -+ }; -+ -+ - soc { - /* - * Defined ranges: diff --git a/target/linux/bcm27xx/patches-5.4/950-0419-hwrng-iproc-rng200-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0419-hwrng-iproc-rng200-Correct-SoC-name.patch new file mode 100644 index 0000000000..f4e93308b1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0419-hwrng-iproc-rng200-Correct-SoC-name.patch @@ -0,0 +1,67 @@ +From 5eafa5065b2ea2c8d1634f045b85b982393d808a Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 31 Jan 2020 09:36:57 +0000 +Subject: [PATCH] hwrng: iproc-rng200: Correct SoC name + +The Pi 4 SoC is called BCM2711, not BCM2838. + +Fixes: "hwrng: iproc-rng200: Add BCM2838 support" + +Signed-off-by: Phil Elwell +--- + drivers/char/hw_random/Kconfig | 2 +- + drivers/char/hw_random/iproc-rng200.c | 11 +++++------ + 2 files changed, 6 insertions(+), 7 deletions(-) + +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -94,7 +94,7 @@ config HW_RANDOM_IPROC_RNG200 + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the RNG200 +- hardware found on the Broadcom iProc, BCM2838 and STB SoCs. ++ hardware found on the Broadcom iProc, BCM2711 and STB SoCs. + + To compile this driver as a module, choose M here: the + module will be called iproc-rng200 +--- a/drivers/char/hw_random/iproc-rng200.c ++++ b/drivers/char/hw_random/iproc-rng200.c +@@ -174,7 +174,7 @@ static int iproc_rng200_init(struct hwrn + return 0; + } + +-static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max, ++static int bcm2711_rng200_read(struct hwrng *rng, void *buf, size_t max, + bool wait) + { + struct iproc_rng200_dev *priv = to_rng_priv(rng); +@@ -211,7 +211,7 @@ static int bcm2838_rng200_read(struct hw + return num_words * sizeof(u32); + } + +-static int bcm2838_rng200_init(struct hwrng *rng) ++static int bcm2711_rng200_init(struct hwrng *rng) + { + struct iproc_rng200_dev *priv = to_rng_priv(rng); + uint32_t val; +@@ -271,9 +271,9 @@ static int iproc_rng200_probe(struct pla + priv->rng.name = pdev->name; + priv->rng.cleanup = iproc_rng200_cleanup; + +- if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) { +- priv->rng.init = bcm2838_rng200_init; +- priv->rng.read = bcm2838_rng200_read; ++ if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-rng200")) { ++ priv->rng.init = bcm2711_rng200_init; ++ priv->rng.read = bcm2711_rng200_read; + } else { + priv->rng.init = iproc_rng200_init; + priv->rng.read = iproc_rng200_read; +@@ -296,7 +296,6 @@ static const struct of_device_id iproc_r + { .compatible = "brcm,bcm7211-rng200", }, + { .compatible = "brcm,bcm7278-rng200", }, + { .compatible = "brcm,iproc-rng200", }, +- { .compatible = "brcm,bcm2838-rng200"}, + {}, + }; + MODULE_DEVICE_TABLE(of, iproc_rng200_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-Correct-SoC-name.patch new file mode 100644 index 0000000000..c18eb8af3c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-Correct-SoC-name.patch @@ -0,0 +1,50 @@ +From 475158d2aab9dc2e8266726f7b026cedfe810619 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 31 Jan 2020 15:24:59 +0000 +Subject: [PATCH] ARM: dts: Correct SoC name + +The Pi 4 SoC is called BCM2711, not BCM2838. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -42,7 +42,7 @@ + + &soc { + thermal: thermal@7d5d2200 { +- compatible = "brcm,avs-tmon-bcm2838"; ++ compatible = "brcm,avs-tmon-bcm2711"; + reg = <0x7d5d2200 0x2c>; + interrupts = ; + interrupt-names = "tmon"; +@@ -106,7 +106,7 @@ + }; + + dma40: dma@7e007b00 { +- compatible = "brcm,bcm2838-dma"; ++ compatible = "brcm,bcm2711-dma"; + reg = <0x0 0x7e007b00 0x400>; + interrupts = + , /* dma4 11 */ +@@ -122,7 +122,7 @@ + }; + + vchiq: mailbox@7e00b840 { +- compatible = "brcm,bcm2838-vchiq"; ++ compatible = "brcm,bcm2711-vchiq"; + reg = <0 0x7e00b840 0x3c>; + interrupts = ; + }; +@@ -195,7 +195,7 @@ + }; + + &random { +- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; ++ compatible = "brcm,bcm2711-rng200"; + status = "okay"; + }; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch b/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch deleted file mode 100644 index e204859fbd..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0420-ARM-dts-bcm2711-rpi-4-Enable-GENET-support.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 32847947e1d1e1ac2a73c7ea8ad47cca49aef5d4 Mon Sep 17 00:00:00 2001 -From: Stefan Wahren -Date: Mon, 11 Nov 2019 20:49:26 +0100 -Subject: [PATCH] ARM: dts: bcm2711-rpi-4: Enable GENET support - -This enables the Gigabit Ethernet support on the Raspberry Pi 4. -The defined PHY mode is equivalent to the default register settings -in the downstream tree. - -Signed-off-by: Matthias Brugger -Signed-off-by: Stefan Wahren -Reviewed-by: Florian Fainelli -Signed-off-by: Florian Fainelli ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 17 +++++++++++++++++ - arch/arm/boot/dts/bcm2711.dtsi | 26 ++++++++++++++++++++++++++ - 2 files changed, 43 insertions(+) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -19,6 +19,10 @@ - reg = <0 0 0>; - }; - -+ aliases { -+ ethernet0 = &genet; -+ }; -+ - leds { - act { - gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -@@ -97,6 +101,19 @@ - status = "okay"; - }; - -+&genet { -+ phy-handle = <&phy1>; -+ phy-mode = "rgmii-rxid"; -+ status = "okay"; -+}; -+ -+&genet_mdio { -+ phy1: ethernet-phy@1 { -+ /* No PHY interrupt */ -+ reg = <0x1>; -+ }; -+}; -+ - /* uart0 communicates with the BT module */ - &uart0 { - pinctrl-names = "default"; ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -325,6 +325,32 @@ - cpu-release-addr = <0x0 0x000000f0>; - }; - }; -+ -+ scb { -+ compatible = "simple-bus"; -+ #address-cells = <2>; -+ #size-cells = <1>; -+ -+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; -+ -+ genet: ethernet@7d580000 { -+ compatible = "brcm,bcm2711-genet-v5"; -+ reg = <0x0 0x7d580000 0x10000>; -+ #address-cells = <0x1>; -+ #size-cells = <0x1>; -+ interrupts = , -+ ; -+ status = "disabled"; -+ -+ genet_mdio: mdio@e14 { -+ compatible = "brcm,genet-mdio-v5"; -+ reg = <0xe14 0x8>; -+ reg-names = "mdio"; -+ #address-cells = <0x0>; -+ #size-cells = <0x1>; -+ }; -+ }; -+ }; - }; - - &clk_osc { diff --git a/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch b/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch new file mode 100644 index 0000000000..2c093459da --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch @@ -0,0 +1,32 @@ +From 1a66f120abddf36eaf2540532ddeb7f7767442c5 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Sat, 1 Feb 2020 08:58:11 +0000 +Subject: [PATCH] ARM: dts: Remove CMA allocation from Pi 4 dts + +The 5.5 tree includes a patch to disable the CMA command line +parameter and replace it with properties from a DT node. +The upstream Pi 4 .dts, now used downstream with modifications, +includes the "linux,cma" node, but only reserves 32MB which is +often not enough. + +Temporarily remove the "linux,cma" node to reenable the command line +parameter. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -167,6 +167,10 @@ + }; + + /delete-node/ wifi-pwrseq; ++ ++ reserved-memory { ++ /delete-node/ linux,cma; ++ }; + }; + + &mmcnr { diff --git a/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch b/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch deleted file mode 100644 index ed0be9b9a3..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0421-ARM-dts-bcm2711-fix-soc-s-node-dma-ranges.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 44d7ee4730fbe3c00aba0457489acd0b6e2937c9 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 4 Dec 2019 13:56:33 +0100 -Subject: [PATCH] ARM: dts: bcm2711: fix soc's node dma-ranges - -Raspberry Pi's firmware has a feature to select how much memory to -reserve for its GPU called 'gpu_mem'. The possible values go from 16MB -to 944MB, with a default of 64MB. This memory resides in the topmost -part of the lower 1GB memory area and grows bigger expanding towards the -begging of memory. - -It turns out that with low 'gpu_mem' values (16MB and 32MB) the size of -the memory available to the system in the lower 1GB area can outgrow the -interconnect's dma-range as its size was selected based on the maximum -system memory available given the default gpu_mem configuration. This -makes that memory slice unavailable for DMA. And may cause nasty kernel -warnings if CMA happens to include it. - -Change soc's dma-ranges to really reflect it's HW limitation, which is -being able to only DMA to the lower 1GB area. - -Fixes: 7dbe8c62ceeb ("ARM: dts: Add minimal Raspberry Pi 4 support") -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Phil Elwell -Signed-off-by: Florian Fainelli ---- - arch/arm/boot/dts/bcm2711.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -43,7 +43,7 @@ - <0x7c000000 0x0 0xfc000000 0x02000000>, - <0x40000000 0x0 0xff800000 0x00800000>; - /* Emulate a contiguous 30-bit address range for DMA */ -- dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>; -+ dma-ranges = <0xc0000000 0x0 0x00000000 0x40000000>; - - /* - * This node is the provider for the enable-method for diff --git a/target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-Rebuild-downstream-DTS-files.patch b/target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-Rebuild-downstream-DTS-files.patch deleted file mode 100644 index 8d230d0edb..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0422-ARM-dts-Rebuild-downstream-DTS-files.patch +++ /dev/null @@ -1,1076 +0,0 @@ -From b229e7f5a6d21d1b52f3f19fed58bba638714884 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 30 Jan 2020 15:48:00 +0000 -Subject: [PATCH] ARM: dts: Rebuild downstream DTS files - -Refactor the tree of downstream DTS files to achieve approximately the -same end result but wihout modifying upstream files (except for -bcm2711-rpi-4-b.dts). - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2708-rpi.dtsi | 133 +-------- - arch/arm/boot/dts/bcm2708.dtsi | 4 + - arch/arm/boot/dts/bcm2709.dtsi | 4 + - arch/arm/boot/dts/bcm270x-rpi.dtsi | 139 +++++++++ - arch/arm/boot/dts/bcm270x.dtsi | 98 ++++--- - arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 13 + - arch/arm/boot/dts/bcm2710.dtsi | 4 + - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 315 ++++++++++++++++++++- - arch/arm/boot/dts/bcm2711-rpi.dtsi | 222 +++++++++++++++ - 9 files changed, 766 insertions(+), 166 deletions(-) - create mode 100644 arch/arm/boot/dts/bcm270x-rpi.dtsi - create mode 100644 arch/arm/boot/dts/bcm2711-rpi.dtsi - ---- a/arch/arm/boot/dts/bcm2708-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi -@@ -1,6 +1,7 @@ --/* Downstream modifications to bcm2835-rpi.dtsi */ -+/* Downstream modifications common to bcm2835, bcm2836, bcm2837 */ - - #include "bcm2835-rpi.dtsi" -+#include "bcm270x-rpi.dtsi" - - / { - memory@0 { -@@ -9,147 +10,27 @@ - }; - - aliases { -- audio = &audio; -- aux = &aux; -- sound = &sound; -- soc = &soc; -- dma = &dma; -- intc = &intc; -- watchdog = &watchdog; -- random = &random; -- mailbox = &mailbox; -- gpio = &gpio; -- uart0 = &uart0; -- sdhost = &sdhost; -- mmc0 = &sdhost; -- i2s = &i2s; -- spi0 = &spi0; -- i2c0 = &i2c0; -- uart1 = &uart1; -- spi1 = &spi1; -- spi2 = &spi2; -- mmc = &mmc; -- mmc1 = &mmc; -- i2c1 = &i2c1; - i2c2 = &i2c2; -- usb = &usb; -- leds = &leds; -- fb = &fb; -- thermal = &thermal; -- axiperf = &axiperf; -- }; -- -- leds: leds { -- compatible = "gpio-leds"; -- }; -- -- soc { -- gpiomem { -- compatible = "brcm,bcm2835-gpiomem"; -- reg = <0x7e200000 0x1000>; -- }; -- -- fb: fb { -- compatible = "brcm,bcm2708-fb"; -- firmware = <&firmware>; -- status = "okay"; -- }; -- -- vcsm: vcsm { -- compatible = "raspberrypi,bcm2835-vcsm"; -- firmware = <&firmware>; -- status = "okay"; -- }; -- -- /* Onboard audio */ -- audio: audio { -- compatible = "brcm,bcm2835-audio"; -- brcm,pwm-channels = <8>; -- status = "disabled"; -- }; -- -- /* External sound card */ -- sound: sound { -- status = "disabled"; -- }; - }; - - __overrides__ { -- cache_line_size; -- -- uart0 = <&uart0>,"status"; -- uart1 = <&uart1>,"status"; -- i2s = <&i2s>,"status"; -- spi = <&spi0>,"status"; -- i2c0 = <&i2c0>,"status"; -- i2c1 = <&i2c1>,"status"; - i2c2_iknowwhatimdoing = <&i2c2>,"status"; -- i2c0_baudrate = <&i2c0>,"clock-frequency:0"; -- i2c1_baudrate = <&i2c1>,"clock-frequency:0"; - i2c2_baudrate = <&i2c2>,"clock-frequency:0"; -- -- audio = <&audio>,"status"; -- watchdog = <&watchdog>,"status"; -- random = <&random>,"status"; -- sd_overclock = <&sdhost>,"brcm,overclock-50:0"; -- sd_poll_once = <&sdhost>,"non-removable?"; -- sd_force_pio = <&sdhost>,"brcm,force-pio?"; -- sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; -- sd_debug = <&sdhost>,"brcm,debug"; -- sdio_overclock = <&mmc>,"brcm,overclock-50:0", -- <&mmcnr>,"brcm,overclock-50:0"; -- axiperf = <&axiperf>,"status"; -+ sd_poll_once = <&sdhost>, "non-removable?"; - }; - }; - --&hdmi { -- power-domains = <&power RPI_POWER_DOMAIN_HDMI>; -- status = "disabled"; --}; -- --&txp { -- status = "disabled"; --}; -- --&i2c0 { -- status = "disabled"; --}; -- --&i2c1 { -- status = "disabled"; --}; -- --&i2c2 { -- status = "disabled"; --}; -- --&clocks { -- firmware = <&firmware>; --}; -- --&sdhci { -- pinctrl-names = "default"; -- pinctrl-0 = <&emmc_gpio48>; -- bus-width = <4>; --}; -- --sdhost_pins: &sdhost_gpio48 { -- /* Add alias */ --}; -- - &sdhost { - pinctrl-names = "default"; - pinctrl-0 = <&sdhost_gpio48>; -- bus-width = <4>; -- brcm,overclock-50 = <0>; -- brcm,pio-limit = <1>; - status = "okay"; - }; - --&cpu_thermal { -- /delete-node/ trips; -+&hdmi { -+ power-domains = <&power RPI_POWER_DOMAIN_HDMI>; -+ status = "disabled"; - }; - --&vec { -+&i2c2 { - status = "disabled"; - }; ---- a/arch/arm/boot/dts/bcm2708.dtsi -+++ b/arch/arm/boot/dts/bcm2708.dtsi -@@ -8,3 +8,7 @@ - arm_freq; - }; - }; -+ -+&vc4 { -+ status = "disabled"; -+}; ---- a/arch/arm/boot/dts/bcm2709.dtsi -+++ b/arch/arm/boot/dts/bcm2709.dtsi -@@ -16,3 +16,7 @@ - <&v7_cpu3>, "clock-frequency:0"; - }; - }; -+ -+&vc4 { -+ status = "disabled"; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi -@@ -0,0 +1,139 @@ -+/* Downstream modifications to bcm2835-rpi.dtsi */ -+ -+/ { -+ aliases { -+ audio = &audio; -+ aux = &aux; -+ sound = &sound; -+ soc = &soc; -+ dma = &dma; -+ intc = &intc; -+ watchdog = &watchdog; -+ random = &random; -+ mailbox = &mailbox; -+ gpio = &gpio; -+ uart0 = &uart0; -+ uart1 = &uart1; -+ sdhost = &sdhost; -+ mmc = &mmc; -+ mmc1 = &mmc; -+ mmc0 = &sdhost; -+ i2s = &i2s; -+ i2c0 = &i2c0; -+ i2c1 = &i2c1; -+ spi0 = &spi0; -+ spi1 = &spi1; -+ spi2 = &spi2; -+ usb = &usb; -+ leds = &leds; -+ fb = &fb; -+ thermal = &thermal; -+ axiperf = &axiperf; -+ }; -+ -+ /* Define these notional regulators for use by overlays */ -+ vdd_3v3_reg: fixedregulator_3v3 { -+ compatible = "regulator-fixed"; -+ regulator-always-on; -+ regulator-max-microvolt = <3300000>; -+ regulator-min-microvolt = <3300000>; -+ regulator-name = "3v3"; -+ }; -+ -+ vdd_5v0_reg: fixedregulator_5v0 { -+ compatible = "regulator-fixed"; -+ regulator-always-on; -+ regulator-max-microvolt = <5000000>; -+ regulator-min-microvolt = <5000000>; -+ regulator-name = "5v0"; -+ }; -+ -+ leds: leds { -+ compatible = "gpio-leds"; -+ }; -+ -+ soc { -+ gpiomem { -+ compatible = "brcm,bcm2835-gpiomem"; -+ reg = <0x7e200000 0x1000>; -+ }; -+ -+ fb: fb { -+ compatible = "brcm,bcm2708-fb"; -+ firmware = <&firmware>; -+ status = "okay"; -+ }; -+ -+ vcsm: vcsm { -+ compatible = "raspberrypi,bcm2835-vcsm"; -+ firmware = <&firmware>; -+ status = "okay"; -+ }; -+ -+ /* Onboard audio */ -+ audio: audio { -+ compatible = "brcm,bcm2835-audio"; -+ brcm,pwm-channels = <8>; -+ status = "disabled"; -+ }; -+ -+ /* External sound card */ -+ sound: sound { -+ status = "disabled"; -+ }; -+ }; -+ -+ __overrides__ { -+ cache_line_size; -+ -+ uart0 = <&uart0>,"status"; -+ uart1 = <&uart1>,"status"; -+ i2s = <&i2s>,"status"; -+ spi = <&spi0>,"status"; -+ i2c0 = <&i2c0>,"status"; -+ i2c1 = <&i2c1>,"status"; -+ i2c0_baudrate = <&i2c0>,"clock-frequency:0"; -+ i2c1_baudrate = <&i2c1>,"clock-frequency:0"; -+ -+ audio = <&audio>,"status"; -+ watchdog = <&watchdog>,"status"; -+ random = <&random>,"status"; -+ sd_overclock = <&sdhost>,"brcm,overclock-50:0"; -+ sd_force_pio = <&sdhost>,"brcm,force-pio?"; -+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0"; -+ sd_debug = <&sdhost>,"brcm,debug"; -+ sdio_overclock = <&mmc>,"brcm,overclock-50:0", -+ <&mmcnr>,"brcm,overclock-50:0"; -+ axiperf = <&axiperf>,"status"; -+ }; -+}; -+ -+&txp { -+ status = "disabled"; -+}; -+ -+&i2c0 { -+ status = "disabled"; -+}; -+ -+&i2c1 { -+ status = "disabled"; -+}; -+ -+&clocks { -+ firmware = <&firmware>; -+}; -+ -+&sdhci { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_gpio48>; -+ bus-width = <4>; -+}; -+ -+&cpu_thermal { -+ /delete-node/ trips; -+}; -+ -+&vec { -+ status = "disabled"; -+}; ---- a/arch/arm/boot/dts/bcm270x.dtsi -+++ b/arch/arm/boot/dts/bcm270x.dtsi -@@ -17,32 +17,8 @@ - /* Add label */ - }; - -- gpio@7e200000 { /* gpio */ -- interrupts = <2 17>, <2 18>; -- -- dpi_18bit_gpio0: dpi_18bit_gpio0 { -- brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11 -- 12 13 14 15 16 17 18 19 -- 20 21>; -- brcm,function = ; -- }; -- }; -- -- serial@7e201000 { /* uart0 */ -- /* Enable CTS bug workaround */ -- cts-event-workaround; -- }; -- -- i2s@7e203000 { /* i2s */ -- #sound-dai-cells = <0>; -- reg = <0x7e203000 0x24>; -- clocks = <&clocks BCM2835_CLOCK_PCM>; -- }; -- - spi0: spi@7e204000 { - /* Add label */ -- dmas = <&dma 6>, <&dma 7>; -- dma-names = "tx", "rx"; - }; - - pixelvalve0: pixelvalve@7e206000 { -@@ -55,17 +31,6 @@ - status = "disabled"; - }; - -- dpi: dpi@7e208000 { -- compatible = "brcm,bcm2835-dpi"; -- reg = <0x7e208000 0x8c>; -- clocks = <&clocks BCM2835_CLOCK_VPU>, -- <&clocks BCM2835_CLOCK_DPI>; -- clock-names = "core", "pixel"; -- #address-cells = <1>; -- #size-cells = <0>; -- status = "disabled"; -- }; -- - /delete-node/ sdhci@7e300000; - - sdhci: mmc: mmc@7e300000 { -@@ -118,6 +83,34 @@ - status = "disabled"; - }; - -+ csi0: csi@7e800000 { -+ compatible = "brcm,bcm2835-unicam"; -+ reg = <0x7e800000 0x800>, -+ <0x7e802000 0x4>; -+ interrupts = <2 6>; -+ clocks = <&clocks BCM2835_CLOCK_CAM0>; -+ clock-names = "lp"; -+ power-domains = <&power RPI_POWER_DOMAIN_UNICAM0>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #clock-cells = <1>; -+ status = "disabled"; -+ }; -+ -+ csi1: csi@7e801000 { -+ compatible = "brcm,bcm2835-unicam"; -+ reg = <0x7e801000 0x800>, -+ <0x7e802004 0x4>; -+ interrupts = <2 7>; -+ clocks = <&clocks BCM2835_CLOCK_CAM1>; -+ clock-names = "lp"; -+ power-domains = <&power RPI_POWER_DOMAIN_UNICAM1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ #clock-cells = <1>; -+ status = "disabled"; -+ }; -+ - pixelvalve2: pixelvalve@7e807000 { - /* Add label */ - status = "disabled"; -@@ -160,6 +153,37 @@ - }; - }; - --&vc4 { -- status = "disabled"; -+&gpio { -+ interrupts = <2 17>, <2 18>; -+ -+ dpi_18bit_gpio0: dpi_18bit_gpio0 { -+ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11 -+ 12 13 14 15 16 17 18 19 -+ 20 21>; -+ brcm,function = ; -+ }; -+}; -+ -+&uart0 { -+ /* Enable CTS bug workaround */ -+ cts-event-workaround; -+}; -+ -+&i2s { -+ #sound-dai-cells = <0>; -+ dmas = <&dma 2>, <&dma 3>; -+ dma-names = "tx", "rx"; -+}; -+ -+&sdhost { -+ dmas = <&dma (13|(1<<29))>; -+ dma-names = "rx-tx"; -+ bus-width = <4>; -+ brcm,overclock-50 = <0>; -+ brcm,pio-limit = <1>; -+}; -+ -+&spi0 { -+ dmas = <&dma 6>, <&dma 7>; -+ dma-names = "tx", "rx"; - }; ---- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts -+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts -@@ -170,6 +170,12 @@ - pinctrl-0 = <&audio_pins>; - }; - -+ð_phy { -+ microchip,eee-enabled; -+ microchip,tx-lpi-timer = <600>; /* non-aggressive*/ -+ microchip,downshift-after = <2>; -+}; -+ - / { - __overrides__ { - act_led_gpio = <&act_led>,"gpios:4"; -@@ -179,5 +185,12 @@ - pwr_led_gpio = <&pwr_led>,"gpios:4"; - pwr_led_activelow = <&pwr_led>,"gpios:8"; - pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; -+ -+ eee = <ð_phy>,"microchip,eee-enabled?"; -+ tx_lpi_timer = <ð_phy>,"microchip,tx-lpi-timer:0"; -+ eth_led0 = <ð_phy>,"microchip,led-modes:0"; -+ eth_led1 = <ð_phy>,"microchip,led-modes:4"; -+ eth_downshift_after = <ð_phy>,"microchip,downshift-after:0"; -+ eth_max_speed = <ð_phy>,"max-speed:0"; - }; - }; ---- a/arch/arm/boot/dts/bcm2710.dtsi -+++ b/arch/arm/boot/dts/bcm2710.dtsi -@@ -23,3 +23,7 @@ - <&cpu3>, "clock-frequency:0"; - }; - }; -+ -+&vc4 { -+ status = "disabled"; -+}; ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -2,7 +2,6 @@ - /dts-v1/; - #include "bcm2711.dtsi" - #include "bcm2835-rpi.dtsi" --#include "bcm283x-rpi-usb-peripheral.dtsi" - - / { - compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; -@@ -65,8 +64,8 @@ - "GLOBAL_RESET", - "VDD_SD_IO_SEL", - "CAM_GPIO", -- "", -- ""; -+ "SD_PWR_ON", -+ "SD_OC_N"; - status = "okay"; - }; - }; -@@ -138,3 +137,313 @@ - &vchiq { - interrupts = ; - }; -+ -+// ============================================= -+// Downstream rpi- changes -+ -+#include "bcm270x.dtsi" -+#include "bcm2711-rpi.dtsi" -+#include "bcm283x-rpi-csi1-2lane.dtsi" -+ -+/ { -+ chosen { -+ bootargs = "coherent_pool=1M 8250.nr_uarts=1 cma=64M"; -+ }; -+ -+ aliases { -+ serial0 = &uart1; -+ serial1 = &uart0; -+ mmc0 = &emmc2; -+ mmc1 = &mmcnr; -+ mmc2 = &sdhost; -+ /delete-property/ i2c2; -+ i2c3 = &i2c3; -+ i2c4 = &i2c4; -+ i2c5 = &i2c5; -+ i2c6 = &i2c6; -+ /delete-property/ ethernet; -+ /delete-property/ intc; -+ pcie0 = &pcie_0; -+ }; -+ -+ /delete-node/ wifi-pwrseq; -+}; -+ -+&mmcnr { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdio_pins>; -+ bus-width = <4>; -+ status = "okay"; -+}; -+ -+&uart0 { -+ pinctrl-0 = <&uart0_pins &bt_pins>; -+ status = "okay"; -+ -+ /delete-node/ bluetooth; -+}; -+ -+&uart1 { -+ pinctrl-0 = <&uart1_pins>; -+}; -+ -+&spi0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&spi0_pins &spi0_cs_pins>; -+ cs-gpios = <&gpio 8 1>, <&gpio 7 1>; -+ -+ spidev0: spidev@0{ -+ compatible = "spidev"; -+ reg = <0>; /* CE0 */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi-max-frequency = <125000000>; -+ }; -+ -+ spidev1: spidev@1{ -+ compatible = "spidev"; -+ reg = <1>; /* CE1 */ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi-max-frequency = <125000000>; -+ }; -+}; -+ -+&gpio { -+ spi0_pins: spi0_pins { -+ brcm,pins = <9 10 11>; -+ brcm,function = ; -+ }; -+ -+ spi0_cs_pins: spi0_cs_pins { -+ brcm,pins = <8 7>; -+ brcm,function = ; -+ }; -+ -+ spi3_pins: spi3_pins { -+ brcm,pins = <1 2 3>; -+ brcm,function = ; -+ }; -+ -+ spi3_cs_pins: spi3_cs_pins { -+ brcm,pins = <0 24>; -+ brcm,function = ; -+ }; -+ -+ spi4_pins: spi4_pins { -+ brcm,pins = <5 6 7>; -+ brcm,function = ; -+ }; -+ -+ spi4_cs_pins: spi4_cs_pins { -+ brcm,pins = <4 25>; -+ brcm,function = ; -+ }; -+ -+ spi5_pins: spi5_pins { -+ brcm,pins = <13 14 15>; -+ brcm,function = ; -+ }; -+ -+ spi5_cs_pins: spi5_cs_pins { -+ brcm,pins = <12 26>; -+ brcm,function = ; -+ }; -+ -+ spi6_pins: spi6_pins { -+ brcm,pins = <19 20 21>; -+ brcm,function = ; -+ }; -+ -+ spi6_cs_pins: spi6_cs_pins { -+ brcm,pins = <18 27>; -+ brcm,function = ; -+ }; -+ -+ i2c0_pins: i2c0 { -+ brcm,pins = <0 1>; -+ brcm,function = ; -+ brcm,pull = ; -+ }; -+ -+ i2c1_pins: i2c1 { -+ brcm,pins = <2 3>; -+ brcm,function = ; -+ brcm,pull = ; -+ }; -+ -+ i2c3_pins: i2c3 { -+ brcm,pins = <4 5>; -+ brcm,function = ; -+ brcm,pull = ; -+ }; -+ -+ i2c4_pins: i2c4 { -+ brcm,pins = <8 9>; -+ brcm,function = ; -+ brcm,pull = ; -+ }; -+ -+ i2c5_pins: i2c5 { -+ brcm,pins = <12 13>; -+ brcm,function = ; -+ brcm,pull = ; -+ }; -+ -+ i2c6_pins: i2c6 { -+ brcm,pins = <22 23>; -+ brcm,function = ; -+ brcm,pull = ; -+ }; -+ -+ i2s_pins: i2s { -+ brcm,pins = <18 19 20 21>; -+ brcm,function = ; -+ }; -+ -+ sdio_pins: sdio_pins { -+ brcm,pins = <34 35 36 37 38 39>; -+ brcm,function = ; // alt3 = SD1 -+ brcm,pull = <0 2 2 2 2 2>; -+ }; -+ -+ bt_pins: bt_pins { -+ brcm,pins = "-"; // non-empty to keep btuart happy, //4 = 0 -+ // to fool pinctrl -+ brcm,function = <0>; -+ brcm,pull = <2>; -+ }; -+ -+ uart0_pins: uart0_pins { -+ brcm,pins = <32 33>; -+ brcm,function = ; -+ brcm,pull = <0 2>; -+ }; -+ -+ uart1_pins: uart1_pins { -+ brcm,pins; -+ brcm,function; -+ brcm,pull; -+ }; -+ -+ uart2_pins: uart2_pins { -+ brcm,pins = <0 1>; -+ brcm,function = ; -+ brcm,pull = <0 2>; -+ }; -+ -+ uart3_pins: uart3_pins { -+ brcm,pins = <4 5>; -+ brcm,function = ; -+ brcm,pull = <0 2>; -+ }; -+ -+ uart4_pins: uart4_pins { -+ brcm,pins = <8 9>; -+ brcm,function = ; -+ brcm,pull = <0 2>; -+ }; -+ -+ uart5_pins: uart5_pins { -+ brcm,pins = <12 13>; -+ brcm,function = ; -+ brcm,pull = <0 2>; -+ }; -+}; -+ -+&i2c0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c0_pins>; -+ clock-frequency = <100000>; -+}; -+ -+&i2c1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c1_pins>; -+ clock-frequency = <100000>; -+}; -+ -+&i2s { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2s_pins>; -+}; -+ -+/ { -+ __overrides__ { -+ /delete-property/ i2c2_baudrate; -+ /delete-property/ i2c2_iknowwhatimdoing; -+ }; -+}; -+ -+// ============================================= -+// Board specific stuff here -+ -+/ { -+ sd_vcc_reg: sd_vcc_reg { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc-sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ enable-active-high; -+ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; -+ }; -+}; -+ -+&sdhost { -+ status = "disabled"; -+}; -+ -+&emmc2 { -+ vmmc-supply = <&sd_vcc_reg>; -+}; -+ -+&phy1 { -+ led-modes = <0x00 0x08>; /* link/activity link */ -+}; -+ -+&gpio { -+ audio_pins: audio_pins { -+ brcm,pins = <40 41>; -+ brcm,function = <4>; -+ }; -+}; -+ -+&leds { -+ act_led: act { -+ label = "led0"; -+ linux,default-trigger = "mmc0"; -+ gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; -+ }; -+ -+ pwr_led: pwr { -+ label = "led1"; -+ linux,default-trigger = "default-on"; -+ gpios = <&expgpio 2 GPIO_ACTIVE_LOW>; -+ }; -+}; -+ -+&pwm1 { -+ status = "disabled"; -+}; -+ -+&audio { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&audio_pins>; -+}; -+ -+/ { -+ __overrides__ { -+ act_led_gpio = <&act_led>,"gpios:4"; -+ act_led_activelow = <&act_led>,"gpios:8"; -+ act_led_trigger = <&act_led>,"linux,default-trigger"; -+ -+ pwr_led_gpio = <&pwr_led>,"gpios:4"; -+ pwr_led_activelow = <&pwr_led>,"gpios:8"; -+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger"; -+ -+ eth_led0 = <&phy1>,"led-modes:0"; -+ eth_led1 = <&phy1>,"led-modes:4"; -+ -+ }; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi -@@ -0,0 +1,222 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include "bcm270x-rpi.dtsi" -+ -+/ { -+ soc { -+ /delete-node/ v3d@7ec00000; -+ /delete-node/ mailbox@7e00b840; -+ }; -+ -+ __overrides__ { -+ arm_freq; -+ sd_poll_once = <&emmc2>, "non-removable?"; -+ }; -+ -+ v3dbus { -+ compatible = "simple-bus"; -+ #address-cells = <1>; -+ #size-cells = <2>; -+ ranges = <0x7c500000 0x0 0xfc500000 0x0 0x03300000>, -+ <0x40000000 0x0 0xff800000 0x0 0x00800000>; -+ dma-ranges = <0x00000000 0x0 0x00000000 0x4 0x00000000>; -+ -+ v3d: v3d@7ec04000 { -+ compatible = "brcm,2711-v3d"; -+ reg = -+ <0x7ec00000 0x0 0x4000>, -+ <0x7ec04000 0x0 0x4000>; -+ reg-names = "hub", "core0"; -+ -+ power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>; -+ resets = <&pm BCM2835_RESET_V3D>; -+ clocks = <&clocks BCM2835_CLOCK_V3D>; -+ interrupts = ; -+ status = "disabled"; -+ }; -+ }; -+ -+ scb: scb { -+ /* Add a label */ -+ }; -+}; -+ -+&soc { -+ thermal: thermal@7d5d2200 { -+ compatible = "brcm,avs-tmon-bcm2838"; -+ reg = <0x7d5d2200 0x2c>; -+ interrupts = ; -+ interrupt-names = "tmon"; -+ clocks = <&clocks BCM2835_CLOCK_TSENS>; -+ #thermal-sensor-cells = <0>; -+ status = "okay"; -+ }; -+ -+ vc4: gpu { -+ compatible = "brcm,bcm2835-vc4"; -+ status = "disabled"; -+ }; -+}; -+ -+&scb { -+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, -+ <0x0 0x40000000 0x0 0xff800000 0x00800000>, -+ <0x6 0x00000000 0x6 0x00000000 0x40000000>, -+ <0x0 0x00000000 0x0 0x00000000 0xfc000000>; -+ dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; -+ -+ pcie_0: pcie@7d500000 { -+ reg = <0x0 0x7d500000 0x9310>, -+ <0x0 0x7e00f300 0x20>; -+ msi-controller; -+ msi-parent = <&pcie_0>; -+ #address-cells = <3>; -+ #interrupt-cells = <1>; -+ #size-cells = <2>; -+ bus-range = <0x0 0x01>; -+ compatible = "brcm,bcm2711b0-pcie", // Safe value -+ "brcm,bcm2711-pcie", -+ "brcm,pci-plat-dev"; -+ max-link-speed = <2>; -+ tot-num-pcie = <1>; -+ linux,pci-domain = <0>; -+ interrupts = , -+ ; -+ interrupt-names = "pcie", "msi"; -+ interrupt-map-mask = <0x0 0x0 0x0 0x7>; -+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 -+ IRQ_TYPE_LEVEL_HIGH -+ 0 0 0 2 &gicv2 GIC_SPI 144 -+ IRQ_TYPE_LEVEL_HIGH -+ 0 0 0 3 &gicv2 GIC_SPI 145 -+ IRQ_TYPE_LEVEL_HIGH -+ 0 0 0 4 &gicv2 GIC_SPI 146 -+ IRQ_TYPE_LEVEL_HIGH>; -+ -+ /* Map outbound accesses from scb:0x6_00000000-03ffffff -+ * to pci:0x0_f8000000-fbffffff -+ */ -+ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 -+ 0x0 0x04000000>; -+ /* Map inbound accesses from pci:0x0_00000000..ffffffff -+ * to scb:0x0_00000000-ffffffff -+ */ -+ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 -+ 0x1 0x00000000>; -+ status = "okay"; -+ }; -+ -+ dma40: dma@7e007b00 { -+ compatible = "brcm,bcm2838-dma"; -+ reg = <0x0 0x7e007b00 0x400>; -+ interrupts = -+ , /* dma4 11 */ -+ , /* dma4 12 */ -+ , /* dma4 13 */ -+ ; /* dma4 14 */ -+ interrupt-names = "dma11", -+ "dma12", -+ "dma13", -+ "dma14"; -+ #dma-cells = <1>; -+ brcm,dma-channel-mask = <0x7800>; -+ }; -+ -+ vchiq: mailbox@7e00b840 { -+ compatible = "brcm,bcm2838-vchiq"; -+ reg = <0 0x7e00b840 0x3c>; -+ interrupts = ; -+ }; -+ -+ xhci: xhci@7e9c0000 { -+ compatible = "generic-xhci"; -+ status = "disabled"; -+ reg = <0x0 0x7e9c0000 0x100000>; -+ interrupts = ; -+ }; -+ -+ hevc-decoder@7eb00000 { -+ compatible = "raspberrypi,rpivid-hevc-decoder"; -+ reg = <0x0 0x7eb00000 0x10000>; -+ status = "okay"; -+ }; -+ -+ rpivid-local-intc@7eb10000 { -+ compatible = "raspberrypi,rpivid-local-intc"; -+ reg = <0x0 0x7eb10000 0x1000>; -+ status = "okay"; -+ interrupts = ; -+ }; -+ -+ h264-decoder@7eb20000 { -+ compatible = "raspberrypi,rpivid-h264-decoder"; -+ reg = <0x0 0x7eb20000 0x10000>; -+ status = "okay"; -+ }; -+ -+ vp9-decoder@7eb30000 { -+ compatible = "raspberrypi,rpivid-vp9-decoder"; -+ reg = <0x0 0x7eb30000 0x10000>; -+ status = "okay"; -+ }; -+}; -+ -+&dma { -+ /* The VPU firmware uses DMA channel 11 for VCHIQ */ -+ brcm,dma-channel-mask = <0x1f5>; -+}; -+ -+&dma40 { -+ /* The VPU firmware DMA channel 11 for VCHIQ */ -+ brcm,dma-channel-mask = <0x7000>; -+}; -+ -+&firmwarekms { -+ interrupts = ; -+}; -+ -+&smi { -+ interrupts = ; -+}; -+ -+&mmc { -+ interrupts = ; -+}; -+ -+&mmcnr { -+ interrupts = ; -+}; -+ -+&csi0 { -+ interrupts = ; -+}; -+ -+&csi1 { -+ interrupts = ; -+}; -+ -+&random { -+ compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; -+ status = "okay"; -+}; -+ -+&usb { -+ /* Enable the FIQ support */ -+ reg = <0x7e980000 0x10000>, -+ <0x7e00b200 0x200>; -+ interrupts = , -+ ; -+ status = "disabled"; -+}; -+ -+&gpio { -+ interrupts = , -+ ; -+}; -+ -+&cpu_thermal { -+ thermal-sensors = <&thermal>; -+}; -+ -+&genet { -+ compatible = "brcm,bcm2711-genet-v5", "brcm,genet-v5"; -+}; diff --git a/target/linux/bcm27xx/patches-5.4/950-0422-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0422-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch new file mode 100644 index 0000000000..7fb3443fa9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0422-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch @@ -0,0 +1,39 @@ +From 9f93264df7a631132f2dacd150d0cc6cb7d20fc4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Feb 2020 17:30:46 +0000 +Subject: [PATCH] staging: vchiq_arm: Give vchiq children DT nodes + +vchiq kernel clients are now instantiated as platform drivers rather +than using DT, but the children of the vchiq interface may still +benefit from access to DT properties. Give them the option of a +a sub-node of the vchiq parent for configuration and to allow +them to be disabled. + +Signed-off-by: Phil Elwell +--- + .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c ++++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +@@ -3190,12 +3190,20 @@ vchiq_register_child(struct platform_dev + pdevinfo.id = PLATFORM_DEVID_NONE; + pdevinfo.dma_mask = DMA_BIT_MASK(32); + ++ np = of_get_child_by_name(pdev->dev.of_node, name); ++ ++ /* Skip the child if it is explicitly disabled */ ++ if (np && !of_device_is_available(np)) ++ return NULL; ++ + child = platform_device_register_full(&pdevinfo); + if (IS_ERR(child)) { + dev_warn(&pdev->dev, "%s not registered\n", name); + child = NULL; + } + ++ child->dev.of_node = np; ++ + /* + * We want the dma-ranges etc to be copied from a device with the + * correct dma-ranges for the VPU. diff --git a/target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch b/target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch new file mode 100644 index 0000000000..b5e59e6464 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0423-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch @@ -0,0 +1,79 @@ +From 6c5efcf09c40d37f72692fdbdf6d461abede20f1 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Feb 2020 17:03:29 +0000 +Subject: [PATCH] ARM: dts: Move audio node under the vchiq parent + +VCHIQ kernel clients are now instantiated as platform drivers rather +than using DT, but the children of the vchiq device can optionally be +given a sub-node of the vchiq parent for configuration and to disable +them. + +Move the existing audio node beneath the vchiq parent, to prevent +multiple instantiation and unpleasant warnings. Note that the node +name has to match the module name - "bcm2835_audio". + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm270x-rpi.dtsi | 16 +++++++++------- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 14 ++++++++++++++ + 2 files changed, 23 insertions(+), 7 deletions(-) + +--- a/arch/arm/boot/dts/bcm270x-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi +@@ -70,13 +70,6 @@ + status = "okay"; + }; + +- /* Onboard audio */ +- audio: audio { +- compatible = "brcm,bcm2835-audio"; +- brcm,pwm-channels = <8>; +- status = "disabled"; +- }; +- + /* External sound card */ + sound: sound { + status = "disabled"; +@@ -137,3 +130,12 @@ + &vec { + status = "disabled"; + }; ++ ++&vchiq { ++ /* Onboard audio */ ++ audio: bcm2835_audio { ++ compatible = "brcm,bcm2835-audio"; ++ brcm,pwm-channels = <8>; ++ status = "disabled"; ++ }; ++}; +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -55,6 +55,8 @@ + compatible = "brcm,bcm2835-vc4"; + status = "disabled"; + }; ++ ++ /delete-node/ audio; + }; + + &scb { +@@ -160,6 +162,18 @@ + }; + }; + ++&vchiq { ++ /* Onboard audio ++ * This node is replicated because the original from bcm270x-rpi.dtsi ++ * was deleted when the vchiq node was deleted above. ++ */ ++ audio: bcm2835_audio { ++ compatible = "brcm,bcm2835-audio"; ++ brcm,pwm-channels = <8>; ++ status = "disabled"; ++ }; ++}; ++ + &dma { + /* The VPU firmware uses DMA channel 11 for VCHIQ */ + brcm,dma-channel-mask = <0x1f5>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0423-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch b/target/linux/bcm27xx/patches-5.4/950-0423-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch deleted file mode 100644 index 4436c0a39d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0423-staging-vchiq_arm-Fix-bcm2711-compatible-string.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 871370c31c23fcd07ec375a088bd09a0a5a31126 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 31 Jan 2020 09:26:18 +0000 -Subject: [PATCH] staging/vchiq_arm: Fix bcm2711 compatible string - -Fixes: "vchiq: Add 36-bit address support" - -Signed-off-by: Phil Elwell ---- - drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -151,7 +151,7 @@ static struct vchiq_drvdata bcm2836_drvd - .cache_line_size = 64, - }; - --static struct vchiq_drvdata bcm2838_drvdata = { -+static struct vchiq_drvdata bcm2711_drvdata = { - .cache_line_size = 64, - .use_36bit_addrs = true, - }; -@@ -3171,7 +3171,7 @@ void vchiq_platform_conn_state_changed(s - static const struct of_device_id vchiq_of_match[] = { - { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata }, - { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata }, -- { .compatible = "brcm,bcm2838-vchiq", .data = &bcm2838_drvdata }, -+ { .compatible = "brcm,bcm2711-vchiq", .data = &bcm2711_drvdata }, - {}, - }; - MODULE_DEVICE_TABLE(of, vchiq_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0424-ARM-dts-overlays-Create-custom-clocks-in.patch b/target/linux/bcm27xx/patches-5.4/950-0424-ARM-dts-overlays-Create-custom-clocks-in.patch new file mode 100644 index 0000000000..ac50884bce --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0424-ARM-dts-overlays-Create-custom-clocks-in.patch @@ -0,0 +1,79 @@ +From c182949e33dc3ac4d718386f97c75583bae0e46b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 28 Feb 2020 11:22:40 +0000 +Subject: [PATCH] ARM: dts: overlays: Create custom clocks in / + +Change [1] removes the simple-bus compatible string from the "/clocks" +node, preventing any custom clocks placed there from being initialised. +Rather than reinstate the compatible string and trigger DT warnings at +kernel build time, change the overlays to instantiate those clocks under +the root node ("/"). + +See: https://github.com/raspberrypi/linux/issues/3481 + +Signed-off-by: Phil Elwell + +[1] 4b2d24662126 ("ARM: dts: bcm283x: Remove simple-bus from fixed clocks") +--- + .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts | 2 +- + 5 files changed, 5 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts +@@ -9,7 +9,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + boss_osc: boss_osc { + compatible = "allo,dac-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dacpro_osc: dacpro_osc { + compatible = "hifiberry,dacpro-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dacpro_osc: dacpro_osc { + compatible = "hifiberry,dacpro-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dacpro_osc: dacpro_osc { + compatible = "hifiberry,dacpro-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts +@@ -8,7 +8,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dachd_osc: pll_dachd_osc { + compatible = "hifiberry,dachd-clk"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0424-hwrng-iproc-rng200-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0424-hwrng-iproc-rng200-Correct-SoC-name.patch deleted file mode 100644 index f4e93308b1..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0424-hwrng-iproc-rng200-Correct-SoC-name.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 5eafa5065b2ea2c8d1634f045b85b982393d808a Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 31 Jan 2020 09:36:57 +0000 -Subject: [PATCH] hwrng: iproc-rng200: Correct SoC name - -The Pi 4 SoC is called BCM2711, not BCM2838. - -Fixes: "hwrng: iproc-rng200: Add BCM2838 support" - -Signed-off-by: Phil Elwell ---- - drivers/char/hw_random/Kconfig | 2 +- - drivers/char/hw_random/iproc-rng200.c | 11 +++++------ - 2 files changed, 6 insertions(+), 7 deletions(-) - ---- a/drivers/char/hw_random/Kconfig -+++ b/drivers/char/hw_random/Kconfig -@@ -94,7 +94,7 @@ config HW_RANDOM_IPROC_RNG200 - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the RNG200 -- hardware found on the Broadcom iProc, BCM2838 and STB SoCs. -+ hardware found on the Broadcom iProc, BCM2711 and STB SoCs. - - To compile this driver as a module, choose M here: the - module will be called iproc-rng200 ---- a/drivers/char/hw_random/iproc-rng200.c -+++ b/drivers/char/hw_random/iproc-rng200.c -@@ -174,7 +174,7 @@ static int iproc_rng200_init(struct hwrn - return 0; - } - --static int bcm2838_rng200_read(struct hwrng *rng, void *buf, size_t max, -+static int bcm2711_rng200_read(struct hwrng *rng, void *buf, size_t max, - bool wait) - { - struct iproc_rng200_dev *priv = to_rng_priv(rng); -@@ -211,7 +211,7 @@ static int bcm2838_rng200_read(struct hw - return num_words * sizeof(u32); - } - --static int bcm2838_rng200_init(struct hwrng *rng) -+static int bcm2711_rng200_init(struct hwrng *rng) - { - struct iproc_rng200_dev *priv = to_rng_priv(rng); - uint32_t val; -@@ -271,9 +271,9 @@ static int iproc_rng200_probe(struct pla - priv->rng.name = pdev->name; - priv->rng.cleanup = iproc_rng200_cleanup; - -- if (of_device_is_compatible(dev->of_node, "brcm,bcm2838-rng200")) { -- priv->rng.init = bcm2838_rng200_init; -- priv->rng.read = bcm2838_rng200_read; -+ if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-rng200")) { -+ priv->rng.init = bcm2711_rng200_init; -+ priv->rng.read = bcm2711_rng200_read; - } else { - priv->rng.init = iproc_rng200_init; - priv->rng.read = iproc_rng200_read; -@@ -296,7 +296,6 @@ static const struct of_device_id iproc_r - { .compatible = "brcm,bcm7211-rng200", }, - { .compatible = "brcm,bcm7278-rng200", }, - { .compatible = "brcm,iproc-rng200", }, -- { .compatible = "brcm,bcm2838-rng200"}, - {}, - }; - MODULE_DEVICE_TABLE(of, iproc_rng200_of_match); diff --git a/target/linux/bcm27xx/patches-5.4/950-0425-ARM-dts-Correct-SoC-name.patch b/target/linux/bcm27xx/patches-5.4/950-0425-ARM-dts-Correct-SoC-name.patch deleted file mode 100644 index c18eb8af3c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0425-ARM-dts-Correct-SoC-name.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 475158d2aab9dc2e8266726f7b026cedfe810619 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 31 Jan 2020 15:24:59 +0000 -Subject: [PATCH] ARM: dts: Correct SoC name - -The Pi 4 SoC is called BCM2711, not BCM2838. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2711-rpi.dtsi | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - ---- a/arch/arm/boot/dts/bcm2711-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi -@@ -42,7 +42,7 @@ - - &soc { - thermal: thermal@7d5d2200 { -- compatible = "brcm,avs-tmon-bcm2838"; -+ compatible = "brcm,avs-tmon-bcm2711"; - reg = <0x7d5d2200 0x2c>; - interrupts = ; - interrupt-names = "tmon"; -@@ -106,7 +106,7 @@ - }; - - dma40: dma@7e007b00 { -- compatible = "brcm,bcm2838-dma"; -+ compatible = "brcm,bcm2711-dma"; - reg = <0x0 0x7e007b00 0x400>; - interrupts = - , /* dma4 11 */ -@@ -122,7 +122,7 @@ - }; - - vchiq: mailbox@7e00b840 { -- compatible = "brcm,bcm2838-vchiq"; -+ compatible = "brcm,bcm2711-vchiq"; - reg = <0 0x7e00b840 0x3c>; - interrupts = ; - }; -@@ -195,7 +195,7 @@ - }; - - &random { -- compatible = "brcm,bcm2711-rng200", "brcm,bcm2838-rng200"; -+ compatible = "brcm,bcm2711-rng200"; - status = "okay"; - }; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0425-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch b/target/linux/bcm27xx/patches-5.4/950-0425-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch new file mode 100644 index 0000000000..4774fd2326 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0425-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch @@ -0,0 +1,26 @@ +From 38e906c77467bf83ec130bea6859b46ea1e0d4b8 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 30 Jan 2020 12:35:44 +0000 +Subject: [PATCH] staging: vc04_services: Fix vcsm overflow bug when + counting transactions + +The response block and local state were using u16 and u32 respectively +to represent transaction id. When the former would wrap, there is a +mismatch and subsequent transactions will be marked as failures. + +Signed-off-by: Naushir Patuck +--- + drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c +@@ -34,7 +34,7 @@ struct sm_cmd_rsp_blk { + /* To be signaled when the response is there */ + struct completion cmplt; + +- u16 id; ++ u32 id; + u16 length; + + u8 msg[VC_SM_MAX_MSG_LEN]; diff --git a/target/linux/bcm27xx/patches-5.4/950-0426-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch b/target/linux/bcm27xx/patches-5.4/950-0426-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch deleted file mode 100644 index 2c093459da..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0426-ARM-dts-Remove-CMA-allocation-from-Pi-4-dts.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 1a66f120abddf36eaf2540532ddeb7f7767442c5 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Sat, 1 Feb 2020 08:58:11 +0000 -Subject: [PATCH] ARM: dts: Remove CMA allocation from Pi 4 dts - -The 5.5 tree includes a patch to disable the CMA command line -parameter and replace it with properties from a DT node. -The upstream Pi 4 .dts, now used downstream with modifications, -includes the "linux,cma" node, but only reserves 32MB which is -often not enough. - -Temporarily remove the "linux,cma" node to reenable the command line -parameter. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -167,6 +167,10 @@ - }; - - /delete-node/ wifi-pwrseq; -+ -+ reserved-memory { -+ /delete-node/ linux,cma; -+ }; - }; - - &mmcnr { diff --git a/target/linux/bcm27xx/patches-5.4/950-0426-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch b/target/linux/bcm27xx/patches-5.4/950-0426-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch new file mode 100644 index 0000000000..213e8b8d9d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0426-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch @@ -0,0 +1,34 @@ +From 04f569021b0d24ec9f5c3671447b77157c859d16 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 7 Feb 2020 09:51:31 +0000 +Subject: [PATCH] overlays: Add timeout_ms parameter to gpio-poweroff + +The timeout_ms parameter specifies in milliseconds how long the kernel +waits for power-down before issuing a WARN. The default value is 3000 ms. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 1 + + 2 files changed, 3 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -821,6 +821,8 @@ Params: gpiopin GPIO for + input Set if the gpio pin should be configured as + an input. + export Set to export the configured pin to sysfs ++ timeout_ms Specify (in ms) how long the kernel waits for ++ power-down before issuing a WARN (default 3000). + + + Name: gpio-shutdown +--- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts ++++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts +@@ -32,5 +32,6 @@ + active_low = <&power_ctrl>,"gpios:8"; + input = <&power_ctrl>,"input?"; + export = <&power_ctrl>,"export?"; ++ timeout_ms = <&power_ctrl>,"timeout-ms:0"; + }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0427-of-overlay-Correct-symbol-path-fixups.patch b/target/linux/bcm27xx/patches-5.4/950-0427-of-overlay-Correct-symbol-path-fixups.patch new file mode 100644 index 0000000000..4b005876de --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0427-of-overlay-Correct-symbol-path-fixups.patch @@ -0,0 +1,37 @@ +From 8f22c4228bbb91697ab3510f5a6176e530c0d639 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 6 Feb 2020 12:23:15 +0000 +Subject: [PATCH] of: overlay: Correct symbol path fixups + +When symbols from overlays are added to the live tree their paths must +be rebased. The translated symbol is normally the result of joining +the fragment-relative path (with a leading "/") to the target path +(either copied directly from the "target-path" property or resolved +from the phandle). This translation fails when the target is the root +node (a common case for Raspberry Pi overlays) because the resulting +path starts with a double slash. For example, if target-path is "/" and +the fragment adds a node called "newnode", the label associated with +that node will be assigned the path "//newnode", which can't be found +in the tree. + +Fix the failure case by explicitly replacing a target path of "/" with +an empty string. + +Fixes: d1651b03c2df ("of: overlay: add overlay symbols to live device tree") + +Signed-off-by: Phil Elwell +--- + drivers/of/overlay.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/of/overlay.c ++++ b/drivers/of/overlay.c +@@ -245,6 +245,8 @@ static struct property *dup_and_fixup_sy + if (!target_path) + return NULL; + target_path_len = strlen(target_path); ++ if (!strcmp(target_path, "/")) ++ target_path_len = 0; + + new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); + if (!new_prop) diff --git a/target/linux/bcm27xx/patches-5.4/950-0427-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0427-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch deleted file mode 100644 index 7fb3443fa9..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0427-staging-vchiq_arm-Give-vchiq-children-DT-nodes.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 9f93264df7a631132f2dacd150d0cc6cb7d20fc4 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 3 Feb 2020 17:30:46 +0000 -Subject: [PATCH] staging: vchiq_arm: Give vchiq children DT nodes - -vchiq kernel clients are now instantiated as platform drivers rather -than using DT, but the children of the vchiq interface may still -benefit from access to DT properties. Give them the option of a -a sub-node of the vchiq parent for configuration and to allow -them to be disabled. - -Signed-off-by: Phil Elwell ---- - .../staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - ---- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c -@@ -3190,12 +3190,20 @@ vchiq_register_child(struct platform_dev - pdevinfo.id = PLATFORM_DEVID_NONE; - pdevinfo.dma_mask = DMA_BIT_MASK(32); - -+ np = of_get_child_by_name(pdev->dev.of_node, name); -+ -+ /* Skip the child if it is explicitly disabled */ -+ if (np && !of_device_is_available(np)) -+ return NULL; -+ - child = platform_device_register_full(&pdevinfo); - if (IS_ERR(child)) { - dev_warn(&pdev->dev, "%s not registered\n", name); - child = NULL; - } - -+ child->dev.of_node = np; -+ - /* - * We want the dma-ranges etc to be copied from a device with the - * correct dma-ranges for the VPU. diff --git a/target/linux/bcm27xx/patches-5.4/950-0428-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0428-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch new file mode 100644 index 0000000000..636ad26a91 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0428-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch @@ -0,0 +1,25 @@ +From 65318cd76f4523acf8ffe8fe7448fb7d913f8c66 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 3 Mar 2020 09:43:41 +0000 +Subject: [PATCH] overlays: sc16ic750-i2c: Fix xtal parameter + +The xtal parameter is targetting the wrong node - fix it. + +See: https://github.com/raspberrypi/linux/issues/3156 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts +@@ -32,7 +32,7 @@ + __overrides__ { + int_pin = <&sc16is750>,"interrupts:0"; + addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name"; +- xtal = <&sc16is750>,"clock-frequency:0"; ++ xtal = <&sc16is750_clk>,"clock-frequency:0"; + }; + + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0429-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch b/target/linux/bcm27xx/patches-5.4/950-0429-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch deleted file mode 100644 index b5e59e6464..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0429-ARM-dts-Move-audio-node-under-the-vchiq-parent.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 6c5efcf09c40d37f72692fdbdf6d461abede20f1 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 3 Feb 2020 17:03:29 +0000 -Subject: [PATCH] ARM: dts: Move audio node under the vchiq parent - -VCHIQ kernel clients are now instantiated as platform drivers rather -than using DT, but the children of the vchiq device can optionally be -given a sub-node of the vchiq parent for configuration and to disable -them. - -Move the existing audio node beneath the vchiq parent, to prevent -multiple instantiation and unpleasant warnings. Note that the node -name has to match the module name - "bcm2835_audio". - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm270x-rpi.dtsi | 16 +++++++++------- - arch/arm/boot/dts/bcm2711-rpi.dtsi | 14 ++++++++++++++ - 2 files changed, 23 insertions(+), 7 deletions(-) - ---- a/arch/arm/boot/dts/bcm270x-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm270x-rpi.dtsi -@@ -70,13 +70,6 @@ - status = "okay"; - }; - -- /* Onboard audio */ -- audio: audio { -- compatible = "brcm,bcm2835-audio"; -- brcm,pwm-channels = <8>; -- status = "disabled"; -- }; -- - /* External sound card */ - sound: sound { - status = "disabled"; -@@ -137,3 +130,12 @@ - &vec { - status = "disabled"; - }; -+ -+&vchiq { -+ /* Onboard audio */ -+ audio: bcm2835_audio { -+ compatible = "brcm,bcm2835-audio"; -+ brcm,pwm-channels = <8>; -+ status = "disabled"; -+ }; -+}; ---- a/arch/arm/boot/dts/bcm2711-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi -@@ -55,6 +55,8 @@ - compatible = "brcm,bcm2835-vc4"; - status = "disabled"; - }; -+ -+ /delete-node/ audio; - }; - - &scb { -@@ -160,6 +162,18 @@ - }; - }; - -+&vchiq { -+ /* Onboard audio -+ * This node is replicated because the original from bcm270x-rpi.dtsi -+ * was deleted when the vchiq node was deleted above. -+ */ -+ audio: bcm2835_audio { -+ compatible = "brcm,bcm2835-audio"; -+ brcm,pwm-channels = <8>; -+ status = "disabled"; -+ }; -+}; -+ - &dma { - /* The VPU firmware uses DMA channel 11 for VCHIQ */ - brcm,dma-channel-mask = <0x1f5>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0429-of-address-Introduce-of_get_next_dma_parent-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0429-of-address-Introduce-of_get_next_dma_parent-helper.patch new file mode 100644 index 0000000000..1056cfc60d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0429-of-address-Introduce-of_get_next_dma_parent-helper.patch @@ -0,0 +1,39 @@ +From 25ab98ceb9844642c994b5766de1033552d1aef2 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Wed, 3 Jul 2019 18:23:01 +0100 +Subject: [PATCH] of/address: Introduce of_get_next_dma_parent() helper + +commit 862ab5578f754117742c8b8c8e5ddf98bdb190ba upstream. + +Add of_get_next_dma_parent() helper which is similar to +__of_get_dma_parent(), but can be used in iterators and decrements the +ref count on the prior parent. + +Signed-off-by: Robin Murphy +Reviewed-by: Geert Uytterhoeven +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring +--- + drivers/of/address.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -695,6 +695,16 @@ static struct device_node *__of_get_dma_ + return of_node_get(args.np); + } + ++static struct device_node *of_get_next_dma_parent(struct device_node *np) ++{ ++ struct device_node *parent; ++ ++ parent = __of_get_dma_parent(np); ++ of_node_put(np); ++ ++ return parent; ++} ++ + u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) + { + struct device_node *host; diff --git a/target/linux/bcm27xx/patches-5.4/950-0430-ARM-dts-overlays-Create-custom-clocks-in.patch b/target/linux/bcm27xx/patches-5.4/950-0430-ARM-dts-overlays-Create-custom-clocks-in.patch deleted file mode 100644 index ac50884bce..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0430-ARM-dts-overlays-Create-custom-clocks-in.patch +++ /dev/null @@ -1,79 +0,0 @@ -From c182949e33dc3ac4d718386f97c75583bae0e46b Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 28 Feb 2020 11:22:40 +0000 -Subject: [PATCH] ARM: dts: overlays: Create custom clocks in / - -Change [1] removes the simple-bus compatible string from the "/clocks" -node, preventing any custom clocks placed there from being initialised. -Rather than reinstate the compatible string and trigger DT warnings at -kernel build time, change the overlays to instantiate those clocks under -the root node ("/"). - -See: https://github.com/raspberrypi/linux/issues/3481 - -Signed-off-by: Phil Elwell - -[1] 4b2d24662126 ("ARM: dts: bcm283x: Remove simple-bus from fixed clocks") ---- - .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts | 2 +- - 5 files changed, 5 insertions(+), 5 deletions(-) - ---- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts -+++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts -@@ -9,7 +9,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - boss_osc: boss_osc { - compatible = "allo,dac-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts -@@ -6,7 +6,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dacpro_osc: dacpro_osc { - compatible = "hifiberry,dacpro-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts -@@ -6,7 +6,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dacpro_osc: dacpro_osc { - compatible = "hifiberry,dacpro-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -@@ -6,7 +6,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dacpro_osc: dacpro_osc { - compatible = "hifiberry,dacpro-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts -@@ -8,7 +8,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dachd_osc: pll_dachd_osc { - compatible = "hifiberry,dachd-clk"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0430-of-address-Follow-DMA-parent-for-dma-coherent.patch b/target/linux/bcm27xx/patches-5.4/950-0430-of-address-Follow-DMA-parent-for-dma-coherent.patch new file mode 100644 index 0000000000..76af58a126 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0430-of-address-Follow-DMA-parent-for-dma-coherent.patch @@ -0,0 +1,30 @@ +From e4a649779ff6857240fe691cdf147a3b4896e71b Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Wed, 3 Jul 2019 14:47:31 +0100 +Subject: [PATCH] of: address: Follow DMA parent for "dma-coherent" + +commit c60bf3eb888a362100aa1bdbea351dab681e262a upstream. + +Much like for address translation, when checking for DMA coherence we +should be sure to walk up the DMA hierarchy, rather than the MMIO one, +now that we can accommodate them being different. + +Signed-off-by: Robin Murphy +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring +--- + drivers/of/address.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -1025,7 +1025,7 @@ bool of_dma_is_coherent(struct device_no + of_node_put(node); + return true; + } +- node = of_get_next_parent(node); ++ node = of_get_next_dma_parent(node); + } + of_node_put(node); + return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0431-of-Factor-out-addr-size-cells-parsing.patch b/target/linux/bcm27xx/patches-5.4/950-0431-of-Factor-out-addr-size-cells-parsing.patch new file mode 100644 index 0000000000..045ee9827f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0431-of-Factor-out-addr-size-cells-parsing.patch @@ -0,0 +1,117 @@ +From 839aeedc908eb729b9014e7d1d38e109778a52d2 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Tue, 2 Jul 2019 18:42:39 +0100 +Subject: [PATCH] of: Factor out #{addr,size}-cells parsing + +In some cases such as PCI host controllers, we may have a "parent bus" +which is an OF leaf node, but still need to correctly parse ranges from +the point of view of that bus. For that, factor out variants of the +"#addr-cells" and "#size-cells" parsers which do not assume they have a +device node and thus immediately traverse upwards before reading the +relevant property. + +Signed-off-by: Robin Murphy +[robh: don't make of_bus_n_{addr,size}_cells() public] +Reviewed-by: Geert Uytterhoeven +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring + +(cherry picked from commit b68ac8dc22ebbf003e26e44bf4dd3030c076df5a) +--- + drivers/of/address.c | 2 ++ + drivers/of/base.c | 32 ++++++++++++++++++++++---------- + drivers/of/of_private.h | 14 ++++++++++++++ + 3 files changed, 38 insertions(+), 10 deletions(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -14,6 +14,8 @@ + #include + #include + ++#include "of_private.h" ++ + /* Max address size we deal with */ + #define OF_MAX_ADDR_CELLS 4 + #define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) +--- a/drivers/of/base.c ++++ b/drivers/of/base.c +@@ -86,34 +86,46 @@ static bool __of_node_is_type(const stru + return np && match && type && !strcmp(match, type); + } + +-int of_n_addr_cells(struct device_node *np) ++int of_bus_n_addr_cells(struct device_node *np) + { + u32 cells; + +- do { +- if (np->parent) +- np = np->parent; ++ for (; np; np = np->parent) + if (!of_property_read_u32(np, "#address-cells", &cells)) + return cells; +- } while (np->parent); ++ + /* No #address-cells property for the root node */ + return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; + } ++ ++int of_n_addr_cells(struct device_node *np) ++{ ++ if (np->parent) ++ np = np->parent; ++ ++ return of_bus_n_addr_cells(np); ++} + EXPORT_SYMBOL(of_n_addr_cells); + +-int of_n_size_cells(struct device_node *np) ++int of_bus_n_size_cells(struct device_node *np) + { + u32 cells; + +- do { +- if (np->parent) +- np = np->parent; ++ for (; np; np = np->parent) + if (!of_property_read_u32(np, "#size-cells", &cells)) + return cells; +- } while (np->parent); ++ + /* No #size-cells property for the root node */ + return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; + } ++ ++int of_n_size_cells(struct device_node *np) ++{ ++ if (np->parent) ++ np = np->parent; ++ ++ return of_bus_n_size_cells(np); ++} + EXPORT_SYMBOL(of_n_size_cells); + + #ifdef CONFIG_NUMA +--- a/drivers/of/of_private.h ++++ b/drivers/of/of_private.h +@@ -158,4 +158,18 @@ extern void __of_sysfs_remove_bin_file(s + #define for_each_transaction_entry_reverse(_oft, _te) \ + list_for_each_entry_reverse(_te, &(_oft)->te_list, node) + ++extern int of_bus_n_addr_cells(struct device_node *np); ++extern int of_bus_n_size_cells(struct device_node *np); ++ ++#ifdef CONFIG_OF_ADDRESS ++extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, ++ u64 *paddr, u64 *size); ++#else ++static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, ++ u64 *paddr, u64 *size) ++{ ++ return -ENODEV; ++} ++#endif ++ + #endif /* _LINUX_OF_PRIVATE_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0431-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch b/target/linux/bcm27xx/patches-5.4/950-0431-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch deleted file mode 100644 index 4774fd2326..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0431-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 38e906c77467bf83ec130bea6859b46ea1e0d4b8 Mon Sep 17 00:00:00 2001 -From: Naushir Patuck -Date: Thu, 30 Jan 2020 12:35:44 +0000 -Subject: [PATCH] staging: vc04_services: Fix vcsm overflow bug when - counting transactions - -The response block and local state were using u16 and u32 respectively -to represent transaction id. When the former would wrap, there is a -mismatch and subsequent transactions will be marked as failures. - -Signed-off-by: Naushir Patuck ---- - drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c -@@ -34,7 +34,7 @@ struct sm_cmd_rsp_blk { - /* To be signaled when the response is there */ - struct completion cmplt; - -- u16 id; -+ u32 id; - u16 length; - - u8 msg[VC_SM_MAX_MSG_LEN]; diff --git a/target/linux/bcm27xx/patches-5.4/950-0432-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch b/target/linux/bcm27xx/patches-5.4/950-0432-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch new file mode 100644 index 0000000000..28d1987a9c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0432-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch @@ -0,0 +1,40 @@ +From 39f5d9e883393e32938eac45b564f74afde8a942 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Wed, 4 Sep 2019 11:43:30 +0100 +Subject: [PATCH] of/address: Translate 'dma-ranges' for parent nodes + missing 'dma-ranges' + +commit 81db12ee15cb83926e290a8a3654a2dfebc80935 upstream. + +'dma-ranges' frequently exists without parent nodes having 'dma-ranges'. +While this is an error for 'ranges', this is fine because DMA capable +devices always have a translatable DMA address. Also, with no +'dma-ranges' at all, the assumption is that DMA addresses are 1:1 with +no restrictions unless perhaps the device itself has implicit +restrictions. + +Cc: Robin Murphy +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring +--- + drivers/of/address.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -519,9 +519,13 @@ static int of_translate_one(struct devic + * + * As far as we know, this damage only exists on Apple machines, so + * This code is only enabled on powerpc. --gcl ++ * ++ * This quirk also applies for 'dma-ranges' which frequently exist in ++ * child nodes without 'dma-ranges' in the parent nodes. --RobH + */ + ranges = of_get_property(parent, rprop, &rlen); +- if (ranges == NULL && !of_empty_ranges_quirk(parent)) { ++ if (ranges == NULL && !of_empty_ranges_quirk(parent) && ++ strcmp(rprop, "dma-ranges")) { + pr_debug("no ranges; cannot translate\n"); + return 1; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0432-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch b/target/linux/bcm27xx/patches-5.4/950-0432-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch deleted file mode 100644 index 213e8b8d9d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0432-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 04f569021b0d24ec9f5c3671447b77157c859d16 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 7 Feb 2020 09:51:31 +0000 -Subject: [PATCH] overlays: Add timeout_ms parameter to gpio-poweroff - -The timeout_ms parameter specifies in milliseconds how long the kernel -waits for power-down before issuing a WARN. The default value is 3000 ms. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/README | 2 ++ - arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 1 + - 2 files changed, 3 insertions(+) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -821,6 +821,8 @@ Params: gpiopin GPIO for - input Set if the gpio pin should be configured as - an input. - export Set to export the configured pin to sysfs -+ timeout_ms Specify (in ms) how long the kernel waits for -+ power-down before issuing a WARN (default 3000). - - - Name: gpio-shutdown ---- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts -+++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts -@@ -32,5 +32,6 @@ - active_low = <&power_ctrl>,"gpios:8"; - input = <&power_ctrl>,"input?"; - export = <&power_ctrl>,"export?"; -+ timeout_ms = <&power_ctrl>,"timeout-ms:0"; - }; - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0433-of-Make-of_dma_get_range-work-on-bus-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0433-of-Make-of_dma_get_range-work-on-bus-nodes.patch new file mode 100644 index 0000000000..1cac2dfcd8 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0433-of-Make-of_dma_get_range-work-on-bus-nodes.patch @@ -0,0 +1,107 @@ +From 7631cb95056f03136c9e0a35484e8bebe7b52650 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Wed, 3 Jul 2019 18:42:20 +0100 +Subject: [PATCH] of: Make of_dma_get_range() work on bus nodes + +commit 951d48855d86e72e0d6de73440fe09d363168064 upstream. + +Since the "dma-ranges" property is only valid for a node representing a +bus, of_dma_get_range() currently assumes the node passed in is a leaf +representing a device, and starts the walk from its parent. In cases +like PCI host controllers on typical FDT systems, however, where the PCI +endpoints are probed dynamically the initial leaf node represents the +'bus' itself, and this logic means we fail to consider any "dma-ranges" +describing the host bridge itself. Rework the logic such that +of_dma_get_range() also works correctly starting from a bus node +containing "dma-ranges". + +While this does mean "dma-ranges" could incorrectly be in a device leaf +node, there isn't really any way in this function to ensure that a leaf +node is or isn't a bus node. + +Signed-off-by: Robin Murphy +[robh: Allow for the bus child node to still be passed in] +Signed-off-by: Rob Herring +Reviewed-by: Robin Murphy +Reviewed-by: Nicolas Saenz Julienne +Tested-by: Nicolas Saenz Julienne +--- + drivers/of/address.c | 44 ++++++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 26 deletions(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -940,47 +940,39 @@ int of_dma_get_range(struct device_node + const __be32 *ranges = NULL; + int len, naddr, nsize, pna; + int ret = 0; ++ bool found_dma_ranges = false; + u64 dmaaddr; + +- if (!node) +- return -EINVAL; +- +- while (1) { +- struct device_node *parent; +- +- naddr = of_n_addr_cells(node); +- nsize = of_n_size_cells(node); +- +- parent = __of_get_dma_parent(node); +- of_node_put(node); +- +- node = parent; +- if (!node) +- break; +- ++ while (node) { + ranges = of_get_property(node, "dma-ranges", &len); + + /* Ignore empty ranges, they imply no translation required */ + if (ranges && len > 0) + break; + +- /* +- * At least empty ranges has to be defined for parent node if +- * DMA is supported +- */ +- if (!ranges) +- break; ++ /* Once we find 'dma-ranges', then a missing one is an error */ ++ if (found_dma_ranges && !ranges) { ++ ret = -ENODEV; ++ goto out; ++ } ++ found_dma_ranges = true; ++ ++ node = of_get_next_dma_parent(node); + } + +- if (!ranges) { ++ if (!node || !ranges) { + pr_debug("no dma-ranges found for node(%pOF)\n", np); + ret = -ENODEV; + goto out; + } + +- len /= sizeof(u32); +- ++ naddr = of_bus_n_addr_cells(node); ++ nsize = of_bus_n_size_cells(node); + pna = of_n_addr_cells(node); ++ if ((len / sizeof(__be32)) % (pna + naddr + nsize)) { ++ ret = -EINVAL; ++ goto out; ++ } + + /* dma-ranges format: + * DMA addr : naddr cells +@@ -988,7 +980,7 @@ int of_dma_get_range(struct device_node + * size : nsize cells + */ + dmaaddr = of_read_number(ranges, naddr); +- *paddr = of_translate_dma_address(np, ranges); ++ *paddr = of_translate_dma_address(node, ranges + naddr); + if (*paddr == OF_BAD_ADDR) { + pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n", + dma_addr, np); diff --git a/target/linux/bcm27xx/patches-5.4/950-0433-of-overlay-Correct-symbol-path-fixups.patch b/target/linux/bcm27xx/patches-5.4/950-0433-of-overlay-Correct-symbol-path-fixups.patch deleted file mode 100644 index 4b005876de..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0433-of-overlay-Correct-symbol-path-fixups.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8f22c4228bbb91697ab3510f5a6176e530c0d639 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 6 Feb 2020 12:23:15 +0000 -Subject: [PATCH] of: overlay: Correct symbol path fixups - -When symbols from overlays are added to the live tree their paths must -be rebased. The translated symbol is normally the result of joining -the fragment-relative path (with a leading "/") to the target path -(either copied directly from the "target-path" property or resolved -from the phandle). This translation fails when the target is the root -node (a common case for Raspberry Pi overlays) because the resulting -path starts with a double slash. For example, if target-path is "/" and -the fragment adds a node called "newnode", the label associated with -that node will be assigned the path "//newnode", which can't be found -in the tree. - -Fix the failure case by explicitly replacing a target path of "/" with -an empty string. - -Fixes: d1651b03c2df ("of: overlay: add overlay symbols to live device tree") - -Signed-off-by: Phil Elwell ---- - drivers/of/overlay.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/of/overlay.c -+++ b/drivers/of/overlay.c -@@ -245,6 +245,8 @@ static struct property *dup_and_fixup_sy - if (!target_path) - return NULL; - target_path_len = strlen(target_path); -+ if (!strcmp(target_path, "/")) -+ target_path_len = 0; - - new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); - if (!new_prop) diff --git a/target/linux/bcm27xx/patches-5.4/950-0434-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch b/target/linux/bcm27xx/patches-5.4/950-0434-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch new file mode 100644 index 0000000000..c697494f8a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0434-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch @@ -0,0 +1,30 @@ +From c17f622cbb33332a305ef383506740d3d01aa831 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:43 +0200 +Subject: [PATCH] arm64: mm: use arm64_dma_phys_limit instead of + calling max_zone_dma_phys() + +commit ae970dc096b2d39f65f2e18d142e3978dc9ee1c7 upstream. + +By the time we call zones_sizes_init() arm64_dma_phys_limit already +contains the result of max_zone_dma_phys(). We use the variable instead +of calling the function directly to save some precious cpu time. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + arch/arm64/mm/init.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -181,7 +181,7 @@ static void __init zone_sizes_init(unsig + unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; + + #ifdef CONFIG_ZONE_DMA32 +- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys()); ++ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); + #endif + max_zone_pfns[ZONE_NORMAL] = max; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0434-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0434-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch deleted file mode 100644 index 636ad26a91..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0434-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 65318cd76f4523acf8ffe8fe7448fb7d913f8c66 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 3 Mar 2020 09:43:41 +0000 -Subject: [PATCH] overlays: sc16ic750-i2c: Fix xtal parameter - -The xtal parameter is targetting the wrong node - fix it. - -See: https://github.com/raspberrypi/linux/issues/3156 - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts -+++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts -@@ -32,7 +32,7 @@ - __overrides__ { - int_pin = <&sc16is750>,"interrupts:0"; - addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name"; -- xtal = <&sc16is750>,"clock-frequency:0"; -+ xtal = <&sc16is750_clk>,"clock-frequency:0"; - }; - - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0435-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch b/target/linux/bcm27xx/patches-5.4/950-0435-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch new file mode 100644 index 0000000000..df184f53ee --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0435-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch @@ -0,0 +1,117 @@ +From 4d2bd7f66bac81b042afc2a6e742bd776a5a3938 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:44 +0200 +Subject: [PATCH] arm64: rename variables used to calculate + ZONE_DMA32's size + +commit a573cdd7973dedd87e62196c400332896bb236c8 upstream. + +Let the name indicate that they are used to calculate ZONE_DMA32's size +as opposed to ZONE_DMA. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + arch/arm64/mm/init.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -50,7 +50,7 @@ + s64 memstart_addr __ro_after_init = -1; + EXPORT_SYMBOL(memstart_addr); + +-phys_addr_t arm64_dma_phys_limit __ro_after_init; ++phys_addr_t arm64_dma32_phys_limit __ro_after_init; + + #ifdef CONFIG_KEXEC_CORE + /* +@@ -168,7 +168,7 @@ static void __init reserve_elfcorehdr(vo + * currently assumes that for memory starting above 4G, 32-bit devices will + * use a DMA offset. + */ +-static phys_addr_t __init max_zone_dma_phys(void) ++static phys_addr_t __init max_zone_dma32_phys(void) + { + phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); + return min(offset + (1ULL << 32), memblock_end_of_DRAM()); +@@ -181,7 +181,7 @@ static void __init zone_sizes_init(unsig + unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; + + #ifdef CONFIG_ZONE_DMA32 +- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); ++ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); + #endif + max_zone_pfns[ZONE_NORMAL] = max; + +@@ -194,16 +194,16 @@ static void __init zone_sizes_init(unsig + { + struct memblock_region *reg; + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; +- unsigned long max_dma = min; ++ unsigned long max_dma32 = min; + + memset(zone_size, 0, sizeof(zone_size)); + + /* 4GB maximum for 32-bit only capable devices */ + #ifdef CONFIG_ZONE_DMA32 +- max_dma = PFN_DOWN(arm64_dma_phys_limit); +- zone_size[ZONE_DMA32] = max_dma - min; ++ max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); ++ zone_size[ZONE_DMA32] = max_dma32 - min; + #endif +- zone_size[ZONE_NORMAL] = max - max_dma; ++ zone_size[ZONE_NORMAL] = max - max_dma32; + + memcpy(zhole_size, zone_size, sizeof(zhole_size)); + +@@ -215,14 +215,14 @@ static void __init zone_sizes_init(unsig + continue; + + #ifdef CONFIG_ZONE_DMA32 +- if (start < max_dma) { +- unsigned long dma_end = min(end, max_dma); ++ if (start < max_dma32) { ++ unsigned long dma_end = min(end, max_dma32); + zhole_size[ZONE_DMA32] -= dma_end - start; + } + #endif +- if (end > max_dma) { ++ if (end > max_dma32) { + unsigned long normal_end = min(end, max); +- unsigned long normal_start = max(start, max_dma); ++ unsigned long normal_start = max(start, max_dma32); + zhole_size[ZONE_NORMAL] -= normal_end - normal_start; + } + } +@@ -410,9 +410,9 @@ void __init arm64_memblock_init(void) + + /* 4GB maximum for 32-bit only capable devices */ + if (IS_ENABLED(CONFIG_ZONE_DMA32)) +- arm64_dma_phys_limit = max_zone_dma_phys(); ++ arm64_dma32_phys_limit = max_zone_dma32_phys(); + else +- arm64_dma_phys_limit = PHYS_MASK + 1; ++ arm64_dma32_phys_limit = PHYS_MASK + 1; + + reserve_crashkernel(); + +@@ -420,7 +420,7 @@ void __init arm64_memblock_init(void) + + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; + +- dma_contiguous_reserve(arm64_dma_phys_limit); ++ dma_contiguous_reserve(arm64_dma32_phys_limit); + } + + void __init bootmem_init(void) +@@ -524,7 +524,7 @@ static void __init free_unused_memmap(vo + void __init mem_init(void) + { + if (swiotlb_force == SWIOTLB_FORCE || +- max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) ++ max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) + swiotlb_init(1); + else + swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0435-of-address-Introduce-of_get_next_dma_parent-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0435-of-address-Introduce-of_get_next_dma_parent-helper.patch deleted file mode 100644 index 1056cfc60d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0435-of-address-Introduce-of_get_next_dma_parent-helper.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 25ab98ceb9844642c994b5766de1033552d1aef2 Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Wed, 3 Jul 2019 18:23:01 +0100 -Subject: [PATCH] of/address: Introduce of_get_next_dma_parent() helper - -commit 862ab5578f754117742c8b8c8e5ddf98bdb190ba upstream. - -Add of_get_next_dma_parent() helper which is similar to -__of_get_dma_parent(), but can be used in iterators and decrements the -ref count on the prior parent. - -Signed-off-by: Robin Murphy -Reviewed-by: Geert Uytterhoeven -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring ---- - drivers/of/address.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -695,6 +695,16 @@ static struct device_node *__of_get_dma_ - return of_node_get(args.np); - } - -+static struct device_node *of_get_next_dma_parent(struct device_node *np) -+{ -+ struct device_node *parent; -+ -+ parent = __of_get_dma_parent(np); -+ of_node_put(np); -+ -+ return parent; -+} -+ - u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) - { - struct device_node *host; diff --git a/target/linux/bcm27xx/patches-5.4/950-0436-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch b/target/linux/bcm27xx/patches-5.4/950-0436-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch new file mode 100644 index 0000000000..ccb2071f17 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0436-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch @@ -0,0 +1,174 @@ +From 1fb65f4bc30fbadd0c89521985ff8142693c9631 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:45 +0200 +Subject: [PATCH] arm64: use both ZONE_DMA and ZONE_DMA32 + +commit 1a8e1cef7603e218339ac63cb3178b25554524e5 upstream. + +So far all arm64 devices have supported 32 bit DMA masks for their +peripherals. This is not true anymore for the Raspberry Pi 4 as most of +it's peripherals can only address the first GB of memory on a total of +up to 4 GB. + +This goes against ZONE_DMA32's intent, as it's expected for ZONE_DMA32 +to be addressable with a 32 bit mask. So it was decided to re-introduce +ZONE_DMA in arm64. + +ZONE_DMA will contain the lower 1G of memory, which is currently the +memory area addressable by any peripheral on an arm64 device. +ZONE_DMA32 will contain the rest of the 32 bit addressable memory. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + arch/arm64/Kconfig | 4 +++ + arch/arm64/include/asm/page.h | 2 ++ + arch/arm64/mm/init.c | 54 +++++++++++++++++++++++++---------- + 3 files changed, 45 insertions(+), 15 deletions(-) + +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -267,6 +267,10 @@ config GENERIC_CSUM + config GENERIC_CALIBRATE_DELAY + def_bool y + ++config ZONE_DMA ++ bool "Support DMA zone" if EXPERT ++ default y ++ + config ZONE_DMA32 + bool "Support DMA32 zone" if EXPERT + default y +--- a/arch/arm64/include/asm/page.h ++++ b/arch/arm64/include/asm/page.h +@@ -38,4 +38,6 @@ extern int pfn_valid(unsigned long); + + #include + ++#define ARCH_ZONE_DMA_BITS 30 ++ + #endif +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -50,6 +50,13 @@ + s64 memstart_addr __ro_after_init = -1; + EXPORT_SYMBOL(memstart_addr); + ++/* ++ * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of ++ * memory as some devices, namely the Raspberry Pi 4, have peripherals with ++ * this limited view of the memory. ZONE_DMA32 will cover the rest of the 32 ++ * bit addressable memory area. ++ */ ++phys_addr_t arm64_dma_phys_limit __ro_after_init; + phys_addr_t arm64_dma32_phys_limit __ro_after_init; + + #ifdef CONFIG_KEXEC_CORE +@@ -163,15 +170,16 @@ static void __init reserve_elfcorehdr(vo + { + } + #endif /* CONFIG_CRASH_DUMP */ ++ + /* +- * Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It +- * currently assumes that for memory starting above 4G, 32-bit devices will +- * use a DMA offset. ++ * Return the maximum physical address for a zone with a given address size ++ * limit. It currently assumes that for memory starting above 4G, 32-bit ++ * devices will use a DMA offset. + */ +-static phys_addr_t __init max_zone_dma32_phys(void) ++static phys_addr_t __init max_zone_phys(unsigned int zone_bits) + { +- phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); +- return min(offset + (1ULL << 32), memblock_end_of_DRAM()); ++ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits); ++ return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM()); + } + + #ifdef CONFIG_NUMA +@@ -180,6 +188,9 @@ static void __init zone_sizes_init(unsig + { + unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; + ++#ifdef CONFIG_ZONE_DMA ++ max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit); ++#endif + #ifdef CONFIG_ZONE_DMA32 + max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); + #endif +@@ -195,13 +206,18 @@ static void __init zone_sizes_init(unsig + struct memblock_region *reg; + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; + unsigned long max_dma32 = min; ++ unsigned long max_dma = min; + + memset(zone_size, 0, sizeof(zone_size)); + +- /* 4GB maximum for 32-bit only capable devices */ ++#ifdef CONFIG_ZONE_DMA ++ max_dma = PFN_DOWN(arm64_dma_phys_limit); ++ zone_size[ZONE_DMA] = max_dma - min; ++ max_dma32 = max_dma; ++#endif + #ifdef CONFIG_ZONE_DMA32 + max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); +- zone_size[ZONE_DMA32] = max_dma32 - min; ++ zone_size[ZONE_DMA32] = max_dma32 - max_dma; + #endif + zone_size[ZONE_NORMAL] = max - max_dma32; + +@@ -213,11 +229,17 @@ static void __init zone_sizes_init(unsig + + if (start >= max) + continue; +- ++#ifdef CONFIG_ZONE_DMA ++ if (start < max_dma) { ++ unsigned long dma_end = min_not_zero(end, max_dma); ++ zhole_size[ZONE_DMA] -= dma_end - start; ++ } ++#endif + #ifdef CONFIG_ZONE_DMA32 + if (start < max_dma32) { +- unsigned long dma_end = min(end, max_dma32); +- zhole_size[ZONE_DMA32] -= dma_end - start; ++ unsigned long dma32_end = min(end, max_dma32); ++ unsigned long dma32_start = max(start, max_dma); ++ zhole_size[ZONE_DMA32] -= dma32_end - dma32_start; + } + #endif + if (end > max_dma32) { +@@ -408,9 +430,11 @@ void __init arm64_memblock_init(void) + + early_init_fdt_scan_reserved_mem(); + +- /* 4GB maximum for 32-bit only capable devices */ ++ if (IS_ENABLED(CONFIG_ZONE_DMA)) ++ arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); ++ + if (IS_ENABLED(CONFIG_ZONE_DMA32)) +- arm64_dma32_phys_limit = max_zone_dma32_phys(); ++ arm64_dma32_phys_limit = max_zone_phys(32); + else + arm64_dma32_phys_limit = PHYS_MASK + 1; + +@@ -420,7 +444,7 @@ void __init arm64_memblock_init(void) + + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; + +- dma_contiguous_reserve(arm64_dma32_phys_limit); ++ dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit); + } + + void __init bootmem_init(void) +@@ -524,7 +548,7 @@ static void __init free_unused_memmap(vo + void __init mem_init(void) + { + if (swiotlb_force == SWIOTLB_FORCE || +- max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) ++ max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit)) + swiotlb_init(1); + else + swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0436-of-address-Follow-DMA-parent-for-dma-coherent.patch b/target/linux/bcm27xx/patches-5.4/950-0436-of-address-Follow-DMA-parent-for-dma-coherent.patch deleted file mode 100644 index 76af58a126..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0436-of-address-Follow-DMA-parent-for-dma-coherent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From e4a649779ff6857240fe691cdf147a3b4896e71b Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Wed, 3 Jul 2019 14:47:31 +0100 -Subject: [PATCH] of: address: Follow DMA parent for "dma-coherent" - -commit c60bf3eb888a362100aa1bdbea351dab681e262a upstream. - -Much like for address translation, when checking for DMA coherence we -should be sure to walk up the DMA hierarchy, rather than the MMIO one, -now that we can accommodate them being different. - -Signed-off-by: Robin Murphy -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring ---- - drivers/of/address.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -1025,7 +1025,7 @@ bool of_dma_is_coherent(struct device_no - of_node_put(node); - return true; - } -- node = of_get_next_parent(node); -+ node = of_get_next_dma_parent(node); - } - of_node_put(node); - return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0437-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch b/target/linux/bcm27xx/patches-5.4/950-0437-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch new file mode 100644 index 0000000000..23811e0b6e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0437-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch @@ -0,0 +1,84 @@ +From 1c108eaeae73a504ac1b2d882bc1fefb91eecf17 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:46 +0200 +Subject: [PATCH] mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum + zone_type' + +commit 734f9246e791d8da278957b2c326d7709b2a97c0 upstream. + +These zones usage has evolved with time and the comments were outdated. +This joins both ZONE_DMA and ZONE_DMA32 explanation and gives up to date +examples on how they are used on different architectures. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Christoph Hellwig +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + include/linux/mmzone.h | 45 ++++++++++++++++++++++++------------------ + 1 file changed, 26 insertions(+), 19 deletions(-) + +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -358,33 +358,40 @@ struct per_cpu_nodestat { + #endif /* !__GENERATING_BOUNDS.H */ + + enum zone_type { +-#ifdef CONFIG_ZONE_DMA + /* +- * ZONE_DMA is used when there are devices that are not able +- * to do DMA to all of addressable memory (ZONE_NORMAL). Then we +- * carve out the portion of memory that is needed for these devices. +- * The range is arch specific. +- * +- * Some examples +- * +- * Architecture Limit +- * --------------------------- +- * parisc, ia64, sparc <4G +- * s390, powerpc <2G +- * arm Various +- * alpha Unlimited or 0-16MB. ++ * ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able ++ * to DMA to all of the addressable memory (ZONE_NORMAL). ++ * On architectures where this area covers the whole 32 bit address ++ * space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller ++ * DMA addressing constraints. This distinction is important as a 32bit ++ * DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit ++ * platforms may need both zones as they support peripherals with ++ * different DMA addressing limitations. ++ * ++ * Some examples: ++ * ++ * - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the ++ * rest of the lower 4G. ++ * ++ * - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on ++ * the specific device. ++ * ++ * - arm64 has a fixed 1G ZONE_DMA and ZONE_DMA32 for the rest of the ++ * lower 4G. ++ * ++ * - powerpc only uses ZONE_DMA, the size, up to 2G, may vary ++ * depending on the specific device. + * +- * i386, x86_64 and multiple other arches +- * <16M. ++ * - s390 uses ZONE_DMA fixed to the lower 2G. ++ * ++ * - ia64 and riscv only use ZONE_DMA32. ++ * ++ * - parisc uses neither. + */ ++#ifdef CONFIG_ZONE_DMA + ZONE_DMA, + #endif + #ifdef CONFIG_ZONE_DMA32 +- /* +- * x86_64 needs two ZONE_DMAs because it supports devices that are +- * only able to do DMA to the lower 16M but also 32 bit devices that +- * can only do DMA areas below 4G. +- */ + ZONE_DMA32, + #endif + /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0437-of-Factor-out-addr-size-cells-parsing.patch b/target/linux/bcm27xx/patches-5.4/950-0437-of-Factor-out-addr-size-cells-parsing.patch deleted file mode 100644 index 045ee9827f..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0437-of-Factor-out-addr-size-cells-parsing.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 839aeedc908eb729b9014e7d1d38e109778a52d2 Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Tue, 2 Jul 2019 18:42:39 +0100 -Subject: [PATCH] of: Factor out #{addr,size}-cells parsing - -In some cases such as PCI host controllers, we may have a "parent bus" -which is an OF leaf node, but still need to correctly parse ranges from -the point of view of that bus. For that, factor out variants of the -"#addr-cells" and "#size-cells" parsers which do not assume they have a -device node and thus immediately traverse upwards before reading the -relevant property. - -Signed-off-by: Robin Murphy -[robh: don't make of_bus_n_{addr,size}_cells() public] -Reviewed-by: Geert Uytterhoeven -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring - -(cherry picked from commit b68ac8dc22ebbf003e26e44bf4dd3030c076df5a) ---- - drivers/of/address.c | 2 ++ - drivers/of/base.c | 32 ++++++++++++++++++++++---------- - drivers/of/of_private.h | 14 ++++++++++++++ - 3 files changed, 38 insertions(+), 10 deletions(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -14,6 +14,8 @@ - #include - #include - -+#include "of_private.h" -+ - /* Max address size we deal with */ - #define OF_MAX_ADDR_CELLS 4 - #define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) ---- a/drivers/of/base.c -+++ b/drivers/of/base.c -@@ -86,34 +86,46 @@ static bool __of_node_is_type(const stru - return np && match && type && !strcmp(match, type); - } - --int of_n_addr_cells(struct device_node *np) -+int of_bus_n_addr_cells(struct device_node *np) - { - u32 cells; - -- do { -- if (np->parent) -- np = np->parent; -+ for (; np; np = np->parent) - if (!of_property_read_u32(np, "#address-cells", &cells)) - return cells; -- } while (np->parent); -+ - /* No #address-cells property for the root node */ - return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; - } -+ -+int of_n_addr_cells(struct device_node *np) -+{ -+ if (np->parent) -+ np = np->parent; -+ -+ return of_bus_n_addr_cells(np); -+} - EXPORT_SYMBOL(of_n_addr_cells); - --int of_n_size_cells(struct device_node *np) -+int of_bus_n_size_cells(struct device_node *np) - { - u32 cells; - -- do { -- if (np->parent) -- np = np->parent; -+ for (; np; np = np->parent) - if (!of_property_read_u32(np, "#size-cells", &cells)) - return cells; -- } while (np->parent); -+ - /* No #size-cells property for the root node */ - return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; - } -+ -+int of_n_size_cells(struct device_node *np) -+{ -+ if (np->parent) -+ np = np->parent; -+ -+ return of_bus_n_size_cells(np); -+} - EXPORT_SYMBOL(of_n_size_cells); - - #ifdef CONFIG_NUMA ---- a/drivers/of/of_private.h -+++ b/drivers/of/of_private.h -@@ -158,4 +158,18 @@ extern void __of_sysfs_remove_bin_file(s - #define for_each_transaction_entry_reverse(_oft, _te) \ - list_for_each_entry_reverse(_te, &(_oft)->te_list, node) - -+extern int of_bus_n_addr_cells(struct device_node *np); -+extern int of_bus_n_size_cells(struct device_node *np); -+ -+#ifdef CONFIG_OF_ADDRESS -+extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, -+ u64 *paddr, u64 *size); -+#else -+static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, -+ u64 *paddr, u64 *size) -+{ -+ return -ENODEV; -+} -+#endif -+ - #endif /* _LINUX_OF_PRIVATE_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0438-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch b/target/linux/bcm27xx/patches-5.4/950-0438-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch deleted file mode 100644 index 28d1987a9c..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0438-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 39f5d9e883393e32938eac45b564f74afde8a942 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Wed, 4 Sep 2019 11:43:30 +0100 -Subject: [PATCH] of/address: Translate 'dma-ranges' for parent nodes - missing 'dma-ranges' - -commit 81db12ee15cb83926e290a8a3654a2dfebc80935 upstream. - -'dma-ranges' frequently exists without parent nodes having 'dma-ranges'. -While this is an error for 'ranges', this is fine because DMA capable -devices always have a translatable DMA address. Also, with no -'dma-ranges' at all, the assumption is that DMA addresses are 1:1 with -no restrictions unless perhaps the device itself has implicit -restrictions. - -Cc: Robin Murphy -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring ---- - drivers/of/address.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -519,9 +519,13 @@ static int of_translate_one(struct devic - * - * As far as we know, this damage only exists on Apple machines, so - * This code is only enabled on powerpc. --gcl -+ * -+ * This quirk also applies for 'dma-ranges' which frequently exist in -+ * child nodes without 'dma-ranges' in the parent nodes. --RobH - */ - ranges = of_get_property(parent, rprop, &rlen); -- if (ranges == NULL && !of_empty_ranges_quirk(parent)) { -+ if (ranges == NULL && !of_empty_ranges_quirk(parent) && -+ strcmp(rprop, "dma-ranges")) { - pr_debug("no ranges; cannot translate\n"); - return 1; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0438-resource-Add-a-resource_list_first_type-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0438-resource-Add-a-resource_list_first_type-helper.patch new file mode 100644 index 0000000000..c2c959a3c1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0438-resource-Add-a-resource_list_first_type-helper.patch @@ -0,0 +1,36 @@ +From dacb1a46835914b8c3862db15726bcc0a68af8f5 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Mon, 28 Oct 2019 11:32:32 -0500 +Subject: [PATCH] resource: Add a resource_list_first_type helper + +commit 494f8b10d832456a96be4ee7317425f6936cabc8 upstream. + +A common pattern is looping over a resource_list just to get a matching +entry with a specific type. Add resource_list_first_type() helper which +implements this. + +Signed-off-by: Rob Herring +Signed-off-by: Lorenzo Pieralisi +--- + include/linux/resource_ext.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/include/linux/resource_ext.h ++++ b/include/linux/resource_ext.h +@@ -66,4 +66,16 @@ resource_list_destroy_entry(struct resou + #define resource_list_for_each_entry_safe(entry, tmp, list) \ + list_for_each_entry_safe((entry), (tmp), (list), node) + ++static inline struct resource_entry * ++resource_list_first_type(struct list_head *list, unsigned long type) ++{ ++ struct resource_entry *entry; ++ ++ resource_list_for_each_entry(entry, list) { ++ if (resource_type(entry->res) == type) ++ return entry; ++ } ++ return NULL; ++} ++ + #endif /* _LINUX_RESOURCE_EXT_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0439-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0439-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch new file mode 100644 index 0000000000..ab04d64b72 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0439-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch @@ -0,0 +1,195 @@ +From 78b03f0aef9f67c4db700ba5dc56e2c8f562d181 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Mon, 14 Oct 2019 20:31:03 +0200 +Subject: [PATCH] dma/direct: turn ARCH_ZONE_DMA_BITS into a variable + +commit 8b5369ea580964dbc982781bfb9fb93459fc5e8d upstream. + +Some architectures, notably ARM, are interested in tweaking this +depending on their runtime DMA addressing limitations. + +Acked-by: Christoph Hellwig +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Catalin Marinas +--- + arch/arm64/include/asm/page.h | 2 -- + arch/arm64/mm/init.c | 9 +++++++-- + arch/powerpc/include/asm/page.h | 9 --------- + arch/powerpc/mm/mem.c | 20 +++++++++++++++----- + arch/s390/include/asm/page.h | 2 -- + arch/s390/mm/init.c | 1 + + include/linux/dma-direct.h | 2 ++ + kernel/dma/direct.c | 13 ++++++------- + 8 files changed, 31 insertions(+), 27 deletions(-) + +--- a/arch/arm64/include/asm/page.h ++++ b/arch/arm64/include/asm/page.h +@@ -38,6 +38,4 @@ extern int pfn_valid(unsigned long); + + #include + +-#define ARCH_ZONE_DMA_BITS 30 +- + #endif +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,6 +42,8 @@ + #include + #include + ++#define ARM64_ZONE_DMA_BITS 30 ++ + /* + * We need to be able to catch inadvertent references to memstart_addr + * that occur (potentially in generic code) before arm64_memblock_init() +@@ -430,8 +433,10 @@ void __init arm64_memblock_init(void) + + early_init_fdt_scan_reserved_mem(); + +- if (IS_ENABLED(CONFIG_ZONE_DMA)) +- arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); ++ if (IS_ENABLED(CONFIG_ZONE_DMA)) { ++ zone_dma_bits = ARM64_ZONE_DMA_BITS; ++ arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS); ++ } + + if (IS_ENABLED(CONFIG_ZONE_DMA32)) + arm64_dma32_phys_limit = max_zone_phys(32); +--- a/arch/powerpc/include/asm/page.h ++++ b/arch/powerpc/include/asm/page.h +@@ -334,13 +334,4 @@ struct vm_area_struct; + #endif /* __ASSEMBLY__ */ + #include + +-/* +- * Allow 30-bit DMA for very limited Broadcom wifi chips on many powerbooks. +- */ +-#ifdef CONFIG_PPC32 +-#define ARCH_ZONE_DMA_BITS 30 +-#else +-#define ARCH_ZONE_DMA_BITS 31 +-#endif +- + #endif /* _ASM_POWERPC_PAGE_H */ +--- a/arch/powerpc/mm/mem.c ++++ b/arch/powerpc/mm/mem.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -223,10 +224,10 @@ static int __init mark_nonram_nosave(voi + * everything else. GFP_DMA32 page allocations automatically fall back to + * ZONE_DMA. + * +- * By using 31-bit unconditionally, we can exploit ARCH_ZONE_DMA_BITS to +- * inform the generic DMA mapping code. 32-bit only devices (if not handled +- * by an IOMMU anyway) will take a first dip into ZONE_NORMAL and get +- * otherwise served by ZONE_DMA. ++ * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the ++ * generic DMA mapping code. 32-bit only devices (if not handled by an IOMMU ++ * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by ++ * ZONE_DMA. + */ + static unsigned long max_zone_pfns[MAX_NR_ZONES]; + +@@ -259,9 +260,18 @@ void __init paging_init(void) + printk(KERN_DEBUG "Memory hole size: %ldMB\n", + (long int)((top_of_ram - total_ram) >> 20)); + ++ /* ++ * Allow 30-bit DMA for very limited Broadcom wifi chips on many ++ * powerbooks. ++ */ ++ if (IS_ENABLED(CONFIG_PPC32)) ++ zone_dma_bits = 30; ++ else ++ zone_dma_bits = 31; ++ + #ifdef CONFIG_ZONE_DMA + max_zone_pfns[ZONE_DMA] = min(max_low_pfn, +- 1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT)); ++ 1UL << (zone_dma_bits - PAGE_SHIFT)); + #endif + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; + #ifdef CONFIG_HIGHMEM +--- a/arch/s390/include/asm/page.h ++++ b/arch/s390/include/asm/page.h +@@ -179,8 +179,6 @@ static inline int devmem_is_allowed(unsi + #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +-#define ARCH_ZONE_DMA_BITS 31 +- + #include + #include + +--- a/arch/s390/mm/init.c ++++ b/arch/s390/mm/init.c +@@ -118,6 +118,7 @@ void __init paging_init(void) + + sparse_memory_present_with_active_regions(MAX_NUMNODES); + sparse_init(); ++ zone_dma_bits = 31; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS); + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -8,6 +8,8 @@ + + static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); + ++extern unsigned int zone_dma_bits; ++ + #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA + #include + #else +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -16,12 +16,11 @@ + #include + + /* +- * Most architectures use ZONE_DMA for the first 16 Megabytes, but +- * some use it for entirely different regions: ++ * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it ++ * it for entirely different regions. In that case the arch code needs to ++ * override the variable below for dma-direct to work properly. + */ +-#ifndef ARCH_ZONE_DMA_BITS +-#define ARCH_ZONE_DMA_BITS 24 +-#endif ++unsigned int zone_dma_bits __ro_after_init = 24; + + static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size) + { +@@ -70,7 +69,7 @@ static gfp_t __dma_direct_optimal_gfp_ma + * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding + * zones. + */ +- if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)) ++ if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) + return GFP_DMA; + if (*phys_mask <= DMA_BIT_MASK(32)) + return GFP_DMA32; +@@ -396,7 +395,7 @@ int dma_direct_supported(struct device * + u64 min_mask; + + if (IS_ENABLED(CONFIG_ZONE_DMA)) +- min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS); ++ min_mask = DMA_BIT_MASK(zone_dma_bits); + else + min_mask = DMA_BIT_MASK(30); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0439-of-Make-of_dma_get_range-work-on-bus-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0439-of-Make-of_dma_get_range-work-on-bus-nodes.patch deleted file mode 100644 index 1cac2dfcd8..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0439-of-Make-of_dma_get_range-work-on-bus-nodes.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 7631cb95056f03136c9e0a35484e8bebe7b52650 Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Wed, 3 Jul 2019 18:42:20 +0100 -Subject: [PATCH] of: Make of_dma_get_range() work on bus nodes - -commit 951d48855d86e72e0d6de73440fe09d363168064 upstream. - -Since the "dma-ranges" property is only valid for a node representing a -bus, of_dma_get_range() currently assumes the node passed in is a leaf -representing a device, and starts the walk from its parent. In cases -like PCI host controllers on typical FDT systems, however, where the PCI -endpoints are probed dynamically the initial leaf node represents the -'bus' itself, and this logic means we fail to consider any "dma-ranges" -describing the host bridge itself. Rework the logic such that -of_dma_get_range() also works correctly starting from a bus node -containing "dma-ranges". - -While this does mean "dma-ranges" could incorrectly be in a device leaf -node, there isn't really any way in this function to ensure that a leaf -node is or isn't a bus node. - -Signed-off-by: Robin Murphy -[robh: Allow for the bus child node to still be passed in] -Signed-off-by: Rob Herring -Reviewed-by: Robin Murphy -Reviewed-by: Nicolas Saenz Julienne -Tested-by: Nicolas Saenz Julienne ---- - drivers/of/address.c | 44 ++++++++++++++++++-------------------------- - 1 file changed, 18 insertions(+), 26 deletions(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -940,47 +940,39 @@ int of_dma_get_range(struct device_node - const __be32 *ranges = NULL; - int len, naddr, nsize, pna; - int ret = 0; -+ bool found_dma_ranges = false; - u64 dmaaddr; - -- if (!node) -- return -EINVAL; -- -- while (1) { -- struct device_node *parent; -- -- naddr = of_n_addr_cells(node); -- nsize = of_n_size_cells(node); -- -- parent = __of_get_dma_parent(node); -- of_node_put(node); -- -- node = parent; -- if (!node) -- break; -- -+ while (node) { - ranges = of_get_property(node, "dma-ranges", &len); - - /* Ignore empty ranges, they imply no translation required */ - if (ranges && len > 0) - break; - -- /* -- * At least empty ranges has to be defined for parent node if -- * DMA is supported -- */ -- if (!ranges) -- break; -+ /* Once we find 'dma-ranges', then a missing one is an error */ -+ if (found_dma_ranges && !ranges) { -+ ret = -ENODEV; -+ goto out; -+ } -+ found_dma_ranges = true; -+ -+ node = of_get_next_dma_parent(node); - } - -- if (!ranges) { -+ if (!node || !ranges) { - pr_debug("no dma-ranges found for node(%pOF)\n", np); - ret = -ENODEV; - goto out; - } - -- len /= sizeof(u32); -- -+ naddr = of_bus_n_addr_cells(node); -+ nsize = of_bus_n_size_cells(node); - pna = of_n_addr_cells(node); -+ if ((len / sizeof(__be32)) % (pna + naddr + nsize)) { -+ ret = -EINVAL; -+ goto out; -+ } - - /* dma-ranges format: - * DMA addr : naddr cells -@@ -988,7 +980,7 @@ int of_dma_get_range(struct device_node - * size : nsize cells - */ - dmaaddr = of_read_number(ranges, naddr); -- *paddr = of_translate_dma_address(np, ranges); -+ *paddr = of_translate_dma_address(node, ranges + naddr); - if (*paddr == OF_BAD_ADDR) { - pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n", - dma_addr, np); diff --git a/target/linux/bcm27xx/patches-5.4/950-0440-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch b/target/linux/bcm27xx/patches-5.4/950-0440-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch deleted file mode 100644 index c697494f8a..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0440-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch +++ /dev/null @@ -1,30 +0,0 @@ -From c17f622cbb33332a305ef383506740d3d01aa831 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:43 +0200 -Subject: [PATCH] arm64: mm: use arm64_dma_phys_limit instead of - calling max_zone_dma_phys() - -commit ae970dc096b2d39f65f2e18d142e3978dc9ee1c7 upstream. - -By the time we call zones_sizes_init() arm64_dma_phys_limit already -contains the result of max_zone_dma_phys(). We use the variable instead -of calling the function directly to save some precious cpu time. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - arch/arm64/mm/init.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -181,7 +181,7 @@ static void __init zone_sizes_init(unsig - unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; - - #ifdef CONFIG_ZONE_DMA32 -- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys()); -+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); - #endif - max_zone_pfns[ZONE_NORMAL] = max; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0440-x86-PCI-sta2x11-use-default-DMA-address-translation.patch b/target/linux/bcm27xx/patches-5.4/950-0440-x86-PCI-sta2x11-use-default-DMA-address-translation.patch new file mode 100644 index 0000000000..51fd4be35e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0440-x86-PCI-sta2x11-use-default-DMA-address-translation.patch @@ -0,0 +1,259 @@ +From 97a48106d1698038720495fdd49c491b283bf110 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 7 Nov 2019 16:06:45 +0100 +Subject: [PATCH] x86/PCI: sta2x11: use default DMA address translation + +commit e380a0394c36a3a878c858418d5dd7f5f195b6fc upstream. + +The devices found behind this PCIe chip have unusual DMA mapping +constraints as there is an AMBA interconnect placed in between them and +the different PCI endpoints. The offset between physical memory +addresses and AMBA's view is provided by reading a PCI config register, +which is saved and used whenever DMA mapping is needed. + +It turns out that this DMA setup can be represented by properly setting +'dma_pfn_offset', 'dma_bus_mask' and 'dma_mask' during the PCI device +enable fixup. And ultimately allows us to get rid of this device's +custom DMA functions. + +Aside from the code deletion and DMA setup, sta2x11_pdev_to_mapping() is +moved to avoid warnings whenever CONFIG_PM is not enabled. + +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Christoph Hellwig +--- + arch/x86/Kconfig | 1 - + arch/x86/include/asm/device.h | 3 - + arch/x86/include/asm/dma-direct.h | 9 -- + arch/x86/pci/sta2x11-fixup.c | 135 ++++++------------------------ + 4 files changed, 26 insertions(+), 122 deletions(-) + delete mode 100644 arch/x86/include/asm/dma-direct.h + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -708,7 +708,6 @@ config X86_SUPPORTS_MEMORY_FAILURE + config STA2X11 + bool "STA2X11 Companion Chip Support" + depends on X86_32_NON_STANDARD && PCI +- select ARCH_HAS_PHYS_TO_DMA + select SWIOTLB + select MFD_STA2X11 + select GPIOLIB +--- a/arch/x86/include/asm/device.h ++++ b/arch/x86/include/asm/device.h +@@ -6,9 +6,6 @@ struct dev_archdata { + #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU) + void *iommu; /* hook for IOMMU specific extension */ + #endif +-#ifdef CONFIG_STA2X11 +- bool is_sta2x11; +-#endif + }; + + #if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS) +--- a/arch/x86/include/asm/dma-direct.h ++++ /dev/null +@@ -1,9 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-#ifndef ASM_X86_DMA_DIRECT_H +-#define ASM_X86_DMA_DIRECT_H 1 +- +-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size); +-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); +-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); +- +-#endif /* ASM_X86_DMA_DIRECT_H */ +--- a/arch/x86/pci/sta2x11-fixup.c ++++ b/arch/x86/pci/sta2x11-fixup.c +@@ -30,7 +30,6 @@ struct sta2x11_ahb_regs { /* saved durin + }; + + struct sta2x11_mapping { +- u32 amba_base; + int is_suspended; + struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS]; + }; +@@ -92,18 +91,6 @@ static int sta2x11_pdev_to_ep(struct pci + return pdev->bus->number - instance->bus0; + } + +-static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) +-{ +- struct sta2x11_instance *instance; +- int ep; +- +- instance = sta2x11_pdev_to_instance(pdev); +- if (!instance) +- return NULL; +- ep = sta2x11_pdev_to_ep(pdev); +- return instance->map + ep; +-} +- + /* This is exported, as some devices need to access the MFD registers */ + struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev) + { +@@ -111,39 +98,6 @@ struct sta2x11_instance *sta2x11_get_ins + } + EXPORT_SYMBOL(sta2x11_get_instance); + +- +-/** +- * p2a - Translate physical address to STA2x11 AMBA address, +- * used for DMA transfers to STA2x11 +- * @p: Physical address +- * @pdev: PCI device (must be hosted within the connext) +- */ +-static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev) +-{ +- struct sta2x11_mapping *map; +- dma_addr_t a; +- +- map = sta2x11_pdev_to_mapping(pdev); +- a = p + map->amba_base; +- return a; +-} +- +-/** +- * a2p - Translate STA2x11 AMBA address to physical address +- * used for DMA transfers from STA2x11 +- * @a: STA2x11 AMBA address +- * @pdev: PCI device (must be hosted within the connext) +- */ +-static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev) +-{ +- struct sta2x11_mapping *map; +- dma_addr_t p; +- +- map = sta2x11_pdev_to_mapping(pdev); +- p = a - map->amba_base; +- return p; +-} +- + /* At setup time, we use our own ops if the device is a ConneXt one */ + static void sta2x11_setup_pdev(struct pci_dev *pdev) + { +@@ -151,9 +105,6 @@ static void sta2x11_setup_pdev(struct pc + + if (!instance) /* either a sta2x11 bridge or another ST device */ + return; +- pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); +- pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); +- pdev->dev.archdata.is_sta2x11 = true; + + /* We must enable all devices as master, for audio DMA to work */ + pci_set_master(pdev); +@@ -161,61 +112,6 @@ static void sta2x11_setup_pdev(struct pc + DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev); + + /* +- * The following three functions are exported (used in swiotlb: FIXME) +- */ +-/** +- * dma_capable - Check if device can manage DMA transfers (FIXME: kill it) +- * @dev: device for a PCI device +- * @addr: DMA address +- * @size: DMA size +- */ +-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- struct sta2x11_mapping *map; +- +- if (!dev->archdata.is_sta2x11) { +- if (!dev->dma_mask) +- return false; +- return addr + size - 1 <= *dev->dma_mask; +- } +- +- map = sta2x11_pdev_to_mapping(to_pci_dev(dev)); +- +- if (!map || (addr < map->amba_base)) +- return false; +- if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) { +- return false; +- } +- +- return true; +-} +- +-/** +- * __phys_to_dma - Return the DMA AMBA address used for this STA2x11 device +- * @dev: device for a PCI device +- * @paddr: Physical address +- */ +-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) +-{ +- if (!dev->archdata.is_sta2x11) +- return paddr; +- return p2a(paddr, to_pci_dev(dev)); +-} +- +-/** +- * dma_to_phys - Return the physical address used for this STA2x11 DMA address +- * @dev: device for a PCI device +- * @daddr: STA2x11 AMBA DMA address +- */ +-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr) +-{ +- if (!dev->archdata.is_sta2x11) +- return daddr; +- return a2p(daddr, to_pci_dev(dev)); +-} +- +- +-/* + * At boot we must set up the mappings for the pcie-to-amba bridge. + * It involves device access, and the same happens at suspend/resume time + */ +@@ -234,12 +130,22 @@ phys_addr_t __dma_to_phys(struct device + /* At probe time, enable mapping for each endpoint, using the pdev */ + static void sta2x11_map_ep(struct pci_dev *pdev) + { +- struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); ++ struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev); ++ struct device *dev = &pdev->dev; ++ u32 amba_base, max_amba_addr; + int i; + +- if (!map) ++ if (!instance) + return; +- pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base); ++ ++ pci_read_config_dword(pdev, AHB_BASE(0), &amba_base); ++ max_amba_addr = amba_base + STA2X11_AMBA_SIZE - 1; ++ ++ dev->dma_pfn_offset = PFN_DOWN(-amba_base); ++ ++ dev->bus_dma_mask = max_amba_addr; ++ pci_set_consistent_dma_mask(pdev, max_amba_addr); ++ pci_set_dma_mask(pdev, max_amba_addr); + + /* Configure AHB mapping */ + pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0); +@@ -253,13 +159,24 @@ static void sta2x11_map_ep(struct pci_de + + dev_info(&pdev->dev, + "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n", +- sta2x11_pdev_to_ep(pdev), map->amba_base, +- map->amba_base + STA2X11_AMBA_SIZE - 1); ++ sta2x11_pdev_to_ep(pdev), amba_base, max_amba_addr); + } + DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep); + + #ifdef CONFIG_PM /* Some register values must be saved and restored */ + ++static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) ++{ ++ struct sta2x11_instance *instance; ++ int ep; ++ ++ instance = sta2x11_pdev_to_instance(pdev); ++ if (!instance) ++ return NULL; ++ ep = sta2x11_pdev_to_ep(pdev); ++ return instance->map + ep; ++} ++ + static void suspend_mapping(struct pci_dev *pdev) + { + struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0441-PCI-of-Add-inbound-resource-parsing-to-helpers.patch b/target/linux/bcm27xx/patches-5.4/950-0441-PCI-of-Add-inbound-resource-parsing-to-helpers.patch new file mode 100644 index 0000000000..493ea63825 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0441-PCI-of-Add-inbound-resource-parsing-to-helpers.patch @@ -0,0 +1,427 @@ +From 125a18144253e3a3f4bcad24484ee9b590dc47c6 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Wed, 30 Oct 2019 17:30:57 -0500 +Subject: [PATCH] PCI: of: Add inbound resource parsing to helpers + +Extend devm_of_pci_get_host_bridge_resources() and +pci_parse_request_of_pci_ranges() helpers to also parse the inbound +addresses from DT 'dma-ranges' and populate a resource list with the +translated addresses. This will help ensure 'dma-ranges' is always +parsed in a consistent way. + +Tested-by: Srinath Mannam +Tested-by: Thomas Petazzoni # for AArdvark +Signed-off-by: Rob Herring +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Srinath Mannam +Reviewed-by: Andrew Murray +Acked-by: Gustavo Pimentel +Cc: Jingoo Han +Cc: Gustavo Pimentel +Cc: Lorenzo Pieralisi +Cc: Bjorn Helgaas +Cc: Thomas Petazzoni +Cc: Will Deacon +Cc: Linus Walleij +Cc: Toan Le +Cc: Ley Foon Tan +Cc: Tom Joseph +Cc: Ray Jui +Cc: Scott Branden +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: Ryder Lee +Cc: Karthikeyan Mitran +Cc: Hou Zhiqiang +Cc: Simon Horman +Cc: Shawn Lin +Cc: Heiko Stuebner +Cc: Michal Simek +Cc: rfi@lists.rocketboards.org +Cc: linux-mediatek@lists.infradead.org +Cc: linux-renesas-soc@vger.kernel.org +Cc: linux-rockchip@lists.infradead.org +(cherry picked from commit 331f63457165a30c708280de2c77f1742c6351dc) +--- + .../pci/controller/dwc/pcie-designware-host.c | 8 +-- + drivers/pci/controller/pci-aardvark.c | 3 +- + drivers/pci/controller/pci-ftpci100.c | 4 +- + drivers/pci/controller/pci-host-common.c | 2 +- + drivers/pci/controller/pci-v3-semi.c | 8 +-- + drivers/pci/controller/pci-versatile.c | 3 +- + drivers/pci/controller/pci-xgene.c | 4 +- + drivers/pci/controller/pcie-altera.c | 5 +- + drivers/pci/controller/pcie-cadence-host.c | 2 +- + drivers/pci/controller/pcie-iproc-platform.c | 4 +- + drivers/pci/controller/pcie-mediatek.c | 4 +- + drivers/pci/controller/pcie-mobiveil.c | 4 +- + drivers/pci/controller/pcie-rcar.c | 3 +- + drivers/pci/controller/pcie-rockchip-host.c | 4 +- + drivers/pci/controller/pcie-xilinx-nwl.c | 4 +- + drivers/pci/controller/pcie-xilinx.c | 4 +- + drivers/pci/of.c | 61 ++++++++++++++++--- + drivers/pci/pci.h | 8 ++- + include/linux/pci.h | 9 ++- + 19 files changed, 96 insertions(+), 48 deletions(-) + +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -345,12 +345,8 @@ int dw_pcie_host_init(struct pcie_port * + if (!bridge) + return -ENOMEM; + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &bridge->windows, &pp->io_base); +- if (ret) +- return ret; +- +- ret = devm_request_pci_bus_resources(dev, &bridge->windows); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-aardvark.c ++++ b/drivers/pci/controller/pci-aardvark.c +@@ -1018,7 +1018,8 @@ static int advk_pcie_probe(struct platfo + return ret; + } + +- ret = advk_pcie_parse_request_of_pci_ranges(pcie); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, &bus); + if (ret) { + dev_err(dev, "Failed to parse resources\n"); + return ret; +--- a/drivers/pci/controller/pci-ftpci100.c ++++ b/drivers/pci/controller/pci-ftpci100.c +@@ -480,8 +480,8 @@ static int faraday_pci_probe(struct plat + if (IS_ERR(p->base)) + return PTR_ERR(p->base); + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &res, &io_base); ++ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, ++ &host->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-host-common.c ++++ b/drivers/pci/controller/pci-host-common.c +@@ -27,7 +27,7 @@ static struct pci_config_window *gen_pci + struct pci_config_window *cfg; + + /* Parse our PCI ranges and request their resources */ +- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); ++ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); + if (err) + return ERR_PTR(err); + +--- a/drivers/pci/controller/pci-v3-semi.c ++++ b/drivers/pci/controller/pci-v3-semi.c +@@ -793,12 +793,8 @@ static int v3_pci_probe(struct platform_ + if (IS_ERR(v3->config_base)) + return PTR_ERR(v3->config_base); + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &io_base); +- if (ret) +- return ret; +- +- ret = devm_request_pci_bus_resources(dev, &res); ++ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, ++ &host->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-versatile.c ++++ b/drivers/pci/controller/pci-versatile.c +@@ -141,7 +141,8 @@ static int versatile_pci_probe(struct pl + if (IS_ERR(versatile_cfg_base[1])) + return PTR_ERR(versatile_cfg_base[1]); + +- ret = versatile_pci_parse_request_of_pci_ranges(dev, &pci_res); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ NULL, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-xgene.c ++++ b/drivers/pci/controller/pci-xgene.c +@@ -634,8 +634,8 @@ static int xgene_pcie_probe(struct platf + if (ret) + return ret; + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &iobase); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pcie-altera.c ++++ b/drivers/pci/controller/pcie-altera.c +@@ -833,9 +833,8 @@ static int altera_pcie_probe(struct plat + return ret; + } + +- INIT_LIST_HEAD(&pcie->resources); +- +- ret = altera_pcie_parse_request_of_pci_ranges(pcie); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) { + dev_err(dev, "Failed add resources\n"); + return ret; +--- a/drivers/pci/controller/pcie-cadence-host.c ++++ b/drivers/pci/controller/pcie-cadence-host.c +@@ -216,7 +216,7 @@ static int cdns_pcie_host_init(struct de + int err; + + /* Parse our PCI ranges and request their resources */ +- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); ++ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); + if (err) + return err; + +--- a/drivers/pci/controller/pcie-iproc-platform.c ++++ b/drivers/pci/controller/pcie-iproc-platform.c +@@ -97,8 +97,8 @@ static int iproc_pcie_pltfm_probe(struct + if (IS_ERR(pcie->phy)) + return PTR_ERR(pcie->phy); + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources, +- &iobase); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) { + dev_err(dev, "unable to get PCI host bridge resources\n"); + return ret; +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -1027,8 +1027,8 @@ static int mtk_pcie_setup(struct mtk_pci + resource_size_t io_base; + int err; + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- windows, &io_base); ++ err = pci_parse_request_of_pci_ranges(dev, windows, ++ &host->dma_ranges, &bus); + if (err) + return err; + +--- a/drivers/pci/controller/pcie-mobiveil.c ++++ b/drivers/pci/controller/pcie-mobiveil.c +@@ -883,8 +883,8 @@ static int mobiveil_pcie_probe(struct pl + INIT_LIST_HEAD(&pcie->resources); + + /* parse the host bridge base addresses from the device tree file */ +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &pcie->resources, &iobase); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) { + dev_err(dev, "Getting bridge resources failed\n"); + return ret; +--- a/drivers/pci/controller/pcie-rcar.c ++++ b/drivers/pci/controller/pcie-rcar.c +@@ -1144,7 +1144,8 @@ static int rcar_pcie_probe(struct platfo + pcie->dev = dev; + platform_set_drvdata(pdev, pcie); + +- err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL); ++ err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, ++ &bridge->dma_ranges, NULL); + if (err) + goto err_free_bridge; + +--- a/drivers/pci/controller/pcie-rockchip-host.c ++++ b/drivers/pci/controller/pcie-rockchip-host.c +@@ -995,8 +995,8 @@ static int rockchip_pcie_probe(struct pl + if (err < 0) + goto err_deinit_port; + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &res, &io_base); ++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, &bus_res); + if (err) + goto err_remove_irq_domain; + +--- a/drivers/pci/controller/pcie-xilinx-nwl.c ++++ b/drivers/pci/controller/pcie-xilinx-nwl.c +@@ -845,8 +845,8 @@ static int nwl_pcie_probe(struct platfor + return err; + } + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &iobase); ++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (err) { + dev_err(dev, "Getting bridge resources failed\n"); + return err; +--- a/drivers/pci/controller/pcie-xilinx.c ++++ b/drivers/pci/controller/pcie-xilinx.c +@@ -647,8 +647,8 @@ static int xilinx_pcie_probe(struct plat + return err; + } + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &iobase); ++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (err) { + dev_err(dev, "Getting bridge resources failed\n"); + return err; +--- a/drivers/pci/of.c ++++ b/drivers/pci/of.c +@@ -257,14 +257,16 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_onl + */ + int devm_of_pci_get_host_bridge_resources(struct device *dev, + unsigned char busno, unsigned char bus_max, +- struct list_head *resources, resource_size_t *io_base) ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ resource_size_t *io_base) + { + struct device_node *dev_node = dev->of_node; + struct resource *res, tmp_res; + struct resource *bus_range; + struct of_pci_range range; + struct of_pci_range_parser parser; +- char range_type[4]; ++ const char *range_type; + int err; + + if (io_base) +@@ -298,12 +300,12 @@ int devm_of_pci_get_host_bridge_resource + for_each_of_pci_range(&parser, &range) { + /* Read next ranges element */ + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) +- snprintf(range_type, 4, " IO"); ++ range_type = "IO"; + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) +- snprintf(range_type, 4, "MEM"); ++ range_type = "MEM"; + else +- snprintf(range_type, 4, "err"); +- dev_info(dev, " %s %#010llx..%#010llx -> %#010llx\n", ++ range_type = "err"; ++ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", + range_type, range.cpu_addr, + range.cpu_addr + range.size - 1, range.pci_addr); + +@@ -340,6 +342,48 @@ int devm_of_pci_get_host_bridge_resource + pci_add_resource_offset(resources, res, res->start - range.pci_addr); + } + ++ /* Check for dma-ranges property */ ++ if (!ib_resources) ++ return 0; ++ err = of_pci_dma_range_parser_init(&parser, dev_node); ++ if (err) ++ return 0; ++ ++ dev_dbg(dev, "Parsing dma-ranges property...\n"); ++ for_each_of_pci_range(&parser, &range) { ++ struct resource_entry *entry; ++ /* ++ * If we failed translation or got a zero-sized region ++ * then skip this range ++ */ ++ if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) || ++ range.cpu_addr == OF_BAD_ADDR || range.size == 0) ++ continue; ++ ++ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", ++ "IB MEM", range.cpu_addr, ++ range.cpu_addr + range.size - 1, range.pci_addr); ++ ++ ++ err = of_pci_range_to_resource(&range, dev_node, &tmp_res); ++ if (err) ++ continue; ++ ++ res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); ++ if (!res) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ /* Keep the resource list sorted */ ++ resource_list_for_each_entry(entry, ib_resources) ++ if (entry->res->start > res->start) ++ break; ++ ++ pci_add_resource_offset(&entry->node, res, ++ res->start - range.pci_addr); ++ } ++ + return 0; + + failed: +@@ -482,6 +526,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_p + + int pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *resources, ++ struct list_head *ib_resources, + struct resource **bus_range) + { + int err, res_valid = 0; +@@ -489,8 +534,10 @@ int pci_parse_request_of_pci_ranges(stru + struct resource_entry *win, *tmp; + + INIT_LIST_HEAD(resources); ++ if (ib_resources) ++ INIT_LIST_HEAD(ib_resources); + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources, +- &iobase); ++ ib_resources, &iobase); + if (err) + return err; + +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -637,11 +637,15 @@ static inline void pci_release_bus_of_no + #if defined(CONFIG_OF_ADDRESS) + int devm_of_pci_get_host_bridge_resources(struct device *dev, + unsigned char busno, unsigned char bus_max, +- struct list_head *resources, resource_size_t *io_base); ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ resource_size_t *io_base); + #else + static inline int devm_of_pci_get_host_bridge_resources(struct device *dev, + unsigned char busno, unsigned char bus_max, +- struct list_head *resources, resource_size_t *io_base) ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ resource_size_t *io_base) + { + return -EINVAL; + } +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -2278,6 +2278,7 @@ struct irq_domain; + struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); + int pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *resources, ++ struct list_head *ib_resources, + struct resource **bus_range); + + /* Arch may override this (weak) */ +@@ -2286,9 +2287,11 @@ struct device_node *pcibios_get_phb_of_n + #else /* CONFIG_OF */ + static inline struct irq_domain * + pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } +-static inline int pci_parse_request_of_pci_ranges(struct device *dev, +- struct list_head *resources, +- struct resource **bus_range) ++static inline int ++pci_parse_request_of_pci_ranges(struct device *dev, ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ struct resource **bus_range) + { + return -EINVAL; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0441-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch b/target/linux/bcm27xx/patches-5.4/950-0441-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch deleted file mode 100644 index df184f53ee..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0441-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 4d2bd7f66bac81b042afc2a6e742bd776a5a3938 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:44 +0200 -Subject: [PATCH] arm64: rename variables used to calculate - ZONE_DMA32's size - -commit a573cdd7973dedd87e62196c400332896bb236c8 upstream. - -Let the name indicate that they are used to calculate ZONE_DMA32's size -as opposed to ZONE_DMA. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - arch/arm64/mm/init.c | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -50,7 +50,7 @@ - s64 memstart_addr __ro_after_init = -1; - EXPORT_SYMBOL(memstart_addr); - --phys_addr_t arm64_dma_phys_limit __ro_after_init; -+phys_addr_t arm64_dma32_phys_limit __ro_after_init; - - #ifdef CONFIG_KEXEC_CORE - /* -@@ -168,7 +168,7 @@ static void __init reserve_elfcorehdr(vo - * currently assumes that for memory starting above 4G, 32-bit devices will - * use a DMA offset. - */ --static phys_addr_t __init max_zone_dma_phys(void) -+static phys_addr_t __init max_zone_dma32_phys(void) - { - phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); - return min(offset + (1ULL << 32), memblock_end_of_DRAM()); -@@ -181,7 +181,7 @@ static void __init zone_sizes_init(unsig - unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; - - #ifdef CONFIG_ZONE_DMA32 -- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); -+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); - #endif - max_zone_pfns[ZONE_NORMAL] = max; - -@@ -194,16 +194,16 @@ static void __init zone_sizes_init(unsig - { - struct memblock_region *reg; - unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; -- unsigned long max_dma = min; -+ unsigned long max_dma32 = min; - - memset(zone_size, 0, sizeof(zone_size)); - - /* 4GB maximum for 32-bit only capable devices */ - #ifdef CONFIG_ZONE_DMA32 -- max_dma = PFN_DOWN(arm64_dma_phys_limit); -- zone_size[ZONE_DMA32] = max_dma - min; -+ max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); -+ zone_size[ZONE_DMA32] = max_dma32 - min; - #endif -- zone_size[ZONE_NORMAL] = max - max_dma; -+ zone_size[ZONE_NORMAL] = max - max_dma32; - - memcpy(zhole_size, zone_size, sizeof(zhole_size)); - -@@ -215,14 +215,14 @@ static void __init zone_sizes_init(unsig - continue; - - #ifdef CONFIG_ZONE_DMA32 -- if (start < max_dma) { -- unsigned long dma_end = min(end, max_dma); -+ if (start < max_dma32) { -+ unsigned long dma_end = min(end, max_dma32); - zhole_size[ZONE_DMA32] -= dma_end - start; - } - #endif -- if (end > max_dma) { -+ if (end > max_dma32) { - unsigned long normal_end = min(end, max); -- unsigned long normal_start = max(start, max_dma); -+ unsigned long normal_start = max(start, max_dma32); - zhole_size[ZONE_NORMAL] -= normal_end - normal_start; - } - } -@@ -410,9 +410,9 @@ void __init arm64_memblock_init(void) - - /* 4GB maximum for 32-bit only capable devices */ - if (IS_ENABLED(CONFIG_ZONE_DMA32)) -- arm64_dma_phys_limit = max_zone_dma_phys(); -+ arm64_dma32_phys_limit = max_zone_dma32_phys(); - else -- arm64_dma_phys_limit = PHYS_MASK + 1; -+ arm64_dma32_phys_limit = PHYS_MASK + 1; - - reserve_crashkernel(); - -@@ -420,7 +420,7 @@ void __init arm64_memblock_init(void) - - high_memory = __va(memblock_end_of_DRAM() - 1) + 1; - -- dma_contiguous_reserve(arm64_dma_phys_limit); -+ dma_contiguous_reserve(arm64_dma32_phys_limit); - } - - void __init bootmem_init(void) -@@ -524,7 +524,7 @@ static void __init free_unused_memmap(vo - void __init mem_init(void) - { - if (swiotlb_force == SWIOTLB_FORCE || -- max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) -+ max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) - swiotlb_init(1); - else - swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0442-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch b/target/linux/bcm27xx/patches-5.4/950-0442-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch deleted file mode 100644 index ccb2071f17..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0442-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 1fb65f4bc30fbadd0c89521985ff8142693c9631 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:45 +0200 -Subject: [PATCH] arm64: use both ZONE_DMA and ZONE_DMA32 - -commit 1a8e1cef7603e218339ac63cb3178b25554524e5 upstream. - -So far all arm64 devices have supported 32 bit DMA masks for their -peripherals. This is not true anymore for the Raspberry Pi 4 as most of -it's peripherals can only address the first GB of memory on a total of -up to 4 GB. - -This goes against ZONE_DMA32's intent, as it's expected for ZONE_DMA32 -to be addressable with a 32 bit mask. So it was decided to re-introduce -ZONE_DMA in arm64. - -ZONE_DMA will contain the lower 1G of memory, which is currently the -memory area addressable by any peripheral on an arm64 device. -ZONE_DMA32 will contain the rest of the 32 bit addressable memory. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - arch/arm64/Kconfig | 4 +++ - arch/arm64/include/asm/page.h | 2 ++ - arch/arm64/mm/init.c | 54 +++++++++++++++++++++++++---------- - 3 files changed, 45 insertions(+), 15 deletions(-) - ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -267,6 +267,10 @@ config GENERIC_CSUM - config GENERIC_CALIBRATE_DELAY - def_bool y - -+config ZONE_DMA -+ bool "Support DMA zone" if EXPERT -+ default y -+ - config ZONE_DMA32 - bool "Support DMA32 zone" if EXPERT - default y ---- a/arch/arm64/include/asm/page.h -+++ b/arch/arm64/include/asm/page.h -@@ -38,4 +38,6 @@ extern int pfn_valid(unsigned long); - - #include - -+#define ARCH_ZONE_DMA_BITS 30 -+ - #endif ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -50,6 +50,13 @@ - s64 memstart_addr __ro_after_init = -1; - EXPORT_SYMBOL(memstart_addr); - -+/* -+ * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of -+ * memory as some devices, namely the Raspberry Pi 4, have peripherals with -+ * this limited view of the memory. ZONE_DMA32 will cover the rest of the 32 -+ * bit addressable memory area. -+ */ -+phys_addr_t arm64_dma_phys_limit __ro_after_init; - phys_addr_t arm64_dma32_phys_limit __ro_after_init; - - #ifdef CONFIG_KEXEC_CORE -@@ -163,15 +170,16 @@ static void __init reserve_elfcorehdr(vo - { - } - #endif /* CONFIG_CRASH_DUMP */ -+ - /* -- * Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It -- * currently assumes that for memory starting above 4G, 32-bit devices will -- * use a DMA offset. -+ * Return the maximum physical address for a zone with a given address size -+ * limit. It currently assumes that for memory starting above 4G, 32-bit -+ * devices will use a DMA offset. - */ --static phys_addr_t __init max_zone_dma32_phys(void) -+static phys_addr_t __init max_zone_phys(unsigned int zone_bits) - { -- phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); -- return min(offset + (1ULL << 32), memblock_end_of_DRAM()); -+ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits); -+ return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM()); - } - - #ifdef CONFIG_NUMA -@@ -180,6 +188,9 @@ static void __init zone_sizes_init(unsig - { - unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; - -+#ifdef CONFIG_ZONE_DMA -+ max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit); -+#endif - #ifdef CONFIG_ZONE_DMA32 - max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); - #endif -@@ -195,13 +206,18 @@ static void __init zone_sizes_init(unsig - struct memblock_region *reg; - unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; - unsigned long max_dma32 = min; -+ unsigned long max_dma = min; - - memset(zone_size, 0, sizeof(zone_size)); - -- /* 4GB maximum for 32-bit only capable devices */ -+#ifdef CONFIG_ZONE_DMA -+ max_dma = PFN_DOWN(arm64_dma_phys_limit); -+ zone_size[ZONE_DMA] = max_dma - min; -+ max_dma32 = max_dma; -+#endif - #ifdef CONFIG_ZONE_DMA32 - max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); -- zone_size[ZONE_DMA32] = max_dma32 - min; -+ zone_size[ZONE_DMA32] = max_dma32 - max_dma; - #endif - zone_size[ZONE_NORMAL] = max - max_dma32; - -@@ -213,11 +229,17 @@ static void __init zone_sizes_init(unsig - - if (start >= max) - continue; -- -+#ifdef CONFIG_ZONE_DMA -+ if (start < max_dma) { -+ unsigned long dma_end = min_not_zero(end, max_dma); -+ zhole_size[ZONE_DMA] -= dma_end - start; -+ } -+#endif - #ifdef CONFIG_ZONE_DMA32 - if (start < max_dma32) { -- unsigned long dma_end = min(end, max_dma32); -- zhole_size[ZONE_DMA32] -= dma_end - start; -+ unsigned long dma32_end = min(end, max_dma32); -+ unsigned long dma32_start = max(start, max_dma); -+ zhole_size[ZONE_DMA32] -= dma32_end - dma32_start; - } - #endif - if (end > max_dma32) { -@@ -408,9 +430,11 @@ void __init arm64_memblock_init(void) - - early_init_fdt_scan_reserved_mem(); - -- /* 4GB maximum for 32-bit only capable devices */ -+ if (IS_ENABLED(CONFIG_ZONE_DMA)) -+ arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); -+ - if (IS_ENABLED(CONFIG_ZONE_DMA32)) -- arm64_dma32_phys_limit = max_zone_dma32_phys(); -+ arm64_dma32_phys_limit = max_zone_phys(32); - else - arm64_dma32_phys_limit = PHYS_MASK + 1; - -@@ -420,7 +444,7 @@ void __init arm64_memblock_init(void) - - high_memory = __va(memblock_end_of_DRAM() - 1) + 1; - -- dma_contiguous_reserve(arm64_dma32_phys_limit); -+ dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit); - } - - void __init bootmem_init(void) -@@ -524,7 +548,7 @@ static void __init free_unused_memmap(vo - void __init mem_init(void) - { - if (swiotlb_force == SWIOTLB_FORCE || -- max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) -+ max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit)) - swiotlb_init(1); - else - swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0442-dma-direct-unify-the-dma_capable-definitions.patch b/target/linux/bcm27xx/patches-5.4/950-0442-dma-direct-unify-the-dma_capable-definitions.patch new file mode 100644 index 0000000000..d115f0eb80 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0442-dma-direct-unify-the-dma_capable-definitions.patch @@ -0,0 +1,103 @@ +From 203e0c39b262fc1da6f976495c32ec38ea93a137 Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Tue, 12 Nov 2019 17:06:04 +0100 +Subject: [PATCH] dma-direct: unify the dma_capable definitions + +commit 130c1ccbf55330b55e82612a6e54eebb82c9d746 upstream. + +Currently each architectures that wants to override dma_to_phys and +phys_to_dma also has to provide dma_capable. But there isn't really +any good reason for that. powerpc and mips just have copies of the +generic one minus the latests fix, and the arm one was the inspiration +for said fix, but misses the bus_dma_mask handling. +Make all architectures use the generic version instead. + +Signed-off-by: Christoph Hellwig +Acked-by: Michael Ellerman (powerpc) +Reviewed-by: Nicolas Saenz Julienne +--- + arch/arm/include/asm/dma-direct.h | 19 ------------------- + arch/mips/include/asm/dma-direct.h | 8 -------- + arch/powerpc/include/asm/dma-direct.h | 9 --------- + include/linux/dma-direct.h | 2 +- + 4 files changed, 1 insertion(+), 37 deletions(-) + +--- a/arch/arm/include/asm/dma-direct.h ++++ b/arch/arm/include/asm/dma-direct.h +@@ -14,23 +14,4 @@ static inline phys_addr_t __dma_to_phys( + return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset; + } + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- u64 limit, mask; +- +- if (!dev->dma_mask) +- return 0; +- +- mask = *dev->dma_mask; +- +- limit = (mask + 1) & ~mask; +- if (limit && size > limit) +- return 0; +- +- if ((addr | (addr + size - 1)) & ~mask) +- return 0; +- +- return 1; +-} +- + #endif /* ASM_ARM_DMA_DIRECT_H */ +--- a/arch/mips/include/asm/dma-direct.h ++++ b/arch/mips/include/asm/dma-direct.h +@@ -2,14 +2,6 @@ + #ifndef _MIPS_DMA_DIRECT_H + #define _MIPS_DMA_DIRECT_H 1 + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- if (!dev->dma_mask) +- return false; +- +- return addr + size - 1 <= *dev->dma_mask; +-} +- + dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); + phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); + +--- a/arch/powerpc/include/asm/dma-direct.h ++++ b/arch/powerpc/include/asm/dma-direct.h +@@ -2,15 +2,6 @@ + #ifndef ASM_POWERPC_DMA_DIRECT_H + #define ASM_POWERPC_DMA_DIRECT_H 1 + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- if (!dev->dma_mask) +- return false; +- +- return addr + size - 1 <= +- min_not_zero(*dev->dma_mask, dev->bus_dma_mask); +-} +- + static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) + { + if (!dev) +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -26,6 +26,7 @@ static inline phys_addr_t __dma_to_phys( + + return paddr + ((phys_addr_t)dev->dma_pfn_offset << PAGE_SHIFT); + } ++#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ + + static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) + { +@@ -40,7 +41,6 @@ static inline bool dma_capable(struct de + + return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); + } +-#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ + + #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED + bool force_dma_unencrypted(struct device *dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0443-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch b/target/linux/bcm27xx/patches-5.4/950-0443-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch new file mode 100644 index 0000000000..a98f1d3852 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0443-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch @@ -0,0 +1,69 @@ +From a3794022e928547de664abd03b61280163c7f13a Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Tue, 12 Nov 2019 17:07:43 +0100 +Subject: [PATCH] dma-direct: avoid a forward declaration for + phys_to_dma + +Move dma_capable down a bit so that we don't need a forward declaration +for phys_to_dma. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Nicolas Saenz Julienne +(cherry picked from commit c7345159f7db6fb69ec1c3b3f8f28cd05c731be2) +--- + include/linux/dma-direct.h | 30 ++++++++++++++---------------- + 1 file changed, 14 insertions(+), 16 deletions(-) + +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -6,8 +6,6 @@ + #include /* for min_low_pfn */ + #include + +-static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); +- + extern unsigned int zone_dma_bits; + + #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA +@@ -28,20 +26,6 @@ static inline phys_addr_t __dma_to_phys( + } + #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- dma_addr_t end = addr + size - 1; +- +- if (!dev->dma_mask) +- return false; +- +- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && +- min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) +- return false; +- +- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); +-} +- + #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED + bool force_dma_unencrypted(struct device *dev); + #else +@@ -67,6 +51,20 @@ static inline phys_addr_t dma_to_phys(st + return __sme_clr(__dma_to_phys(dev, daddr)); + } + ++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) ++{ ++ dma_addr_t end = addr + size - 1; ++ ++ if (!dev->dma_mask) ++ return false; ++ ++ if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && ++ min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) ++ return false; ++ ++ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); ++} ++ + u64 dma_direct_get_required_mask(struct device *dev); + void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t gfp, unsigned long attrs); diff --git a/target/linux/bcm27xx/patches-5.4/950-0443-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch b/target/linux/bcm27xx/patches-5.4/950-0443-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch deleted file mode 100644 index 23811e0b6e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0443-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 1c108eaeae73a504ac1b2d882bc1fefb91eecf17 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:46 +0200 -Subject: [PATCH] mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum - zone_type' - -commit 734f9246e791d8da278957b2c326d7709b2a97c0 upstream. - -These zones usage has evolved with time and the comments were outdated. -This joins both ZONE_DMA and ZONE_DMA32 explanation and gives up to date -examples on how they are used on different architectures. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Christoph Hellwig -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - include/linux/mmzone.h | 45 ++++++++++++++++++++++++------------------ - 1 file changed, 26 insertions(+), 19 deletions(-) - ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -358,33 +358,40 @@ struct per_cpu_nodestat { - #endif /* !__GENERATING_BOUNDS.H */ - - enum zone_type { --#ifdef CONFIG_ZONE_DMA - /* -- * ZONE_DMA is used when there are devices that are not able -- * to do DMA to all of addressable memory (ZONE_NORMAL). Then we -- * carve out the portion of memory that is needed for these devices. -- * The range is arch specific. -- * -- * Some examples -- * -- * Architecture Limit -- * --------------------------- -- * parisc, ia64, sparc <4G -- * s390, powerpc <2G -- * arm Various -- * alpha Unlimited or 0-16MB. -+ * ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able -+ * to DMA to all of the addressable memory (ZONE_NORMAL). -+ * On architectures where this area covers the whole 32 bit address -+ * space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller -+ * DMA addressing constraints. This distinction is important as a 32bit -+ * DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit -+ * platforms may need both zones as they support peripherals with -+ * different DMA addressing limitations. -+ * -+ * Some examples: -+ * -+ * - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the -+ * rest of the lower 4G. -+ * -+ * - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on -+ * the specific device. -+ * -+ * - arm64 has a fixed 1G ZONE_DMA and ZONE_DMA32 for the rest of the -+ * lower 4G. -+ * -+ * - powerpc only uses ZONE_DMA, the size, up to 2G, may vary -+ * depending on the specific device. - * -- * i386, x86_64 and multiple other arches -- * <16M. -+ * - s390 uses ZONE_DMA fixed to the lower 2G. -+ * -+ * - ia64 and riscv only use ZONE_DMA32. -+ * -+ * - parisc uses neither. - */ -+#ifdef CONFIG_ZONE_DMA - ZONE_DMA, - #endif - #ifdef CONFIG_ZONE_DMA32 -- /* -- * x86_64 needs two ZONE_DMAs because it supports devices that are -- * only able to do DMA to the lower 16M but also 32 bit devices that -- * can only do DMA areas below 4G. -- */ - ZONE_DMA32, - #endif - /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0444-dma-direct-exclude-dma_direct_map_resource-from-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0444-dma-direct-exclude-dma_direct_map_resource-from-the-.patch new file mode 100644 index 0000000000..2534b71b73 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0444-dma-direct-exclude-dma_direct_map_resource-from-the-.patch @@ -0,0 +1,115 @@ +From b763f24aed409296eb76d085c279b2c40462f8a1 Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Tue, 19 Nov 2019 17:38:58 +0100 +Subject: [PATCH] dma-direct: exclude dma_direct_map_resource from the + min_low_pfn check + +commit 68a33b1794665ba8a1d1ef1d3bfcc7c587d380a6 upstream. + +The valid memory address check in dma_capable only makes sense when mapping +normal memory, not when using dma_map_resource to map a device resource. +Add a new boolean argument to dma_capable to exclude that check for the +dma_map_resource case. + +Fixes: b12d66278dd6 ("dma-direct: check for overflows on 32 bit DMA addresses") +Reported-by: Marek Szyprowski +Signed-off-by: Christoph Hellwig +Acked-by: Marek Szyprowski +Tested-by: Marek Szyprowski +--- + arch/x86/kernel/amd_gart_64.c | 4 ++-- + drivers/xen/swiotlb-xen.c | 4 ++-- + include/linux/dma-direct.h | 5 +++-- + kernel/dma/direct.c | 4 ++-- + kernel/dma/swiotlb.c | 2 +- + 5 files changed, 10 insertions(+), 9 deletions(-) + +--- a/arch/x86/kernel/amd_gart_64.c ++++ b/arch/x86/kernel/amd_gart_64.c +@@ -185,13 +185,13 @@ static void iommu_full(struct device *de + static inline int + need_iommu(struct device *dev, unsigned long addr, size_t size) + { +- return force_iommu || !dma_capable(dev, addr, size); ++ return force_iommu || !dma_capable(dev, addr, size, true); + } + + static inline int + nonforced_iommu(struct device *dev, unsigned long addr, size_t size) + { +- return !dma_capable(dev, addr, size); ++ return !dma_capable(dev, addr, size, true); + } + + /* Map a single continuous physical area into the IOMMU. +--- a/drivers/xen/swiotlb-xen.c ++++ b/drivers/xen/swiotlb-xen.c +@@ -381,7 +381,7 @@ static dma_addr_t xen_swiotlb_map_page(s + * we can safely return the device addr and not worry about bounce + * buffering it. + */ +- if (dma_capable(dev, dev_addr, size) && ++ if (dma_capable(dev, dev_addr, size, true) && + !range_straddles_page_boundary(phys, size) && + !xen_arch_need_swiotlb(dev, phys, dev_addr) && + swiotlb_force != SWIOTLB_FORCE) +@@ -403,7 +403,7 @@ static dma_addr_t xen_swiotlb_map_page(s + /* + * Ensure that the address returned is DMA'ble + */ +- if (unlikely(!dma_capable(dev, dev_addr, size))) { ++ if (unlikely(!dma_capable(dev, dev_addr, size, true))) { + swiotlb_tbl_unmap_single(dev, map, size, size, dir, + attrs | DMA_ATTR_SKIP_CPU_SYNC); + return DMA_MAPPING_ERROR; +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -51,14 +51,15 @@ static inline phys_addr_t dma_to_phys(st + return __sme_clr(__dma_to_phys(dev, daddr)); + } + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) ++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size, ++ bool is_ram) + { + dma_addr_t end = addr + size - 1; + + if (!dev->dma_mask) + return false; + +- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && ++ if (is_ram && !IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && + min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) + return false; + +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -326,7 +326,7 @@ static inline bool dma_direct_possible(s + size_t size) + { + return swiotlb_force != SWIOTLB_FORCE && +- dma_capable(dev, dma_addr, size); ++ dma_capable(dev, dma_addr, size, true); + } + + dma_addr_t dma_direct_map_page(struct device *dev, struct page *page, +@@ -375,7 +375,7 @@ dma_addr_t dma_direct_map_resource(struc + { + dma_addr_t dma_addr = paddr; + +- if (unlikely(!dma_capable(dev, dma_addr, size))) { ++ if (unlikely(!dma_capable(dev, dma_addr, size, false))) { + report_addr(dev, dma_addr, size); + return DMA_MAPPING_ERROR; + } +--- a/kernel/dma/swiotlb.c ++++ b/kernel/dma/swiotlb.c +@@ -682,7 +682,7 @@ bool swiotlb_map(struct device *dev, phy + + /* Ensure that the address returned is DMA'ble */ + *dma_addr = __phys_to_dma(dev, *phys); +- if (unlikely(!dma_capable(dev, *dma_addr, size))) { ++ if (unlikely(!dma_capable(dev, *dma_addr, size, true))) { + swiotlb_tbl_unmap_single(dev, *phys, size, size, dir, + attrs | DMA_ATTR_SKIP_CPU_SYNC); + return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0444-resource-Add-a-resource_list_first_type-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0444-resource-Add-a-resource_list_first_type-helper.patch deleted file mode 100644 index c2c959a3c1..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0444-resource-Add-a-resource_list_first_type-helper.patch +++ /dev/null @@ -1,36 +0,0 @@ -From dacb1a46835914b8c3862db15726bcc0a68af8f5 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Mon, 28 Oct 2019 11:32:32 -0500 -Subject: [PATCH] resource: Add a resource_list_first_type helper - -commit 494f8b10d832456a96be4ee7317425f6936cabc8 upstream. - -A common pattern is looping over a resource_list just to get a matching -entry with a specific type. Add resource_list_first_type() helper which -implements this. - -Signed-off-by: Rob Herring -Signed-off-by: Lorenzo Pieralisi ---- - include/linux/resource_ext.h | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/include/linux/resource_ext.h -+++ b/include/linux/resource_ext.h -@@ -66,4 +66,16 @@ resource_list_destroy_entry(struct resou - #define resource_list_for_each_entry_safe(entry, tmp, list) \ - list_for_each_entry_safe((entry), (tmp), (list), node) - -+static inline struct resource_entry * -+resource_list_first_type(struct list_head *list, unsigned long type) -+{ -+ struct resource_entry *entry; -+ -+ resource_list_for_each_entry(entry, list) { -+ if (resource_type(entry->res) == type) -+ return entry; -+ } -+ return NULL; -+} -+ - #endif /* _LINUX_RESOURCE_EXT_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0445-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0445-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch deleted file mode 100644 index ab04d64b72..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0445-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 78b03f0aef9f67c4db700ba5dc56e2c8f562d181 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Mon, 14 Oct 2019 20:31:03 +0200 -Subject: [PATCH] dma/direct: turn ARCH_ZONE_DMA_BITS into a variable - -commit 8b5369ea580964dbc982781bfb9fb93459fc5e8d upstream. - -Some architectures, notably ARM, are interested in tweaking this -depending on their runtime DMA addressing limitations. - -Acked-by: Christoph Hellwig -Signed-off-by: Nicolas Saenz Julienne -Signed-off-by: Catalin Marinas ---- - arch/arm64/include/asm/page.h | 2 -- - arch/arm64/mm/init.c | 9 +++++++-- - arch/powerpc/include/asm/page.h | 9 --------- - arch/powerpc/mm/mem.c | 20 +++++++++++++++----- - arch/s390/include/asm/page.h | 2 -- - arch/s390/mm/init.c | 1 + - include/linux/dma-direct.h | 2 ++ - kernel/dma/direct.c | 13 ++++++------- - 8 files changed, 31 insertions(+), 27 deletions(-) - ---- a/arch/arm64/include/asm/page.h -+++ b/arch/arm64/include/asm/page.h -@@ -38,6 +38,4 @@ extern int pfn_valid(unsigned long); - - #include - --#define ARCH_ZONE_DMA_BITS 30 -- - #endif ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -41,6 +42,8 @@ - #include - #include - -+#define ARM64_ZONE_DMA_BITS 30 -+ - /* - * We need to be able to catch inadvertent references to memstart_addr - * that occur (potentially in generic code) before arm64_memblock_init() -@@ -430,8 +433,10 @@ void __init arm64_memblock_init(void) - - early_init_fdt_scan_reserved_mem(); - -- if (IS_ENABLED(CONFIG_ZONE_DMA)) -- arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); -+ if (IS_ENABLED(CONFIG_ZONE_DMA)) { -+ zone_dma_bits = ARM64_ZONE_DMA_BITS; -+ arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS); -+ } - - if (IS_ENABLED(CONFIG_ZONE_DMA32)) - arm64_dma32_phys_limit = max_zone_phys(32); ---- a/arch/powerpc/include/asm/page.h -+++ b/arch/powerpc/include/asm/page.h -@@ -334,13 +334,4 @@ struct vm_area_struct; - #endif /* __ASSEMBLY__ */ - #include - --/* -- * Allow 30-bit DMA for very limited Broadcom wifi chips on many powerbooks. -- */ --#ifdef CONFIG_PPC32 --#define ARCH_ZONE_DMA_BITS 30 --#else --#define ARCH_ZONE_DMA_BITS 31 --#endif -- - #endif /* _ASM_POWERPC_PAGE_H */ ---- a/arch/powerpc/mm/mem.c -+++ b/arch/powerpc/mm/mem.c -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -223,10 +224,10 @@ static int __init mark_nonram_nosave(voi - * everything else. GFP_DMA32 page allocations automatically fall back to - * ZONE_DMA. - * -- * By using 31-bit unconditionally, we can exploit ARCH_ZONE_DMA_BITS to -- * inform the generic DMA mapping code. 32-bit only devices (if not handled -- * by an IOMMU anyway) will take a first dip into ZONE_NORMAL and get -- * otherwise served by ZONE_DMA. -+ * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the -+ * generic DMA mapping code. 32-bit only devices (if not handled by an IOMMU -+ * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by -+ * ZONE_DMA. - */ - static unsigned long max_zone_pfns[MAX_NR_ZONES]; - -@@ -259,9 +260,18 @@ void __init paging_init(void) - printk(KERN_DEBUG "Memory hole size: %ldMB\n", - (long int)((top_of_ram - total_ram) >> 20)); - -+ /* -+ * Allow 30-bit DMA for very limited Broadcom wifi chips on many -+ * powerbooks. -+ */ -+ if (IS_ENABLED(CONFIG_PPC32)) -+ zone_dma_bits = 30; -+ else -+ zone_dma_bits = 31; -+ - #ifdef CONFIG_ZONE_DMA - max_zone_pfns[ZONE_DMA] = min(max_low_pfn, -- 1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT)); -+ 1UL << (zone_dma_bits - PAGE_SHIFT)); - #endif - max_zone_pfns[ZONE_NORMAL] = max_low_pfn; - #ifdef CONFIG_HIGHMEM ---- a/arch/s390/include/asm/page.h -+++ b/arch/s390/include/asm/page.h -@@ -179,8 +179,6 @@ static inline int devmem_is_allowed(unsi - #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) - --#define ARCH_ZONE_DMA_BITS 31 -- - #include - #include - ---- a/arch/s390/mm/init.c -+++ b/arch/s390/mm/init.c -@@ -118,6 +118,7 @@ void __init paging_init(void) - - sparse_memory_present_with_active_regions(MAX_NUMNODES); - sparse_init(); -+ zone_dma_bits = 31; - memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); - max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS); - max_zone_pfns[ZONE_NORMAL] = max_low_pfn; ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -8,6 +8,8 @@ - - static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); - -+extern unsigned int zone_dma_bits; -+ - #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA - #include - #else ---- a/kernel/dma/direct.c -+++ b/kernel/dma/direct.c -@@ -16,12 +16,11 @@ - #include - - /* -- * Most architectures use ZONE_DMA for the first 16 Megabytes, but -- * some use it for entirely different regions: -+ * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it -+ * it for entirely different regions. In that case the arch code needs to -+ * override the variable below for dma-direct to work properly. - */ --#ifndef ARCH_ZONE_DMA_BITS --#define ARCH_ZONE_DMA_BITS 24 --#endif -+unsigned int zone_dma_bits __ro_after_init = 24; - - static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size) - { -@@ -70,7 +69,7 @@ static gfp_t __dma_direct_optimal_gfp_ma - * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding - * zones. - */ -- if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)) -+ if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) - return GFP_DMA; - if (*phys_mask <= DMA_BIT_MASK(32)) - return GFP_DMA32; -@@ -396,7 +395,7 @@ int dma_direct_supported(struct device * - u64 min_mask; - - if (IS_ENABLED(CONFIG_ZONE_DMA)) -- min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS); -+ min_mask = DMA_BIT_MASK(zone_dma_bits); - else - min_mask = DMA_BIT_MASK(30); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0445-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch b/target/linux/bcm27xx/patches-5.4/950-0445-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch new file mode 100644 index 0000000000..d968e93153 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0445-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch @@ -0,0 +1,366 @@ +From d5430c466b3c3b5f631ee37be333a40924575b72 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 21 Nov 2019 10:26:44 +0100 +Subject: [PATCH] dma-mapping: treat dev->bus_dma_mask as a DMA limit + +commit a7ba70f1787f977f970cd116076c6fce4b9e01cc upstream. + +Using a mask to represent bus DMA constraints has a set of limitations. +The biggest one being it can only hold a power of two (minus one). The +DMA mapping code is already aware of this and treats dev->bus_dma_mask +as a limit. This quirk is already used by some architectures although +still rare. + +With the introduction of the Raspberry Pi 4 we've found a new contender +for the use of bus DMA limits, as its PCIe bus can only address the +lower 3GB of memory (of a total of 4GB). This is impossible to represent +with a mask. To make things worse the device-tree code rounds non power +of two bus DMA limits to the next power of two, which is unacceptable in +this case. + +In the light of this, rename dev->bus_dma_mask to dev->bus_dma_limit all +over the tree and treat it as such. Note that dev->bus_dma_limit should +contain the higher accessible DMA address. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Robin Murphy +Signed-off-by: Christoph Hellwig +--- + arch/mips/pci/fixup-sb1250.c | 16 ++++++++-------- + arch/powerpc/sysdev/fsl_pci.c | 6 +++--- + arch/x86/kernel/pci-dma.c | 2 +- + arch/x86/mm/mem_encrypt.c | 2 +- + arch/x86/pci/sta2x11-fixup.c | 2 +- + drivers/acpi/arm64/iort.c | 20 +++++++------------- + drivers/ata/ahci.c | 2 +- + drivers/iommu/dma-iommu.c | 3 +-- + drivers/of/device.c | 9 +++++---- + include/linux/device.h | 6 +++--- + include/linux/dma-direct.h | 2 +- + include/linux/dma-mapping.h | 2 +- + kernel/dma/direct.c | 27 +++++++++++++-------------- + 13 files changed, 46 insertions(+), 53 deletions(-) + +--- a/arch/mips/pci/fixup-sb1250.c ++++ b/arch/mips/pci/fixup-sb1250.c +@@ -21,22 +21,22 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SI + + /* + * The BCM1250, etc. PCI host bridge does not support DAC on its 32-bit +- * bus, so we set the bus's DMA mask accordingly. However the HT link ++ * bus, so we set the bus's DMA limit accordingly. However the HT link + * down the artificial PCI-HT bridge supports 40-bit addressing and the + * SP1011 HT-PCI bridge downstream supports both DAC and a 64-bit bus + * width, so we record the PCI-HT bridge's secondary and subordinate bus +- * numbers and do not set the mask for devices present in the inclusive ++ * numbers and do not set the limit for devices present in the inclusive + * range of those. + */ +-struct sb1250_bus_dma_mask_exclude { ++struct sb1250_bus_dma_limit_exclude { + bool set; + unsigned char start; + unsigned char end; + }; + +-static int sb1250_bus_dma_mask(struct pci_dev *dev, void *data) ++static int sb1250_bus_dma_limit(struct pci_dev *dev, void *data) + { +- struct sb1250_bus_dma_mask_exclude *exclude = data; ++ struct sb1250_bus_dma_limit_exclude *exclude = data; + bool exclude_this; + bool ht_bridge; + +@@ -55,7 +55,7 @@ static int sb1250_bus_dma_mask(struct pc + exclude->start, exclude->end); + } else { + dev_dbg(&dev->dev, "disabling DAC for device"); +- dev->dev.bus_dma_mask = DMA_BIT_MASK(32); ++ dev->dev.bus_dma_limit = DMA_BIT_MASK(32); + } + + return 0; +@@ -63,9 +63,9 @@ static int sb1250_bus_dma_mask(struct pc + + static void quirk_sb1250_pci_dac(struct pci_dev *dev) + { +- struct sb1250_bus_dma_mask_exclude exclude = { .set = false }; ++ struct sb1250_bus_dma_limit_exclude exclude = { .set = false }; + +- pci_walk_bus(dev->bus, sb1250_bus_dma_mask, &exclude); ++ pci_walk_bus(dev->bus, sb1250_bus_dma_limit, &exclude); + } + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI, + quirk_sb1250_pci_dac); +--- a/arch/powerpc/sysdev/fsl_pci.c ++++ b/arch/powerpc/sysdev/fsl_pci.c +@@ -115,8 +115,8 @@ static void pci_dma_dev_setup_swiotlb(st + { + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + +- pdev->dev.bus_dma_mask = +- hose->dma_window_base_cur + hose->dma_window_size; ++ pdev->dev.bus_dma_limit = ++ hose->dma_window_base_cur + hose->dma_window_size - 1; + } + + static void setup_swiotlb_ops(struct pci_controller *hose) +@@ -135,7 +135,7 @@ static void fsl_pci_dma_set_mask(struct + * mapping that allows addressing any RAM address from across PCI. + */ + if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) { +- dev->bus_dma_mask = 0; ++ dev->bus_dma_limit = 0; + dev->archdata.dma_offset = pci64_dma_offset; + } + } +--- a/arch/x86/kernel/pci-dma.c ++++ b/arch/x86/kernel/pci-dma.c +@@ -146,7 +146,7 @@ rootfs_initcall(pci_iommu_init); + + static int via_no_dac_cb(struct pci_dev *pdev, void *data) + { +- pdev->dev.bus_dma_mask = DMA_BIT_MASK(32); ++ pdev->dev.bus_dma_limit = DMA_BIT_MASK(32); + return 0; + } + +--- a/arch/x86/mm/mem_encrypt.c ++++ b/arch/x86/mm/mem_encrypt.c +@@ -367,7 +367,7 @@ bool force_dma_unencrypted(struct device + if (sme_active()) { + u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask)); + u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask, +- dev->bus_dma_mask); ++ dev->bus_dma_limit); + + if (dma_dev_mask <= dma_enc_mask) + return true; +--- a/arch/x86/pci/sta2x11-fixup.c ++++ b/arch/x86/pci/sta2x11-fixup.c +@@ -143,7 +143,7 @@ static void sta2x11_map_ep(struct pci_de + + dev->dma_pfn_offset = PFN_DOWN(-amba_base); + +- dev->bus_dma_mask = max_amba_addr; ++ dev->bus_dma_limit = max_amba_addr; + pci_set_consistent_dma_mask(pdev, max_amba_addr); + pci_set_dma_mask(pdev, max_amba_addr); + +--- a/drivers/acpi/arm64/iort.c ++++ b/drivers/acpi/arm64/iort.c +@@ -1062,8 +1062,8 @@ static int rc_dma_get_range(struct devic + */ + void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) + { +- u64 mask, dmaaddr = 0, size = 0, offset = 0; +- int ret, msb; ++ u64 end, mask, dmaaddr = 0, size = 0, offset = 0; ++ int ret; + + /* + * If @dev is expected to be DMA-capable then the bus code that created +@@ -1090,19 +1090,13 @@ void iort_dma_setup(struct device *dev, + } + + if (!ret) { +- msb = fls64(dmaaddr + size - 1); + /* +- * Round-up to the power-of-two mask or set +- * the mask to the whole 64-bit address space +- * in case the DMA region covers the full +- * memory window. ++ * Limit coherent and dma mask based on size retrieved from ++ * firmware. + */ +- mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; +- /* +- * Limit coherent and dma mask based on size +- * retrieved from firmware. +- */ +- dev->bus_dma_mask = mask; ++ end = dmaaddr + size - 1; ++ mask = DMA_BIT_MASK(ilog2(end) + 1); ++ dev->bus_dma_limit = end; + dev->coherent_dma_mask = mask; + *dev->dma_mask = mask; + } +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -900,7 +900,7 @@ static int ahci_configure_dma_masks(stru + * value, don't extend it here. This happens on STA2X11, for example. + * + * XXX: manipulating the DMA mask from platform code is completely +- * bogus, platform code should use dev->bus_dma_mask instead.. ++ * bogus, platform code should use dev->bus_dma_limit instead.. + */ + if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32)) + return 0; +--- a/drivers/iommu/dma-iommu.c ++++ b/drivers/iommu/dma-iommu.c +@@ -404,8 +404,7 @@ static dma_addr_t iommu_dma_alloc_iova(s + if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) + iova_len = roundup_pow_of_two(iova_len); + +- if (dev->bus_dma_mask) +- dma_limit &= dev->bus_dma_mask; ++ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); + + if (domain->geometry.force_aperture) + dma_limit = min(dma_limit, domain->geometry.aperture_end); +--- a/drivers/of/device.c ++++ b/drivers/of/device.c +@@ -93,7 +93,7 @@ int of_dma_configure(struct device *dev, + bool coherent; + unsigned long offset; + const struct iommu_ops *iommu; +- u64 mask; ++ u64 mask, end; + + ret = of_dma_get_range(np, &dma_addr, &paddr, &size); + if (ret < 0) { +@@ -148,12 +148,13 @@ int of_dma_configure(struct device *dev, + * Limit coherent and dma mask based on size and default mask + * set by the driver. + */ +- mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1); ++ end = dma_addr + size - 1; ++ mask = DMA_BIT_MASK(ilog2(end) + 1); + dev->coherent_dma_mask &= mask; + *dev->dma_mask &= mask; +- /* ...but only set bus mask if we found valid dma-ranges earlier */ ++ /* ...but only set bus limit if we found valid dma-ranges earlier */ + if (!ret) +- dev->bus_dma_mask = mask; ++ dev->bus_dma_limit = end; + + coherent = of_dma_is_coherent(np); + dev_dbg(dev, "device is%sdma coherent\n", +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1186,8 +1186,8 @@ struct dev_links_info { + * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all + * hardware supports 64-bit addresses for consistent allocations + * such descriptors. +- * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA +- * limit than the device itself supports. ++ * @bus_dma_limit: Limit of an upstream bridge or bus which imposes a smaller ++ * DMA limit than the device itself supports. + * @dma_pfn_offset: offset of DMA memory range relatively of RAM + * @dma_parms: A low level driver may set these to teach IOMMU code about + * segment limitations. +@@ -1270,7 +1270,7 @@ struct device { + not all hardware supports + 64 bit addresses for consistent + allocations such descriptors. */ +- u64 bus_dma_mask; /* upstream dma_mask constraint */ ++ u64 bus_dma_limit; /* upstream dma constraint */ + unsigned long dma_pfn_offset; + + struct device_dma_parameters *dma_parms; +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -63,7 +63,7 @@ static inline bool dma_capable(struct de + min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) + return false; + +- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); ++ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_limit); + } + + u64 dma_direct_get_required_mask(struct device *dev); +--- a/include/linux/dma-mapping.h ++++ b/include/linux/dma-mapping.h +@@ -697,7 +697,7 @@ static inline int dma_coerce_mask_and_co + */ + static inline bool dma_addressing_limited(struct device *dev) + { +- return min_not_zero(dma_get_mask(dev), dev->bus_dma_mask) < ++ return min_not_zero(dma_get_mask(dev), dev->bus_dma_limit) < + dma_get_required_mask(dev); + } + +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -26,10 +26,10 @@ static void report_addr(struct device *d + { + if (!dev->dma_mask) { + dev_err_once(dev, "DMA map on device without dma_mask\n"); +- } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_mask) { ++ } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_limit) { + dev_err_once(dev, +- "overflow %pad+%zu of DMA mask %llx bus mask %llx\n", +- &dma_addr, size, *dev->dma_mask, dev->bus_dma_mask); ++ "overflow %pad+%zu of DMA mask %llx bus limit %llx\n", ++ &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit); + } + WARN_ON_ONCE(1); + } +@@ -51,15 +51,14 @@ u64 dma_direct_get_required_mask(struct + } + + static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask, +- u64 *phys_mask) ++ u64 *phys_limit) + { +- if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask) +- dma_mask = dev->bus_dma_mask; ++ u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit); + + if (force_dma_unencrypted(dev)) +- *phys_mask = __dma_to_phys(dev, dma_mask); ++ *phys_limit = __dma_to_phys(dev, dma_limit); + else +- *phys_mask = dma_to_phys(dev, dma_mask); ++ *phys_limit = dma_to_phys(dev, dma_limit); + + /* + * Optimistically try the zone that the physical address mask falls +@@ -69,9 +68,9 @@ static gfp_t __dma_direct_optimal_gfp_ma + * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding + * zones. + */ +- if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) ++ if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits)) + return GFP_DMA; +- if (*phys_mask <= DMA_BIT_MASK(32)) ++ if (*phys_limit <= DMA_BIT_MASK(32)) + return GFP_DMA32; + return 0; + } +@@ -79,7 +78,7 @@ static gfp_t __dma_direct_optimal_gfp_ma + static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size) + { + return phys_to_dma_direct(dev, phys) + size - 1 <= +- min_not_zero(dev->coherent_dma_mask, dev->bus_dma_mask); ++ min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit); + } + + struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, +@@ -88,7 +87,7 @@ struct page *__dma_direct_alloc_pages(st + size_t alloc_size = PAGE_ALIGN(size); + int node = dev_to_node(dev); + struct page *page = NULL; +- u64 phys_mask; ++ u64 phys_limit; + + if (attrs & DMA_ATTR_NO_WARN) + gfp |= __GFP_NOWARN; +@@ -96,7 +95,7 @@ struct page *__dma_direct_alloc_pages(st + /* we always manually zero the memory once we are done: */ + gfp &= ~__GFP_ZERO; + gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, +- &phys_mask); ++ &phys_limit); + page = dma_alloc_contiguous(dev, alloc_size, gfp); + if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { + dma_free_contiguous(dev, page, alloc_size); +@@ -110,7 +109,7 @@ again: + page = NULL; + + if (IS_ENABLED(CONFIG_ZONE_DMA32) && +- phys_mask < DMA_BIT_MASK(64) && ++ phys_limit < DMA_BIT_MASK(64) && + !(gfp & (GFP_DMA32 | GFP_DMA))) { + gfp |= GFP_DMA32; + goto again; diff --git a/target/linux/bcm27xx/patches-5.4/950-0446-ARM-dts-bcm2711-Enable-PCIe-controller.patch b/target/linux/bcm27xx/patches-5.4/950-0446-ARM-dts-bcm2711-Enable-PCIe-controller.patch new file mode 100644 index 0000000000..9f114c1633 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0446-ARM-dts-bcm2711-Enable-PCIe-controller.patch @@ -0,0 +1,56 @@ +From 0ec0bc884f6cf1ec9775c750f78ce28be7da4340 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Mon, 16 Dec 2019 12:01:08 +0100 +Subject: [PATCH] ARM: dts: bcm2711: Enable PCIe controller + +commit d5c8dc0d4c880fbde5293cc186b1ab23466254c4 upstream. + +This enables bcm2711's PCIe bus, which is hardwired to a VIA +Technologies XHCI USB 3.0 controller. + +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm2711.dtsi | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -331,7 +331,36 @@ + #address-cells = <2>; + #size-cells = <1>; + +- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; ++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, ++ <0x6 0x00000000 0x6 0x00000000 0x40000000>; ++ ++ pcie0: pcie@7d500000 { ++ compatible = "brcm,bcm2711-pcie"; ++ reg = <0x0 0x7d500000 0x9310>; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 ++ IRQ_TYPE_LEVEL_HIGH>; ++ msi-controller; ++ msi-parent = <&pcie0>; ++ ++ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 ++ 0x0 0x04000000>; ++ /* ++ * The wrapper around the PCIe block has a bug ++ * preventing it from accessing beyond the first 3GB of ++ * memory. ++ */ ++ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 ++ 0x0 0xc0000000>; ++ brcm,enable-ssc; ++ }; + + genet: ethernet@7d580000 { + compatible = "brcm,bcm2711-genet-v5"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0446-x86-PCI-sta2x11-use-default-DMA-address-translation.patch b/target/linux/bcm27xx/patches-5.4/950-0446-x86-PCI-sta2x11-use-default-DMA-address-translation.patch deleted file mode 100644 index 51fd4be35e..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0446-x86-PCI-sta2x11-use-default-DMA-address-translation.patch +++ /dev/null @@ -1,259 +0,0 @@ -From 97a48106d1698038720495fdd49c491b283bf110 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Thu, 7 Nov 2019 16:06:45 +0100 -Subject: [PATCH] x86/PCI: sta2x11: use default DMA address translation - -commit e380a0394c36a3a878c858418d5dd7f5f195b6fc upstream. - -The devices found behind this PCIe chip have unusual DMA mapping -constraints as there is an AMBA interconnect placed in between them and -the different PCI endpoints. The offset between physical memory -addresses and AMBA's view is provided by reading a PCI config register, -which is saved and used whenever DMA mapping is needed. - -It turns out that this DMA setup can be represented by properly setting -'dma_pfn_offset', 'dma_bus_mask' and 'dma_mask' during the PCI device -enable fixup. And ultimately allows us to get rid of this device's -custom DMA functions. - -Aside from the code deletion and DMA setup, sta2x11_pdev_to_mapping() is -moved to avoid warnings whenever CONFIG_PM is not enabled. - -Signed-off-by: Nicolas Saenz Julienne -Signed-off-by: Christoph Hellwig ---- - arch/x86/Kconfig | 1 - - arch/x86/include/asm/device.h | 3 - - arch/x86/include/asm/dma-direct.h | 9 -- - arch/x86/pci/sta2x11-fixup.c | 135 ++++++------------------------ - 4 files changed, 26 insertions(+), 122 deletions(-) - delete mode 100644 arch/x86/include/asm/dma-direct.h - ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -708,7 +708,6 @@ config X86_SUPPORTS_MEMORY_FAILURE - config STA2X11 - bool "STA2X11 Companion Chip Support" - depends on X86_32_NON_STANDARD && PCI -- select ARCH_HAS_PHYS_TO_DMA - select SWIOTLB - select MFD_STA2X11 - select GPIOLIB ---- a/arch/x86/include/asm/device.h -+++ b/arch/x86/include/asm/device.h -@@ -6,9 +6,6 @@ struct dev_archdata { - #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU) - void *iommu; /* hook for IOMMU specific extension */ - #endif --#ifdef CONFIG_STA2X11 -- bool is_sta2x11; --#endif - }; - - #if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS) ---- a/arch/x86/include/asm/dma-direct.h -+++ /dev/null -@@ -1,9 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --#ifndef ASM_X86_DMA_DIRECT_H --#define ASM_X86_DMA_DIRECT_H 1 -- --bool dma_capable(struct device *dev, dma_addr_t addr, size_t size); --dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); --phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); -- --#endif /* ASM_X86_DMA_DIRECT_H */ ---- a/arch/x86/pci/sta2x11-fixup.c -+++ b/arch/x86/pci/sta2x11-fixup.c -@@ -30,7 +30,6 @@ struct sta2x11_ahb_regs { /* saved durin - }; - - struct sta2x11_mapping { -- u32 amba_base; - int is_suspended; - struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS]; - }; -@@ -92,18 +91,6 @@ static int sta2x11_pdev_to_ep(struct pci - return pdev->bus->number - instance->bus0; - } - --static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) --{ -- struct sta2x11_instance *instance; -- int ep; -- -- instance = sta2x11_pdev_to_instance(pdev); -- if (!instance) -- return NULL; -- ep = sta2x11_pdev_to_ep(pdev); -- return instance->map + ep; --} -- - /* This is exported, as some devices need to access the MFD registers */ - struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev) - { -@@ -111,39 +98,6 @@ struct sta2x11_instance *sta2x11_get_ins - } - EXPORT_SYMBOL(sta2x11_get_instance); - -- --/** -- * p2a - Translate physical address to STA2x11 AMBA address, -- * used for DMA transfers to STA2x11 -- * @p: Physical address -- * @pdev: PCI device (must be hosted within the connext) -- */ --static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev) --{ -- struct sta2x11_mapping *map; -- dma_addr_t a; -- -- map = sta2x11_pdev_to_mapping(pdev); -- a = p + map->amba_base; -- return a; --} -- --/** -- * a2p - Translate STA2x11 AMBA address to physical address -- * used for DMA transfers from STA2x11 -- * @a: STA2x11 AMBA address -- * @pdev: PCI device (must be hosted within the connext) -- */ --static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev) --{ -- struct sta2x11_mapping *map; -- dma_addr_t p; -- -- map = sta2x11_pdev_to_mapping(pdev); -- p = a - map->amba_base; -- return p; --} -- - /* At setup time, we use our own ops if the device is a ConneXt one */ - static void sta2x11_setup_pdev(struct pci_dev *pdev) - { -@@ -151,9 +105,6 @@ static void sta2x11_setup_pdev(struct pc - - if (!instance) /* either a sta2x11 bridge or another ST device */ - return; -- pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); -- pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); -- pdev->dev.archdata.is_sta2x11 = true; - - /* We must enable all devices as master, for audio DMA to work */ - pci_set_master(pdev); -@@ -161,61 +112,6 @@ static void sta2x11_setup_pdev(struct pc - DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev); - - /* -- * The following three functions are exported (used in swiotlb: FIXME) -- */ --/** -- * dma_capable - Check if device can manage DMA transfers (FIXME: kill it) -- * @dev: device for a PCI device -- * @addr: DMA address -- * @size: DMA size -- */ --bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- struct sta2x11_mapping *map; -- -- if (!dev->archdata.is_sta2x11) { -- if (!dev->dma_mask) -- return false; -- return addr + size - 1 <= *dev->dma_mask; -- } -- -- map = sta2x11_pdev_to_mapping(to_pci_dev(dev)); -- -- if (!map || (addr < map->amba_base)) -- return false; -- if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) { -- return false; -- } -- -- return true; --} -- --/** -- * __phys_to_dma - Return the DMA AMBA address used for this STA2x11 device -- * @dev: device for a PCI device -- * @paddr: Physical address -- */ --dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) --{ -- if (!dev->archdata.is_sta2x11) -- return paddr; -- return p2a(paddr, to_pci_dev(dev)); --} -- --/** -- * dma_to_phys - Return the physical address used for this STA2x11 DMA address -- * @dev: device for a PCI device -- * @daddr: STA2x11 AMBA DMA address -- */ --phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr) --{ -- if (!dev->archdata.is_sta2x11) -- return daddr; -- return a2p(daddr, to_pci_dev(dev)); --} -- -- --/* - * At boot we must set up the mappings for the pcie-to-amba bridge. - * It involves device access, and the same happens at suspend/resume time - */ -@@ -234,12 +130,22 @@ phys_addr_t __dma_to_phys(struct device - /* At probe time, enable mapping for each endpoint, using the pdev */ - static void sta2x11_map_ep(struct pci_dev *pdev) - { -- struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); -+ struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev); -+ struct device *dev = &pdev->dev; -+ u32 amba_base, max_amba_addr; - int i; - -- if (!map) -+ if (!instance) - return; -- pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base); -+ -+ pci_read_config_dword(pdev, AHB_BASE(0), &amba_base); -+ max_amba_addr = amba_base + STA2X11_AMBA_SIZE - 1; -+ -+ dev->dma_pfn_offset = PFN_DOWN(-amba_base); -+ -+ dev->bus_dma_mask = max_amba_addr; -+ pci_set_consistent_dma_mask(pdev, max_amba_addr); -+ pci_set_dma_mask(pdev, max_amba_addr); - - /* Configure AHB mapping */ - pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0); -@@ -253,13 +159,24 @@ static void sta2x11_map_ep(struct pci_de - - dev_info(&pdev->dev, - "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n", -- sta2x11_pdev_to_ep(pdev), map->amba_base, -- map->amba_base + STA2X11_AMBA_SIZE - 1); -+ sta2x11_pdev_to_ep(pdev), amba_base, max_amba_addr); - } - DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep); - - #ifdef CONFIG_PM /* Some register values must be saved and restored */ - -+static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) -+{ -+ struct sta2x11_instance *instance; -+ int ep; -+ -+ instance = sta2x11_pdev_to_instance(pdev); -+ if (!instance) -+ return NULL; -+ ep = sta2x11_pdev_to_ep(pdev); -+ return instance->map + ep; -+} -+ - static void suspend_mapping(struct pci_dev *pdev) - { - struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0447-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0447-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch new file mode 100644 index 0000000000..ca97a1966e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0447-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch @@ -0,0 +1,810 @@ +From 4d9470c29736bf81bdb0d21da24cf350b1e99402 Mon Sep 17 00:00:00 2001 +From: Jim Quinlan +Date: Mon, 16 Dec 2019 12:01:09 +0100 +Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller + driver + +commit c0452137034bda8f686dd9a2e167949bfffd6776 upstream. + +This adds a basic driver for Broadcom's STB PCIe controller, for now +aimed at Raspberry Pi 4's SoC, bcm2711. + +Signed-off-by: Jim Quinlan +Co-developed-by: Nicolas Saenz Julienne +Signed-off-by: Nicolas Saenz Julienne +[lorenzo.pieralisi@arm.com: updated brcm_pcie_get_rc_bar2_size_and_offset()according to https://lore.kernel.org/linux-pci/be8ddb33a7360af1815cf686f77f3f0913d02be3.camel@suse.de] +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Andrew Murray +Reviewed-by: Jeremy Linton +--- + drivers/pci/controller/Kconfig | 8 + + drivers/pci/controller/Makefile | 1 + + drivers/pci/controller/pcie-brcmstb.c | 755 ++++++++++++++++++++++++++ + 3 files changed, 764 insertions(+) + create mode 100644 drivers/pci/controller/pcie-brcmstb.c + +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -281,6 +281,14 @@ config VMD + To compile this driver as a module, choose M here: the + module will be called vmd. + ++config PCIE_BRCMSTB ++ tristate "Broadcom Brcmstb PCIe host controller" ++ depends on ARCH_BCM2835 || COMPILE_TEST ++ depends on OF ++ help ++ Say Y here to enable PCIe host controller support for ++ Broadcom STB based SoCs, like the Raspberry Pi 4. ++ + config PCI_HYPERV_INTERFACE + tristate "Hyper-V PCI Interface" + depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 +--- a/drivers/pci/controller/Makefile ++++ b/drivers/pci/controller/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi + obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o + obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o + obj-$(CONFIG_VMD) += vmd.o ++obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o + # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW + obj-y += dwc/ + +--- /dev/null ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -0,0 +1,755 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Copyright (C) 2009 - 2019 Broadcom */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../pci.h" ++ ++/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */ ++#define BRCM_PCIE_CAP_REGS 0x00ac ++ ++/* Broadcom STB PCIe Register Offsets */ ++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188 ++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc ++#define PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN 0x0 ++ ++#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c ++#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff ++ ++#define PCIE_RC_DL_MDIO_ADDR 0x1100 ++#define PCIE_RC_DL_MDIO_WR_DATA 0x1104 ++#define PCIE_RC_DL_MDIO_RD_DATA 0x1108 ++ ++#define PCIE_MISC_MISC_CTRL 0x4008 ++#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 ++#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 ++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 ++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 0x0 ++#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c ++#define PCIE_MEM_WIN0_LO(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4) ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 ++#define PCIE_MEM_WIN0_HI(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4) ++ ++#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c ++#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f ++ ++#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 ++#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038 ++ ++#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c ++#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f ++ ++#define PCIE_MISC_PCIE_CTRL 0x4064 ++#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 ++ ++#define PCIE_MISC_PCIE_STATUS 0x4068 ++#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 ++#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20 ++#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 ++#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 ++#define PCIE_MEM_WIN0_BASE_LIMIT(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4) ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff ++#define PCIE_MEM_WIN0_BASE_HI(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8) ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff ++#define PCIE_MEM_WIN0_LIMIT_HI(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) ++ ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 ++ ++#define PCIE_MSI_INTR2_STATUS 0x4500 ++#define PCIE_MSI_INTR2_CLR 0x4508 ++#define PCIE_MSI_INTR2_MASK_SET 0x4510 ++#define PCIE_MSI_INTR2_MASK_CLR 0x4514 ++ ++#define PCIE_EXT_CFG_DATA 0x8000 ++ ++#define PCIE_EXT_CFG_INDEX 0x9000 ++#define PCIE_EXT_BUSNUM_SHIFT 20 ++#define PCIE_EXT_SLOT_SHIFT 15 ++#define PCIE_EXT_FUNC_SHIFT 12 ++ ++#define PCIE_RGR1_SW_INIT_1 0x9210 ++#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 ++#define PCIE_RGR1_SW_INIT_1_INIT_MASK 0x2 ++ ++/* PCIe parameters */ ++#define BRCM_NUM_PCIE_OUT_WINS 0x4 ++ ++/* MDIO registers */ ++#define MDIO_PORT0 0x0 ++#define MDIO_DATA_MASK 0x7fffffff ++#define MDIO_PORT_MASK 0xf0000 ++#define MDIO_REGAD_MASK 0xffff ++#define MDIO_CMD_MASK 0xfff00000 ++#define MDIO_CMD_READ 0x1 ++#define MDIO_CMD_WRITE 0x0 ++#define MDIO_DATA_DONE_MASK 0x80000000 ++#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0) ++#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1) ++#define SSC_REGS_ADDR 0x1100 ++#define SET_ADDR_OFFSET 0x1f ++#define SSC_CNTL_OFFSET 0x2 ++#define SSC_CNTL_OVRD_EN_MASK 0x8000 ++#define SSC_CNTL_OVRD_VAL_MASK 0x4000 ++#define SSC_STATUS_OFFSET 0x1 ++#define SSC_STATUS_SSC_MASK 0x400 ++#define SSC_STATUS_PLL_LOCK_MASK 0x800 ++ ++/* Internal PCIe Host Controller Information.*/ ++struct brcm_pcie { ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ struct pci_bus *root_bus; ++ struct device_node *np; ++ bool ssc; ++ int gen; ++}; ++ ++/* ++ * This is to convert the size of the inbound "BAR" region to the ++ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE ++ */ ++static int brcm_pcie_encode_ibar_size(u64 size) ++{ ++ int log2_in = ilog2(size); ++ ++ if (log2_in >= 12 && log2_in <= 15) ++ /* Covers 4KB to 32KB (inclusive) */ ++ return (log2_in - 12) + 0x1c; ++ else if (log2_in >= 16 && log2_in <= 35) ++ /* Covers 64KB to 32GB, (inclusive) */ ++ return log2_in - 15; ++ /* Something is awry so disable */ ++ return 0; ++} ++ ++static u32 brcm_pcie_mdio_form_pkt(int port, int regad, int cmd) ++{ ++ u32 pkt = 0; ++ ++ pkt |= FIELD_PREP(MDIO_PORT_MASK, port); ++ pkt |= FIELD_PREP(MDIO_REGAD_MASK, regad); ++ pkt |= FIELD_PREP(MDIO_CMD_MASK, cmd); ++ ++ return pkt; ++} ++ ++/* negative return value indicates error */ ++static int brcm_pcie_mdio_read(void __iomem *base, u8 port, u8 regad, u32 *val) ++{ ++ int tries; ++ u32 data; ++ ++ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ), ++ base + PCIE_RC_DL_MDIO_ADDR); ++ readl(base + PCIE_RC_DL_MDIO_ADDR); ++ ++ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA); ++ for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) { ++ udelay(10); ++ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA); ++ } ++ ++ *val = FIELD_GET(MDIO_DATA_MASK, data); ++ return MDIO_RD_DONE(data) ? 0 : -EIO; ++} ++ ++/* negative return value indicates error */ ++static int brcm_pcie_mdio_write(void __iomem *base, u8 port, ++ u8 regad, u16 wrdata) ++{ ++ int tries; ++ u32 data; ++ ++ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE), ++ base + PCIE_RC_DL_MDIO_ADDR); ++ readl(base + PCIE_RC_DL_MDIO_ADDR); ++ writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA); ++ ++ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA); ++ for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) { ++ udelay(10); ++ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA); ++ } ++ ++ return MDIO_WT_DONE(data) ? 0 : -EIO; ++} ++ ++/* ++ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative ++ * return value indicates error. ++ */ ++static int brcm_pcie_set_ssc(struct brcm_pcie *pcie) ++{ ++ int pll, ssc; ++ int ret; ++ u32 tmp; ++ ++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, ++ SSC_REGS_ADDR); ++ if (ret < 0) ++ return ret; ++ ++ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, ++ SSC_CNTL_OFFSET, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_EN_MASK); ++ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_VAL_MASK); ++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, ++ SSC_CNTL_OFFSET, tmp); ++ if (ret < 0) ++ return ret; ++ ++ usleep_range(1000, 2000); ++ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, ++ SSC_STATUS_OFFSET, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ ssc = FIELD_GET(SSC_STATUS_SSC_MASK, tmp); ++ pll = FIELD_GET(SSC_STATUS_PLL_LOCK_MASK, tmp); ++ ++ return ssc && pll ? 0 : -EIO; ++} ++ ++/* Limits operation to a specific generation (1, 2, or 3) */ ++static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen) ++{ ++ u16 lnkctl2 = readw(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2); ++ u32 lnkcap = readl(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); ++ ++ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen; ++ writel(lnkcap, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); ++ ++ lnkctl2 = (lnkctl2 & ~0xf) | gen; ++ writew(lnkctl2, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2); ++} ++ ++static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, ++ unsigned int win, u64 cpu_addr, ++ u64 pcie_addr, u64 size) ++{ ++ u32 cpu_addr_mb_high, limit_addr_mb_high; ++ phys_addr_t cpu_addr_mb, limit_addr_mb; ++ int high_addr_shift; ++ u32 tmp; ++ ++ /* Set the base of the pcie_addr window */ ++ writel(lower_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_LO(win)); ++ writel(upper_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_HI(win)); ++ ++ /* Write the addr base & limit lower bits (in MBs) */ ++ cpu_addr_mb = cpu_addr / SZ_1M; ++ limit_addr_mb = (cpu_addr + size - 1) / SZ_1M; ++ ++ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)); ++ u32p_replace_bits(&tmp, cpu_addr_mb, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); ++ u32p_replace_bits(&tmp, limit_addr_mb, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK); ++ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)); ++ ++ /* Write the cpu & limit addr upper bits */ ++ high_addr_shift = ++ HWEIGHT32(PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); ++ ++ cpu_addr_mb_high = cpu_addr_mb >> high_addr_shift; ++ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_HI(win)); ++ u32p_replace_bits(&tmp, cpu_addr_mb_high, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK); ++ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_HI(win)); ++ ++ limit_addr_mb_high = limit_addr_mb >> high_addr_shift; ++ tmp = readl(pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); ++ u32p_replace_bits(&tmp, limit_addr_mb_high, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK); ++ writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); ++} ++ ++/* The controller is capable of serving in both RC and EP roles */ ++static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ u32 val = readl(base + PCIE_MISC_PCIE_STATUS); ++ ++ return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); ++} ++ ++static bool brcm_pcie_link_up(struct brcm_pcie *pcie) ++{ ++ u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS); ++ u32 dla = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK, val); ++ u32 plu = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK, val); ++ ++ return dla && plu; ++} ++ ++/* Configuration space read/write support */ ++static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg) ++{ ++ return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT) ++ | ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT) ++ | (busnr << PCIE_EXT_BUSNUM_SHIFT) ++ | (reg & ~3); ++} ++ ++static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn, ++ int where) ++{ ++ struct brcm_pcie *pcie = bus->sysdata; ++ void __iomem *base = pcie->base; ++ int idx; ++ ++ /* Accesses to the RC go right to the RC registers if slot==0 */ ++ if (pci_is_root_bus(bus)) ++ return PCI_SLOT(devfn) ? NULL : base + where; ++ ++ /* For devices, write to the config space index register */ ++ idx = brcm_pcie_cfg_index(bus->number, devfn, 0); ++ writel(idx, pcie->base + PCIE_EXT_CFG_INDEX); ++ return base + PCIE_EXT_CFG_DATA + where; ++} ++ ++static struct pci_ops brcm_pcie_ops = { ++ .map_bus = brcm_pcie_map_conf, ++ .read = pci_generic_config_read, ++ .write = pci_generic_config_write, ++}; ++ ++static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) ++{ ++ u32 tmp; ++ ++ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); ++ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK); ++ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); ++} ++ ++static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val) ++{ ++ u32 tmp; ++ ++ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); ++ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK); ++ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); ++} ++ ++static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, ++ u64 *rc_bar2_size, ++ u64 *rc_bar2_offset) ++{ ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ struct device *dev = pcie->dev; ++ struct resource_entry *entry; ++ ++ entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM); ++ if (!entry) ++ return -ENODEV; ++ ++ ++ /* ++ * The controller expects the inbound window offset to be calculated as ++ * the difference between PCIe's address space and CPU's. The offset ++ * provided by the firmware is calculated the opposite way, so we ++ * negate it. ++ */ ++ *rc_bar2_offset = -entry->offset; ++ *rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start); ++ ++ /* ++ * We validate the inbound memory view even though we should trust ++ * whatever the device-tree provides. This is because of an HW issue on ++ * early Raspberry Pi 4's revisions (bcm2711). It turns out its ++ * firmware has to dynamically edit dma-ranges due to a bug on the ++ * PCIe controller integration, which prohibits any access above the ++ * lower 3GB of memory. Given this, we decided to keep the dma-ranges ++ * in check, avoiding hard to debug device-tree related issues in the ++ * future: ++ * ++ * The PCIe host controller by design must set the inbound viewport to ++ * be a contiguous arrangement of all of the system's memory. In ++ * addition, its size mut be a power of two. To further complicate ++ * matters, the viewport must start on a pcie-address that is aligned ++ * on a multiple of its size. If a portion of the viewport does not ++ * represent system memory -- e.g. 3GB of memory requires a 4GB ++ * viewport -- we can map the outbound memory in or after 3GB and even ++ * though the viewport will overlap the outbound memory the controller ++ * will know to send outbound memory downstream and everything else ++ * upstream. ++ * ++ * For example: ++ * ++ * - The best-case scenario, memory up to 3GB, is to place the inbound ++ * region in the first 4GB of pcie-space, as some legacy devices can ++ * only address 32bits. We would also like to put the MSI under 4GB ++ * as well, since some devices require a 32bit MSI target address. ++ * ++ * - If the system memory is 4GB or larger we cannot start the inbound ++ * region at location 0 (since we have to allow some space for ++ * outbound memory @ 3GB). So instead it will start at the 1x ++ * multiple of its size ++ */ ++ if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size || ++ (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) { ++ dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n", ++ *rc_bar2_size, *rc_bar2_offset); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int brcm_pcie_setup(struct brcm_pcie *pcie) ++{ ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ u64 rc_bar2_offset, rc_bar2_size; ++ void __iomem *base = pcie->base; ++ struct device *dev = pcie->dev; ++ struct resource_entry *entry; ++ unsigned int scb_size_val; ++ bool ssc_good = false; ++ struct resource *res; ++ int num_out_wins = 0; ++ u16 nlw, cls, lnksta; ++ int i, ret; ++ u32 tmp; ++ ++ /* Reset the bridge */ ++ brcm_pcie_bridge_sw_init_set(pcie, 1); ++ ++ usleep_range(100, 200); ++ ++ /* Take the bridge out of reset */ ++ brcm_pcie_bridge_sw_init_set(pcie, 0); ++ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK; ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ /* Wait for SerDes to be stable */ ++ usleep_range(100, 200); ++ ++ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); ++ u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128, ++ PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_MISC_CTRL); ++ ++ ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, ++ &rc_bar2_offset); ++ if (ret) ++ return ret; ++ ++ tmp = lower_32_bits(rc_bar2_offset); ++ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size), ++ PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO); ++ writel(upper_32_bits(rc_bar2_offset), ++ base + PCIE_MISC_RC_BAR2_CONFIG_HI); ++ ++ scb_size_val = rc_bar2_size ? ++ ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */ ++ tmp = readl(base + PCIE_MISC_MISC_CTRL); ++ u32p_replace_bits(&tmp, scb_size_val, ++ PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_MISC_CTRL); ++ ++ /* disable the PCIe->GISB memory window (RC_BAR1) */ ++ tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); ++ tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; ++ writel(tmp, base + PCIE_MISC_RC_BAR1_CONFIG_LO); ++ ++ /* disable the PCIe->SCB memory window (RC_BAR3) */ ++ tmp = readl(base + PCIE_MISC_RC_BAR3_CONFIG_LO); ++ tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK; ++ writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO); ++ ++ /* Mask all interrupts since we are not handling any yet */ ++ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET); ++ ++ /* clear any interrupts we find on boot */ ++ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR); ++ ++ if (pcie->gen) ++ brcm_pcie_set_gen(pcie, pcie->gen); ++ ++ /* Unassert the fundamental reset */ ++ brcm_pcie_perst_set(pcie, 0); ++ ++ /* ++ * Give the RC/EP time to wake up, before trying to configure RC. ++ * Intermittently check status for link-up, up to a total of 100ms. ++ */ ++ for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5) ++ msleep(5); ++ ++ if (!brcm_pcie_link_up(pcie)) { ++ dev_err(dev, "link down\n"); ++ return -ENODEV; ++ } ++ ++ if (!brcm_pcie_rc_mode(pcie)) { ++ dev_err(dev, "PCIe misconfigured; is in EP mode\n"); ++ return -EINVAL; ++ } ++ ++ resource_list_for_each_entry(entry, &bridge->windows) { ++ res = entry->res; ++ ++ if (resource_type(res) != IORESOURCE_MEM) ++ continue; ++ ++ if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) { ++ dev_err(pcie->dev, "too many outbound wins\n"); ++ return -EINVAL; ++ } ++ ++ brcm_pcie_set_outbound_win(pcie, num_out_wins, res->start, ++ res->start - entry->offset, ++ resource_size(res)); ++ num_out_wins++; ++ } ++ ++ /* ++ * For config space accesses on the RC, show the right class for ++ * a PCIe-PCIe bridge (the default setting is to be EP mode). ++ */ ++ tmp = readl(base + PCIE_RC_CFG_PRIV1_ID_VAL3); ++ u32p_replace_bits(&tmp, 0x060400, ++ PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK); ++ writel(tmp, base + PCIE_RC_CFG_PRIV1_ID_VAL3); ++ ++ if (pcie->ssc) { ++ ret = brcm_pcie_set_ssc(pcie); ++ if (ret == 0) ++ ssc_good = true; ++ else ++ dev_err(dev, "failed attempt to enter ssc mode\n"); ++ } ++ ++ lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA); ++ cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta); ++ nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); ++ dev_info(dev, "link up, %s x%u %s\n", ++ PCIE_SPEED2STR(cls + PCI_SPEED_133MHz_PCIX_533), ++ nlw, ssc_good ? "(SSC)" : "(!SSC)"); ++ ++ /* PCIe->SCB endian mode for BAR */ ++ tmp = readl(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); ++ u32p_replace_bits(&tmp, PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN, ++ PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK); ++ writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); ++ ++ /* ++ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1 ++ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1. ++ */ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ return 0; ++} ++ ++/* L23 is a low-power PCIe link state */ ++static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ int l23, i; ++ u32 tmp; ++ ++ /* Assert request for L23 */ ++ tmp = readl(base + PCIE_MISC_PCIE_CTRL); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); ++ writel(tmp, base + PCIE_MISC_PCIE_CTRL); ++ ++ /* Wait up to 36 msec for L23 */ ++ tmp = readl(base + PCIE_MISC_PCIE_STATUS); ++ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, tmp); ++ for (i = 0; i < 15 && !l23; i++) { ++ usleep_range(2000, 2400); ++ tmp = readl(base + PCIE_MISC_PCIE_STATUS); ++ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, ++ tmp); ++ } ++ ++ if (!l23) ++ dev_err(pcie->dev, "failed to enter low-power link state\n"); ++} ++ ++static void brcm_pcie_turn_off(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ int tmp; ++ ++ if (brcm_pcie_link_up(pcie)) ++ brcm_pcie_enter_l23(pcie); ++ /* Assert fundamental reset */ ++ brcm_pcie_perst_set(pcie, 1); ++ ++ /* Deassert request for L23 in case it was asserted */ ++ tmp = readl(base + PCIE_MISC_PCIE_CTRL); ++ u32p_replace_bits(&tmp, 0, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); ++ writel(tmp, base + PCIE_MISC_PCIE_CTRL); ++ ++ /* Turn off SerDes */ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ /* Shutdown PCIe bridge */ ++ brcm_pcie_bridge_sw_init_set(pcie, 1); ++} ++ ++static void __brcm_pcie_remove(struct brcm_pcie *pcie) ++{ ++ brcm_pcie_turn_off(pcie); ++ clk_disable_unprepare(pcie->clk); ++ clk_put(pcie->clk); ++} ++ ++static int brcm_pcie_remove(struct platform_device *pdev) ++{ ++ struct brcm_pcie *pcie = platform_get_drvdata(pdev); ++ ++ pci_stop_root_bus(pcie->root_bus); ++ pci_remove_root_bus(pcie->root_bus); ++ __brcm_pcie_remove(pcie); ++ ++ return 0; ++} ++ ++static int brcm_pcie_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct pci_host_bridge *bridge; ++ struct brcm_pcie *pcie; ++ struct pci_bus *child; ++ struct resource *res; ++ int ret; ++ ++ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie)); ++ if (!bridge) ++ return -ENOMEM; ++ ++ pcie = pci_host_bridge_priv(bridge); ++ pcie->dev = &pdev->dev; ++ pcie->np = np; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pcie->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(pcie->base)) ++ return PTR_ERR(pcie->base); ++ ++ pcie->clk = devm_clk_get_optional(&pdev->dev, "sw_pcie"); ++ if (IS_ERR(pcie->clk)) ++ return PTR_ERR(pcie->clk); ++ ++ ret = of_pci_get_max_link_speed(np); ++ pcie->gen = (ret < 0) ? 0 : ret; ++ ++ pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc"); ++ ++ ret = pci_parse_request_of_pci_ranges(pcie->dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(pcie->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "could not enable clock\n"); ++ return ret; ++ } ++ ++ ret = brcm_pcie_setup(pcie); ++ if (ret) ++ goto fail; ++ ++ bridge->dev.parent = &pdev->dev; ++ bridge->busnr = 0; ++ bridge->ops = &brcm_pcie_ops; ++ bridge->sysdata = pcie; ++ bridge->map_irq = of_irq_parse_and_map_pci; ++ bridge->swizzle_irq = pci_common_swizzle; ++ ++ ret = pci_scan_root_bus_bridge(bridge); ++ if (ret < 0) { ++ dev_err(pcie->dev, "Scanning root bridge failed\n"); ++ goto fail; ++ } ++ ++ pci_assign_unassigned_bus_resources(bridge->bus); ++ list_for_each_entry(child, &bridge->bus->children, node) ++ pcie_bus_configure_settings(child); ++ pci_bus_add_devices(bridge->bus); ++ platform_set_drvdata(pdev, pcie); ++ pcie->root_bus = bridge->bus; ++ ++ return 0; ++fail: ++ __brcm_pcie_remove(pcie); ++ return ret; ++} ++ ++static const struct of_device_id brcm_pcie_match[] = { ++ { .compatible = "brcm,bcm2711-pcie" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, brcm_pcie_match); ++ ++static struct platform_driver brcm_pcie_driver = { ++ .probe = brcm_pcie_probe, ++ .remove = brcm_pcie_remove, ++ .driver = { ++ .name = "brcm-pcie", ++ .of_match_table = brcm_pcie_match, ++ }, ++}; ++module_platform_driver(brcm_pcie_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Broadcom STB PCIe RC driver"); ++MODULE_AUTHOR("Broadcom"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0447-PCI-of-Add-inbound-resource-parsing-to-helpers.patch b/target/linux/bcm27xx/patches-5.4/950-0447-PCI-of-Add-inbound-resource-parsing-to-helpers.patch deleted file mode 100644 index 493ea63825..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0447-PCI-of-Add-inbound-resource-parsing-to-helpers.patch +++ /dev/null @@ -1,427 +0,0 @@ -From 125a18144253e3a3f4bcad24484ee9b590dc47c6 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Wed, 30 Oct 2019 17:30:57 -0500 -Subject: [PATCH] PCI: of: Add inbound resource parsing to helpers - -Extend devm_of_pci_get_host_bridge_resources() and -pci_parse_request_of_pci_ranges() helpers to also parse the inbound -addresses from DT 'dma-ranges' and populate a resource list with the -translated addresses. This will help ensure 'dma-ranges' is always -parsed in a consistent way. - -Tested-by: Srinath Mannam -Tested-by: Thomas Petazzoni # for AArdvark -Signed-off-by: Rob Herring -Signed-off-by: Lorenzo Pieralisi -Reviewed-by: Srinath Mannam -Reviewed-by: Andrew Murray -Acked-by: Gustavo Pimentel -Cc: Jingoo Han -Cc: Gustavo Pimentel -Cc: Lorenzo Pieralisi -Cc: Bjorn Helgaas -Cc: Thomas Petazzoni -Cc: Will Deacon -Cc: Linus Walleij -Cc: Toan Le -Cc: Ley Foon Tan -Cc: Tom Joseph -Cc: Ray Jui -Cc: Scott Branden -Cc: bcm-kernel-feedback-list@broadcom.com -Cc: Ryder Lee -Cc: Karthikeyan Mitran -Cc: Hou Zhiqiang -Cc: Simon Horman -Cc: Shawn Lin -Cc: Heiko Stuebner -Cc: Michal Simek -Cc: rfi@lists.rocketboards.org -Cc: linux-mediatek@lists.infradead.org -Cc: linux-renesas-soc@vger.kernel.org -Cc: linux-rockchip@lists.infradead.org -(cherry picked from commit 331f63457165a30c708280de2c77f1742c6351dc) ---- - .../pci/controller/dwc/pcie-designware-host.c | 8 +-- - drivers/pci/controller/pci-aardvark.c | 3 +- - drivers/pci/controller/pci-ftpci100.c | 4 +- - drivers/pci/controller/pci-host-common.c | 2 +- - drivers/pci/controller/pci-v3-semi.c | 8 +-- - drivers/pci/controller/pci-versatile.c | 3 +- - drivers/pci/controller/pci-xgene.c | 4 +- - drivers/pci/controller/pcie-altera.c | 5 +- - drivers/pci/controller/pcie-cadence-host.c | 2 +- - drivers/pci/controller/pcie-iproc-platform.c | 4 +- - drivers/pci/controller/pcie-mediatek.c | 4 +- - drivers/pci/controller/pcie-mobiveil.c | 4 +- - drivers/pci/controller/pcie-rcar.c | 3 +- - drivers/pci/controller/pcie-rockchip-host.c | 4 +- - drivers/pci/controller/pcie-xilinx-nwl.c | 4 +- - drivers/pci/controller/pcie-xilinx.c | 4 +- - drivers/pci/of.c | 61 ++++++++++++++++--- - drivers/pci/pci.h | 8 ++- - include/linux/pci.h | 9 ++- - 19 files changed, 96 insertions(+), 48 deletions(-) - ---- a/drivers/pci/controller/dwc/pcie-designware-host.c -+++ b/drivers/pci/controller/dwc/pcie-designware-host.c -@@ -345,12 +345,8 @@ int dw_pcie_host_init(struct pcie_port * - if (!bridge) - return -ENOMEM; - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &bridge->windows, &pp->io_base); -- if (ret) -- return ret; -- -- ret = devm_request_pci_bus_resources(dev, &bridge->windows); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-aardvark.c -+++ b/drivers/pci/controller/pci-aardvark.c -@@ -1018,7 +1018,8 @@ static int advk_pcie_probe(struct platfo - return ret; - } - -- ret = advk_pcie_parse_request_of_pci_ranges(pcie); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, &bus); - if (ret) { - dev_err(dev, "Failed to parse resources\n"); - return ret; ---- a/drivers/pci/controller/pci-ftpci100.c -+++ b/drivers/pci/controller/pci-ftpci100.c -@@ -480,8 +480,8 @@ static int faraday_pci_probe(struct plat - if (IS_ERR(p->base)) - return PTR_ERR(p->base); - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &res, &io_base); -+ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, -+ &host->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-host-common.c -+++ b/drivers/pci/controller/pci-host-common.c -@@ -27,7 +27,7 @@ static struct pci_config_window *gen_pci - struct pci_config_window *cfg; - - /* Parse our PCI ranges and request their resources */ -- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); -+ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); - if (err) - return ERR_PTR(err); - ---- a/drivers/pci/controller/pci-v3-semi.c -+++ b/drivers/pci/controller/pci-v3-semi.c -@@ -793,12 +793,8 @@ static int v3_pci_probe(struct platform_ - if (IS_ERR(v3->config_base)) - return PTR_ERR(v3->config_base); - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &io_base); -- if (ret) -- return ret; -- -- ret = devm_request_pci_bus_resources(dev, &res); -+ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, -+ &host->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-versatile.c -+++ b/drivers/pci/controller/pci-versatile.c -@@ -141,7 +141,8 @@ static int versatile_pci_probe(struct pl - if (IS_ERR(versatile_cfg_base[1])) - return PTR_ERR(versatile_cfg_base[1]); - -- ret = versatile_pci_parse_request_of_pci_ranges(dev, &pci_res); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ NULL, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-xgene.c -+++ b/drivers/pci/controller/pci-xgene.c -@@ -634,8 +634,8 @@ static int xgene_pcie_probe(struct platf - if (ret) - return ret; - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &iobase); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pcie-altera.c -+++ b/drivers/pci/controller/pcie-altera.c -@@ -833,9 +833,8 @@ static int altera_pcie_probe(struct plat - return ret; - } - -- INIT_LIST_HEAD(&pcie->resources); -- -- ret = altera_pcie_parse_request_of_pci_ranges(pcie); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) { - dev_err(dev, "Failed add resources\n"); - return ret; ---- a/drivers/pci/controller/pcie-cadence-host.c -+++ b/drivers/pci/controller/pcie-cadence-host.c -@@ -216,7 +216,7 @@ static int cdns_pcie_host_init(struct de - int err; - - /* Parse our PCI ranges and request their resources */ -- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); -+ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); - if (err) - return err; - ---- a/drivers/pci/controller/pcie-iproc-platform.c -+++ b/drivers/pci/controller/pcie-iproc-platform.c -@@ -97,8 +97,8 @@ static int iproc_pcie_pltfm_probe(struct - if (IS_ERR(pcie->phy)) - return PTR_ERR(pcie->phy); - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources, -- &iobase); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) { - dev_err(dev, "unable to get PCI host bridge resources\n"); - return ret; ---- a/drivers/pci/controller/pcie-mediatek.c -+++ b/drivers/pci/controller/pcie-mediatek.c -@@ -1027,8 +1027,8 @@ static int mtk_pcie_setup(struct mtk_pci - resource_size_t io_base; - int err; - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- windows, &io_base); -+ err = pci_parse_request_of_pci_ranges(dev, windows, -+ &host->dma_ranges, &bus); - if (err) - return err; - ---- a/drivers/pci/controller/pcie-mobiveil.c -+++ b/drivers/pci/controller/pcie-mobiveil.c -@@ -883,8 +883,8 @@ static int mobiveil_pcie_probe(struct pl - INIT_LIST_HEAD(&pcie->resources); - - /* parse the host bridge base addresses from the device tree file */ -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &pcie->resources, &iobase); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) { - dev_err(dev, "Getting bridge resources failed\n"); - return ret; ---- a/drivers/pci/controller/pcie-rcar.c -+++ b/drivers/pci/controller/pcie-rcar.c -@@ -1144,7 +1144,8 @@ static int rcar_pcie_probe(struct platfo - pcie->dev = dev; - platform_set_drvdata(pdev, pcie); - -- err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL); -+ err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, -+ &bridge->dma_ranges, NULL); - if (err) - goto err_free_bridge; - ---- a/drivers/pci/controller/pcie-rockchip-host.c -+++ b/drivers/pci/controller/pcie-rockchip-host.c -@@ -995,8 +995,8 @@ static int rockchip_pcie_probe(struct pl - if (err < 0) - goto err_deinit_port; - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &res, &io_base); -+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, &bus_res); - if (err) - goto err_remove_irq_domain; - ---- a/drivers/pci/controller/pcie-xilinx-nwl.c -+++ b/drivers/pci/controller/pcie-xilinx-nwl.c -@@ -845,8 +845,8 @@ static int nwl_pcie_probe(struct platfor - return err; - } - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &iobase); -+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (err) { - dev_err(dev, "Getting bridge resources failed\n"); - return err; ---- a/drivers/pci/controller/pcie-xilinx.c -+++ b/drivers/pci/controller/pcie-xilinx.c -@@ -647,8 +647,8 @@ static int xilinx_pcie_probe(struct plat - return err; - } - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &iobase); -+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (err) { - dev_err(dev, "Getting bridge resources failed\n"); - return err; ---- a/drivers/pci/of.c -+++ b/drivers/pci/of.c -@@ -257,14 +257,16 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_onl - */ - int devm_of_pci_get_host_bridge_resources(struct device *dev, - unsigned char busno, unsigned char bus_max, -- struct list_head *resources, resource_size_t *io_base) -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ resource_size_t *io_base) - { - struct device_node *dev_node = dev->of_node; - struct resource *res, tmp_res; - struct resource *bus_range; - struct of_pci_range range; - struct of_pci_range_parser parser; -- char range_type[4]; -+ const char *range_type; - int err; - - if (io_base) -@@ -298,12 +300,12 @@ int devm_of_pci_get_host_bridge_resource - for_each_of_pci_range(&parser, &range) { - /* Read next ranges element */ - if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) -- snprintf(range_type, 4, " IO"); -+ range_type = "IO"; - else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) -- snprintf(range_type, 4, "MEM"); -+ range_type = "MEM"; - else -- snprintf(range_type, 4, "err"); -- dev_info(dev, " %s %#010llx..%#010llx -> %#010llx\n", -+ range_type = "err"; -+ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", - range_type, range.cpu_addr, - range.cpu_addr + range.size - 1, range.pci_addr); - -@@ -340,6 +342,48 @@ int devm_of_pci_get_host_bridge_resource - pci_add_resource_offset(resources, res, res->start - range.pci_addr); - } - -+ /* Check for dma-ranges property */ -+ if (!ib_resources) -+ return 0; -+ err = of_pci_dma_range_parser_init(&parser, dev_node); -+ if (err) -+ return 0; -+ -+ dev_dbg(dev, "Parsing dma-ranges property...\n"); -+ for_each_of_pci_range(&parser, &range) { -+ struct resource_entry *entry; -+ /* -+ * If we failed translation or got a zero-sized region -+ * then skip this range -+ */ -+ if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) || -+ range.cpu_addr == OF_BAD_ADDR || range.size == 0) -+ continue; -+ -+ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", -+ "IB MEM", range.cpu_addr, -+ range.cpu_addr + range.size - 1, range.pci_addr); -+ -+ -+ err = of_pci_range_to_resource(&range, dev_node, &tmp_res); -+ if (err) -+ continue; -+ -+ res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); -+ if (!res) { -+ err = -ENOMEM; -+ goto failed; -+ } -+ -+ /* Keep the resource list sorted */ -+ resource_list_for_each_entry(entry, ib_resources) -+ if (entry->res->start > res->start) -+ break; -+ -+ pci_add_resource_offset(&entry->node, res, -+ res->start - range.pci_addr); -+ } -+ - return 0; - - failed: -@@ -482,6 +526,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_p - - int pci_parse_request_of_pci_ranges(struct device *dev, - struct list_head *resources, -+ struct list_head *ib_resources, - struct resource **bus_range) - { - int err, res_valid = 0; -@@ -489,8 +534,10 @@ int pci_parse_request_of_pci_ranges(stru - struct resource_entry *win, *tmp; - - INIT_LIST_HEAD(resources); -+ if (ib_resources) -+ INIT_LIST_HEAD(ib_resources); - err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources, -- &iobase); -+ ib_resources, &iobase); - if (err) - return err; - ---- a/drivers/pci/pci.h -+++ b/drivers/pci/pci.h -@@ -637,11 +637,15 @@ static inline void pci_release_bus_of_no - #if defined(CONFIG_OF_ADDRESS) - int devm_of_pci_get_host_bridge_resources(struct device *dev, - unsigned char busno, unsigned char bus_max, -- struct list_head *resources, resource_size_t *io_base); -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ resource_size_t *io_base); - #else - static inline int devm_of_pci_get_host_bridge_resources(struct device *dev, - unsigned char busno, unsigned char bus_max, -- struct list_head *resources, resource_size_t *io_base) -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ resource_size_t *io_base) - { - return -EINVAL; - } ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -2278,6 +2278,7 @@ struct irq_domain; - struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); - int pci_parse_request_of_pci_ranges(struct device *dev, - struct list_head *resources, -+ struct list_head *ib_resources, - struct resource **bus_range); - - /* Arch may override this (weak) */ -@@ -2286,9 +2287,11 @@ struct device_node *pcibios_get_phb_of_n - #else /* CONFIG_OF */ - static inline struct irq_domain * - pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } --static inline int pci_parse_request_of_pci_ranges(struct device *dev, -- struct list_head *resources, -- struct resource **bus_range) -+static inline int -+pci_parse_request_of_pci_ranges(struct device *dev, -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ struct resource **bus_range) - { - return -EINVAL; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0448-PCI-brcmstb-Add-MSI-support.patch b/target/linux/bcm27xx/patches-5.4/950-0448-PCI-brcmstb-Add-MSI-support.patch new file mode 100644 index 0000000000..a27259bd19 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0448-PCI-brcmstb-Add-MSI-support.patch @@ -0,0 +1,383 @@ +From 1a90ecdfae1c0cf1b242276f6f0e3d98b5877f14 Mon Sep 17 00:00:00 2001 +From: Jim Quinlan +Date: Mon, 16 Dec 2019 12:01:10 +0100 +Subject: [PATCH] PCI: brcmstb: Add MSI support + +commit 40ca1bf580ef24df30702032ba5e40dfdcaa200b upstream. + +This adds MSI support to the Broadcom STB PCIe host controller. The MSI +controller is physically located within the PCIe block, however, there +is no reason why the MSI controller could not be moved elsewhere in the +future. MSIX is not supported by the HW. + +Since the internal Brcmstb MSI controller is intertwined with the PCIe +controller, it is not its own platform device but rather part of the +PCIe platform device. + +Signed-off-by: Jim Quinlan +Co-developed-by: Nicolas Saenz Julienne +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Marc Zyngier +Reviewed-by: Andrew Murray +--- + drivers/pci/controller/Kconfig | 1 + + drivers/pci/controller/pcie-brcmstb.c | 262 +++++++++++++++++++++++++- + 2 files changed, 262 insertions(+), 1 deletion(-) + +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -285,6 +285,7 @@ config PCIE_BRCMSTB + tristate "Broadcom Brcmstb PCIe host controller" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on OF ++ depends on PCI_MSI_IRQ_DOMAIN + help + Say Y here to enable PCIe host controller support for + Broadcom STB based SoCs, like the Raspberry Pi 4. +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -2,6 +2,7 @@ + /* Copyright (C) 2009 - 2019 Broadcom */ + + #include ++#include + #include + #include + #include +@@ -9,11 +10,13 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -67,6 +70,12 @@ + #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c + #define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f + ++#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 ++#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 ++ ++#define PCIE_MISC_MSI_DATA_CONFIG 0x404c ++#define PCIE_MISC_MSI_DATA_CONFIG_VAL 0xffe06540 ++ + #define PCIE_MISC_PCIE_CTRL 0x4064 + #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 + +@@ -114,6 +123,11 @@ + + /* PCIe parameters */ + #define BRCM_NUM_PCIE_OUT_WINS 0x4 ++#define BRCM_INT_PCI_MSI_NR 32 ++ ++/* MSI target adresses */ ++#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL ++#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL + + /* MDIO registers */ + #define MDIO_PORT0 0x0 +@@ -135,6 +149,19 @@ + #define SSC_STATUS_SSC_MASK 0x400 + #define SSC_STATUS_PLL_LOCK_MASK 0x800 + ++struct brcm_msi { ++ struct device *dev; ++ void __iomem *base; ++ struct device_node *np; ++ struct irq_domain *msi_domain; ++ struct irq_domain *inner_domain; ++ struct mutex lock; /* guards the alloc/free operations */ ++ u64 target_addr; ++ int irq; ++ /* used indicates which MSI interrupts have been alloc'd */ ++ unsigned long used; ++}; ++ + /* Internal PCIe Host Controller Information.*/ + struct brcm_pcie { + struct device *dev; +@@ -144,6 +171,8 @@ struct brcm_pcie { + struct device_node *np; + bool ssc; + int gen; ++ u64 msi_target_addr; ++ struct brcm_msi *msi; + }; + + /* +@@ -309,6 +338,215 @@ static void brcm_pcie_set_outbound_win(s + writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); + } + ++static struct irq_chip brcm_msi_irq_chip = { ++ .name = "BRCM STB 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 brcm_msi_domain_info = { ++ /* Multi MSI is supported by the controller, but not by this driver */ ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), ++ .chip = &brcm_msi_irq_chip, ++}; ++ ++static void brcm_pcie_msi_isr(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ unsigned long status, virq; ++ struct brcm_msi *msi; ++ struct device *dev; ++ u32 bit; ++ ++ chained_irq_enter(chip, desc); ++ msi = irq_desc_get_handler_data(desc); ++ dev = msi->dev; ++ ++ status = readl(msi->base + PCIE_MSI_INTR2_STATUS); ++ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) { ++ virq = irq_find_mapping(msi->inner_domain, bit); ++ if (virq) ++ generic_handle_irq(virq); ++ else ++ dev_dbg(dev, "unexpected MSI\n"); ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) ++{ ++ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); ++ ++ msg->address_lo = lower_32_bits(msi->target_addr); ++ msg->address_hi = upper_32_bits(msi->target_addr); ++ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq; ++} ++ ++static int brcm_msi_set_affinity(struct irq_data *irq_data, ++ const struct cpumask *mask, bool force) ++{ ++ return -EINVAL; ++} ++ ++static void brcm_msi_ack_irq(struct irq_data *data) ++{ ++ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); ++ ++ writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR); ++} ++ ++ ++static struct irq_chip brcm_msi_bottom_irq_chip = { ++ .name = "BRCM STB MSI", ++ .irq_compose_msi_msg = brcm_msi_compose_msi_msg, ++ .irq_set_affinity = brcm_msi_set_affinity, ++ .irq_ack = brcm_msi_ack_irq, ++}; ++ ++static int brcm_msi_alloc(struct brcm_msi *msi) ++{ ++ int hwirq; ++ ++ mutex_lock(&msi->lock); ++ hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0); ++ mutex_unlock(&msi->lock); ++ ++ return hwirq; ++} ++ ++static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq) ++{ ++ mutex_lock(&msi->lock); ++ bitmap_release_region(&msi->used, hwirq, 0); ++ mutex_unlock(&msi->lock); ++} ++ ++static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs, void *args) ++{ ++ struct brcm_msi *msi = domain->host_data; ++ int hwirq; ++ ++ hwirq = brcm_msi_alloc(msi); ++ ++ if (hwirq < 0) ++ return hwirq; ++ ++ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq, ++ &brcm_msi_bottom_irq_chip, domain->host_data, ++ handle_edge_irq, NULL, NULL); ++ return 0; ++} ++ ++static void brcm_irq_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 brcm_msi *msi = irq_data_get_irq_chip_data(d); ++ ++ brcm_msi_free(msi, d->hwirq); ++} ++ ++static const struct irq_domain_ops msi_domain_ops = { ++ .alloc = brcm_irq_domain_alloc, ++ .free = brcm_irq_domain_free, ++}; ++ ++static int brcm_allocate_domains(struct brcm_msi *msi) ++{ ++ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np); ++ struct device *dev = msi->dev; ++ ++ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR, ++ &msi_domain_ops, msi); ++ if (!msi->inner_domain) { ++ dev_err(dev, "failed to create IRQ domain\n"); ++ return -ENOMEM; ++ } ++ ++ msi->msi_domain = pci_msi_create_irq_domain(fwnode, ++ &brcm_msi_domain_info, ++ msi->inner_domain); ++ if (!msi->msi_domain) { ++ dev_err(dev, "failed to create MSI domain\n"); ++ irq_domain_remove(msi->inner_domain); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void brcm_free_domains(struct brcm_msi *msi) ++{ ++ irq_domain_remove(msi->msi_domain); ++ irq_domain_remove(msi->inner_domain); ++} ++ ++static void brcm_msi_remove(struct brcm_pcie *pcie) ++{ ++ struct brcm_msi *msi = pcie->msi; ++ ++ if (!msi) ++ return; ++ irq_set_chained_handler(msi->irq, NULL); ++ irq_set_handler_data(msi->irq, NULL); ++ brcm_free_domains(msi); ++} ++ ++static void brcm_msi_set_regs(struct brcm_msi *msi) ++{ ++ writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR); ++ ++ /* ++ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI ++ * enable, which we set to 1. ++ */ ++ writel(lower_32_bits(msi->target_addr) | 0x1, ++ msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO); ++ writel(upper_32_bits(msi->target_addr), ++ msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI); ++ ++ writel(PCIE_MISC_MSI_DATA_CONFIG_VAL, ++ msi->base + PCIE_MISC_MSI_DATA_CONFIG); ++} ++ ++static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) ++{ ++ struct brcm_msi *msi; ++ int irq, ret; ++ struct device *dev = pcie->dev; ++ ++ irq = irq_of_parse_and_map(dev->of_node, 1); ++ if (irq <= 0) { ++ dev_err(dev, "cannot map MSI interrupt\n"); ++ return -ENODEV; ++ } ++ ++ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL); ++ if (!msi) ++ return -ENOMEM; ++ ++ mutex_init(&msi->lock); ++ msi->dev = dev; ++ msi->base = pcie->base; ++ msi->np = pcie->np; ++ msi->target_addr = pcie->msi_target_addr; ++ msi->irq = irq; ++ ++ ret = brcm_allocate_domains(msi); ++ if (ret) ++ return ret; ++ ++ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi); ++ ++ brcm_msi_set_regs(msi); ++ pcie->msi = msi; ++ ++ return 0; ++} ++ + /* The controller is capable of serving in both RC and EP roles */ + static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) + { +@@ -497,6 +735,18 @@ static int brcm_pcie_setup(struct brcm_p + PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); + writel(tmp, base + PCIE_MISC_MISC_CTRL); + ++ /* ++ * We ideally want the MSI target address to be located in the 32bit ++ * addressable memory area. Some devices might depend on it. This is ++ * possible either when the inbound window is located above the lower ++ * 4GB or when the inbound area is smaller than 4GB (taking into ++ * account the rounding-up we're forced to perform). ++ */ ++ if (rc_bar2_offset >= SZ_4G || (rc_bar2_size + rc_bar2_offset) < SZ_4G) ++ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB; ++ else ++ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; ++ + /* disable the PCIe->GISB memory window (RC_BAR1) */ + tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); + tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; +@@ -646,6 +896,7 @@ static void brcm_pcie_turn_off(struct br + + static void __brcm_pcie_remove(struct brcm_pcie *pcie) + { ++ brcm_msi_remove(pcie); + brcm_pcie_turn_off(pcie); + clk_disable_unprepare(pcie->clk); + clk_put(pcie->clk); +@@ -664,7 +915,7 @@ static int brcm_pcie_remove(struct platf + + static int brcm_pcie_probe(struct platform_device *pdev) + { +- struct device_node *np = pdev->dev.of_node; ++ struct device_node *np = pdev->dev.of_node, *msi_np; + struct pci_host_bridge *bridge; + struct brcm_pcie *pcie; + struct pci_bus *child; +@@ -708,6 +959,15 @@ static int brcm_pcie_probe(struct platfo + if (ret) + goto fail; + ++ msi_np = of_parse_phandle(pcie->np, "msi-parent", 0); ++ if (pci_msi_enabled() && msi_np == pcie->np) { ++ ret = brcm_pcie_enable_msi(pcie); ++ if (ret) { ++ dev_err(pcie->dev, "probe of internal MSI failed"); ++ goto fail; ++ } ++ } ++ + bridge->dev.parent = &pdev->dev; + bridge->busnr = 0; + bridge->ops = &brcm_pcie_ops; diff --git a/target/linux/bcm27xx/patches-5.4/950-0448-dma-direct-unify-the-dma_capable-definitions.patch b/target/linux/bcm27xx/patches-5.4/950-0448-dma-direct-unify-the-dma_capable-definitions.patch deleted file mode 100644 index d115f0eb80..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0448-dma-direct-unify-the-dma_capable-definitions.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 203e0c39b262fc1da6f976495c32ec38ea93a137 Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -Date: Tue, 12 Nov 2019 17:06:04 +0100 -Subject: [PATCH] dma-direct: unify the dma_capable definitions - -commit 130c1ccbf55330b55e82612a6e54eebb82c9d746 upstream. - -Currently each architectures that wants to override dma_to_phys and -phys_to_dma also has to provide dma_capable. But there isn't really -any good reason for that. powerpc and mips just have copies of the -generic one minus the latests fix, and the arm one was the inspiration -for said fix, but misses the bus_dma_mask handling. -Make all architectures use the generic version instead. - -Signed-off-by: Christoph Hellwig -Acked-by: Michael Ellerman (powerpc) -Reviewed-by: Nicolas Saenz Julienne ---- - arch/arm/include/asm/dma-direct.h | 19 ------------------- - arch/mips/include/asm/dma-direct.h | 8 -------- - arch/powerpc/include/asm/dma-direct.h | 9 --------- - include/linux/dma-direct.h | 2 +- - 4 files changed, 1 insertion(+), 37 deletions(-) - ---- a/arch/arm/include/asm/dma-direct.h -+++ b/arch/arm/include/asm/dma-direct.h -@@ -14,23 +14,4 @@ static inline phys_addr_t __dma_to_phys( - return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset; - } - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- u64 limit, mask; -- -- if (!dev->dma_mask) -- return 0; -- -- mask = *dev->dma_mask; -- -- limit = (mask + 1) & ~mask; -- if (limit && size > limit) -- return 0; -- -- if ((addr | (addr + size - 1)) & ~mask) -- return 0; -- -- return 1; --} -- - #endif /* ASM_ARM_DMA_DIRECT_H */ ---- a/arch/mips/include/asm/dma-direct.h -+++ b/arch/mips/include/asm/dma-direct.h -@@ -2,14 +2,6 @@ - #ifndef _MIPS_DMA_DIRECT_H - #define _MIPS_DMA_DIRECT_H 1 - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- if (!dev->dma_mask) -- return false; -- -- return addr + size - 1 <= *dev->dma_mask; --} -- - dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); - phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); - ---- a/arch/powerpc/include/asm/dma-direct.h -+++ b/arch/powerpc/include/asm/dma-direct.h -@@ -2,15 +2,6 @@ - #ifndef ASM_POWERPC_DMA_DIRECT_H - #define ASM_POWERPC_DMA_DIRECT_H 1 - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- if (!dev->dma_mask) -- return false; -- -- return addr + size - 1 <= -- min_not_zero(*dev->dma_mask, dev->bus_dma_mask); --} -- - static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) - { - if (!dev) ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -26,6 +26,7 @@ static inline phys_addr_t __dma_to_phys( - - return paddr + ((phys_addr_t)dev->dma_pfn_offset << PAGE_SHIFT); - } -+#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ - - static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) - { -@@ -40,7 +41,6 @@ static inline bool dma_capable(struct de - - return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); - } --#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ - - #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED - bool force_dma_unencrypted(struct device *dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0449-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch b/target/linux/bcm27xx/patches-5.4/950-0449-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch new file mode 100644 index 0000000000..6bb45ccb1f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0449-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch @@ -0,0 +1,38 @@ +From 39192141aa16809323c24d8910e3a63488f7f55d Mon Sep 17 00:00:00 2001 +From: Marek Szyprowski +Date: Thu, 27 Feb 2020 12:51:46 +0100 +Subject: [PATCH] PCI: brcmstb: Fix build on 32bit ARM platforms with + older compilers + +commit 73a7a271b3eee7b83f29b13866163776f1cbef89 upstream. + +Some older compilers have no implementation for the helper for 64-bit +unsigned division/modulo, so linking pcie-brcmstb driver causes the +"undefined reference to `__aeabi_uldivmod'" error. + +*rc_bar2_size is always a power of two, because it is calculated as: +"1ULL << fls64(entry->res->end - entry->res->start)", so the modulo +operation in the subsequent check can be replaced by a simple logical +AND with a proper mask. + +Link: https://lore.kernel.org/r/20200227115146.24515-1-m.szyprowski@samsung.com +Fixes: c0452137034b ("PCI: brcmstb: Add Broadcom STB PCIe host controller driver") +Signed-off-by: Marek Szyprowski +Signed-off-by: Bjorn Helgaas +Acked-by: Nicolas Saenz Julienne +Acked-by: Lorenzo Pieralisi +--- + drivers/pci/controller/pcie-brcmstb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -670,7 +670,7 @@ static inline int brcm_pcie_get_rc_bar2_ + * outbound memory @ 3GB). So instead it will start at the 1x + * multiple of its size + */ +- if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size || ++ if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) || + (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) { + dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n", + *rc_bar2_size, *rc_bar2_offset); diff --git a/target/linux/bcm27xx/patches-5.4/950-0449-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch b/target/linux/bcm27xx/patches-5.4/950-0449-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch deleted file mode 100644 index a98f1d3852..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0449-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch +++ /dev/null @@ -1,69 +0,0 @@ -From a3794022e928547de664abd03b61280163c7f13a Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -Date: Tue, 12 Nov 2019 17:07:43 +0100 -Subject: [PATCH] dma-direct: avoid a forward declaration for - phys_to_dma - -Move dma_capable down a bit so that we don't need a forward declaration -for phys_to_dma. - -Signed-off-by: Christoph Hellwig -Reviewed-by: Nicolas Saenz Julienne -(cherry picked from commit c7345159f7db6fb69ec1c3b3f8f28cd05c731be2) ---- - include/linux/dma-direct.h | 30 ++++++++++++++---------------- - 1 file changed, 14 insertions(+), 16 deletions(-) - ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -6,8 +6,6 @@ - #include /* for min_low_pfn */ - #include - --static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); -- - extern unsigned int zone_dma_bits; - - #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA -@@ -28,20 +26,6 @@ static inline phys_addr_t __dma_to_phys( - } - #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- dma_addr_t end = addr + size - 1; -- -- if (!dev->dma_mask) -- return false; -- -- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && -- min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) -- return false; -- -- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); --} -- - #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED - bool force_dma_unencrypted(struct device *dev); - #else -@@ -67,6 +51,20 @@ static inline phys_addr_t dma_to_phys(st - return __sme_clr(__dma_to_phys(dev, daddr)); - } - -+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) -+{ -+ dma_addr_t end = addr + size - 1; -+ -+ if (!dev->dma_mask) -+ return false; -+ -+ if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && -+ min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) -+ return false; -+ -+ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); -+} -+ - u64 dma_direct_get_required_mask(struct device *dev); - void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t gfp, unsigned long attrs); diff --git a/target/linux/bcm27xx/patches-5.4/950-0450-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch b/target/linux/bcm27xx/patches-5.4/950-0450-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch new file mode 100644 index 0000000000..729d6e68ba --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0450-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch @@ -0,0 +1,75 @@ +From 5e9b9f246802f492e7740ab2589aa8c81df5ef20 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 2 Mar 2020 15:05:25 +0000 +Subject: [PATCH] bcm2711-rpi.dtsi: Use upstream pcie node + +Now that the upstream bcm2711 DT has a pcie DT node there's no need to +define one downstream. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 41 --------------------------- + 2 files changed, 1 insertion(+), 42 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -163,7 +163,7 @@ + i2c6 = &i2c6; + /delete-property/ ethernet; + /delete-property/ intc; +- pcie0 = &pcie_0; ++ pcie0 = &pcie0; + }; + + /delete-node/ wifi-pwrseq; +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -66,47 +66,6 @@ + <0x0 0x00000000 0x0 0x00000000 0xfc000000>; + dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; + +- pcie_0: pcie@7d500000 { +- reg = <0x0 0x7d500000 0x9310>, +- <0x0 0x7e00f300 0x20>; +- msi-controller; +- msi-parent = <&pcie_0>; +- #address-cells = <3>; +- #interrupt-cells = <1>; +- #size-cells = <2>; +- bus-range = <0x0 0x01>; +- compatible = "brcm,bcm2711b0-pcie", // Safe value +- "brcm,bcm2711-pcie", +- "brcm,pci-plat-dev"; +- max-link-speed = <2>; +- tot-num-pcie = <1>; +- linux,pci-domain = <0>; +- interrupts = , +- ; +- interrupt-names = "pcie", "msi"; +- interrupt-map-mask = <0x0 0x0 0x0 0x7>; +- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 2 &gicv2 GIC_SPI 144 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 3 &gicv2 GIC_SPI 145 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 4 &gicv2 GIC_SPI 146 +- IRQ_TYPE_LEVEL_HIGH>; +- +- /* Map outbound accesses from scb:0x6_00000000-03ffffff +- * to pci:0x0_f8000000-fbffffff +- */ +- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 +- 0x0 0x04000000>; +- /* Map inbound accesses from pci:0x0_00000000..ffffffff +- * to scb:0x0_00000000-ffffffff +- */ +- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 +- 0x1 0x00000000>; +- status = "okay"; +- }; +- + dma40: dma@7e007b00 { + compatible = "brcm,bcm2711-dma"; + reg = <0x0 0x7e007b00 0x400>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-exclude-dma_direct_map_resource-from-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-exclude-dma_direct_map_resource-from-the-.patch deleted file mode 100644 index 2534b71b73..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-exclude-dma_direct_map_resource-from-the-.patch +++ /dev/null @@ -1,115 +0,0 @@ -From b763f24aed409296eb76d085c279b2c40462f8a1 Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -Date: Tue, 19 Nov 2019 17:38:58 +0100 -Subject: [PATCH] dma-direct: exclude dma_direct_map_resource from the - min_low_pfn check - -commit 68a33b1794665ba8a1d1ef1d3bfcc7c587d380a6 upstream. - -The valid memory address check in dma_capable only makes sense when mapping -normal memory, not when using dma_map_resource to map a device resource. -Add a new boolean argument to dma_capable to exclude that check for the -dma_map_resource case. - -Fixes: b12d66278dd6 ("dma-direct: check for overflows on 32 bit DMA addresses") -Reported-by: Marek Szyprowski -Signed-off-by: Christoph Hellwig -Acked-by: Marek Szyprowski -Tested-by: Marek Szyprowski ---- - arch/x86/kernel/amd_gart_64.c | 4 ++-- - drivers/xen/swiotlb-xen.c | 4 ++-- - include/linux/dma-direct.h | 5 +++-- - kernel/dma/direct.c | 4 ++-- - kernel/dma/swiotlb.c | 2 +- - 5 files changed, 10 insertions(+), 9 deletions(-) - ---- a/arch/x86/kernel/amd_gart_64.c -+++ b/arch/x86/kernel/amd_gart_64.c -@@ -185,13 +185,13 @@ static void iommu_full(struct device *de - static inline int - need_iommu(struct device *dev, unsigned long addr, size_t size) - { -- return force_iommu || !dma_capable(dev, addr, size); -+ return force_iommu || !dma_capable(dev, addr, size, true); - } - - static inline int - nonforced_iommu(struct device *dev, unsigned long addr, size_t size) - { -- return !dma_capable(dev, addr, size); -+ return !dma_capable(dev, addr, size, true); - } - - /* Map a single continuous physical area into the IOMMU. ---- a/drivers/xen/swiotlb-xen.c -+++ b/drivers/xen/swiotlb-xen.c -@@ -381,7 +381,7 @@ static dma_addr_t xen_swiotlb_map_page(s - * we can safely return the device addr and not worry about bounce - * buffering it. - */ -- if (dma_capable(dev, dev_addr, size) && -+ if (dma_capable(dev, dev_addr, size, true) && - !range_straddles_page_boundary(phys, size) && - !xen_arch_need_swiotlb(dev, phys, dev_addr) && - swiotlb_force != SWIOTLB_FORCE) -@@ -403,7 +403,7 @@ static dma_addr_t xen_swiotlb_map_page(s - /* - * Ensure that the address returned is DMA'ble - */ -- if (unlikely(!dma_capable(dev, dev_addr, size))) { -+ if (unlikely(!dma_capable(dev, dev_addr, size, true))) { - swiotlb_tbl_unmap_single(dev, map, size, size, dir, - attrs | DMA_ATTR_SKIP_CPU_SYNC); - return DMA_MAPPING_ERROR; ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -51,14 +51,15 @@ static inline phys_addr_t dma_to_phys(st - return __sme_clr(__dma_to_phys(dev, daddr)); - } - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) -+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size, -+ bool is_ram) - { - dma_addr_t end = addr + size - 1; - - if (!dev->dma_mask) - return false; - -- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && -+ if (is_ram && !IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && - min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) - return false; - ---- a/kernel/dma/direct.c -+++ b/kernel/dma/direct.c -@@ -326,7 +326,7 @@ static inline bool dma_direct_possible(s - size_t size) - { - return swiotlb_force != SWIOTLB_FORCE && -- dma_capable(dev, dma_addr, size); -+ dma_capable(dev, dma_addr, size, true); - } - - dma_addr_t dma_direct_map_page(struct device *dev, struct page *page, -@@ -375,7 +375,7 @@ dma_addr_t dma_direct_map_resource(struc - { - dma_addr_t dma_addr = paddr; - -- if (unlikely(!dma_capable(dev, dma_addr, size))) { -+ if (unlikely(!dma_capable(dev, dma_addr, size, false))) { - report_addr(dev, dma_addr, size); - return DMA_MAPPING_ERROR; - } ---- a/kernel/dma/swiotlb.c -+++ b/kernel/dma/swiotlb.c -@@ -682,7 +682,7 @@ bool swiotlb_map(struct device *dev, phy - - /* Ensure that the address returned is DMA'ble */ - *dma_addr = __phys_to_dma(dev, *phys); -- if (unlikely(!dma_capable(dev, *dma_addr, size))) { -+ if (unlikely(!dma_capable(dev, *dma_addr, size, true))) { - swiotlb_tbl_unmap_single(dev, *phys, size, size, dir, - attrs | DMA_ATTR_SKIP_CPU_SYNC); - return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0451-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch b/target/linux/bcm27xx/patches-5.4/950-0451-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch deleted file mode 100644 index d968e93153..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0451-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch +++ /dev/null @@ -1,366 +0,0 @@ -From d5430c466b3c3b5f631ee37be333a40924575b72 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Thu, 21 Nov 2019 10:26:44 +0100 -Subject: [PATCH] dma-mapping: treat dev->bus_dma_mask as a DMA limit - -commit a7ba70f1787f977f970cd116076c6fce4b9e01cc upstream. - -Using a mask to represent bus DMA constraints has a set of limitations. -The biggest one being it can only hold a power of two (minus one). The -DMA mapping code is already aware of this and treats dev->bus_dma_mask -as a limit. This quirk is already used by some architectures although -still rare. - -With the introduction of the Raspberry Pi 4 we've found a new contender -for the use of bus DMA limits, as its PCIe bus can only address the -lower 3GB of memory (of a total of 4GB). This is impossible to represent -with a mask. To make things worse the device-tree code rounds non power -of two bus DMA limits to the next power of two, which is unacceptable in -this case. - -In the light of this, rename dev->bus_dma_mask to dev->bus_dma_limit all -over the tree and treat it as such. Note that dev->bus_dma_limit should -contain the higher accessible DMA address. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Robin Murphy -Signed-off-by: Christoph Hellwig ---- - arch/mips/pci/fixup-sb1250.c | 16 ++++++++-------- - arch/powerpc/sysdev/fsl_pci.c | 6 +++--- - arch/x86/kernel/pci-dma.c | 2 +- - arch/x86/mm/mem_encrypt.c | 2 +- - arch/x86/pci/sta2x11-fixup.c | 2 +- - drivers/acpi/arm64/iort.c | 20 +++++++------------- - drivers/ata/ahci.c | 2 +- - drivers/iommu/dma-iommu.c | 3 +-- - drivers/of/device.c | 9 +++++---- - include/linux/device.h | 6 +++--- - include/linux/dma-direct.h | 2 +- - include/linux/dma-mapping.h | 2 +- - kernel/dma/direct.c | 27 +++++++++++++-------------- - 13 files changed, 46 insertions(+), 53 deletions(-) - ---- a/arch/mips/pci/fixup-sb1250.c -+++ b/arch/mips/pci/fixup-sb1250.c -@@ -21,22 +21,22 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SI - - /* - * The BCM1250, etc. PCI host bridge does not support DAC on its 32-bit -- * bus, so we set the bus's DMA mask accordingly. However the HT link -+ * bus, so we set the bus's DMA limit accordingly. However the HT link - * down the artificial PCI-HT bridge supports 40-bit addressing and the - * SP1011 HT-PCI bridge downstream supports both DAC and a 64-bit bus - * width, so we record the PCI-HT bridge's secondary and subordinate bus -- * numbers and do not set the mask for devices present in the inclusive -+ * numbers and do not set the limit for devices present in the inclusive - * range of those. - */ --struct sb1250_bus_dma_mask_exclude { -+struct sb1250_bus_dma_limit_exclude { - bool set; - unsigned char start; - unsigned char end; - }; - --static int sb1250_bus_dma_mask(struct pci_dev *dev, void *data) -+static int sb1250_bus_dma_limit(struct pci_dev *dev, void *data) - { -- struct sb1250_bus_dma_mask_exclude *exclude = data; -+ struct sb1250_bus_dma_limit_exclude *exclude = data; - bool exclude_this; - bool ht_bridge; - -@@ -55,7 +55,7 @@ static int sb1250_bus_dma_mask(struct pc - exclude->start, exclude->end); - } else { - dev_dbg(&dev->dev, "disabling DAC for device"); -- dev->dev.bus_dma_mask = DMA_BIT_MASK(32); -+ dev->dev.bus_dma_limit = DMA_BIT_MASK(32); - } - - return 0; -@@ -63,9 +63,9 @@ static int sb1250_bus_dma_mask(struct pc - - static void quirk_sb1250_pci_dac(struct pci_dev *dev) - { -- struct sb1250_bus_dma_mask_exclude exclude = { .set = false }; -+ struct sb1250_bus_dma_limit_exclude exclude = { .set = false }; - -- pci_walk_bus(dev->bus, sb1250_bus_dma_mask, &exclude); -+ pci_walk_bus(dev->bus, sb1250_bus_dma_limit, &exclude); - } - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI, - quirk_sb1250_pci_dac); ---- a/arch/powerpc/sysdev/fsl_pci.c -+++ b/arch/powerpc/sysdev/fsl_pci.c -@@ -115,8 +115,8 @@ static void pci_dma_dev_setup_swiotlb(st - { - struct pci_controller *hose = pci_bus_to_host(pdev->bus); - -- pdev->dev.bus_dma_mask = -- hose->dma_window_base_cur + hose->dma_window_size; -+ pdev->dev.bus_dma_limit = -+ hose->dma_window_base_cur + hose->dma_window_size - 1; - } - - static void setup_swiotlb_ops(struct pci_controller *hose) -@@ -135,7 +135,7 @@ static void fsl_pci_dma_set_mask(struct - * mapping that allows addressing any RAM address from across PCI. - */ - if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) { -- dev->bus_dma_mask = 0; -+ dev->bus_dma_limit = 0; - dev->archdata.dma_offset = pci64_dma_offset; - } - } ---- a/arch/x86/kernel/pci-dma.c -+++ b/arch/x86/kernel/pci-dma.c -@@ -146,7 +146,7 @@ rootfs_initcall(pci_iommu_init); - - static int via_no_dac_cb(struct pci_dev *pdev, void *data) - { -- pdev->dev.bus_dma_mask = DMA_BIT_MASK(32); -+ pdev->dev.bus_dma_limit = DMA_BIT_MASK(32); - return 0; - } - ---- a/arch/x86/mm/mem_encrypt.c -+++ b/arch/x86/mm/mem_encrypt.c -@@ -367,7 +367,7 @@ bool force_dma_unencrypted(struct device - if (sme_active()) { - u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask)); - u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask, -- dev->bus_dma_mask); -+ dev->bus_dma_limit); - - if (dma_dev_mask <= dma_enc_mask) - return true; ---- a/arch/x86/pci/sta2x11-fixup.c -+++ b/arch/x86/pci/sta2x11-fixup.c -@@ -143,7 +143,7 @@ static void sta2x11_map_ep(struct pci_de - - dev->dma_pfn_offset = PFN_DOWN(-amba_base); - -- dev->bus_dma_mask = max_amba_addr; -+ dev->bus_dma_limit = max_amba_addr; - pci_set_consistent_dma_mask(pdev, max_amba_addr); - pci_set_dma_mask(pdev, max_amba_addr); - ---- a/drivers/acpi/arm64/iort.c -+++ b/drivers/acpi/arm64/iort.c -@@ -1062,8 +1062,8 @@ static int rc_dma_get_range(struct devic - */ - void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) - { -- u64 mask, dmaaddr = 0, size = 0, offset = 0; -- int ret, msb; -+ u64 end, mask, dmaaddr = 0, size = 0, offset = 0; -+ int ret; - - /* - * If @dev is expected to be DMA-capable then the bus code that created -@@ -1090,19 +1090,13 @@ void iort_dma_setup(struct device *dev, - } - - if (!ret) { -- msb = fls64(dmaaddr + size - 1); - /* -- * Round-up to the power-of-two mask or set -- * the mask to the whole 64-bit address space -- * in case the DMA region covers the full -- * memory window. -+ * Limit coherent and dma mask based on size retrieved from -+ * firmware. - */ -- mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; -- /* -- * Limit coherent and dma mask based on size -- * retrieved from firmware. -- */ -- dev->bus_dma_mask = mask; -+ end = dmaaddr + size - 1; -+ mask = DMA_BIT_MASK(ilog2(end) + 1); -+ dev->bus_dma_limit = end; - dev->coherent_dma_mask = mask; - *dev->dma_mask = mask; - } ---- a/drivers/ata/ahci.c -+++ b/drivers/ata/ahci.c -@@ -900,7 +900,7 @@ static int ahci_configure_dma_masks(stru - * value, don't extend it here. This happens on STA2X11, for example. - * - * XXX: manipulating the DMA mask from platform code is completely -- * bogus, platform code should use dev->bus_dma_mask instead.. -+ * bogus, platform code should use dev->bus_dma_limit instead.. - */ - if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32)) - return 0; ---- a/drivers/iommu/dma-iommu.c -+++ b/drivers/iommu/dma-iommu.c -@@ -404,8 +404,7 @@ static dma_addr_t iommu_dma_alloc_iova(s - if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) - iova_len = roundup_pow_of_two(iova_len); - -- if (dev->bus_dma_mask) -- dma_limit &= dev->bus_dma_mask; -+ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); - - if (domain->geometry.force_aperture) - dma_limit = min(dma_limit, domain->geometry.aperture_end); ---- a/drivers/of/device.c -+++ b/drivers/of/device.c -@@ -93,7 +93,7 @@ int of_dma_configure(struct device *dev, - bool coherent; - unsigned long offset; - const struct iommu_ops *iommu; -- u64 mask; -+ u64 mask, end; - - ret = of_dma_get_range(np, &dma_addr, &paddr, &size); - if (ret < 0) { -@@ -148,12 +148,13 @@ int of_dma_configure(struct device *dev, - * Limit coherent and dma mask based on size and default mask - * set by the driver. - */ -- mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1); -+ end = dma_addr + size - 1; -+ mask = DMA_BIT_MASK(ilog2(end) + 1); - dev->coherent_dma_mask &= mask; - *dev->dma_mask &= mask; -- /* ...but only set bus mask if we found valid dma-ranges earlier */ -+ /* ...but only set bus limit if we found valid dma-ranges earlier */ - if (!ret) -- dev->bus_dma_mask = mask; -+ dev->bus_dma_limit = end; - - coherent = of_dma_is_coherent(np); - dev_dbg(dev, "device is%sdma coherent\n", ---- a/include/linux/device.h -+++ b/include/linux/device.h -@@ -1186,8 +1186,8 @@ struct dev_links_info { - * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all - * hardware supports 64-bit addresses for consistent allocations - * such descriptors. -- * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA -- * limit than the device itself supports. -+ * @bus_dma_limit: Limit of an upstream bridge or bus which imposes a smaller -+ * DMA limit than the device itself supports. - * @dma_pfn_offset: offset of DMA memory range relatively of RAM - * @dma_parms: A low level driver may set these to teach IOMMU code about - * segment limitations. -@@ -1270,7 +1270,7 @@ struct device { - not all hardware supports - 64 bit addresses for consistent - allocations such descriptors. */ -- u64 bus_dma_mask; /* upstream dma_mask constraint */ -+ u64 bus_dma_limit; /* upstream dma constraint */ - unsigned long dma_pfn_offset; - - struct device_dma_parameters *dma_parms; ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -63,7 +63,7 @@ static inline bool dma_capable(struct de - min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) - return false; - -- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); -+ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_limit); - } - - u64 dma_direct_get_required_mask(struct device *dev); ---- a/include/linux/dma-mapping.h -+++ b/include/linux/dma-mapping.h -@@ -697,7 +697,7 @@ static inline int dma_coerce_mask_and_co - */ - static inline bool dma_addressing_limited(struct device *dev) - { -- return min_not_zero(dma_get_mask(dev), dev->bus_dma_mask) < -+ return min_not_zero(dma_get_mask(dev), dev->bus_dma_limit) < - dma_get_required_mask(dev); - } - ---- a/kernel/dma/direct.c -+++ b/kernel/dma/direct.c -@@ -26,10 +26,10 @@ static void report_addr(struct device *d - { - if (!dev->dma_mask) { - dev_err_once(dev, "DMA map on device without dma_mask\n"); -- } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_mask) { -+ } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_limit) { - dev_err_once(dev, -- "overflow %pad+%zu of DMA mask %llx bus mask %llx\n", -- &dma_addr, size, *dev->dma_mask, dev->bus_dma_mask); -+ "overflow %pad+%zu of DMA mask %llx bus limit %llx\n", -+ &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit); - } - WARN_ON_ONCE(1); - } -@@ -51,15 +51,14 @@ u64 dma_direct_get_required_mask(struct - } - - static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask, -- u64 *phys_mask) -+ u64 *phys_limit) - { -- if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask) -- dma_mask = dev->bus_dma_mask; -+ u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit); - - if (force_dma_unencrypted(dev)) -- *phys_mask = __dma_to_phys(dev, dma_mask); -+ *phys_limit = __dma_to_phys(dev, dma_limit); - else -- *phys_mask = dma_to_phys(dev, dma_mask); -+ *phys_limit = dma_to_phys(dev, dma_limit); - - /* - * Optimistically try the zone that the physical address mask falls -@@ -69,9 +68,9 @@ static gfp_t __dma_direct_optimal_gfp_ma - * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding - * zones. - */ -- if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) -+ if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits)) - return GFP_DMA; -- if (*phys_mask <= DMA_BIT_MASK(32)) -+ if (*phys_limit <= DMA_BIT_MASK(32)) - return GFP_DMA32; - return 0; - } -@@ -79,7 +78,7 @@ static gfp_t __dma_direct_optimal_gfp_ma - static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size) - { - return phys_to_dma_direct(dev, phys) + size - 1 <= -- min_not_zero(dev->coherent_dma_mask, dev->bus_dma_mask); -+ min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit); - } - - struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, -@@ -88,7 +87,7 @@ struct page *__dma_direct_alloc_pages(st - size_t alloc_size = PAGE_ALIGN(size); - int node = dev_to_node(dev); - struct page *page = NULL; -- u64 phys_mask; -+ u64 phys_limit; - - if (attrs & DMA_ATTR_NO_WARN) - gfp |= __GFP_NOWARN; -@@ -96,7 +95,7 @@ struct page *__dma_direct_alloc_pages(st - /* we always manually zero the memory once we are done: */ - gfp &= ~__GFP_ZERO; - gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, -- &phys_mask); -+ &phys_limit); - page = dma_alloc_contiguous(dev, alloc_size, gfp); - if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { - dma_free_contiguous(dev, page, alloc_size); -@@ -110,7 +109,7 @@ again: - page = NULL; - - if (IS_ENABLED(CONFIG_ZONE_DMA32) && -- phys_mask < DMA_BIT_MASK(64) && -+ phys_limit < DMA_BIT_MASK(64) && - !(gfp & (GFP_DMA32 | GFP_DMA))) { - gfp |= GFP_DMA32; - goto again; diff --git a/target/linux/bcm27xx/patches-5.4/950-0451-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch b/target/linux/bcm27xx/patches-5.4/950-0451-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch new file mode 100644 index 0000000000..c93f4501c4 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0451-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch @@ -0,0 +1,156 @@ +From a3ceeebaaa66e6786490e850b5019808da3785c0 Mon Sep 17 00:00:00 2001 +From: Andrey Konovalov +Date: Mon, 20 Jan 2020 05:15:57 -0300 +Subject: [PATCH] media: dt-bindings: media: i2c: Add IMX219 CMOS + sensor binding + +Commit 9d730f2cf4c0391785855dd231577d2de2594df9 upstream. +(Currently on linux-media/master, queued for 5.7) + +Add YAML device tree binding for IMX219 CMOS image sensor, and +the relevant MAINTAINERS entries. + +Signed-off-by: Andrey Konovalov +Reviewed-by: Rob Herring +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + .../devicetree/bindings/media/i2c/imx219.yaml | 114 ++++++++++++++++++ + MAINTAINERS | 8 ++ + 2 files changed, 122 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml +@@ -0,0 +1,114 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/imx219.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor ++ ++maintainers: ++ - Dave Stevenson ++ ++description: |- ++ The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor ++ with an active array size of 3280H x 2464V. It is programmable through ++ I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet. ++ Image data is sent through MIPI CSI-2, which is configured as either 2 or ++ 4 data lanes. ++ ++properties: ++ compatible: ++ const: sony,imx219 ++ ++ reg: ++ description: I2C device address ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ VDIG-supply: ++ description: ++ Digital I/O voltage supply, 1.8 volts ++ ++ VANA-supply: ++ description: ++ Analog voltage supply, 2.8 volts ++ ++ VDDL-supply: ++ description: ++ Digital core voltage supply, 1.2 volts ++ ++ reset-gpios: ++ description: |- ++ Reference to the GPIO connected to the xclr pin, if any. ++ Must be released (set high) after all supplies are 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 four-lane operation. ++ If this property is omitted four-lane operation is assumed. ++ For two-lane operation the property must be set to <1 2>. ++ items: ++ - const: 1 ++ - const: 2 ++ ++ clock-noncontinuous: ++ type: boolean ++ description: |- ++ MIPI CSI-2 clock is non-continuous if this property is present, ++ otherwise it's continuous. ++ ++ link-frequencies: ++ allOf: ++ - $ref: /schemas/types.yaml#/definitions/uint64-array ++ description: ++ Allowed data bus frequencies. ++ ++ required: ++ - link-frequencies ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - VANA-supply ++ - VDIG-supply ++ - VDDL-supply ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ imx219: sensor@10 { ++ compatible = "sony,imx219"; ++ reg = <0x10>; ++ clocks = <&imx219_clk>; ++ VANA-supply = <&imx219_vana>; /* 2.8v */ ++ VDIG-supply = <&imx219_vdig>; /* 1.8v */ ++ VDDL-supply = <&imx219_vddl>; /* 1.2v */ ++ ++ port { ++ imx219_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = /bits/ 64 <456000000>; ++ }; ++ }; ++ }; ++ }; ++ ++... +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15143,6 +15143,14 @@ S: Maintained + F: drivers/media/i2c/imx214.c + F: Documentation/devicetree/bindings/media/i2c/sony,imx214.txt + ++SONY IMX219 SENSOR DRIVER ++M: Dave Stevenson ++L: linux-media@vger.kernel.org ++T: git git://linuxtv.org/media_tree.git ++S: Maintained ++F: drivers/media/i2c/imx219.c ++F: Documentation/devicetree/bindings/media/i2c/imx219.yaml ++ + SONY IMX258 SENSOR DRIVER + M: Sakari Ailus + L: linux-media@vger.kernel.org diff --git a/target/linux/bcm27xx/patches-5.4/950-0452-ARM-dts-bcm2711-Enable-PCIe-controller.patch b/target/linux/bcm27xx/patches-5.4/950-0452-ARM-dts-bcm2711-Enable-PCIe-controller.patch deleted file mode 100644 index 9f114c1633..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0452-ARM-dts-bcm2711-Enable-PCIe-controller.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0ec0bc884f6cf1ec9775c750f78ce28be7da4340 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Mon, 16 Dec 2019 12:01:08 +0100 -Subject: [PATCH] ARM: dts: bcm2711: Enable PCIe controller - -commit d5c8dc0d4c880fbde5293cc186b1ab23466254c4 upstream. - -This enables bcm2711's PCIe bus, which is hardwired to a VIA -Technologies XHCI USB 3.0 controller. - -Signed-off-by: Nicolas Saenz Julienne -Signed-off-by: Florian Fainelli ---- - arch/arm/boot/dts/bcm2711.dtsi | 31 ++++++++++++++++++++++++++++++- - 1 file changed, 30 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -331,7 +331,36 @@ - #address-cells = <2>; - #size-cells = <1>; - -- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; -+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, -+ <0x6 0x00000000 0x6 0x00000000 0x40000000>; -+ -+ pcie0: pcie@7d500000 { -+ compatible = "brcm,bcm2711-pcie"; -+ reg = <0x0 0x7d500000 0x9310>; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #interrupt-cells = <1>; -+ #size-cells = <2>; -+ interrupts = , -+ ; -+ interrupt-names = "pcie", "msi"; -+ interrupt-map-mask = <0x0 0x0 0x0 0x7>; -+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 -+ IRQ_TYPE_LEVEL_HIGH>; -+ msi-controller; -+ msi-parent = <&pcie0>; -+ -+ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 -+ 0x0 0x04000000>; -+ /* -+ * The wrapper around the PCIe block has a bug -+ * preventing it from accessing beyond the first 3GB of -+ * memory. -+ */ -+ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 -+ 0x0 0xc0000000>; -+ brcm,enable-ssc; -+ }; - - genet: ethernet@7d580000 { - compatible = "brcm,bcm2711-genet-v5"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0452-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch b/target/linux/bcm27xx/patches-5.4/950-0452-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch new file mode 100644 index 0000000000..4ca345f2ad --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0452-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch @@ -0,0 +1,1372 @@ +From 5cd8c4efeb46ce1ef370dd3012a7951ba430b58f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 20 Jan 2020 05:15:58 -0300 +Subject: [PATCH] media: i2c: Add driver for Sony IMX219 sensor + +Commit 1283b3b8f82b9004fbb94398cade5c8e797a2c8d upstream. +(Currently on linux-media/master, queued for 5.7) + +Adds a driver for the 8MPix Sony IMX219 CSI2 sensor. +Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver +currently only supports 2 lanes. +8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned) +@ 30fps are currently supported. + +[Sakari Ailus: make imx219_check_hwcfg static] + +Signed-off-by: Dave Stevenson +Signed-off-by: Andrey Konovalov +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/Kconfig | 11 + + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/imx219.c | 1312 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 1324 insertions(+) + create mode 100644 drivers/media/i2c/imx219.c + +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -578,6 +578,17 @@ config VIDEO_IMX214 + To compile this driver as a module, choose M here: the + module will be called imx214. + ++config VIDEO_IMX219 ++ tristate "Sony IMX219 sensor support" ++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ++ select V4L2_FWNODE ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX219 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called imx219. ++ + config VIDEO_IMX258 + tristate "Sony IMX258 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -111,6 +111,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v76 + obj-$(CONFIG_VIDEO_OV2659) += ov2659.o + obj-$(CONFIG_VIDEO_TC358743) += tc358743.o + obj-$(CONFIG_VIDEO_IMX214) += imx214.o ++obj-$(CONFIG_VIDEO_IMX219) += imx219.o + obj-$(CONFIG_VIDEO_IMX258) += imx258.o + obj-$(CONFIG_VIDEO_IMX274) += imx274.o + obj-$(CONFIG_VIDEO_IMX319) += imx319.o +--- /dev/null ++++ b/drivers/media/i2c/imx219.c +@@ -0,0 +1,1312 @@ ++// 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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_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 0x0 ++ ++/* 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 ++ ++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; ++ ++ /* 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, and 1640x1232 = mode 4. ++ */ ++static const struct imx219_reg mode_3280x2464_regs[] = { ++ {0x0100, 0x00}, ++ {0x30eb, 0x0c}, ++ {0x30eb, 0x05}, ++ {0x300a, 0xff}, ++ {0x300b, 0xff}, ++ {0x30eb, 0x05}, ++ {0x30eb, 0x09}, ++ {0x0114, 0x01}, ++ {0x0128, 0x00}, ++ {0x012a, 0x18}, ++ {0x012b, 0x00}, ++ {0x0164, 0x00}, ++ {0x0165, 0x00}, ++ {0x0166, 0x0c}, ++ {0x0167, 0xcf}, ++ {0x0168, 0x00}, ++ {0x0169, 0x00}, ++ {0x016a, 0x09}, ++ {0x016b, 0x9f}, ++ {0x016c, 0x0c}, ++ {0x016d, 0xd0}, ++ {0x016e, 0x09}, ++ {0x016f, 0xa0}, ++ {0x0170, 0x01}, ++ {0x0171, 0x01}, ++ {0x0174, 0x00}, ++ {0x0175, 0x00}, ++ {0x018c, 0x0a}, ++ {0x018d, 0x0a}, ++ {0x0301, 0x05}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x0305, 0x03}, ++ {0x0306, 0x00}, ++ {0x0307, 0x39}, ++ {0x0309, 0x0a}, ++ {0x030b, 0x01}, ++ {0x030c, 0x00}, ++ {0x030d, 0x72}, ++ {0x0624, 0x0c}, ++ {0x0625, 0xd0}, ++ {0x0626, 0x09}, ++ {0x0627, 0xa0}, ++ {0x455e, 0x00}, ++ {0x471e, 0x4b}, ++ {0x4767, 0x0f}, ++ {0x4750, 0x14}, ++ {0x4540, 0x00}, ++ {0x47b4, 0x14}, ++ {0x4713, 0x30}, ++ {0x478b, 0x10}, ++ {0x478f, 0x10}, ++ {0x4793, 0x10}, ++ {0x4797, 0x0e}, ++ {0x479b, 0x0e}, ++ {0x0162, 0x0d}, ++ {0x0163, 0x78}, ++}; ++ ++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}, ++ {0x018c, 0x0a}, ++ {0x018d, 0x0a}, ++ {0x0301, 0x05}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x0305, 0x03}, ++ {0x0306, 0x00}, ++ {0x0307, 0x39}, ++ {0x0309, 0x0a}, ++ {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}, ++ {0x0162, 0x0d}, ++ {0x0163, 0x78}, ++}; ++ ++static const struct imx219_reg mode_1640_1232_regs[] = { ++ {0x0100, 0x00}, ++ {0x30eb, 0x0c}, ++ {0x30eb, 0x05}, ++ {0x300a, 0xff}, ++ {0x300b, 0xff}, ++ {0x30eb, 0x05}, ++ {0x30eb, 0x09}, ++ {0x0114, 0x01}, ++ {0x0128, 0x00}, ++ {0x012a, 0x18}, ++ {0x012b, 0x00}, ++ {0x0164, 0x00}, ++ {0x0165, 0x00}, ++ {0x0166, 0x0c}, ++ {0x0167, 0xcf}, ++ {0x0168, 0x00}, ++ {0x0169, 0x00}, ++ {0x016a, 0x09}, ++ {0x016b, 0x9f}, ++ {0x016c, 0x06}, ++ {0x016d, 0x68}, ++ {0x016e, 0x04}, ++ {0x016f, 0xd0}, ++ {0x0170, 0x01}, ++ {0x0171, 0x01}, ++ {0x0174, 0x01}, ++ {0x0175, 0x01}, ++ {0x018c, 0x0a}, ++ {0x018d, 0x0a}, ++ {0x0301, 0x05}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x0305, 0x03}, ++ {0x0306, 0x00}, ++ {0x0307, 0x39}, ++ {0x0309, 0x0a}, ++ {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}, ++ {0x0162, 0x0d}, ++ {0x0163, 0x78}, ++}; ++ ++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) ++ ++/* ++ * 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 +