mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-02-14 12:21:53 +00:00
Add RPI4 beta support
This commit is contained in:
parent
abf18246f5
commit
5f08b288eb
155 changed files with 29237 additions and 0 deletions
5
config-rpi4
Normal file
5
config-rpi4
Normal file
|
@ -0,0 +1,5 @@
|
|||
CONFIG_TARGET_brcm2708=y
|
||||
CONFIG_TARGET_brcm2708_bcm2711=y
|
||||
CONFIG_TARGET_brcm2708_bcm2711_DEVICE_rpi-4=y
|
||||
CONFIG_PACKAGE_kmod-ath10k-ct=n
|
||||
CONFIG_PACKAGE_kmod-ath9k=y
|
34
root/target/linux/brcm2708/Makefile
Normal file
34
root/target/linux/brcm2708/Makefile
Normal file
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Copyright (C) 2012-2016 OpenWrt.org
|
||||
# Copyright (C) 2017 LEDE project
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
ARCH:=arm
|
||||
BOARD:=brcm2708
|
||||
BOARDNAME:=Broadcom BCM27xx
|
||||
FEATURES:=ext4 audio usb usbgadget display gpio fpu squashfs rootfs-part boot-part
|
||||
MAINTAINER:=Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
SUBTARGETS:=bcm2708 bcm2709 bcm2710 bcm2711
|
||||
|
||||
KERNEL_PATCHVER:=4.14
|
||||
|
||||
define Target/Description
|
||||
Build firmware image for Broadcom BCM27xx SoC devices.
|
||||
Currently produces SD Card image for Raspberry Pi.
|
||||
endef
|
||||
|
||||
include $(INCLUDE_DIR)/target.mk
|
||||
DEFAULT_PACKAGES += \
|
||||
brcm2708-gpu-fw \
|
||||
kmod-usb-hid \
|
||||
kmod-sound-core kmod-sound-arm-bcm2835 \
|
||||
kmod-fs-vfat kmod-nls-cp437 kmod-nls-iso8859-1 \
|
||||
partx-utils mkf2fs e2fsprogs
|
||||
|
||||
KERNELNAME:=Image dtbs
|
||||
|
||||
$(eval $(call BuildTarget))
|
|
@ -119,6 +119,7 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
|||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2835_DEVGPIOMEM is not set
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
CONFIG_BCM2835_THERMAL=y
|
||||
CONFIG_BCM2835_VCHIQ=y
|
||||
|
@ -135,6 +136,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
|
|||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
CONFIG_BRCMSTB_THERMAL=y
|
||||
CONFIG_BUILD_BIN2C=y
|
||||
CONFIG_CAVIUM_ERRATUM_22375=y
|
||||
CONFIG_CAVIUM_ERRATUM_23154=y
|
||||
|
|
541
root/target/linux/brcm2708/bcm2711/config-4.19
Normal file
541
root/target/linux/brcm2708/bcm2711/config-4.19
Normal file
|
@ -0,0 +1,541 @@
|
|||
CONFIG_64BIT=y
|
||||
# CONFIG_AIO is not set
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
CONFIG_ARCH_CLOCKSOURCE_DATA=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=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_HOLES_MEMORYMODEL=y
|
||||
CONFIG_ARCH_HAS_KCOV=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_SG_CHAIN=y
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=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_MMAP_RND_BITS=18
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MAX=24
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MIN=18
|
||||
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
|
||||
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_QUEUED_RWLOCKS=y
|
||||
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
|
||||
CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
|
||||
CONFIG_ARCH_WANT_FRAME_POINTERS=y
|
||||
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
|
||||
CONFIG_ARM64=y
|
||||
# CONFIG_ARM64_16K_PAGES is not set
|
||||
CONFIG_ARM64_4K_PAGES=y
|
||||
# CONFIG_ARM64_64K_PAGES is not set
|
||||
CONFIG_ARM64_CONT_SHIFT=4
|
||||
# CONFIG_ARM64_CRYPTO is not set
|
||||
CONFIG_ARM64_ERRATUM_1024718=y
|
||||
CONFIG_ARM64_ERRATUM_1463225=y
|
||||
CONFIG_ARM64_ERRATUM_819472=y
|
||||
CONFIG_ARM64_ERRATUM_824069=y
|
||||
CONFIG_ARM64_ERRATUM_826319=y
|
||||
CONFIG_ARM64_ERRATUM_827319=y
|
||||
CONFIG_ARM64_ERRATUM_832075=y
|
||||
CONFIG_ARM64_ERRATUM_843419=y
|
||||
CONFIG_ARM64_HW_AFDBM=y
|
||||
# CONFIG_ARM64_LSE_ATOMICS is not set
|
||||
CONFIG_ARM64_MODULE_PLTS=y
|
||||
CONFIG_ARM64_PAGE_SHIFT=12
|
||||
CONFIG_ARM64_PAN=y
|
||||
CONFIG_ARM64_PA_BITS=48
|
||||
CONFIG_ARM64_PA_BITS_48=y
|
||||
# CONFIG_ARM64_PMEM is not set
|
||||
# CONFIG_ARM64_PTDUMP_DEBUGFS is not set
|
||||
# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
|
||||
CONFIG_ARM64_SSBD=y
|
||||
CONFIG_ARM64_SVE=y
|
||||
# CONFIG_ARM64_SW_TTBR0_PAN is not set
|
||||
CONFIG_ARM64_UAO=y
|
||||
CONFIG_ARM64_VA_BITS=39
|
||||
CONFIG_ARM64_VA_BITS_39=y
|
||||
# CONFIG_ARM64_VA_BITS_48 is not set
|
||||
CONFIG_ARM64_VHE=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
|
||||
CONFIG_ARM_BCM2835_CPUFREQ=y
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_GIC_V3=y
|
||||
CONFIG_ARM_GIC_V3_ITS=y
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SP805_WATCHDOG is not set
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2835_DEVGPIOMEM is not set
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
CONFIG_BCM2835_THERMAL=y
|
||||
CONFIG_BCM2835_VCHIQ=y
|
||||
CONFIG_BCM2835_VCHIQ_MMAL=y
|
||||
CONFIG_BCM2835_WDT=y
|
||||
# CONFIG_BCM_VCIO is not set
|
||||
# CONFIG_BCM_VC_SM is not set
|
||||
CONFIG_BCM_VIDEOCORE=y
|
||||
# CONFIG_BLK_DEV_INITRD is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_COUNT=16
|
||||
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BRCMSTB_THERMAL=y
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
CONFIG_BUILD_BIN2C=y
|
||||
CONFIG_CAVIUM_ERRATUM_22375=y
|
||||
CONFIG_CAVIUM_ERRATUM_23154=y
|
||||
CONFIG_CAVIUM_ERRATUM_27456=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLONE_BACKWARDS=y
|
||||
CONFIG_CMA=y
|
||||
CONFIG_CMA_ALIGNMENT=8
|
||||
CONFIG_CMA_AREAS=7
|
||||
# CONFIG_CMA_DEBUG is not set
|
||||
# CONFIG_CMA_DEBUGFS is not set
|
||||
CONFIG_CMA_SIZE_MBYTES=16
|
||||
# CONFIG_CMA_SIZE_SEL_MAX is not set
|
||||
CONFIG_CMA_SIZE_SEL_MBYTES=y
|
||||
# CONFIG_CMA_SIZE_SEL_MIN is not set
|
||||
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_COMMON_CLK_XGENE=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
# CONFIG_CPUFREQ_DT is not set
|
||||
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
|
||||
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
|
||||
CONFIG_CPU_FREQ_GOV_COMMON=y
|
||||
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
|
||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
||||
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_STAT=y
|
||||
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
# CONFIG_CPU_THERMAL is not set
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_AEAD=y
|
||||
CONFIG_CRYPTO_AEAD2=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_WORKQUEUE=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEFAULT_MPTCP_PM="fullmesh"
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_DIRECT_OPS=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_SHARED_BUFFER=m
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
# CONFIG_F2FS_CHECK_FS is not set
|
||||
# CONFIG_F2FS_FS_SECURITY is not set
|
||||
# CONFIG_F2FS_FS_XATTR is not set
|
||||
# CONFIG_F2FS_STAT_FS is not set
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_BCM2708=y
|
||||
CONFIG_FB_CFB_COPYAREA=y
|
||||
CONFIG_FB_CFB_FILLRECT=y
|
||||
CONFIG_FB_CFB_IMAGEBLIT=y
|
||||
CONFIG_FB_CMDLINE=y
|
||||
# CONFIG_FB_RPISENSE is not set
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
# CONFIG_FLATMEM_MANUAL is not set
|
||||
# CONFIG_FONTS is not set
|
||||
CONFIG_FONT_8x16=y
|
||||
CONFIG_FONT_8x8=y
|
||||
CONFIG_FONT_SUPPORT=y
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_FREEZER=y
|
||||
CONFIG_FSL_ERRATUM_A008585=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_GENERIC_ALLOCATOR=y
|
||||
CONFIG_GENERIC_ARCH_TOPOLOGY=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_CSUM=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
|
||||
CONFIG_GENERIC_IRQ_MIGRATION=y
|
||||
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_GENERIC_PCI_IOMAP=y
|
||||
CONFIG_GENERIC_PINCONF=y
|
||||
CONFIG_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
|
||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||
CONFIG_GENERIC_STRNLEN_USER=y
|
||||
CONFIG_GENERIC_TIME_VSYSCALL=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
CONFIG_GPIO_BCM_VIRT=y
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_HANDLE_DOMAIN_IRQ=y
|
||||
CONFIG_HARDEN_BRANCH_PREDICTOR=y
|
||||
CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=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_KASAN=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_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_CLK=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_HAVE_CMPXCHG_DOUBLE=y
|
||||
CONFIG_HAVE_CMPXCHG_LOCAL=y
|
||||
CONFIG_HAVE_CONTEXT_TRACKING=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_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||
CONFIG_HAVE_GENERIC_GUP=y
|
||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
||||
CONFIG_HAVE_MEMBLOCK=y
|
||||
CONFIG_HAVE_MEMORY_PRESENT=y
|
||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
CONFIG_HAVE_PATA_PLATFORM=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_HUGETLBFS is not set
|
||||
CONFIG_HW_CONSOLE=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
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
|
||||
CONFIG_IOSCHED_CFQ=y
|
||||
CONFIG_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JBD2=y
|
||||
# CONFIG_LCD_CLASS_DEVICE is not set
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_LOCK_SPIN_ON_OWNER=y
|
||||
CONFIG_LOGO=y
|
||||
CONFIG_LOGO_LINUX_CLUT224=y
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_MAILBOX=y
|
||||
# CONFIG_MAILBOX_TEST is not set
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MICROCHIP_PHY=y
|
||||
CONFIG_MIGRATION=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_BCM2835=y
|
||||
CONFIG_MMC_BCM2835_DMA=y
|
||||
CONFIG_MMC_BCM2835_MMC=y
|
||||
CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2
|
||||
CONFIG_MMC_BCM2835_SDHOST=y
|
||||
CONFIG_MMC_BLOCK=y
|
||||
CONFIG_MMC_BLOCK_MINORS=32
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_PLTFM=y
|
||||
CONFIG_MODULES_USE_ELF_RELA=y
|
||||
# CONFIG_MTD is not set
|
||||
CONFIG_MUTEX_SPIN_ON_OWNER=y
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_SG_DMA_LENGTH=y
|
||||
CONFIG_NET_FLOW_LIMIT=y
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NLS_DEFAULT="utf8"
|
||||
CONFIG_NO_BOOTMEM=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NO_IOPORT_MAP=y
|
||||
CONFIG_NR_CPUS=4
|
||||
# CONFIG_NUMA is not set
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_ADDRESS=y
|
||||
CONFIG_OF_CONFIGFS=y
|
||||
CONFIG_OF_DYNAMIC=y
|
||||
CONFIG_OF_EARLY_FLATTREE=y
|
||||
CONFIG_OF_FLATTREE=y
|
||||
CONFIG_OF_GPIO=y
|
||||
CONFIG_OF_IRQ=y
|
||||
CONFIG_OF_KOBJ=y
|
||||
CONFIG_OF_MDIO=y
|
||||
CONFIG_OF_NET=y
|
||||
CONFIG_OF_OVERLAY=y
|
||||
CONFIG_OF_RESERVED_MEM=y
|
||||
CONFIG_OF_RESOLVE=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PARTITION_PERCPU=y
|
||||
CONFIG_PGTABLE_LEVELS=3
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_BCM2835=y
|
||||
CONFIG_PLUGIN_HOSTCC="g++"
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_CLK=y
|
||||
# CONFIG_PM_DEBUG is not set
|
||||
CONFIG_PM_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_PROC_PAGE_MONITOR=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_BCM2835=y
|
||||
CONFIG_PWM_SYSFS=y
|
||||
CONFIG_QUEUED_RWLOCKS=y
|
||||
CONFIG_QUEUED_SPINLOCKS=y
|
||||
# CONFIG_RANDOMIZE_BASE is not set
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_RCU_NEED_SEGCBLIST=y
|
||||
CONFIG_RCU_STALL_COMMON=y
|
||||
CONFIG_REFCOUNT_FULL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS is not set
|
||||
# CONFIG_SENSORS_RASPBERRYPI_HWMON is not set
|
||||
CONFIG_SERIAL_8250_BCM2835AUX=y
|
||||
# CONFIG_SERIAL_8250_DMA is not set
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_FSL=y
|
||||
CONFIG_SERIAL_8250_NR_UARTS=1
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=0
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMP=y
|
||||
# CONFIG_SND_AUDIOSENSE_PI is not set
|
||||
# CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC is not set
|
||||
# CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M is not set
|
||||
# CONFIG_SND_RPI_SIMPLE_SOUNDCARD is not set
|
||||
# CONFIG_SND_RPI_WM8804_SOUNDCARD is not set
|
||||
# CONFIG_SND_SOC_AD193X_SPI is not set
|
||||
CONFIG_SPARSEMEM=y
|
||||
CONFIG_SPARSEMEM_EXTREME=y
|
||||
CONFIG_SPARSEMEM_MANUAL=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SRCU=y
|
||||
CONFIG_STREAM_PARSER=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=y
|
||||
CONFIG_SWIOTLB=y
|
||||
CONFIG_SWPHY=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
CONFIG_SYS_SUPPORTS_HUGETLBFS=y
|
||||
# CONFIG_TEXTSEARCH is not set
|
||||
CONFIG_THERMAL=y
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_OF=y
|
||||
CONFIG_THREAD_INFO_IN_TASK=y
|
||||
CONFIG_TICK_CPU_ACCOUNTING=y
|
||||
CONFIG_TIMER_OF=y
|
||||
CONFIG_TIMER_PROBE=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set
|
||||
CONFIG_TREE_RCU=y
|
||||
CONFIG_TREE_SRCU=y
|
||||
CONFIG_UEVENT_HELPER_PATH=""
|
||||
CONFIG_UNMAP_KERNEL_AT_EL0=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_DWCOTG=y
|
||||
# CONFIG_USB_EHCI_HCD is not set
|
||||
CONFIG_USB_LAN78XX=y
|
||||
CONFIG_USB_NET_DRIVERS=y
|
||||
CONFIG_USB_NET_SMSC95XX=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_USB_UAS=y
|
||||
CONFIG_USB_USBNET=y
|
||||
# CONFIG_VIDEO_CODEC_BCM2835 is not set
|
||||
CONFIG_VMAP_STACK=y
|
||||
CONFIG_VT=y
|
||||
CONFIG_VT_CONSOLE=y
|
||||
CONFIG_VT_CONSOLE_SLEEP=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_XPS=y
|
||||
CONFIG_XZ_DEC_ARM=y
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
CONFIG_ZONE_DMA32=y
|
14
root/target/linux/brcm2708/bcm2711/target.mk
Normal file
14
root/target/linux/brcm2708/bcm2711/target.mk
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Copyright (C) 2016 OpenWrt.org
|
||||
# Copyright (C) 2017 LEDE project
|
||||
# Copyright (C) 2019 Ycarus (Yannick Chabanois) ycarus@zugaina.org for OpenMPTCProuter project
|
||||
#
|
||||
|
||||
ARCH:=aarch64
|
||||
SUBTARGET:=bcm2711
|
||||
BOARDNAME:=BCM2711 64 bit based boards
|
||||
CPU_TYPE:=cortex-a72
|
||||
|
||||
define Target/Description
|
||||
Build firmware image for Broadcom BCM2711 64 bit SoC devices.
|
||||
endef
|
|
@ -0,0 +1,223 @@
|
|||
From e1272fcce7564b066995ebe92da132cec8e77656 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 7 May 2019 14:29:38 +0100
|
||||
Subject: [PATCH 512/678] BCM270X_DT: Add non-removable clone of mmc node
|
||||
|
||||
non-removable is a boolean property, and as such can't be unset by an
|
||||
overlay if it is set in a base DTB. Until now the workaround for this
|
||||
problem has been for overlays to clone non-removable nodes without
|
||||
the offending property, but this involves a lot of unnecessary
|
||||
replication. Instead, add a clone of the mmc node with non-removable
|
||||
already set to the base DTB, selecting the required version using
|
||||
the status properties.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
arch/arm/boot/dts/bcm2708-rpi-0-w.dts | 4 +--
|
||||
arch/arm/boot/dts/bcm2708-rpi.dtsi | 3 +-
|
||||
arch/arm/boot/dts/bcm270x.dtsi | 13 ++++++++
|
||||
arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts | 5 ++--
|
||||
arch/arm/boot/dts/bcm2710-rpi-3-b.dts | 5 ++--
|
||||
arch/arm/boot/dts/overlays/mmc-overlay.dts | 7 +++++
|
||||
arch/arm/boot/dts/overlays/sdio-overlay.dts | 33 +++++++--------------
|
||||
7 files changed, 38 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts b/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
|
||||
index aa33646fcf53..23ff3e4970ae 100644
|
||||
--- a/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
|
||||
+++ b/arch/arm/boot/dts/bcm2708-rpi-0-w.dts
|
||||
@@ -14,6 +14,7 @@
|
||||
aliases {
|
||||
serial0 = &uart1;
|
||||
serial1 = &uart0;
|
||||
+ mmc1 = &mmcnr;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -73,10 +74,9 @@
|
||||
};
|
||||
};
|
||||
|
||||
-&mmc {
|
||||
+&mmcnr {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdio_pins>;
|
||||
- non-removable;
|
||||
bus-width = <4>;
|
||||
status = "okay";
|
||||
};
|
||||
diff --git a/arch/arm/boot/dts/bcm2708-rpi.dtsi b/arch/arm/boot/dts/bcm2708-rpi.dtsi
|
||||
index 9e1492186728..0cce7d1b99d3 100644
|
||||
--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
|
||||
@@ -118,7 +118,8 @@
|
||||
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";
|
||||
+ sdio_overclock = <&mmc>,"brcm,overclock-50:0",
|
||||
+ <&mmcnr>,"brcm,overclock-50:0";
|
||||
axiperf = <&axiperf>,"status";
|
||||
};
|
||||
};
|
||||
diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi
|
||||
index ecdb36e69c87..6d2563b25a42 100644
|
||||
--- a/arch/arm/boot/dts/bcm270x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm270x.dtsi
|
||||
@@ -79,6 +79,19 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ /* A clone of mmc but with non-removable set */
|
||||
+ mmcnr: mmcnr@7e300000 {
|
||||
+ compatible = "brcm,bcm2835-mmc", "brcm,bcm2835-sdhci";
|
||||
+ reg = <0x7e300000 0x100>;
|
||||
+ interrupts = <2 30>;
|
||||
+ clocks = <&clocks BCM2835_CLOCK_EMMC>;
|
||||
+ dmas = <&dma 11>;
|
||||
+ dma-names = "rx-tx";
|
||||
+ brcm,overclock-50 = <0>;
|
||||
+ non-removable;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
hvs: hvs@7e400000 {
|
||||
/* Add alias */
|
||||
status = "disabled";
|
||||
diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
|
||||
index b5f125296e1e..6e526d7e4989 100644
|
||||
--- a/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
|
||||
+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b-plus.dts
|
||||
@@ -15,6 +15,7 @@
|
||||
aliases {
|
||||
serial0 = &uart1;
|
||||
serial1 = &uart0;
|
||||
+ mmc1 = &mmcnr;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -74,13 +75,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
-&mmc {
|
||||
+&mmcnr {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdio_pins>;
|
||||
- non-removable;
|
||||
bus-width = <4>;
|
||||
status = "okay";
|
||||
- brcm,overclock-50 = <0>;
|
||||
};
|
||||
|
||||
&firmware {
|
||||
diff --git a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
|
||||
index d9d9505c6693..9d77cb1e9b0b 100644
|
||||
--- a/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
|
||||
+++ b/arch/arm/boot/dts/bcm2710-rpi-3-b.dts
|
||||
@@ -15,6 +15,7 @@
|
||||
aliases {
|
||||
serial0 = &uart1;
|
||||
serial1 = &uart0;
|
||||
+ mmc1 = &mmcnr;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -74,13 +75,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
-&mmc {
|
||||
+&mmcnr {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdio_pins>;
|
||||
- non-removable;
|
||||
bus-width = <4>;
|
||||
status = "okay";
|
||||
- brcm,overclock-50 = <0>;
|
||||
};
|
||||
|
||||
&soc {
|
||||
diff --git a/arch/arm/boot/dts/overlays/mmc-overlay.dts b/arch/arm/boot/dts/overlays/mmc-overlay.dts
|
||||
index 85994b099bc0..c1a2f691aa1e 100644
|
||||
--- a/arch/arm/boot/dts/overlays/mmc-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/mmc-overlay.dts
|
||||
@@ -33,6 +33,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ fragment@3 {
|
||||
+ target = <&mmcnr>;
|
||||
+ __overlay__ {
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
__overrides__ {
|
||||
overclock_50 = <&frag0>,"brcm,overclock-50:0";
|
||||
};
|
||||
diff --git a/arch/arm/boot/dts/overlays/sdio-overlay.dts b/arch/arm/boot/dts/overlays/sdio-overlay.dts
|
||||
index d63df20afdf7..873e49056379 100644
|
||||
--- a/arch/arm/boot/dts/overlays/sdio-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/sdio-overlay.dts
|
||||
@@ -1,39 +1,26 @@
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
-/* Enable SDIO from MMC interface via GPIOs 22-27. Includes sdhost overlay. */
|
||||
+/* Enable SDIO from MMC interface via various GPIO groups */
|
||||
|
||||
/{
|
||||
compatible = "brcm,bcm2708";
|
||||
|
||||
fragment@0 {
|
||||
- target = <&mmc>;
|
||||
+ target = <&mmcnr>;
|
||||
__overlay__ {
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
fragment@1 {
|
||||
- target = <&soc>;
|
||||
- __overlay__ {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
-
|
||||
- sdio_ovl: sdio@7e300000 {
|
||||
- compatible = "brcm,bcm2835-mmc",
|
||||
- "brcm,bcm2835-sdhci";
|
||||
- reg = <0x7e300000 0x100>;
|
||||
- interrupts = <2 30>;
|
||||
- clocks = <&clocks 28/*BCM2835_CLOCK_EMMC*/>;
|
||||
- dmas = <&dma 11>;
|
||||
- dma-names = "rx-tx";
|
||||
- brcm,overclock-50 = <0>;
|
||||
- status = "okay";
|
||||
- pinctrl-names = "default";
|
||||
- pinctrl-0 = <&sdio_ovl_pins>;
|
||||
- non-removable;
|
||||
- bus-width = <4>;
|
||||
- };
|
||||
+ target = <&mmc>;
|
||||
+ sdio_ovl: __overlay__ {
|
||||
+ pinctrl-0 = <&sdio_ovl_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ non-removable;
|
||||
+ bus-width = <4>;
|
||||
+ status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -75,7 +62,7 @@
|
||||
fragment@6 {
|
||||
target-path = "/aliases";
|
||||
__overlay__ {
|
||||
- mmc1 = "/soc/sdio@7e300000";
|
||||
+ mmc1 = "/soc/mmc@7e300000";
|
||||
};
|
||||
};
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
From 277acd3db0cf7adebacd13c965a92f9d9ed86713 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 17 Sep 2018 09:22:21 +0100
|
||||
Subject: [PATCH 529/678] staging/vc04_services: Use correct cache line size
|
||||
|
||||
Use the compatible string in the DTB to select the correct cache line
|
||||
size for the SoC - 32 for BCM2835, and 64 for BCM2836 and BCM2837.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
.../interface/vchiq_arm/vchiq_2835_arm.c | 15 ++------
|
||||
.../interface/vchiq_arm/vchiq_arm.c | 35 +++++++++++++------
|
||||
.../interface/vchiq_arm/vchiq_arm.h | 5 +++
|
||||
3 files changed, 33 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
|
||||
index 85e881e454b4..7694a4fc7cac 100644
|
||||
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
|
||||
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
|
||||
@@ -117,7 +117,8 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo,
|
||||
int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
- struct rpi_firmware *fw = platform_get_drvdata(pdev);
|
||||
+ struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
+ struct rpi_firmware *fw = drvdata->fw;
|
||||
VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
|
||||
struct resource *res;
|
||||
void *slot_mem;
|
||||
@@ -135,17 +136,7 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
- /*
|
||||
- * The tempting L1_CACHE_BYTES macro doesn't work in the case of
|
||||
- * a kernel built with bcm2835_defconfig running on a BCM2836/7
|
||||
- * processor, hence the need for a runtime check. The dcache line size
|
||||
- * is encoded in one of the coprocessor registers, but there is no
|
||||
- * convenient way to access it short of embedded assembler, hence
|
||||
- * the use of read_cpuid_id(). The following test evaluates to true
|
||||
- * on a BCM2835 showing that it is ARMv6-ish, whereas
|
||||
- * cpu_architecture() will indicate that it is an ARMv7.
|
||||
- */
|
||||
- g_cache_line_size = ((read_cpuid_id() & 0x7f000) == 0x7b000) ? 32 : 64;
|
||||
+ g_cache_line_size = drvdata->cache_line_size;
|
||||
g_fragments_size = 2 * g_cache_line_size;
|
||||
|
||||
/* Allocate space for the channels in coherent memory */
|
||||
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
|
||||
index b955fe7915a8..a38b4a8b14c6 100644
|
||||
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
|
||||
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
|
||||
@@ -173,6 +173,14 @@ static struct platform_device *bcm2835_camera;
|
||||
static struct platform_device *bcm2835_codec;
|
||||
static struct platform_device *vcsm_cma;
|
||||
|
||||
+static struct vchiq_drvdata bcm2835_drvdata = {
|
||||
+ .cache_line_size = 32,
|
||||
+};
|
||||
+
|
||||
+static struct vchiq_drvdata bcm2836_drvdata = {
|
||||
+ .cache_line_size = 64,
|
||||
+};
|
||||
+
|
||||
static const char *const ioctl_names[] = {
|
||||
"CONNECT",
|
||||
"SHUTDOWN",
|
||||
@@ -3607,12 +3615,25 @@ vchiq_register_child(struct platform_device *pdev, const char *name)
|
||||
return new_dev;
|
||||
}
|
||||
|
||||
+static const struct of_device_id vchiq_of_match[] = {
|
||||
+ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
|
||||
+ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, vchiq_of_match);
|
||||
+
|
||||
static int vchiq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *fw_node;
|
||||
- struct rpi_firmware *fw;
|
||||
+ const struct of_device_id *of_id;
|
||||
+ struct vchiq_drvdata *drvdata;
|
||||
int err;
|
||||
|
||||
+ of_id = of_match_node(vchiq_of_match, pdev->dev.of_node);
|
||||
+ drvdata = (struct vchiq_drvdata *)of_id->data;
|
||||
+ if (!drvdata)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
fw_node = of_find_compatible_node(NULL, NULL,
|
||||
"raspberrypi,bcm2835-firmware");
|
||||
if (!fw_node) {
|
||||
@@ -3620,12 +3641,12 @@ static int vchiq_probe(struct platform_device *pdev)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
- fw = rpi_firmware_get(fw_node);
|
||||
+ drvdata->fw = rpi_firmware_get(fw_node);
|
||||
of_node_put(fw_node);
|
||||
- if (!fw)
|
||||
+ if (!drvdata->fw)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
- platform_set_drvdata(pdev, fw);
|
||||
+ platform_set_drvdata(pdev, drvdata);
|
||||
|
||||
err = vchiq_platform_init(pdev, &g_state);
|
||||
if (err != 0)
|
||||
@@ -3703,12 +3724,6 @@ static int vchiq_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static const struct of_device_id vchiq_of_match[] = {
|
||||
- { .compatible = "brcm,bcm2835-vchiq", },
|
||||
- {},
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(of, vchiq_of_match);
|
||||
-
|
||||
static struct platform_driver vchiq_driver = {
|
||||
.driver = {
|
||||
.name = "bcm2835_vchiq",
|
||||
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
|
||||
index 40bb0c63b1a9..2f3ebc99cbcf 100644
|
||||
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
|
||||
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
|
||||
@@ -123,6 +123,11 @@ typedef struct vchiq_arm_state_struct {
|
||||
|
||||
} VCHIQ_ARM_STATE_T;
|
||||
|
||||
+struct vchiq_drvdata {
|
||||
+ const unsigned int cache_line_size;
|
||||
+ struct rpi_firmware *fw;
|
||||
+};
|
||||
+
|
||||
extern int vchiq_arm_log_level;
|
||||
extern int vchiq_susp_log_level;
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From f86ed460ad9827b247298e2cf1d271027fcba0a0 Mon Sep 17 00:00:00 2001
|
||||
From: Doug Berger <opendmb@gmail.com>
|
||||
Date: Mon, 13 May 2019 20:59:45 +0200
|
||||
Subject: [PATCH 530/678] tty: amba-pl011: allow shared interrupt
|
||||
|
||||
The PL011 register space includes all necessary status bits to
|
||||
determine whether a device instance requires handling in response
|
||||
to an interrupt. Therefore, multiple instances of the device could
|
||||
be serviced by a single shared interrupt, which is the case on BCM7211.
|
||||
|
||||
Signed-off-by: Doug Berger <opendmb@gmail.com>
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
---
|
||||
drivers/tty/serial/amba-pl011.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||||
index 6f15f32fa194..1121df572ca6 100644
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -1735,7 +1735,8 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
|
||||
{
|
||||
pl011_write(uap->im, uap, REG_IMSC);
|
||||
|
||||
- return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
|
||||
+ return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011",
|
||||
+ uap);
|
||||
}
|
||||
|
||||
/*
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
From a29a9c8067beb1cb7dbed5f25ac81458e62142f4 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <wahrenst@gmx.net>
|
||||
Date: Sun, 19 May 2019 12:20:00 +0200
|
||||
Subject: [PATCH 531/678] ARM: bcm283x: Reduce register ranges for UART, SPI
|
||||
and I2C
|
||||
|
||||
The assigned register ranges for UART, SPI and I2C were too wasteful.
|
||||
In order to avoid overlapping with the new functions on BCM2838
|
||||
reduce the ranges.
|
||||
|
||||
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
|
||||
---
|
||||
arch/arm/boot/dts/bcm283x.dtsi | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
index 1b53339a1c57..ded463cec30c 100644
|
||||
--- a/arch/arm/boot/dts/bcm283x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
@@ -387,7 +387,7 @@
|
||||
|
||||
uart0: serial@7e201000 {
|
||||
compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
|
||||
- reg = <0x7e201000 0x1000>;
|
||||
+ reg = <0x7e201000 0x200>;
|
||||
interrupts = <2 25>;
|
||||
clocks = <&clocks BCM2835_CLOCK_UART>,
|
||||
<&clocks BCM2835_CLOCK_VPU>;
|
||||
@@ -418,7 +418,7 @@
|
||||
|
||||
spi: spi@7e204000 {
|
||||
compatible = "brcm,bcm2835-spi";
|
||||
- reg = <0x7e204000 0x1000>;
|
||||
+ reg = <0x7e204000 0x200>;
|
||||
interrupts = <2 22>;
|
||||
clocks = <&clocks BCM2835_CLOCK_VPU>;
|
||||
#address-cells = <1>;
|
||||
@@ -428,7 +428,7 @@
|
||||
|
||||
i2c0: i2c@7e205000 {
|
||||
compatible = "brcm,bcm2835-i2c";
|
||||
- reg = <0x7e205000 0x1000>;
|
||||
+ reg = <0x7e205000 0x200>;
|
||||
interrupts = <2 21>;
|
||||
clocks = <&clocks BCM2835_CLOCK_VPU>;
|
||||
#address-cells = <1>;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From c373e88e0a64ce7de6ca250c3d32c0850d0b016c Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 12 Dec 2018 15:51:49 -0800
|
||||
Subject: [PATCH 532/678] ARM: bcm283x: Extend the WDT DT node out to cover the
|
||||
whole PM block. (v4)
|
||||
|
||||
It was covering part of the PM block's range, up to the WDT regs. To
|
||||
support the rest of the PM block's functionality, we need the full
|
||||
register range plus the AXI Async Bridge regs for PM sequencing.
|
||||
|
||||
This doesn't convert any of the consumers over to the new binding yet,
|
||||
since we will need to be careful in coordinating our usage of firmware
|
||||
services that might power domains on and off versus the bcm2835-pm
|
||||
driver's access of those same domains.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
(cherry picked from commit 29abc92c1d93e28a8f4d55e6343eec4faf44025a)
|
||||
---
|
||||
arch/arm/boot/dts/bcm283x.dtsi | 13 +++++++++++--
|
||||
1 file changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
index ded463cec30c..334c0dffc450 100644
|
||||
--- a/arch/arm/boot/dts/bcm283x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
@@ -121,8 +121,17 @@
|
||||
};
|
||||
|
||||
watchdog@7e100000 {
|
||||
- compatible = "brcm,bcm2835-pm-wdt";
|
||||
- reg = <0x7e100000 0x28>;
|
||||
+ 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 {
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
From 76313dda813c29e6f185b63338a499b63401ffbc Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <wahrenst@gmx.net>
|
||||
Date: Sat, 4 May 2019 17:06:54 +0200
|
||||
Subject: [PATCH 533/678] ARM: dts: Add label to bcm2835 RNG
|
||||
|
||||
---
|
||||
arch/arm/boot/dts/bcm283x.dtsi | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
index 334c0dffc450..65f666e41fa7 100644
|
||||
--- a/arch/arm/boot/dts/bcm283x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm283x.dtsi
|
||||
@@ -148,7 +148,7 @@
|
||||
<&dsi1 0>, <&dsi1 1>, <&dsi1 2>;
|
||||
};
|
||||
|
||||
- rng@7e104000 {
|
||||
+ rng: rng@7e104000 {
|
||||
compatible = "brcm,bcm2835-rng";
|
||||
reg = <0x7e104000 0x10>;
|
||||
interrupts = <2 29>;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
From ac938a20520a9e80899c13c695660c7fdf50cfaa Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Thu, 12 Oct 2017 18:11:32 +0100
|
||||
Subject: [PATCH 534/678] dts: Use fb rather than leds for dpi overlay
|
||||
|
||||
---
|
||||
arch/arm/boot/dts/overlays/dpi18-overlay.dts | 2 +-
|
||||
arch/arm/boot/dts/overlays/dpi24-overlay.dts | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/overlays/dpi18-overlay.dts b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
|
||||
index 64dc2dd42150..4bf5ef832747 100644
|
||||
--- a/arch/arm/boot/dts/overlays/dpi18-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/dpi18-overlay.dts
|
||||
@@ -9,7 +9,7 @@
|
||||
// reference on - leds will do
|
||||
|
||||
fragment@0 {
|
||||
- target = <&leds>;
|
||||
+ target = <&fb>;
|
||||
__overlay__ {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&dpi18_pins>;
|
||||
diff --git a/arch/arm/boot/dts/overlays/dpi24-overlay.dts b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
|
||||
index 6021bc33b5af..d5f7c3f58890 100644
|
||||
--- a/arch/arm/boot/dts/overlays/dpi24-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/dpi24-overlay.dts
|
||||
@@ -9,7 +9,7 @@
|
||||
// reference on - leds will do
|
||||
|
||||
fragment@0 {
|
||||
- target = <&leds>;
|
||||
+ target = <&fb>;
|
||||
__overlay__ {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&dpi24_pins>;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
From 711cca4250649d13fd805fa9025c3377f957b0bc Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 29 May 2019 15:19:21 +0100
|
||||
Subject: [PATCH 535/678] BCM270X_DT: Minor tidy up
|
||||
|
||||
Move arm_pmu out of soc on bcm2710, and labels aren't aliases.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
arch/arm/boot/dts/bcm270x.dtsi | 14 +++++++-------
|
||||
arch/arm/boot/dts/bcm2710.dtsi | 13 +++++--------
|
||||
2 files changed, 12 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/bcm270x.dtsi b/arch/arm/boot/dts/bcm270x.dtsi
|
||||
index 86f3eb2d3f48..3b6c101dcd91 100644
|
||||
--- a/arch/arm/boot/dts/bcm270x.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm270x.dtsi
|
||||
@@ -10,11 +10,11 @@
|
||||
soc: soc {
|
||||
|
||||
watchdog: watchdog@7e100000 {
|
||||
- /* Add alias */
|
||||
+ /* Add label */
|
||||
};
|
||||
|
||||
random: rng@7e104000 {
|
||||
- /* Add alias */
|
||||
+ /* Add label */
|
||||
};
|
||||
|
||||
gpio@7e200000 { /* gpio */
|
||||
@@ -40,18 +40,18 @@
|
||||
};
|
||||
|
||||
spi0: spi@7e204000 {
|
||||
- /* Add alias */
|
||||
+ /* Add label */
|
||||
dmas = <&dma 6>, <&dma 7>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
|
||||
pixelvalve0: pixelvalve@7e206000 {
|
||||
- /* Add alias */
|
||||
+ /* Add label */
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pixelvalve1: pixelvalve@7e207000 {
|
||||
- /* Add alias */
|
||||
+ /* Add label */
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
};
|
||||
|
||||
hvs: hvs@7e400000 {
|
||||
- /* Add alias */
|
||||
+ /* Add label */
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
};
|
||||
|
||||
pixelvalve2: pixelvalve@7e807000 {
|
||||
- /* Add alias */
|
||||
+ /* Add label */
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
diff --git a/arch/arm/boot/dts/bcm2710.dtsi b/arch/arm/boot/dts/bcm2710.dtsi
|
||||
index 56d58f588203..7628ca59f028 100644
|
||||
--- a/arch/arm/boot/dts/bcm2710.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm2710.dtsi
|
||||
@@ -5,18 +5,15 @@
|
||||
/ {
|
||||
compatible = "brcm,bcm2837", "brcm,bcm2836";
|
||||
|
||||
- soc {
|
||||
-
|
||||
- arm-pmu {
|
||||
+ arm-pmu {
|
||||
#ifdef RPI364
|
||||
- compatible = "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
|
||||
+ compatible = "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
|
||||
#else
|
||||
- compatible = "arm,cortex-a7-pmu";
|
||||
+ compatible = "arm,cortex-a7-pmu";
|
||||
#endif
|
||||
- interrupt-parent = <&local_intc>;
|
||||
- interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
|
||||
- };
|
||||
+ };
|
||||
|
||||
+ soc {
|
||||
/delete-node/ timer@7e003000;
|
||||
};
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
From c528b0bc35cbf689c72bcb1386ab84a853d02957 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 20 Feb 2019 08:49:39 +0000
|
||||
Subject: [PATCH 536/678] 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 <phil@raspberrypi.org>
|
||||
---
|
||||
arch/arm/mach-bcm/board_bcm2835.c | 21 +++++++++++++++------
|
||||
1 file changed, 15 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/mach-bcm/board_bcm2835.c b/arch/arm/mach-bcm/board_bcm2835.c
|
||||
index 28db892e3af4..db426d73d963 100644
|
||||
--- a/arch/arm/mach-bcm/board_bcm2835.c
|
||||
+++ b/arch/arm/mach-bcm/board_bcm2835.c
|
||||
@@ -14,17 +14,20 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/irqchip.h>
|
||||
+#include <linux/mm.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <asm/system_info.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
+#include <asm/memory.h>
|
||||
+#include <asm/pgtable.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
@@ -83,20 +86,26 @@ static int __init bcm2835_map_usb(unsigned long node, const char *uname,
|
||||
|
||||
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);
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
From 2e10dde86defb0fdb0126440199b365b7c6ea03f Mon Sep 17 00:00:00 2001
|
||||
From: Tim Gover <tim.gover@raspberrypi.org>
|
||||
Date: Thu, 14 Mar 2019 10:16:02 +0000
|
||||
Subject: [PATCH 537/678] 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(+)
|
||||
|
||||
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
|
||||
index 1ea66521768d..d4b04afc6411 100644
|
||||
--- a/arch/arm/lib/uaccess_with_memcpy.c
|
||||
+++ b/arch/arm/lib/uaccess_with_memcpy.c
|
||||
@@ -257,6 +257,7 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
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
|
||||
@@ -271,6 +272,11 @@ arm_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
} 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;
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,574 @@
|
|||
From 6bfa7e5836f3f94b73c82136b9eef54ef9318dde Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 19 Feb 2019 22:06:59 +0000
|
||||
Subject: [PATCH 539/678] PCI: brcmstb: Add dma-range mapping for inbound
|
||||
traffic
|
||||
|
||||
The Broadcom STB PCIe host controller is intimately related to the
|
||||
memory subsystem. This close relationship adds complexity to how cpu
|
||||
system memory is mapped to PCIe memory. Ideally, this mapping is an
|
||||
identity mapping, or an identity mapping off by a constant. Not so in
|
||||
this case.
|
||||
|
||||
Consider the Broadcom reference board BCM97445LCC_4X8 which has 6 GB
|
||||
of system memory. Here is how the PCIe controller maps the
|
||||
system memory to PCIe memory:
|
||||
|
||||
memc0-a@[ 0....3fffffff] <=> pci@[ 0....3fffffff]
|
||||
memc0-b@[100000000...13fffffff] <=> pci@[ 40000000....7fffffff]
|
||||
memc1-a@[ 40000000....7fffffff] <=> pci@[ 80000000....bfffffff]
|
||||
memc1-b@[300000000...33fffffff] <=> pci@[ c0000000....ffffffff]
|
||||
memc2-a@[ 80000000....bfffffff] <=> pci@[100000000...13fffffff]
|
||||
memc2-b@[c00000000...c3fffffff] <=> pci@[140000000...17fffffff]
|
||||
|
||||
Although there are some "gaps" that can be added between the
|
||||
individual mappings by software, the permutation of memory regions for
|
||||
the most part is fixed by HW. The solution of having something close
|
||||
to an identity mapping is not possible.
|
||||
|
||||
The idea behind this HW design is that the same PCIe module can
|
||||
act as an RC or EP, and if it acts as an EP it concatenates all
|
||||
of system memory into a BAR so anything can be accessed. Unfortunately,
|
||||
when the PCIe block is in the role of an RC it also presents this
|
||||
"BAR" to downstream PCIe devices, rather than offering an identity map
|
||||
between its system memory and PCIe space.
|
||||
|
||||
Suppose that an endpoint driver allocs some DMA memory. Suppose this
|
||||
memory is located at 0x6000_0000, which is in the middle of memc1-a.
|
||||
The driver wants a dma_addr_t value that it can pass on to the EP to
|
||||
use. Without doing any custom mapping, the EP will use this value for
|
||||
DMA: the driver will get a dma_addr_t equal to 0x6000_0000. But this
|
||||
won't work; the device needs a dma_addr_t that reflects the PCIe space
|
||||
address, namely 0xa000_0000.
|
||||
|
||||
So, essentially the solution to this problem must modify the
|
||||
dma_addr_t returned by the DMA routines routines. There are two
|
||||
ways (I know of) of doing this:
|
||||
|
||||
(a) overriding/redefining the dma_to_phys() and phys_to_dma() calls
|
||||
that are used by the dma_ops routines. This is the approach of
|
||||
|
||||
arch/mips/cavium-octeon/dma-octeon.c
|
||||
|
||||
In ARM and ARM64 these two routines are defiend in asm/dma-mapping.h
|
||||
as static inline functions.
|
||||
|
||||
(b) Subscribe to a notifier that notifies when a device is added to a
|
||||
bus. When this happens, set_dma_ops() can be called for the device.
|
||||
This method is mentioned in:
|
||||
|
||||
http://lxr.free-electrons.com/source/drivers/of/platform.c?v=3.16#L152
|
||||
|
||||
where it says as a comment
|
||||
|
||||
"In case if platform code need to use own special DMA
|
||||
configuration, it can use Platform bus notifier and
|
||||
handle BUS_NOTIFY_ADD_DEVICE event to fix up DMA
|
||||
configuration."
|
||||
|
||||
Solution (b) is what this commit does. It uses its own set of
|
||||
dma_ops which are wrappers around the arch_dma_ops. The
|
||||
wrappers translate the dma addresses before/after invoking
|
||||
the arch_dma_ops, as appropriate.
|
||||
|
||||
Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
|
||||
---
|
||||
drivers/pci/controller/pcie-brcmstb.c | 420 +++++++++++++++++++++++++-
|
||||
1 file changed, 411 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
|
||||
index babef9191e88..27bcf83c99d7 100644
|
||||
--- a/drivers/pci/controller/pcie-brcmstb.c
|
||||
+++ b/drivers/pci/controller/pcie-brcmstb.c
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/delay.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
@@ -319,11 +320,307 @@ static struct pci_ops brcm_pcie_ops = {
|
||||
((val & ~reg##_##field##_MASK) | \
|
||||
(reg##_##field##_MASK & (field_val << reg##_##field##_SHIFT)))
|
||||
|
||||
+static const struct dma_map_ops *arch_dma_ops;
|
||||
+static const struct dma_map_ops *brcm_dma_ops_ptr;
|
||||
+static struct of_pci_range *dma_ranges;
|
||||
+static int num_dma_ranges;
|
||||
+
|
||||
static phys_addr_t scb_size[BRCM_MAX_SCB];
|
||||
static int num_memc;
|
||||
static int num_pcie;
|
||||
static DEFINE_MUTEX(brcm_pcie_lock);
|
||||
|
||||
+static dma_addr_t brcm_to_pci(dma_addr_t addr)
|
||||
+{
|
||||
+ struct of_pci_range *p;
|
||||
+
|
||||
+ if (!num_dma_ranges)
|
||||
+ return addr;
|
||||
+
|
||||
+ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
|
||||
+ if (addr >= p->cpu_addr && addr < (p->cpu_addr + p->size))
|
||||
+ return addr - p->cpu_addr + p->pci_addr;
|
||||
+
|
||||
+ return addr;
|
||||
+}
|
||||
+
|
||||
+static dma_addr_t brcm_to_cpu(dma_addr_t addr)
|
||||
+{
|
||||
+ struct of_pci_range *p;
|
||||
+
|
||||
+ if (!num_dma_ranges)
|
||||
+ return addr;
|
||||
+
|
||||
+ for (p = dma_ranges; p < &dma_ranges[num_dma_ranges]; p++)
|
||||
+ if (addr >= p->pci_addr && addr < (p->pci_addr + p->size))
|
||||
+ return addr - p->pci_addr + p->cpu_addr;
|
||||
+
|
||||
+ return addr;
|
||||
+}
|
||||
+
|
||||
+static void *brcm_alloc(struct device *dev, size_t size, dma_addr_t *handle,
|
||||
+ gfp_t gfp, unsigned long attrs)
|
||||
+{
|
||||
+ void *ret;
|
||||
+
|
||||
+ ret = arch_dma_ops->alloc(dev, size, handle, gfp, attrs);
|
||||
+ if (ret)
|
||||
+ *handle = brcm_to_pci(*handle);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void brcm_free(struct device *dev, size_t size, void *cpu_addr,
|
||||
+ dma_addr_t handle, unsigned long attrs)
|
||||
+{
|
||||
+ handle = brcm_to_cpu(handle);
|
||||
+ arch_dma_ops->free(dev, size, cpu_addr, handle, attrs);
|
||||
+}
|
||||
+
|
||||
+static int brcm_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ dma_addr = brcm_to_cpu(dma_addr);
|
||||
+ return arch_dma_ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
|
||||
+}
|
||||
+
|
||||
+static int brcm_get_sgtable(struct device *dev, struct sg_table *sgt,
|
||||
+ void *cpu_addr, dma_addr_t handle, size_t size,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ handle = brcm_to_cpu(handle);
|
||||
+ return arch_dma_ops->get_sgtable(dev, sgt, cpu_addr, handle, size,
|
||||
+ attrs);
|
||||
+}
|
||||
+
|
||||
+static dma_addr_t brcm_map_page(struct device *dev, struct page *page,
|
||||
+ unsigned long offset, size_t size,
|
||||
+ enum dma_data_direction dir,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ return brcm_to_pci(arch_dma_ops->map_page(dev, page, offset, size,
|
||||
+ dir, attrs));
|
||||
+}
|
||||
+
|
||||
+static void brcm_unmap_page(struct device *dev, dma_addr_t handle,
|
||||
+ size_t size, enum dma_data_direction dir,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ handle = brcm_to_cpu(handle);
|
||||
+ arch_dma_ops->unmap_page(dev, handle, size, dir, attrs);
|
||||
+}
|
||||
+
|
||||
+static int brcm_map_sg(struct device *dev, struct scatterlist *sgl,
|
||||
+ int nents, enum dma_data_direction dir,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ int i, j;
|
||||
+ struct scatterlist *sg;
|
||||
+
|
||||
+ for_each_sg(sgl, sg, nents, i) {
|
||||
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
|
||||
+ sg->dma_length = sg->length;
|
||||
+#endif
|
||||
+ sg->dma_address =
|
||||
+ brcm_dma_ops_ptr->map_page(dev, sg_page(sg), sg->offset,
|
||||
+ sg->length, dir, attrs);
|
||||
+ if (dma_mapping_error(dev, sg->dma_address))
|
||||
+ goto bad_mapping;
|
||||
+ }
|
||||
+ return nents;
|
||||
+
|
||||
+bad_mapping:
|
||||
+ for_each_sg(sgl, sg, i, j)
|
||||
+ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
|
||||
+ sg_dma_len(sg), dir, attrs);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void brcm_unmap_sg(struct device *dev,
|
||||
+ struct scatterlist *sgl, int nents,
|
||||
+ enum dma_data_direction dir,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct scatterlist *sg;
|
||||
+
|
||||
+ for_each_sg(sgl, sg, nents, i)
|
||||
+ brcm_dma_ops_ptr->unmap_page(dev, sg_dma_address(sg),
|
||||
+ sg_dma_len(sg), dir, attrs);
|
||||
+}
|
||||
+
|
||||
+static void brcm_sync_single_for_cpu(struct device *dev,
|
||||
+ dma_addr_t handle, size_t size,
|
||||
+ enum dma_data_direction dir)
|
||||
+{
|
||||
+ handle = brcm_to_cpu(handle);
|
||||
+ arch_dma_ops->sync_single_for_cpu(dev, handle, size, dir);
|
||||
+}
|
||||
+
|
||||
+static void brcm_sync_single_for_device(struct device *dev,
|
||||
+ dma_addr_t handle, size_t size,
|
||||
+ enum dma_data_direction dir)
|
||||
+{
|
||||
+ handle = brcm_to_cpu(handle);
|
||||
+ arch_dma_ops->sync_single_for_device(dev, handle, size, dir);
|
||||
+}
|
||||
+
|
||||
+static dma_addr_t brcm_map_resource(struct device *dev, phys_addr_t phys,
|
||||
+ size_t size,
|
||||
+ enum dma_data_direction dir,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ if (arch_dma_ops->map_resource)
|
||||
+ return brcm_to_pci(arch_dma_ops->map_resource
|
||||
+ (dev, phys, size, dir, attrs));
|
||||
+ return brcm_to_pci((dma_addr_t)phys);
|
||||
+}
|
||||
+
|
||||
+static void brcm_unmap_resource(struct device *dev, dma_addr_t handle,
|
||||
+ size_t size, enum dma_data_direction dir,
|
||||
+ unsigned long attrs)
|
||||
+{
|
||||
+ if (arch_dma_ops->unmap_resource)
|
||||
+ arch_dma_ops->unmap_resource(dev, brcm_to_cpu(handle), size,
|
||||
+ dir, attrs);
|
||||
+}
|
||||
+
|
||||
+void brcm_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
|
||||
+ int nents, enum dma_data_direction dir)
|
||||
+{
|
||||
+ struct scatterlist *sg;
|
||||
+ int i;
|
||||
+
|
||||
+ for_each_sg(sgl, sg, nents, i)
|
||||
+ brcm_dma_ops_ptr->sync_single_for_cpu(dev, sg_dma_address(sg),
|
||||
+ sg->length, dir);
|
||||
+}
|
||||
+
|
||||
+void brcm_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
|
||||
+ int nents, enum dma_data_direction dir)
|
||||
+{
|
||||
+ struct scatterlist *sg;
|
||||
+ int i;
|
||||
+
|
||||
+ for_each_sg(sgl, sg, nents, i)
|
||||
+ brcm_dma_ops_ptr->sync_single_for_device(dev,
|
||||
+ sg_dma_address(sg),
|
||||
+ sg->length, dir);
|
||||
+}
|
||||
+
|
||||
+static int brcm_mapping_error(struct device *dev, dma_addr_t dma_addr)
|
||||
+{
|
||||
+ return arch_dma_ops->mapping_error(dev, dma_addr);
|
||||
+}
|
||||
+
|
||||
+static int brcm_dma_supported(struct device *dev, u64 mask)
|
||||
+{
|
||||
+ if (num_dma_ranges) {
|
||||
+ /*
|
||||
+ * It is our translated addresses that the EP will "see", so
|
||||
+ * we check all of the ranges for the largest possible value.
|
||||
+ */
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < num_dma_ranges; i++)
|
||||
+ if (dma_ranges[i].pci_addr + dma_ranges[i].size - 1
|
||||
+ > mask)
|
||||
+ return 0;
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return arch_dma_ops->dma_supported(dev, mask);
|
||||
+}
|
||||
+
|
||||
+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
|
||||
+u64 brcm_get_required_mask)(struct device *dev)
|
||||
+{
|
||||
+ return arch_dma_ops->get_required_mask(dev);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static const struct dma_map_ops brcm_dma_ops = {
|
||||
+ .alloc = brcm_alloc,
|
||||
+ .free = brcm_free,
|
||||
+ .mmap = brcm_mmap,
|
||||
+ .get_sgtable = brcm_get_sgtable,
|
||||
+ .map_page = brcm_map_page,
|
||||
+ .unmap_page = brcm_unmap_page,
|
||||
+ .map_sg = brcm_map_sg,
|
||||
+ .unmap_sg = brcm_unmap_sg,
|
||||
+ .map_resource = brcm_map_resource,
|
||||
+ .unmap_resource = brcm_unmap_resource,
|
||||
+ .sync_single_for_cpu = brcm_sync_single_for_cpu,
|
||||
+ .sync_single_for_device = brcm_sync_single_for_device,
|
||||
+ .sync_sg_for_cpu = brcm_sync_sg_for_cpu,
|
||||
+ .sync_sg_for_device = brcm_sync_sg_for_device,
|
||||
+ .mapping_error = brcm_mapping_error,
|
||||
+ .dma_supported = brcm_dma_supported,
|
||||
+#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
|
||||
+ .get_required_mask = brcm_get_required_mask,
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static void brcm_set_dma_ops(struct device *dev)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_ARM64)) {
|
||||
+ /*
|
||||
+ * We are going to invoke get_dma_ops(). That
|
||||
+ * function, at this point in time, invokes
|
||||
+ * get_arch_dma_ops(), and for ARM64 that function
|
||||
+ * returns a pointer to dummy_dma_ops. So then we'd
|
||||
+ * like to call arch_setup_dma_ops(), but that isn't
|
||||
+ * exported. Instead, we call of_dma_configure(),
|
||||
+ * which is exported, and this calls
|
||||
+ * arch_setup_dma_ops(). Once we do this the call to
|
||||
+ * get_dma_ops() will work properly because
|
||||
+ * dev->dma_ops will be set.
|
||||
+ */
|
||||
+ ret = of_dma_configure(dev, dev->of_node, true);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "of_dma_configure() failed: %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ arch_dma_ops = get_dma_ops(dev);
|
||||
+ if (!arch_dma_ops) {
|
||||
+ dev_err(dev, "failed to get arch_dma_ops\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ set_dma_ops(dev, &brcm_dma_ops);
|
||||
+}
|
||||
+
|
||||
+static int brcmstb_platform_notifier(struct notifier_block *nb,
|
||||
+ unsigned long event, void *__dev)
|
||||
+{
|
||||
+ struct device *dev = __dev;
|
||||
+
|
||||
+ brcm_dma_ops_ptr = &brcm_dma_ops;
|
||||
+ if (event != BUS_NOTIFY_ADD_DEVICE)
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ brcm_set_dma_ops(dev);
|
||||
+ return NOTIFY_OK;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block brcmstb_platform_nb = {
|
||||
+ .notifier_call = brcmstb_platform_notifier,
|
||||
+};
|
||||
+
|
||||
+static int brcm_register_notifier(void)
|
||||
+{
|
||||
+ return bus_register_notifier(&pci_bus_type, &brcmstb_platform_nb);
|
||||
+}
|
||||
+
|
||||
+static int brcm_unregister_notifier(void)
|
||||
+{
|
||||
+ return bus_unregister_notifier(&pci_bus_type, &brcmstb_platform_nb);
|
||||
+}
|
||||
+
|
||||
static u32 rd_fld(void __iomem *p, u32 mask, int shift)
|
||||
{
|
||||
return (bcm_readl(p) & mask) >> shift;
|
||||
@@ -597,9 +894,71 @@ static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie,
|
||||
WR_FLD_RB(pcie->base, PCIE_MISC_PCIE_CTRL, PCIE_PERSTB, !val);
|
||||
}
|
||||
|
||||
+static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
|
||||
+ struct device_node *node)
|
||||
+{
|
||||
+ const int na = 3, ns = 2;
|
||||
+ int rlen;
|
||||
+
|
||||
+ parser->node = node;
|
||||
+ parser->pna = of_n_addr_cells(node);
|
||||
+ parser->np = parser->pna + na + ns;
|
||||
+
|
||||
+ parser->range = of_get_property(node, "dma-ranges", &rlen);
|
||||
+ if (!parser->range)
|
||||
+ return -ENOENT;
|
||||
+
|
||||
+ parser->end = parser->range + rlen / sizeof(__be32);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int brcm_pcie_parse_map_dma_ranges(struct brcm_pcie *pcie)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct of_pci_range_parser parser;
|
||||
+ struct device_node *dn = pcie->dn;
|
||||
+
|
||||
+ /*
|
||||
+ * Parse dma-ranges property if present. If there are multiple
|
||||
+ * PCIe controllers, we only have to parse from one of them since
|
||||
+ * the others will have an identical mapping.
|
||||
+ */
|
||||
+ if (!pci_dma_range_parser_init(&parser, dn)) {
|
||||
+ unsigned int max_ranges
|
||||
+ = (parser.end - parser.range) / parser.np;
|
||||
+
|
||||
+ dma_ranges = kcalloc(max_ranges, sizeof(struct of_pci_range),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!dma_ranges)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (i = 0; of_pci_range_parser_one(&parser, dma_ranges + i);
|
||||
+ i++)
|
||||
+ num_dma_ranges++;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
|
||||
+ u64 size = brcmstb_memory_memc_size(i);
|
||||
+
|
||||
+ if (size == (u64)-1) {
|
||||
+ dev_err(pcie->dev, "cannot get memc%d size", i);
|
||||
+ return -EINVAL;
|
||||
+ } else if (size) {
|
||||
+ scb_size[i] = roundup_pow_of_two_64(size);
|
||||
+ num_memc++;
|
||||
+ } else {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
|
||||
{
|
||||
int i, ret = 0;
|
||||
+ struct device *dev = pcie->dev;
|
||||
|
||||
mutex_lock(&brcm_pcie_lock);
|
||||
if (num_pcie > 0) {
|
||||
@@ -607,12 +966,21 @@ static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
|
||||
goto done;
|
||||
}
|
||||
|
||||
+ ret = brcm_register_notifier();
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "failed to register pci bus notifier\n");
|
||||
+ goto done;
|
||||
+ }
|
||||
+ ret = brcm_pcie_parse_map_dma_ranges(pcie);
|
||||
+ if (ret)
|
||||
+ goto done;
|
||||
+
|
||||
/* Determine num_memc and their sizes */
|
||||
for (i = 0, num_memc = 0; i < BRCM_MAX_SCB; i++) {
|
||||
u64 size = brcmstb_memory_memc_size(i);
|
||||
|
||||
if (size == (u64)-1) {
|
||||
- dev_err(pcie->dev, "cannot get memc%d size\n", i);
|
||||
+ dev_err(dev, "cannot get memc%d size\n", i);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
} else if (size) {
|
||||
@@ -636,8 +1004,16 @@ static int brcm_pcie_add_controller(struct brcm_pcie *pcie)
|
||||
static void brcm_pcie_remove_controller(struct brcm_pcie *pcie)
|
||||
{
|
||||
mutex_lock(&brcm_pcie_lock);
|
||||
- if (--num_pcie == 0)
|
||||
- num_memc = 0;
|
||||
+ if (--num_pcie > 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (brcm_unregister_notifier())
|
||||
+ dev_err(pcie->dev, "failed to unregister pci bus notifier\n");
|
||||
+ kfree(dma_ranges);
|
||||
+ dma_ranges = NULL;
|
||||
+ num_dma_ranges = 0;
|
||||
+ num_memc = 0;
|
||||
+out:
|
||||
mutex_unlock(&brcm_pcie_lock);
|
||||
}
|
||||
|
||||
@@ -757,6 +1133,38 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
*/
|
||||
rc_bar2_offset = 0;
|
||||
|
||||
+ if (dma_ranges) {
|
||||
+ /*
|
||||
+ * The best-case scenario is to place the inbound
|
||||
+ * region in the first 4GB of pci-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 (total_mem_size <= 0xc0000000ULL &&
|
||||
+ rc_bar2_size <= 0x100000000ULL) {
|
||||
+ rc_bar2_offset = 0;
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * The system memory is 4GB or larger so we
|
||||
+ * cannot start the inbound region at location
|
||||
+ * 0 (since we have to allow some space for
|
||||
+ * outbound memory @ 3GB). So instead we
|
||||
+ * start it at the 1x multiple of its size
|
||||
+ */
|
||||
+ rc_bar2_offset = rc_bar2_size;
|
||||
+ }
|
||||
+
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * Set simple configuration based on memory sizes
|
||||
+ * only. We always start the viewport at address 0,
|
||||
+ * and set the MSI target address accordingly.
|
||||
+ */
|
||||
+ rc_bar2_offset = 0;
|
||||
+ }
|
||||
+
|
||||
tmp = lower_32_bits(rc_bar2_offset);
|
||||
tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
|
||||
encode_ibar_size(rc_bar2_size));
|
||||
@@ -967,7 +1375,6 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
struct brcm_pcie *pcie;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
- u32 tmp;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct pci_bus *child;
|
||||
|
||||
@@ -984,11 +1391,6 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if (of_property_read_u32(dn, "dma-ranges", &tmp) == 0) {
|
||||
- dev_err(&pdev->dev, "cannot yet handle dma-ranges\n");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
data = of_id->data;
|
||||
pcie->reg_offsets = data->offsets;
|
||||
pcie->reg_field_info = data->reg_field_info;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,548 @@
|
|||
From 6fbefe88547929eff37b094b0704203f5bbfdc80 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 19 Feb 2019 22:06:59 +0000
|
||||
Subject: [PATCH 540/678] PCI: brcmstb: Add MSI capability
|
||||
|
||||
This commit adds MSI to the Broadcom STB PCIe host controller. It does
|
||||
not add MSIX since that functionality is not in the HW. 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.
|
||||
|
||||
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 <jim2101024@gmail.com>
|
||||
---
|
||||
drivers/pci/controller/pcie-brcmstb.c | 374 ++++++++++++++++++++++++--
|
||||
1 file changed, 353 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
|
||||
index 27bcf83c99d7..b028d4be81a2 100644
|
||||
--- a/drivers/pci/controller/pcie-brcmstb.c
|
||||
+++ b/drivers/pci/controller/pcie-brcmstb.c
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (C) 2009 - 2017 Broadcom */
|
||||
|
||||
+#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -9,11 +10,13 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
+#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/msi.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_pci.h>
|
||||
@@ -47,6 +50,9 @@
|
||||
#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
|
||||
#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
|
||||
#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
|
||||
+#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_PCIE_CTRL 0x4064
|
||||
#define PCIE_MISC_PCIE_STATUS 0x4068
|
||||
#define PCIE_MISC_REVISION 0x406c
|
||||
@@ -55,6 +61,7 @@
|
||||
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
|
||||
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
|
||||
#define PCIE_INTR2_CPU_BASE 0x4300
|
||||
+#define PCIE_MSI_INTR2_BASE 0x4500
|
||||
|
||||
/*
|
||||
* Broadcom Settop Box PCIe Register Field shift and mask info. The
|
||||
@@ -115,6 +122,8 @@
|
||||
|
||||
#define BRCM_NUM_PCIE_OUT_WINS 0x4
|
||||
#define BRCM_MAX_SCB 0x4
|
||||
+#define BRCM_INT_PCI_MSI_NR 32
|
||||
+#define BRCM_PCIE_HW_REV_33 0x0303
|
||||
|
||||
#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL
|
||||
#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL
|
||||
@@ -203,6 +212,33 @@ struct brcm_window {
|
||||
dma_addr_t size;
|
||||
};
|
||||
|
||||
+struct brcm_msi {
|
||||
+ struct device *dev;
|
||||
+ void __iomem *base;
|
||||
+ struct device_node *dn;
|
||||
+ struct irq_domain *msi_domain;
|
||||
+ struct irq_domain *inner_domain;
|
||||
+ struct mutex lock; /* guards the alloc/free operations */
|
||||
+ u64 target_addr;
|
||||
+ int irq;
|
||||
+
|
||||
+ /* intr_base is the base pointer for interrupt status/set/clr regs */
|
||||
+ void __iomem *intr_base;
|
||||
+
|
||||
+ /* intr_legacy_mask indicates how many bits are MSI interrupts */
|
||||
+ u32 intr_legacy_mask;
|
||||
+
|
||||
+ /*
|
||||
+ * intr_legacy_offset indicates bit position of MSI_01. It is
|
||||
+ * to map the register bit position to a hwirq that starts at 0.
|
||||
+ */
|
||||
+ u32 intr_legacy_offset;
|
||||
+
|
||||
+ /* used indicates which MSI interrupts have been alloc'd */
|
||||
+ unsigned long used;
|
||||
+ unsigned int rev;
|
||||
+};
|
||||
+
|
||||
/* Internal PCIe Host Controller Information.*/
|
||||
struct brcm_pcie {
|
||||
struct device *dev;
|
||||
@@ -217,7 +253,10 @@ struct brcm_pcie {
|
||||
int num_out_wins;
|
||||
bool ssc;
|
||||
int gen;
|
||||
+ u64 msi_target_addr;
|
||||
struct brcm_window out_wins[BRCM_NUM_PCIE_OUT_WINS];
|
||||
+ struct brcm_msi *msi;
|
||||
+ bool msi_internal;
|
||||
unsigned int rev;
|
||||
const int *reg_offsets;
|
||||
const int *reg_field_info;
|
||||
@@ -225,9 +264,9 @@ struct brcm_pcie {
|
||||
};
|
||||
|
||||
struct pcie_cfg_data {
|
||||
- const int *reg_field_info;
|
||||
- const int *offsets;
|
||||
- const enum pcie_type type;
|
||||
+ const int *reg_field_info;
|
||||
+ const int *offsets;
|
||||
+ const enum pcie_type type;
|
||||
};
|
||||
|
||||
static const int pcie_reg_field_info[] = {
|
||||
@@ -828,6 +867,267 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie,
|
||||
}
|
||||
}
|
||||
|
||||
+static struct irq_chip brcm_msi_irq_chip = {
|
||||
+ .name = "Brcm_MSI",
|
||||
+ .irq_mask = pci_msi_mask_irq,
|
||||
+ .irq_unmask = pci_msi_unmask_irq,
|
||||
+};
|
||||
+
|
||||
+static struct msi_domain_info brcm_msi_domain_info = {
|
||||
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
+ MSI_FLAG_PCI_MSIX),
|
||||
+ .chip = &brcm_msi_irq_chip,
|
||||
+};
|
||||
+
|
||||
+static void brcm_pcie_msi_isr(struct irq_desc *desc)
|
||||
+{
|
||||
+ struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
+ struct brcm_msi *msi;
|
||||
+ unsigned long status, virq;
|
||||
+ u32 mask, bit, hwirq;
|
||||
+ struct device *dev;
|
||||
+
|
||||
+ chained_irq_enter(chip, desc);
|
||||
+ msi = irq_desc_get_handler_data(desc);
|
||||
+ mask = msi->intr_legacy_mask;
|
||||
+ dev = msi->dev;
|
||||
+
|
||||
+ while ((status = bcm_readl(msi->intr_base + STATUS) & mask)) {
|
||||
+ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
|
||||
+ /* clear the interrupt */
|
||||
+ bcm_writel(1 << bit, msi->intr_base + CLR);
|
||||
+
|
||||
+ /* Account for legacy interrupt offset */
|
||||
+ hwirq = bit - msi->intr_legacy_offset;
|
||||
+
|
||||
+ virq = irq_find_mapping(msi->inner_domain, hwirq);
|
||||
+ if (virq) {
|
||||
+ if (msi->used & (1 << hwirq))
|
||||
+ generic_handle_irq(virq);
|
||||
+ else
|
||||
+ dev_info(dev, "unhandled MSI %d\n",
|
||||
+ hwirq);
|
||||
+ } else {
|
||||
+ /* Unknown MSI, just clear it */
|
||||
+ dev_dbg(dev, "unexpected MSI\n");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ chained_irq_exit(chip, desc);
|
||||
+}
|
||||
+
|
||||
+static void brcm_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
+{
|
||||
+ struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
|
||||
+ u32 temp;
|
||||
+
|
||||
+ msg->address_lo = lower_32_bits(msi->target_addr);
|
||||
+ msg->address_hi = upper_32_bits(msi->target_addr);
|
||||
+ temp = bcm_readl(msi->base + PCIE_MISC_MSI_DATA_CONFIG);
|
||||
+ msg->data = ((temp >> 16) & (temp & 0xffff)) | data->hwirq;
|
||||
+}
|
||||
+
|
||||
+static int brcm_msi_set_affinity(struct irq_data *irq_data,
|
||||
+ const struct cpumask *mask, bool force)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static struct irq_chip brcm_msi_bottom_irq_chip = {
|
||||
+ .name = "Brcm_MSI",
|
||||
+ .irq_compose_msi_msg = brcm_compose_msi_msg,
|
||||
+ .irq_set_affinity = brcm_msi_set_affinity,
|
||||
+};
|
||||
+
|
||||
+static int brcm_msi_alloc(struct brcm_msi *msi)
|
||||
+{
|
||||
+ int bit, hwirq;
|
||||
+
|
||||
+ mutex_lock(&msi->lock);
|
||||
+ bit = ~msi->used ? ffz(msi->used) : -1;
|
||||
+
|
||||
+ if (bit >= 0 && bit < BRCM_INT_PCI_MSI_NR) {
|
||||
+ msi->used |= (1 << bit);
|
||||
+ hwirq = bit - msi->intr_legacy_offset;
|
||||
+ } else {
|
||||
+ hwirq = -ENOSPC;
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&msi->lock);
|
||||
+ return hwirq;
|
||||
+}
|
||||
+
|
||||
+static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq)
|
||||
+{
|
||||
+ mutex_lock(&msi->lock);
|
||||
+ msi->used &= ~(1 << (hwirq + msi->intr_legacy_offset));
|
||||
+ 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_simple_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 void brcm_msi_set_regs(struct brcm_msi *msi)
|
||||
+{
|
||||
+ u32 data_val, msi_lo, msi_hi;
|
||||
+
|
||||
+ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
|
||||
+ /*
|
||||
+ * ffe0 -- least sig 5 bits are 0 indicating 32 msgs
|
||||
+ * 6540 -- this is our arbitrary unique data value
|
||||
+ */
|
||||
+ data_val = 0xffe06540;
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * fff8 -- least sig 3 bits are 0 indicating 8 msgs
|
||||
+ * 6540 -- this is our arbitrary unique data value
|
||||
+ */
|
||||
+ data_val = 0xfff86540;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure we are not masking MSIs. Note that MSIs can be masked,
|
||||
+ * but that occurs on the PCIe EP device
|
||||
+ */
|
||||
+ bcm_writel(0xffffffff & msi->intr_legacy_mask,
|
||||
+ msi->intr_base + MASK_CLR);
|
||||
+
|
||||
+ msi_lo = lower_32_bits(msi->target_addr);
|
||||
+ msi_hi = upper_32_bits(msi->target_addr);
|
||||
+ /*
|
||||
+ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
|
||||
+ * enable, which we set to 1.
|
||||
+ */
|
||||
+ bcm_writel(msi_lo | 1, msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO);
|
||||
+ bcm_writel(msi_hi, msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);
|
||||
+ bcm_writel(data_val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
|
||||
+}
|
||||
+
|
||||
+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->dn);
|
||||
+ 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 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 intr\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL);
|
||||
+ if (!msi)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ msi->dev = dev;
|
||||
+ msi->base = pcie->base;
|
||||
+ msi->rev = pcie->rev;
|
||||
+ msi->dn = pcie->dn;
|
||||
+ 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);
|
||||
+
|
||||
+ if (msi->rev >= BRCM_PCIE_HW_REV_33) {
|
||||
+ msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
|
||||
+ /*
|
||||
+ * This version of PCIe hw has only 32 intr bits
|
||||
+ * starting at bit position 0.
|
||||
+ */
|
||||
+ msi->intr_legacy_mask = 0xffffffff;
|
||||
+ msi->intr_legacy_offset = 0x0;
|
||||
+ msi->used = 0x0;
|
||||
+
|
||||
+ } else {
|
||||
+ msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
|
||||
+ /*
|
||||
+ * This version of PCIe hw has only 8 intr bits starting
|
||||
+ * at bit position 24.
|
||||
+ */
|
||||
+ msi->intr_legacy_mask = 0xff000000;
|
||||
+ msi->intr_legacy_offset = 24;
|
||||
+ msi->used = 0x00ffffff;
|
||||
+ }
|
||||
+
|
||||
+ brcm_msi_set_regs(msi);
|
||||
+ pcie->msi = msi;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/* Configuration space read/write support */
|
||||
static int cfg_index(int busnr, int devfn, int reg)
|
||||
{
|
||||
@@ -1072,6 +1372,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
u16 nlw, cls, lnksta;
|
||||
bool ssc_good = false;
|
||||
struct device *dev = pcie->dev;
|
||||
+ u64 msi_target_addr;
|
||||
|
||||
/* Reset the bridge */
|
||||
brcm_pcie_bridge_sw_init_set(pcie, 1);
|
||||
@@ -1116,27 +1417,24 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
* 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.
|
||||
+ * two. Further, the MSI target address must NOT be placed
|
||||
+ * inside this region, as the decoding logic will consider its
|
||||
+ * address to be inbound memory traffic. 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.
|
||||
*/
|
||||
rc_bar2_size = roundup_pow_of_two_64(total_mem_size);
|
||||
|
||||
- /*
|
||||
- * Set simple configuration based on memory sizes
|
||||
- * only. We always start the viewport at address 0.
|
||||
- */
|
||||
- rc_bar2_offset = 0;
|
||||
-
|
||||
if (dma_ranges) {
|
||||
/*
|
||||
* The best-case scenario is to place the inbound
|
||||
- * region in the first 4GB of pci-space, as some
|
||||
+ * 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
|
||||
@@ -1145,6 +1443,14 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
if (total_mem_size <= 0xc0000000ULL &&
|
||||
rc_bar2_size <= 0x100000000ULL) {
|
||||
rc_bar2_offset = 0;
|
||||
+ /* If the viewport is less then 4GB we can fit
|
||||
+ * the MSI target address under 4GB. Otherwise
|
||||
+ * put it right below 64GB.
|
||||
+ */
|
||||
+ msi_target_addr =
|
||||
+ (rc_bar2_size == 0x100000000ULL)
|
||||
+ ? BRCM_MSI_TARGET_ADDR_GT_4GB
|
||||
+ : BRCM_MSI_TARGET_ADDR_LT_4GB;
|
||||
} else {
|
||||
/*
|
||||
* The system memory is 4GB or larger so we
|
||||
@@ -1154,8 +1460,12 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
* start it at the 1x multiple of its size
|
||||
*/
|
||||
rc_bar2_offset = rc_bar2_size;
|
||||
- }
|
||||
|
||||
+ /* Since we are starting the viewport at 4GB or
|
||||
+ * higher, put the MSI target address below 4GB
|
||||
+ */
|
||||
+ msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB;
|
||||
+ }
|
||||
} else {
|
||||
/*
|
||||
* Set simple configuration based on memory sizes
|
||||
@@ -1163,7 +1473,12 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
* and set the MSI target address accordingly.
|
||||
*/
|
||||
rc_bar2_offset = 0;
|
||||
+
|
||||
+ msi_target_addr = (rc_bar2_size >= 0x100000000ULL)
|
||||
+ ? BRCM_MSI_TARGET_ADDR_GT_4GB
|
||||
+ : BRCM_MSI_TARGET_ADDR_LT_4GB;
|
||||
}
|
||||
+ pcie->msi_target_addr = msi_target_addr;
|
||||
|
||||
tmp = lower_32_bits(rc_bar2_offset);
|
||||
tmp = INSERT_FIELD(tmp, PCIE_MISC_RC_BAR2_CONFIG_LO, SIZE,
|
||||
@@ -1333,6 +1648,9 @@ static int brcm_pcie_resume(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ if (pcie->msi && pcie->msi_internal)
|
||||
+ brcm_msi_set_regs(pcie->msi);
|
||||
+
|
||||
pcie->suspended = false;
|
||||
|
||||
return 0;
|
||||
@@ -1340,6 +1658,7 @@ static int brcm_pcie_resume(struct device *dev)
|
||||
|
||||
static void _brcm_pcie_remove(struct brcm_pcie *pcie)
|
||||
{
|
||||
+ brcm_msi_remove(pcie);
|
||||
turn_off(pcie);
|
||||
clk_disable_unprepare(pcie->clk);
|
||||
clk_put(pcie->clk);
|
||||
@@ -1368,7 +1687,7 @@ MODULE_DEVICE_TABLE(of, brcm_pcie_match);
|
||||
|
||||
static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
- struct device_node *dn = pdev->dev.of_node;
|
||||
+ struct device_node *dn = pdev->dev.of_node, *msi_dn;
|
||||
const struct of_device_id *of_id;
|
||||
const struct pcie_cfg_data *data;
|
||||
int ret;
|
||||
@@ -1448,6 +1767,20 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
+ msi_dn = of_parse_phandle(pcie->dn, "msi-parent", 0);
|
||||
+ /* Use the internal MSI if no msi-parent property */
|
||||
+ if (!msi_dn)
|
||||
+ msi_dn = pcie->dn;
|
||||
+
|
||||
+ if (pci_msi_enabled() && msi_dn == pcie->dn) {
|
||||
+ ret = brcm_pcie_enable_msi(pcie);
|
||||
+ if (ret)
|
||||
+ dev_err(pcie->dev,
|
||||
+ "probe of internal MSI failed: %d)", ret);
|
||||
+ else
|
||||
+ pcie->msi_internal = true;
|
||||
+ }
|
||||
+
|
||||
list_splice_init(&pcie->resources, &bridge->windows);
|
||||
bridge->dev.parent = &pdev->dev;
|
||||
bridge->busnr = 0;
|
||||
@@ -1470,7 +1803,6 @@ static int brcm_pcie_probe(struct platform_device *pdev)
|
||||
pcie->root_bus = bridge->bus;
|
||||
|
||||
return 0;
|
||||
-
|
||||
fail:
|
||||
_brcm_pcie_remove(pcie);
|
||||
return ret;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
From e3b54a0b302e3314bf06bf64bb0726280c5504d5 Mon Sep 17 00:00:00 2001
|
||||
From: Jim Quinlan <jim2101024@gmail.com>
|
||||
Date: Mon, 15 Jan 2018 18:28:39 -0500
|
||||
Subject: [PATCH 541/678] 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 <jim2101024@gmail.com>
|
||||
---
|
||||
.../devicetree/bindings/pci/brcmstb-pcie.txt | 59 +++++++++++++++++++
|
||||
1 file changed, 59 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt b/Documentation/devicetree/bindings/pci/brcmstb-pcie.txt
|
||||
new file mode 100644
|
||||
index 000000000000..a1a9ad5e70ca
|
||||
--- /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>;
|
||||
+ };
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,30 @@
|
|||
From 278f37a1cbb70636a6eb000c1c9fd56bf7097f6c Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 29 May 2019 15:47:42 +0100
|
||||
Subject: [PATCH 543/678] 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 <phil@raspberrypi.org>
|
||||
---
|
||||
arch/arm/mach-bcm/board_bcm2835.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/mach-bcm/board_bcm2835.c b/arch/arm/mach-bcm/board_bcm2835.c
|
||||
index db426d73d963..fd6c7130bfb6 100644
|
||||
--- a/arch/arm/mach-bcm/board_bcm2835.c
|
||||
+++ b/arch/arm/mach-bcm/board_bcm2835.c
|
||||
@@ -123,6 +123,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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
From ea1a6dab51c23e9ca4c6db02a0cad4cc058782f4 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 29 Aug 2018 09:05:15 +0100
|
||||
Subject: [PATCH 544/678] mmc: bcm2835-sdhost: Support 64-bit physical
|
||||
addresses
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/mmc/host/bcm2835-sdhost.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/host/bcm2835-sdhost.c b/drivers/mmc/host/bcm2835-sdhost.c
|
||||
index 844bed552bae..3716a80a879b 100644
|
||||
--- a/drivers/mmc/host/bcm2835-sdhost.c
|
||||
+++ b/drivers/mmc/host/bcm2835-sdhost.c
|
||||
@@ -148,7 +148,7 @@ struct bcm2835_host {
|
||||
spinlock_t lock;
|
||||
|
||||
void __iomem *ioaddr;
|
||||
- u32 bus_addr;
|
||||
+ phys_addr_t bus_addr;
|
||||
|
||||
struct mmc_host *mmc;
|
||||
|
||||
@@ -246,8 +246,8 @@ static void log_init(struct device *dev, u32 bus_to_phys)
|
||||
sdhost_log_buf = dma_zalloc_coherent(dev, LOG_SIZE, &sdhost_log_addr,
|
||||
GFP_KERNEL);
|
||||
if (sdhost_log_buf) {
|
||||
- pr_info("sdhost: log_buf @ %p (%x)\n",
|
||||
- sdhost_log_buf, (u32)sdhost_log_addr);
|
||||
+ pr_info("sdhost: log_buf @ %p (%llx)\n",
|
||||
+ sdhost_log_buf, (u64)sdhost_log_addr);
|
||||
timer_base = ioremap_nocache(bus_to_phys + 0x7e003000, SZ_4K);
|
||||
if (!timer_base)
|
||||
pr_err("sdhost: failed to remap timer\n");
|
||||
@@ -2024,6 +2024,7 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev)
|
||||
struct mmc_host *mmc;
|
||||
const __be32 *addr;
|
||||
u32 msg[3];
|
||||
+ int na;
|
||||
int ret;
|
||||
|
||||
pr_debug("bcm2835_sdhost_probe\n");
|
||||
@@ -2047,12 +2048,13 @@ static int bcm2835_sdhost_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
+ na = of_n_addr_cells(node);
|
||||
addr = of_get_address(node, 0, NULL, NULL);
|
||||
if (!addr) {
|
||||
dev_err(dev, "could not get DMA-register address\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
- host->bus_addr = be32_to_cpup(addr);
|
||||
+ host->bus_addr = (phys_addr_t)of_read_number(addr, na);
|
||||
pr_debug(" - ioaddr %lx, iomem->start %lx, bus_addr %lx\n",
|
||||
(unsigned long)host->ioaddr,
|
||||
(unsigned long)iomem->start,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
From 39afbd02cb63d932d495e91f68800efd59d620af Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 28 Sep 2018 16:24:05 +0100
|
||||
Subject: [PATCH 545/678] mmc: sdhci: Mask "spurious" interrupts
|
||||
|
||||
Add a filter for "spurious" Transfer Complete interrupts, attempting
|
||||
to make it as specific as possible:
|
||||
* INT_DATA_END (transfer complete) is set
|
||||
* There is a stop command in progress
|
||||
* There is no data transfer in progress
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/mmc/host/sdhci.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
|
||||
index c749d3dc1d36..bb753ba947d8 100644
|
||||
--- a/drivers/mmc/host/sdhci.c
|
||||
+++ b/drivers/mmc/host/sdhci.c
|
||||
@@ -2930,6 +2930,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
|
||||
result = IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
+ if ((intmask & SDHCI_INT_DATA_END) && !host->data &&
|
||||
+ host->cmd && (host->cmd == host->cmd->mrq->stop))
|
||||
+ intmask &= ~SDHCI_INT_DATA_END;
|
||||
+
|
||||
if (intmask & SDHCI_INT_CMD_MASK)
|
||||
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, &intmask);
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
From 04c979ea47cc0f0c390b5b628094b9b67a91d55c Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <wahrenst@gmx.net>
|
||||
Date: Sat, 27 Apr 2019 12:33:57 +0200
|
||||
Subject: [PATCH 546/678] mmc: sdhci-iproc: Add support for emmc2 of the
|
||||
BCM2838
|
||||
|
||||
The emmc2 interface of the BCM2838 should be integrated in sdhci-iproc
|
||||
to avoid code redundancy. Except 32 bit only access no other quirks are
|
||||
known yet. Add an additional compatible string for upstream proposal.
|
||||
|
||||
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
|
||||
---
|
||||
drivers/mmc/host/sdhci-iproc.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
|
||||
index f903ab96aa21..983cddce9147 100644
|
||||
--- a/drivers/mmc/host/sdhci-iproc.c
|
||||
+++ b/drivers/mmc/host/sdhci-iproc.c
|
||||
@@ -250,8 +250,18 @@ static const struct sdhci_iproc_data bcm2835_data = {
|
||||
.mmc_caps = 0x00000000,
|
||||
};
|
||||
|
||||
+static const struct sdhci_pltfm_data sdhci_bcm2838_pltfm_data = {
|
||||
+ .ops = &sdhci_iproc_32only_ops,
|
||||
+};
|
||||
+
|
||||
+static const struct sdhci_iproc_data bcm2838_data = {
|
||||
+ .pdata = &sdhci_bcm2838_pltfm_data,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id sdhci_iproc_of_match[] = {
|
||||
{ .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
|
||||
+ { .compatible = "brcm,bcm2838-sdhci", .data = &bcm2838_data },
|
||||
+ { .compatible = "brcm,bcm2711-emmc2", .data = &bcm2838_data },
|
||||
{ .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_cygnus_data},
|
||||
{ .compatible = "brcm,sdhci-iproc", .data = &iproc_data },
|
||||
{ }
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
From 5e74aadfd1e0e6c00994521863ba044ce25b40de Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <wahrenst@gmx.net>
|
||||
Date: Sat, 4 May 2019 17:06:15 +0200
|
||||
Subject: [PATCH 547/678] 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 <wahrenst@gmx.net>
|
||||
---
|
||||
drivers/char/hw_random/Kconfig | 4 +-
|
||||
drivers/char/hw_random/iproc-rng200.c | 81 +++++++++++++++++++++++++--
|
||||
2 files changed, 79 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
|
||||
index dac895dc01b9..74fcbdae376c 100644
|
||||
--- a/drivers/char/hw_random/Kconfig
|
||||
+++ b/drivers/char/hw_random/Kconfig
|
||||
@@ -89,11 +89,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
|
||||
diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c
|
||||
index 8b5a20b35293..063dfea53059 100644
|
||||
--- 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 hwrng *rng)
|
||||
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 platform_device *pdev)
|
||||
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);
|
||||
@@ -222,6 +294,7 @@ static int iproc_rng200_probe(struct platform_device *pdev)
|
||||
static const struct of_device_id iproc_rng200_of_match[] = {
|
||||
{ .compatible = "brcm,bcm7278-rng200", },
|
||||
{ .compatible = "brcm,iproc-rng200", },
|
||||
+ { .compatible = "brcm,bcm2838-rng200"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, iproc_rng200_of_match);
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
From f4d6c841192baab7979c38e075a581680b6a4c87 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <wahrenst@gmx.net>
|
||||
Date: Sat, 18 May 2019 12:26:11 +0200
|
||||
Subject: [PATCH 548/678] thermal: brcmstb_thermal: Add BCM2838 support
|
||||
|
||||
The BCM2838 has an AVS TMON hardware block. This adds the necessary
|
||||
support to the brcmstb_thermal driver ( no trip handling ).
|
||||
|
||||
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
|
||||
---
|
||||
drivers/thermal/broadcom/Kconfig | 2 +-
|
||||
drivers/thermal/broadcom/brcmstb_thermal.c | 65 +++++++++++++++++++---
|
||||
2 files changed, 58 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/thermal/broadcom/Kconfig b/drivers/thermal/broadcom/Kconfig
|
||||
index c106a15bf7f9..d494073b4187 100644
|
||||
--- a/drivers/thermal/broadcom/Kconfig
|
||||
+++ b/drivers/thermal/broadcom/Kconfig
|
||||
@@ -8,7 +8,7 @@ config BCM2835_THERMAL
|
||||
|
||||
config BRCMSTB_THERMAL
|
||||
tristate "Broadcom STB AVS TMON thermal driver"
|
||||
- depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
+ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
|
||||
help
|
||||
Enable this driver if you have a Broadcom STB SoC and would like
|
||||
thermal framework support.
|
||||
diff --git a/drivers/thermal/broadcom/brcmstb_thermal.c b/drivers/thermal/broadcom/brcmstb_thermal.c
|
||||
index 1919f91fa756..36289c5e1624 100644
|
||||
--- a/drivers/thermal/broadcom/brcmstb_thermal.c
|
||||
+++ b/drivers/thermal/broadcom/brcmstb_thermal.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#define pr_fmt(fmt) DRV_NAME ": " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
+#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
@@ -31,9 +32,6 @@
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#define AVS_TMON_STATUS 0x00
|
||||
- #define AVS_TMON_STATUS_valid_msk BIT(11)
|
||||
- #define AVS_TMON_STATUS_data_msk GENMASK(10, 1)
|
||||
- #define AVS_TMON_STATUS_data_shift 1
|
||||
|
||||
#define AVS_TMON_EN_OVERTEMP_RESET 0x04
|
||||
#define AVS_TMON_EN_OVERTEMP_RESET_msk BIT(0)
|
||||
@@ -111,10 +109,19 @@ static struct avs_tmon_trip avs_tmon_trips[] = {
|
||||
},
|
||||
};
|
||||
|
||||
+struct brcmstb_thermal_of_data {
|
||||
+ const struct thermal_zone_of_device_ops *of_ops;
|
||||
+ u32 status_valid_mask;
|
||||
+ u32 status_data_mask;
|
||||
+ u32 status_data_shift;
|
||||
+};
|
||||
+
|
||||
struct brcmstb_thermal_priv {
|
||||
void __iomem *tmon_base;
|
||||
struct device *dev;
|
||||
struct thermal_zone_device *thermal;
|
||||
+ struct clk *clk;
|
||||
+ const struct brcmstb_thermal_of_data *socdata;
|
||||
};
|
||||
|
||||
static void avs_tmon_get_coeffs(struct thermal_zone_device *tz, int *slope,
|
||||
@@ -164,17 +171,18 @@ static inline u32 avs_tmon_temp_to_code(struct thermal_zone_device *tz,
|
||||
static int brcmstb_get_temp(void *data, int *temp)
|
||||
{
|
||||
struct brcmstb_thermal_priv *priv = data;
|
||||
+ const struct brcmstb_thermal_of_data *socdata = priv->socdata;
|
||||
u32 val;
|
||||
long t;
|
||||
|
||||
val = __raw_readl(priv->tmon_base + AVS_TMON_STATUS);
|
||||
|
||||
- if (!(val & AVS_TMON_STATUS_valid_msk)) {
|
||||
+ if (!(val & socdata->status_valid_mask)) {
|
||||
dev_err(priv->dev, "reading not valid\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
- val = (val & AVS_TMON_STATUS_data_msk) >> AVS_TMON_STATUS_data_shift;
|
||||
+ val = (val & socdata->status_data_mask) >> socdata->status_data_shift;
|
||||
|
||||
t = avs_tmon_code_to_temp(priv->thermal, val);
|
||||
if (t < 0)
|
||||
@@ -299,13 +307,34 @@ static int brcmstb_set_trips(void *data, int low, int high)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static struct thermal_zone_of_device_ops of_ops = {
|
||||
+static const struct thermal_zone_of_device_ops bcm7445_thermal_of_ops = {
|
||||
.get_temp = brcmstb_get_temp,
|
||||
.set_trips = brcmstb_set_trips,
|
||||
};
|
||||
|
||||
+static const struct thermal_zone_of_device_ops bcm2838_thermal_of_ops = {
|
||||
+ .get_temp = brcmstb_get_temp,
|
||||
+};
|
||||
+
|
||||
+static const struct brcmstb_thermal_of_data bcm7445_thermal_of_data = {
|
||||
+ .of_ops = &bcm7445_thermal_of_ops,
|
||||
+ .status_valid_mask = BIT(11),
|
||||
+ .status_data_mask = GENMASK(10, 1),
|
||||
+ .status_data_shift = 1,
|
||||
+};
|
||||
+
|
||||
+static const struct brcmstb_thermal_of_data bcm2838_thermal_of_data = {
|
||||
+ .of_ops = &bcm2838_thermal_of_ops,
|
||||
+ .status_valid_mask = BIT(10),
|
||||
+ .status_data_mask = GENMASK(9, 0),
|
||||
+ .status_data_shift = 0,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id brcmstb_thermal_id_table[] = {
|
||||
- { .compatible = "brcm,avs-tmon" },
|
||||
+ { .compatible = "brcm,avs-tmon",
|
||||
+ .data = &bcm7445_thermal_of_data },
|
||||
+ { .compatible = "brcm,avs-tmon-bcm2838",
|
||||
+ .data = &bcm2838_thermal_of_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, brcmstb_thermal_id_table);
|
||||
@@ -326,10 +355,27 @@ static int brcmstb_thermal_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(priv->tmon_base))
|
||||
return PTR_ERR(priv->tmon_base);
|
||||
|
||||
+ priv->socdata = of_device_get_match_data(&pdev->dev);
|
||||
+ if (!priv->socdata) {
|
||||
+ dev_err(&pdev->dev, "no device match found\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ if (!IS_ERR(priv->clk)) {
|
||||
+ ret = clk_prepare_enable(priv->clk);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
priv->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
- thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv, &of_ops);
|
||||
+ thermal = thermal_zone_of_sensor_register(&pdev->dev, 0, priv,
|
||||
+ priv->socdata->of_ops);
|
||||
if (IS_ERR(thermal)) {
|
||||
ret = PTR_ERR(thermal);
|
||||
dev_err(&pdev->dev, "could not register sensor: %d\n", ret);
|
||||
@@ -369,6 +415,9 @@ static int brcmstb_thermal_exit(struct platform_device *pdev)
|
||||
if (thermal)
|
||||
thermal_zone_of_sensor_unregister(&pdev->dev, priv->thermal);
|
||||
|
||||
+ if (!IS_ERR(priv->clk))
|
||||
+ clk_disable_unprepare(priv->clk);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
From f30d552e148eb73d265751713d53cae17ef214a6 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 1 Nov 2018 17:31:37 +0000
|
||||
Subject: [PATCH 549/678] 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 <phil@raspberrypi.org>
|
||||
---
|
||||
.../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(-)
|
||||
|
||||
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
|
||||
index 7694a4fc7cac..66ee1886c9a1 100644
|
||||
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
|
||||
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
|
||||
@@ -47,6 +47,8 @@
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
#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"
|
||||
@@ -96,6 +98,7 @@ static void __iomem *g_regs;
|
||||
*/
|
||||
static unsigned int g_cache_line_size;
|
||||
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;
|
||||
@@ -139,6 +142,8 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
|
||||
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);
|
||||
@@ -150,14 +155,21 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
|
||||
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;
|
||||
|
||||
@@ -193,7 +205,6 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
@@ -282,7 +293,7 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
|
||||
return VCHIQ_ERROR;
|
||||
|
||||
bulk->handle = memhandle;
|
||||
- bulk->data = (void *)(unsigned long)pagelistinfo->dma_addr;
|
||||
+ bulk->data = (void *)VC_SAFE(pagelistinfo->dma_addr);
|
||||
|
||||
/*
|
||||
* Store the pagelistinfo address in remote_data,
|
||||
@@ -570,25 +581,60 @@ create_pagelist(char __user *buf, size_t count, unsigned short type)
|
||||
|
||||
/* 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 */
|
||||
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
|
||||
index a38b4a8b14c6..4bc1d4738069 100644
|
||||
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
|
||||
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
|
||||
@@ -181,6 +181,11 @@ static struct vchiq_drvdata bcm2836_drvdata = {
|
||||
.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",
|
||||
@@ -3618,6 +3623,7 @@ vchiq_register_child(struct platform_device *pdev, const char *name)
|
||||
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);
|
||||
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
|
||||
index 2f3ebc99cbcf..249437d0618d 100644
|
||||
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
|
||||
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
|
||||
@@ -125,6 +125,7 @@ typedef struct vchiq_arm_state_struct {
|
||||
|
||||
struct vchiq_drvdata {
|
||||
const unsigned int cache_line_size;
|
||||
+ const bool use_36bit_addrs;
|
||||
struct rpi_firmware *fw;
|
||||
};
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
From 56c07246ad0cb594299286f76d07d6efca105350 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 30 Apr 2019 19:15:30 +0100
|
||||
Subject: [PATCH 550/678] bcm2835-pcm.c: Support multichannel audio
|
||||
|
||||
---
|
||||
.../vc04_services/bcm2835-audio/bcm2835-pcm.c | 17 +++++++++--------
|
||||
1 file changed, 9 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
|
||||
index bc1eaa3a0773..1c19c4e4598f 100644
|
||||
--- 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_bcm2835_playback_hw = {
|
||||
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_DRAIN_TRIGGER | 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_bcm2835_playback_spdif_hw = {
|
||||
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_DRAIN_TRIGGER | 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,
|
||||
};
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
From 90711e7fcc30c317e4240f26ac59f1dd0122b04f Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
Date: Wed, 12 Sep 2018 14:44:53 +0100
|
||||
Subject: [PATCH 551/678] bcmgenet: constrain max DMA burst length
|
||||
|
||||
---
|
||||
drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
|
||||
index 14b49612aa86..7730a09b9e7c 100644
|
||||
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
|
||||
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
|
||||
@@ -31,7 +31,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
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
From 6502950aad1ba53d3eb7aab309d9d3d232050f52 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 27 Mar 2019 13:45:46 +0000
|
||||
Subject: [PATCH 552/678] 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 <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
index 2d6f090bf644..bdd7717c890b 100644
|
||||
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
@@ -2147,7 +2147,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
|
||||
|
||||
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);
|
||||
@@ -3576,9 +3576,12 @@ static int bcmgenet_probe(struct platform_device *pdev)
|
||||
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);
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
From eb5df670a81d7dfa879938ba0eaac679f024b264 Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
Date: Tue, 14 May 2019 17:17:59 +0100
|
||||
Subject: [PATCH 553/678] 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 <jonathan@raspberrypi.org>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
|
||||
index de0e24d912fe..20689b1a220b 100644
|
||||
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
|
||||
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
|
||||
@@ -280,7 +280,10 @@ int bcmgenet_mii_probe(struct net_device *dev)
|
||||
int ret;
|
||||
|
||||
/* Communicate the integrated PHY revision */
|
||||
- phy_flags = priv->gphy_rev;
|
||||
+ 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;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
From 360c8e98883f9cd075564be8a7fc25ac0785dee4 Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
Date: Tue, 14 May 2019 17:00:41 +0100
|
||||
Subject: [PATCH 554/678] phy: broadcom: split out the BCM54213PE from the
|
||||
BCM54210E IDs
|
||||
|
||||
The last nibble is a revision ID, and the 54213pe is a later rev
|
||||
than the 54210e. Running the 54210e setup code on a 54213pe results
|
||||
in a broken RGMII interface.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
---
|
||||
drivers/net/phy/broadcom.c | 17 ++++++++++++++---
|
||||
include/linux/brcmphy.h | 1 +
|
||||
2 files changed, 15 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
|
||||
index e86ea105c802..9bded877cd6e 100644
|
||||
--- a/drivers/net/phy/broadcom.c
|
||||
+++ b/drivers/net/phy/broadcom.c
|
||||
@@ -222,7 +222,8 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
|
||||
/* Abort if we are using an untested phy. */
|
||||
if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
|
||||
BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
|
||||
- BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
|
||||
+ BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
|
||||
+ BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54213PE)
|
||||
return;
|
||||
|
||||
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
|
||||
@@ -604,13 +605,22 @@ static struct phy_driver broadcom_drivers[] = {
|
||||
.config_intr = bcm_phy_config_intr,
|
||||
}, {
|
||||
.phy_id = PHY_ID_BCM54210E,
|
||||
- .phy_id_mask = 0xfffffff0,
|
||||
+ .phy_id_mask = 0xffffffff,
|
||||
.name = "Broadcom BCM54210E",
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.flags = PHY_HAS_INTERRUPT,
|
||||
.config_init = bcm54xx_config_init,
|
||||
.ack_interrupt = bcm_phy_ack_intr,
|
||||
.config_intr = bcm_phy_config_intr,
|
||||
+}, {
|
||||
+ .phy_id = PHY_ID_BCM54213PE,
|
||||
+ .phy_id_mask = 0xffffffff,
|
||||
+ .name = "Broadcom BCM54213PE",
|
||||
+ .features = PHY_GBIT_FEATURES,
|
||||
+ .flags = PHY_HAS_INTERRUPT,
|
||||
+ .config_init = bcm54xx_config_init,
|
||||
+ .ack_interrupt = bcm_phy_ack_intr,
|
||||
+ .config_intr = bcm_phy_config_intr,
|
||||
}, {
|
||||
.phy_id = PHY_ID_BCM5461,
|
||||
.phy_id_mask = 0xfffffff0,
|
||||
@@ -748,7 +758,8 @@ module_phy_driver(broadcom_drivers);
|
||||
static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
|
||||
{ PHY_ID_BCM5411, 0xfffffff0 },
|
||||
{ PHY_ID_BCM5421, 0xfffffff0 },
|
||||
- { PHY_ID_BCM54210E, 0xfffffff0 },
|
||||
+ { PHY_ID_BCM54210E, 0xffffffff },
|
||||
+ { PHY_ID_BCM54213PE, 0xffffffff },
|
||||
{ PHY_ID_BCM5461, 0xfffffff0 },
|
||||
{ PHY_ID_BCM54612E, 0xfffffff0 },
|
||||
{ PHY_ID_BCM54616S, 0xfffffff0 },
|
||||
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
|
||||
index 949e9af8d9d6..67c7939b8307 100644
|
||||
--- a/include/linux/brcmphy.h
|
||||
+++ b/include/linux/brcmphy.h
|
||||
@@ -20,6 +20,7 @@
|
||||
#define PHY_ID_BCM5411 0x00206070
|
||||
#define PHY_ID_BCM5421 0x002060e0
|
||||
#define PHY_ID_BCM54210E 0x600d84a0
|
||||
+#define PHY_ID_BCM54213PE 0x600d84a2
|
||||
#define PHY_ID_BCM5464 0x002060b0
|
||||
#define PHY_ID_BCM5461 0x002060c0
|
||||
#define PHY_ID_BCM54612E 0x03625e60
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
From af502b2acafb23364b5757f01ae2c43e2943f195 Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
Date: Fri, 17 May 2019 13:31:21 +0100
|
||||
Subject: [PATCH 555/678] phy: bcm54213pe: configure the LED outputs to be more
|
||||
user-friendly
|
||||
|
||||
The default state was both LEDs indicating link speed.
|
||||
|
||||
Change the default configuration to
|
||||
- Amber: 1000/100 link speed indication
|
||||
- Green: link present + activity indication
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
---
|
||||
drivers/net/phy/broadcom.c | 17 +++++++++++++++++
|
||||
include/linux/brcmphy.h | 4 ++++
|
||||
2 files changed, 21 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
|
||||
index 9bded877cd6e..a919a6a4c970 100644
|
||||
--- a/drivers/net/phy/broadcom.c
|
||||
+++ b/drivers/net/phy/broadcom.c
|
||||
@@ -52,6 +52,21 @@ static int bcm54210e_config_init(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void bcm54213pe_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ u16 val;
|
||||
+
|
||||
+ /* Enable ACT+LINK indication on ACTIVITY trigger */
|
||||
+ val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_LEDCTL);
|
||||
+ val |= BCM54XX_SHD_LEDCTL_ACTLINK_EN;
|
||||
+ bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDCTL, val);
|
||||
+
|
||||
+ /* Set ACTIVITY on LED "1" output, LINKSPD[1] on LED "3" output */
|
||||
+ val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
|
||||
+ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD1);
|
||||
+ bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
|
||||
+}
|
||||
+
|
||||
static int bcm54612e_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int reg;
|
||||
@@ -310,6 +325,8 @@ static int bcm54xx_config_init(struct phy_device *phydev)
|
||||
err = bcm54210e_config_init(phydev);
|
||||
if (err)
|
||||
return err;
|
||||
+ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54213PE) {
|
||||
+ bcm54213pe_config_init(phydev);
|
||||
} else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
|
||||
err = bcm54612e_config_init(phydev);
|
||||
if (err)
|
||||
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
|
||||
index 67c7939b8307..f4c80638c515 100644
|
||||
--- a/include/linux/brcmphy.h
|
||||
+++ b/include/linux/brcmphy.h
|
||||
@@ -168,6 +168,10 @@
|
||||
#define BCM54XX_SHD_SCR3_DLLAPD_DIS 0x0002
|
||||
#define BCM54XX_SHD_SCR3_TRDDAPD 0x0004
|
||||
|
||||
+/* 01001: Additional LED trigger options */
|
||||
+#define BCM54XX_SHD_LEDCTL 0x09
|
||||
+#define BCM54XX_SHD_LEDCTL_ACTLINK_EN 0x0010
|
||||
+
|
||||
/* 01010: Auto Power-Down */
|
||||
#define BCM54XX_SHD_APD 0x0a
|
||||
#define BCM_APD_CLR_MASK 0xFE9F /* clear bits 5, 6 & 8 */
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
From 0a1cf0d4b15cd1e2d96f7c85cadc1b60c9337151 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 21 May 2019 13:36:52 +0100
|
||||
Subject: [PATCH 556/678] dwc_otg: Choose appropriate IRQ handover strategy
|
||||
|
||||
2711 has no MPHI peripheral, but the ARM Control block can fake
|
||||
interrupts. Use the size of the DTB "mphi" reg block to determine
|
||||
which is required.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/usb/host/dwc_otg/dwc_otg_driver.c | 9 +++--
|
||||
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 21 ++++++----
|
||||
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 2 +
|
||||
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 12 ++++--
|
||||
drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 41 +++++++++++++-------
|
||||
drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 3 ++
|
||||
6 files changed, 60 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
|
||||
index 3fd21c7ba360..6bfd35c57814 100644
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
|
||||
@@ -806,14 +806,15 @@ static int dwc_otg_driver_probe(
|
||||
if (!request_mem_region(_dev->resource[1].start,
|
||||
_dev->resource[1].end - _dev->resource[1].start + 1,
|
||||
"dwc_otg")) {
|
||||
- dev_dbg(&_dev->dev, "error reserving mapped memory\n");
|
||||
- retval = -EFAULT;
|
||||
- goto fail;
|
||||
- }
|
||||
+ dev_dbg(&_dev->dev, "error reserving mapped memory\n");
|
||||
+ retval = -EFAULT;
|
||||
+ goto fail;
|
||||
+ }
|
||||
|
||||
dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
|
||||
_dev->resource[1].end -
|
||||
_dev->resource[1].start + 1);
|
||||
+ dwc_otg_device->os_dep.use_swirq = (_dev->resource[1].end - _dev->resource[1].start) == 0x200;
|
||||
}
|
||||
|
||||
#else
|
||||
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
|
||||
index 3ac4c7984ce5..a86d8ed77140 100644
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
|
||||
@@ -1347,8 +1347,12 @@ void notrace dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels)
|
||||
/* We got an interrupt, didn't handle it. */
|
||||
if (kick_irq) {
|
||||
state->mphi_int_count++;
|
||||
- FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
|
||||
- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
|
||||
+ if (state->mphi_regs.swirq_set) {
|
||||
+ FIQ_WRITE(state->mphi_regs.swirq_set, 1);
|
||||
+ } else {
|
||||
+ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
|
||||
+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
|
||||
+ }
|
||||
|
||||
}
|
||||
state->fiq_done++;
|
||||
@@ -1406,11 +1410,14 @@ void notrace dwc_otg_fiq_nop(struct fiq_state *state)
|
||||
state->mphi_int_count++;
|
||||
gintmsk.d32 &= state->gintmsk_saved.d32;
|
||||
FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32);
|
||||
- /* Force a clear before another dummy send */
|
||||
- FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
|
||||
- FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
|
||||
- FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
|
||||
-
|
||||
+ if (state->mphi_regs.swirq_set) {
|
||||
+ FIQ_WRITE(state->mphi_regs.swirq_set, 1);
|
||||
+ } else {
|
||||
+ /* Force a clear before another dummy send */
|
||||
+ FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
|
||||
+ FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
|
||||
+ FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
|
||||
+ }
|
||||
}
|
||||
state->fiq_done++;
|
||||
mb();
|
||||
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
|
||||
index f51737142188..537cc237b4bc 100644
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
|
||||
@@ -118,6 +118,8 @@ typedef struct {
|
||||
volatile void* outdda;
|
||||
volatile void* outddb;
|
||||
volatile void* intstat;
|
||||
+ volatile void* swirq_set;
|
||||
+ volatile void* swirq_clr;
|
||||
} mphi_regs_t;
|
||||
|
||||
enum fiq_debug_level {
|
||||
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
|
||||
index 6947e98b87ad..d3097ef3728c 100644
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
|
||||
@@ -220,16 +220,20 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
|
||||
|
||||
/* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */
|
||||
if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) {
|
||||
+ if (dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr) {
|
||||
+ DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr, 1);
|
||||
+ } else {
|
||||
DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16));
|
||||
- if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
|
||||
- fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
|
||||
+ }
|
||||
+ if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
|
||||
+ fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
|
||||
DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16)));
|
||||
while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17)))
|
||||
;
|
||||
DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31));
|
||||
dwc_otg_hcd->fiq_state->mphi_int_count = 0;
|
||||
- }
|
||||
- int_done++;
|
||||
+ }
|
||||
+ int_done++;
|
||||
}
|
||||
haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
|
||||
/* Re-enable interrupts that the FIQ masked (first time round) */
|
||||
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
|
||||
index fc43f2a66d6a..08a3e41038a3 100644
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
|
||||
@@ -474,22 +474,37 @@ static void hcd_init_fiq(void *cookie)
|
||||
set_fiq_regs(®s);
|
||||
#endif
|
||||
|
||||
- //Set the mphi periph to the required registers
|
||||
- dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
|
||||
- dwc_otg_hcd->fiq_state->mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c;
|
||||
- dwc_otg_hcd->fiq_state->mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28;
|
||||
- dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
|
||||
- dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
|
||||
dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
|
||||
- DWC_WARN("MPHI regs_base at %px", dwc_otg_hcd->fiq_state->mphi_regs.base);
|
||||
- //Enable mphi peripheral
|
||||
- writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
|
||||
+ //Set the mphi periph to the required registers
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
|
||||
+ if (otg_dev->os_dep.use_swirq) {
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.swirq_set =
|
||||
+ otg_dev->os_dep.mphi_base + 0x1f0;
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr =
|
||||
+ otg_dev->os_dep.mphi_base + 0x1f4;
|
||||
+ DWC_WARN("Fake MPHI regs_base at 0x%08x",
|
||||
+ (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
|
||||
+ } else {
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.ctrl =
|
||||
+ otg_dev->os_dep.mphi_base + 0x4c;
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.outdda
|
||||
+ = otg_dev->os_dep.mphi_base + 0x28;
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.outddb
|
||||
+ = otg_dev->os_dep.mphi_base + 0x2c;
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.intstat
|
||||
+ = otg_dev->os_dep.mphi_base + 0x50;
|
||||
+ DWC_WARN("MPHI regs_base at %px",
|
||||
+ dwc_otg_hcd->fiq_state->mphi_regs.base);
|
||||
+
|
||||
+ //Enable mphi peripheral
|
||||
+ writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
|
||||
#ifdef DEBUG
|
||||
- if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
|
||||
- DWC_WARN("MPHI periph has been enabled");
|
||||
- else
|
||||
- DWC_WARN("MPHI periph has NOT been enabled");
|
||||
+ if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
|
||||
+ DWC_WARN("MPHI periph has been enabled");
|
||||
+ else
|
||||
+ DWC_WARN("MPHI periph has NOT been enabled");
|
||||
#endif
|
||||
+ }
|
||||
// Enable FIQ interrupt from USB peripheral
|
||||
#ifdef CONFIG_ARM64
|
||||
irq = otg_dev->os_dep.fiq_num;
|
||||
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
|
||||
index 3da96b253155..0e9a34fe3a5c 100644
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
|
||||
@@ -102,6 +102,9 @@ typedef struct os_dependent {
|
||||
/** Base address for MPHI peripheral */
|
||||
void *mphi_base;
|
||||
|
||||
+ /** mphi_base actually points to the SWIRQ block */
|
||||
+ bool use_swirq;
|
||||
+
|
||||
/** IRQ number (<0 if not valid) */
|
||||
int irq_num;
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
From 255ee621cf84e52ecc902d888ca3103d4c5456a4 Mon Sep 17 00:00:00 2001
|
||||
From: Tim Gover <tim.gover@raspberrypi.org>
|
||||
Date: Fri, 22 Mar 2019 09:47:14 +0000
|
||||
Subject: [PATCH 557/678] 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(-)
|
||||
|
||||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
|
||||
index f30b065095fa..e9edd823fe91 100644
|
||||
--- 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;
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
From 1909f49bd03f600ce35583b30452430f2e8633ee Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 23 May 2019 15:08:30 +0100
|
||||
Subject: [PATCH 558/678] usb: xhci: Show that the VIA VL805 supports LPM
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/usb/host/xhci-pci.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
|
||||
index 1493d0fdf5ad..ac0d7a684fae 100644
|
||||
--- a/drivers/usb/host/xhci-pci.c
|
||||
+++ b/drivers/usb/host/xhci-pci.c
|
||||
@@ -222,6 +222,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||
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 == 0x1042)
|
||||
xhci->quirks |= XHCI_BROKEN_STREAMS;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
From 1e6abe096683e7520b9692cc490d02bf4d6e705c Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
Date: Thu, 30 May 2019 10:38:40 +0100
|
||||
Subject: [PATCH 559/678] usb: xhci: hack xhci_urb_enqueue to support
|
||||
hid.mousepoll behaviour
|
||||
|
||||
xHCI creates endpoint contexts directly from the device's endpoint
|
||||
data, so submitting URBs with urb->interval different from the hardware
|
||||
interval has no effect.
|
||||
|
||||
Add an explicit reconfiguration of the endpoint context when requested,
|
||||
which will happen only when the interval is different from the cached
|
||||
value. In practice, the reconfiguration only happens on the first URB
|
||||
submitted for the endpoint.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
---
|
||||
drivers/usb/host/xhci.c | 86 +++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 86 insertions(+)
|
||||
|
||||
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
|
||||
index e9edd823fe91..2d73827fe74e 100644
|
||||
--- a/drivers/usb/host/xhci.c
|
||||
+++ b/drivers/usb/host/xhci.c
|
||||
@@ -1415,6 +1415,87 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * 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
|
||||
+ */
|
||||
+static void xhci_fixup_interval(struct xhci_hcd *xhci, struct urb *urb,
|
||||
+ unsigned int slot_id, unsigned int ep_index)
|
||||
+{
|
||||
+ 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, ep_interval;
|
||||
+ int ret;
|
||||
+ unsigned long flags;
|
||||
+ u32 ep_info_tmp;
|
||||
+
|
||||
+ spin_lock_irqsave(&xhci->lock, flags);
|
||||
+
|
||||
+ vdev = xhci->devs[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));
|
||||
+ ep_interval = urb->interval * 8;
|
||||
+
|
||||
+ if (ep_interval == xhci_interval) {
|
||||
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ xhci_dbg(xhci, "Fixup interval ep_interval=%d xhci_interval=%d\n",
|
||||
+ ep_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);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* xHCI uses exponents for intervals... */
|
||||
+ xhci_interval = fls(ep_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);
|
||||
+ 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, urb->dev, command,
|
||||
+ false, false);
|
||||
+ if (ret)
|
||||
+ xhci_warn(xhci, "%s: Configure endpoint failed: %d\n",
|
||||
+ __func__, ret);
|
||||
+ xhci_free_command(xhci, command);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* non-error returns are a promise to giveback() the urb later
|
||||
* we drop ownership so next owner (or urb unlink) can get it
|
||||
@@ -1479,6 +1560,11 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
|
||||
}
|
||||
}
|
||||
|
||||
+ if (usb_endpoint_xfer_int(&urb->ep->desc) &&
|
||||
+ (urb->dev->speed == USB_SPEED_FULL ||
|
||||
+ urb->dev->speed == USB_SPEED_LOW))
|
||||
+ xhci_fixup_interval(xhci, urb, slot_id, ep_index);
|
||||
+
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
if (xhci->xhc_state & XHCI_STATE_DYING) {
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
From abcfd092860760087b87acbdda0963fe7906839c Mon Sep 17 00:00:00 2001
|
||||
From: Tim Gover <tim.gover@raspberrypi.org>
|
||||
Date: Wed, 9 Jan 2019 14:43:36 +0000
|
||||
Subject: [PATCH 560/678] pinctrl-bcm2835: Add support for BCM2838
|
||||
|
||||
GPIO configuration on BCM2838 is largely the same as BCM2835 except for
|
||||
the pull up/down configuration. The old mechanism has been replaced
|
||||
by new registers which don't require the fixed delay.
|
||||
|
||||
Detect BCN2838 at run-time and use the new mechanism. Backwards
|
||||
compatibility for the device-tree configuration has been retained.
|
||||
---
|
||||
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 58 ++++++++++++++++++++-------
|
||||
1 file changed, 44 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
index 475e0fbd03c8..0a61292924ec 100644
|
||||
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
@@ -67,6 +67,12 @@
|
||||
#define GPPUD 0x94 /* Pin Pull-up/down Enable */
|
||||
#define GPPUDCLK0 0x98 /* Pin Pull-up/down Enable Clock */
|
||||
|
||||
+/* 2711 has a different mechanism for pin pull-up/down/enable */
|
||||
+#define GPPUPPDN0 0xe4 /* Pin pull-up/down for pins 15:0 */
|
||||
+#define GPPUPPDN1 0xe8 /* Pin pull-up/down for pins 31:16 */
|
||||
+#define GPPUPPDN2 0xec /* Pin pull-up/down for pins 47:32 */
|
||||
+#define GPPUPPDN3 0xf0 /* Pin pull-up/down for pins 57:48 */
|
||||
+
|
||||
#define FSEL_REG(p) (GPFSEL0 + (((p) / 10) * 4))
|
||||
#define FSEL_SHIFT(p) (((p) % 10) * 3)
|
||||
#define GPIO_REG_OFFSET(p) ((p) / 32)
|
||||
@@ -917,21 +923,45 @@ static void bcm2835_pull_config_set(struct bcm2835_pinctrl *pc,
|
||||
unsigned int pin, unsigned int arg)
|
||||
{
|
||||
u32 off, bit;
|
||||
+ /* BCM2835, BCM2836 & BCM2837 return 'gpio' for this unused register */
|
||||
+ int is_2835 = bcm2835_gpio_rd(pc, GPPUPPDN3) == 0x6770696f;
|
||||
|
||||
- off = GPIO_REG_OFFSET(pin);
|
||||
- bit = GPIO_REG_SHIFT(pin);
|
||||
-
|
||||
- bcm2835_gpio_wr(pc, GPPUD, arg & 3);
|
||||
- /*
|
||||
- * BCM2835 datasheet say to wait 150 cycles, but not of what.
|
||||
- * But the VideoCore firmware delay for this operation
|
||||
- * based nearly on the same amount of VPU cycles and this clock
|
||||
- * runs at 250 MHz.
|
||||
- */
|
||||
- udelay(1);
|
||||
- bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
|
||||
- udelay(1);
|
||||
- bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
|
||||
+ if (is_2835) {
|
||||
+ off = GPIO_REG_OFFSET(pin);
|
||||
+ bit = GPIO_REG_SHIFT(pin);
|
||||
+ /*
|
||||
+ * BCM2835 datasheet say to wait 150 cycles, but not of what.
|
||||
+ * But the VideoCore firmware delay for this operation
|
||||
+ * based nearly on the same amount of VPU cycles and this clock
|
||||
+ * runs at 250 MHz.
|
||||
+ */
|
||||
+ bcm2835_gpio_wr(pc, GPPUD, arg & 3);
|
||||
+ udelay(1);
|
||||
+ bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
|
||||
+ udelay(1);
|
||||
+ bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
|
||||
+ } else {
|
||||
+ u32 reg;
|
||||
+ int lsb;
|
||||
+
|
||||
+ off = (pin >> 4);
|
||||
+ if (off > 3)
|
||||
+ return;
|
||||
+ lsb = (pin & 0xf) << 1;
|
||||
+
|
||||
+ /* The up/down semantics are reversed compared to BCM2835.
|
||||
+ * Instead of updating all the device tree files, translate the
|
||||
+ * values here.
|
||||
+ */
|
||||
+ if (arg == 2)
|
||||
+ arg = 1;
|
||||
+ else if (arg == 1)
|
||||
+ arg = 2;
|
||||
+ reg = bcm2835_gpio_rd(pc, GPPUPPDN0 + (off *4));
|
||||
+ reg &= ~(0x3 << lsb);
|
||||
+ reg |= (arg & 3) << lsb;
|
||||
+ bcm2835_gpio_wr(pc, GPPUPPDN0 + (off * 4), reg);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
From e33c10004ef2e1ed0e637de603ab3941e758f8af Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sperl <kernel@martin.sperl.org>
|
||||
Date: Mon, 13 May 2019 11:05:27 +0000
|
||||
Subject: [PATCH 561/678] spi: bcm2835: enable shared interrupt support
|
||||
|
||||
Add shared interrupt support for this driver.
|
||||
|
||||
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
|
||||
---
|
||||
drivers/spi/spi-bcm2835.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
|
||||
index 5816bae19d58..885740ccedfa 100644
|
||||
--- a/drivers/spi/spi-bcm2835.c
|
||||
+++ b/drivers/spi/spi-bcm2835.c
|
||||
@@ -150,6 +150,10 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
|
||||
struct spi_master *master = dev_id;
|
||||
struct bcm2835_spi *bs = spi_master_get_devdata(master);
|
||||
|
||||
+ /* 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 */
|
||||
@@ -755,7 +759,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
||||
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), master);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
From dbe83432062b4be86800da7b208434fde208437e Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
Date: Thu, 9 May 2019 14:30:37 +0100
|
||||
Subject: [PATCH 562/678] drivers: char: add chardev for mmap'ing Argon 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 <jonathan@raspberrypi.org>
|
||||
---
|
||||
drivers/char/broadcom/Kconfig | 8 +
|
||||
drivers/char/broadcom/Makefile | 1 +
|
||||
drivers/char/broadcom/argon-mem.c | 277 ++++++++++++++++++++++++++++++
|
||||
3 files changed, 286 insertions(+)
|
||||
create mode 100644 drivers/char/broadcom/argon-mem.c
|
||||
|
||||
diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig
|
||||
index cffd17df6a1b..4ba3fb4049eb 100644
|
||||
--- 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 ARGON_MEM
|
||||
+ tristate "Character device driver for the Argon 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 Argon
|
||||
+ video decoder hardware.
|
||||
diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile
|
||||
index 7d9cb3e0b1c3..50767fc1b569 100644
|
||||
--- 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_ARGON_MEM) += argon-mem.o
|
||||
diff --git a/drivers/char/broadcom/argon-mem.c b/drivers/char/broadcom/argon-mem.c
|
||||
new file mode 100644
|
||||
index 000000000000..01c36db7754a
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/argon-mem.c
|
||||
@@ -0,0 +1,277 @@
|
||||
+/**
|
||||
+ * argon-mem.c - character device access to the Argon 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 <jonathan@raspberrypi.org>
|
||||
+ * 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 <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/cdev.h>
|
||||
+#include <linux/pagemap.h>
|
||||
+#include <linux/io.h>
|
||||
+
|
||||
+#define DRIVER_NAME "argon-mem"
|
||||
+#define DEVICE_MINOR 0
|
||||
+
|
||||
+struct argon_mem_priv {
|
||||
+ dev_t devid;
|
||||
+ struct class *class;
|
||||
+ struct cdev argon_mem_cdev;
|
||||
+ unsigned long regs_phys;
|
||||
+ unsigned long mem_window_len;
|
||||
+ struct device *dev;
|
||||
+ const char *name;
|
||||
+};
|
||||
+
|
||||
+static int argon_mem_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ int dev = iminor(inode);
|
||||
+ int ret = 0;
|
||||
+ struct argon_mem_priv *priv;
|
||||
+ if (dev != DEVICE_MINOR)
|
||||
+ ret = -ENXIO;
|
||||
+
|
||||
+ priv = container_of(inode->i_cdev, struct argon_mem_priv,
|
||||
+ argon_mem_cdev);
|
||||
+ if (!priv)
|
||||
+ return -EINVAL;
|
||||
+ file->private_data = priv;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int argon_mem_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ int dev = iminor(inode);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (dev != DEVICE_MINOR)
|
||||
+ ret = -ENXIO;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct vm_operations_struct argon_mem_vm_ops = {
|
||||
+#ifdef CONFIG_HAVE_IOREMAP_PROT
|
||||
+ .access = generic_access_phys
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static int argon_mem_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
+{
|
||||
+ struct argon_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 = &argon_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
|
||||
+argon_mem_fops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .open = argon_mem_open,
|
||||
+ .release = argon_mem_release,
|
||||
+ .mmap = argon_mem_mmap,
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id argon_mem_of_match[];
|
||||
+static int argon_mem_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int err;
|
||||
+ void *ptr_err;
|
||||
+ const struct of_device_id *id;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device *argon_mem_dev;
|
||||
+ struct resource *ioresource;
|
||||
+ struct argon_mem_priv *priv;
|
||||
+
|
||||
+
|
||||
+ /* Allocate buffers and instance data */
|
||||
+
|
||||
+ priv = kzalloc(sizeof(struct argon_mem_priv), GFP_KERNEL);
|
||||
+
|
||||
+ if (!priv) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto failed_inst_alloc;
|
||||
+ }
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ priv->dev = dev;
|
||||
+ id = of_match_device(argon_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, 1, priv->name);
|
||||
+ if (err != 0) {
|
||||
+ dev_err(priv->dev, "unable to allocate device number");
|
||||
+ goto failed_alloc_chrdev;
|
||||
+ }
|
||||
+ cdev_init(&priv->argon_mem_cdev, &argon_mem_fops);
|
||||
+ priv->argon_mem_cdev.owner = THIS_MODULE;
|
||||
+ err = cdev_add(&priv->argon_mem_cdev, priv->devid, 1);
|
||||
+ 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;
|
||||
+
|
||||
+ argon_mem_dev = device_create(priv->class, NULL,
|
||||
+ priv->devid, NULL,
|
||||
+ priv->name);
|
||||
+ ptr_err = argon_mem_dev;
|
||||
+ if (IS_ERR(ptr_err))
|
||||
+ goto failed_device_create;
|
||||
+
|
||||
+ 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->argon_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 argon_mem");
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int argon_mem_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct argon_mem_priv *priv = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ device_destroy(priv->class, priv->devid);
|
||||
+ class_destroy(priv->class);
|
||||
+ cdev_del(&priv->argon_mem_cdev);
|
||||
+ unregister_chrdev_region(priv->devid, 1);
|
||||
+ kfree(priv);
|
||||
+
|
||||
+ dev_info(dev, "%s driver removed - OK", priv->name);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const char argon_hevc_name[] = "argon-hevcmem";
|
||||
+static const char argon_h264_name[] = "argon-h264mem";
|
||||
+static const char argon_vp9_name[] = "argon-vp9mem";
|
||||
+static const char argon_intc_name[] = "argon-intcmem";
|
||||
+
|
||||
+static const struct of_device_id argon_mem_of_match[] = {
|
||||
+ {
|
||||
+ .compatible = "raspberrypi,argon-hevc-decoder",
|
||||
+ .data = &argon_hevc_name,
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "raspberrypi,argon-h264-decoder",
|
||||
+ .data = &argon_h264_name,
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "raspberrypi,argon-vp9-decoder",
|
||||
+ .data = &argon_vp9_name,
|
||||
+ },
|
||||
+ /* The "intc" is included as this block of hardware contains the
|
||||
+ * "frame done" status flags.
|
||||
+ */
|
||||
+ {
|
||||
+ .compatible = "raspberrypi,argon-local-intc",
|
||||
+ .data = &argon_intc_name,
|
||||
+ },
|
||||
+ { /* sentinel */ },
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(of, argon_mem_of_match);
|
||||
+
|
||||
+static struct platform_driver argon_mem_driver = {
|
||||
+ .probe = argon_mem_probe,
|
||||
+ .remove = argon_mem_remove,
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = argon_mem_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(argon_mem_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:argon-mem");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION("Driver for accessing Argon decoder registers from userspace");
|
||||
+MODULE_AUTHOR("Jonathan Bell <jonathan@raspberrypi.org>");
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From e0a2bde82fc2323f2d6e2d51218df66b50b76fd0 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 23 Jan 2019 16:11:50 +0000
|
||||
Subject: [PATCH 563/678] clk-bcm2835: Don't wait for pllh lock
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 18 ++++++++++--------
|
||||
1 file changed, 10 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index 3e001a7467a0..b8da17a6e6cd 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -627,15 +627,17 @@ static int bcm2835_pll_on(struct clk_hw *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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
From ae3f6780c32d263019c1ac87f896b3a4066322a0 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 12 Dec 2018 15:51:47 -0800
|
||||
Subject: [PATCH 564/678] bcm2835-pm: Move bcm2835-watchdog's DT probe to an
|
||||
MFD.
|
||||
|
||||
The PM block that the wdt driver was binding to actually has multiple
|
||||
features we want to expose (power domains, reset, watchdog). Move the
|
||||
DT attachment to a MFD driver and make WDT probe against MFD.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
|
||||
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
(cherry picked from commit 5e6acc3e678ed3db746ab4fb53a980861cd711b6)
|
||||
---
|
||||
drivers/mfd/Makefile | 1 +
|
||||
drivers/mfd/bcm2835-pm.c | 64 ++++++++++++++++++++++++++++++++++
|
||||
drivers/watchdog/bcm2835_wdt.c | 26 +++++---------
|
||||
include/linux/mfd/bcm2835-pm.h | 13 +++++++
|
||||
4 files changed, 87 insertions(+), 17 deletions(-)
|
||||
create mode 100644 drivers/mfd/bcm2835-pm.c
|
||||
create mode 100644 include/linux/mfd/bcm2835-pm.h
|
||||
|
||||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
|
||||
index aa72f59f94c8..417ebd3abda6 100644
|
||||
--- a/drivers/mfd/Makefile
|
||||
+++ b/drivers/mfd/Makefile
|
||||
@@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o
|
||||
obj-$(CONFIG_MFD_ACT8945A) += act8945a.o
|
||||
obj-$(CONFIG_MFD_SM501) += sm501.o
|
||||
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
|
||||
+obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o
|
||||
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
|
||||
obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
|
||||
cros_ec_core-objs := cros_ec.o
|
||||
diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c
|
||||
new file mode 100644
|
||||
index 000000000000..53839e6a81e7
|
||||
--- /dev/null
|
||||
+++ b/drivers/mfd/bcm2835-pm.c
|
||||
@@ -0,0 +1,64 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * PM MFD driver for Broadcom BCM2835
|
||||
+ *
|
||||
+ * This driver binds to the PM block and creates the MFD device for
|
||||
+ * the WDT driver.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/mfd/bcm2835-pm.h>
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/watchdog.h>
|
||||
+
|
||||
+static const struct mfd_cell bcm2835_pm_devs[] = {
|
||||
+ { .name = "bcm2835-wdt" },
|
||||
+};
|
||||
+
|
||||
+static int bcm2835_pm_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct resource *res;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct bcm2835_pm *pm;
|
||||
+
|
||||
+ pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
|
||||
+ if (!pm)
|
||||
+ return -ENOMEM;
|
||||
+ platform_set_drvdata(pdev, pm);
|
||||
+
|
||||
+ pm->dev = dev;
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ pm->base = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(pm->base))
|
||||
+ return PTR_ERR(pm->base);
|
||||
+
|
||||
+ return devm_mfd_add_devices(dev, -1,
|
||||
+ bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
|
||||
+ NULL, 0, NULL);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id bcm2835_pm_of_match[] = {
|
||||
+ { .compatible = "brcm,bcm2835-pm-wdt", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
|
||||
+
|
||||
+static struct platform_driver bcm2835_pm_driver = {
|
||||
+ .probe = bcm2835_pm_probe,
|
||||
+ .driver = {
|
||||
+ .name = "bcm2835-pm",
|
||||
+ .of_match_table = bcm2835_pm_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(bcm2835_pm_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
|
||||
+MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM MFD");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
|
||||
index 9699e07119a7..4ed73194a64d 100644
|
||||
--- a/drivers/watchdog/bcm2835_wdt.c
|
||||
+++ b/drivers/watchdog/bcm2835_wdt.c
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/types.h>
|
||||
+#include <linux/mfd/bcm2835-pm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/watchdog.h>
|
||||
@@ -41,6 +42,8 @@ struct bcm2835_wdt {
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
+static struct bcm2835_wdt *bcm2835_power_off_wdt;
|
||||
+
|
||||
static unsigned int heartbeat;
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
|
||||
@@ -163,10 +166,7 @@ static struct watchdog_device bcm2835_wdt_wdd = {
|
||||
*/
|
||||
static void bcm2835_power_off(void)
|
||||
{
|
||||
- struct device_node *np =
|
||||
- of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
|
||||
- struct platform_device *pdev = of_find_device_by_node(np);
|
||||
- struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
|
||||
+ struct bcm2835_wdt *wdt = bcm2835_power_off_wdt;
|
||||
|
||||
/* Partition 63 tells the firmware that this is a halt */
|
||||
__bcm2835_restart(wdt, 63);
|
||||
@@ -174,7 +174,7 @@ static void bcm2835_power_off(void)
|
||||
|
||||
static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
- struct resource *res;
|
||||
+ struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm2835_wdt *wdt;
|
||||
int err;
|
||||
@@ -186,10 +186,7 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&wdt->lock);
|
||||
|
||||
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
- wdt->base = devm_ioremap_resource(dev, res);
|
||||
- if (IS_ERR(wdt->base))
|
||||
- return PTR_ERR(wdt->base);
|
||||
+ wdt->base = pm->base;
|
||||
|
||||
watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt);
|
||||
watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev);
|
||||
@@ -216,8 +213,10 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
- if (pm_power_off == NULL)
|
||||
+ if (pm_power_off == NULL) {
|
||||
pm_power_off = bcm2835_power_off;
|
||||
+ bcm2835_power_off_wdt = wdt;
|
||||
+ }
|
||||
|
||||
dev_info(dev, "Broadcom BCM2835 watchdog timer");
|
||||
return 0;
|
||||
@@ -231,18 +230,11 @@ static int bcm2835_wdt_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static const struct of_device_id bcm2835_wdt_of_match[] = {
|
||||
- { .compatible = "brcm,bcm2835-pm-wdt", },
|
||||
- {},
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match);
|
||||
-
|
||||
static struct platform_driver bcm2835_wdt_driver = {
|
||||
.probe = bcm2835_wdt_probe,
|
||||
.remove = bcm2835_wdt_remove,
|
||||
.driver = {
|
||||
.name = "bcm2835-wdt",
|
||||
- .of_match_table = bcm2835_wdt_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(bcm2835_wdt_driver);
|
||||
diff --git a/include/linux/mfd/bcm2835-pm.h b/include/linux/mfd/bcm2835-pm.h
|
||||
new file mode 100644
|
||||
index 000000000000..b7d0ee1feffa
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/bcm2835-pm.h
|
||||
@@ -0,0 +1,13 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+
|
||||
+#ifndef BCM2835_MFD_PM_H
|
||||
+#define BCM2835_MFD_PM_H
|
||||
+
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+struct bcm2835_pm {
|
||||
+ struct device *dev;
|
||||
+ void __iomem *base;
|
||||
+};
|
||||
+
|
||||
+#endif /* BCM2835_MFD_PM_H */
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,842 @@
|
|||
From 716e6e18ca272365477d63d03aad91c8adb1422d Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 12 Dec 2018 15:51:48 -0800
|
||||
Subject: [PATCH 565/678] soc: bcm: bcm2835-pm: Add support for power domains
|
||||
under a new binding.
|
||||
|
||||
This provides a free software alternative to raspberrypi-power.c's
|
||||
firmware calls to manage power domains. It also exposes a reset line,
|
||||
where previously the vc4 driver had to try to force power off the
|
||||
domain in order to trigger a reset.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Acked-by: Rob Herring <robh@kernel.org>
|
||||
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
|
||||
(cherry picked from commit 670c672608a1ffcbc7ac0f872734843593bb8b15)
|
||||
---
|
||||
drivers/mfd/bcm2835-pm.c | 36 +-
|
||||
drivers/soc/bcm/Kconfig | 11 +
|
||||
drivers/soc/bcm/Makefile | 1 +
|
||||
drivers/soc/bcm/bcm2835-power.c | 661 +++++++++++++++++++++++++++
|
||||
include/dt-bindings/soc/bcm2835-pm.h | 28 ++
|
||||
include/linux/mfd/bcm2835-pm.h | 1 +
|
||||
6 files changed, 734 insertions(+), 4 deletions(-)
|
||||
create mode 100644 drivers/soc/bcm/bcm2835-power.c
|
||||
create mode 100644 include/dt-bindings/soc/bcm2835-pm.h
|
||||
|
||||
diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c
|
||||
index 53839e6a81e7..42fe67f1538e 100644
|
||||
--- a/drivers/mfd/bcm2835-pm.c
|
||||
+++ b/drivers/mfd/bcm2835-pm.c
|
||||
@@ -3,7 +3,7 @@
|
||||
* PM MFD driver for Broadcom BCM2835
|
||||
*
|
||||
* This driver binds to the PM block and creates the MFD device for
|
||||
- * the WDT driver.
|
||||
+ * the WDT and power drivers.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
@@ -21,11 +21,16 @@ static const struct mfd_cell bcm2835_pm_devs[] = {
|
||||
{ .name = "bcm2835-wdt" },
|
||||
};
|
||||
|
||||
+static const struct mfd_cell bcm2835_power_devs[] = {
|
||||
+ { .name = "bcm2835-power" },
|
||||
+};
|
||||
+
|
||||
static int bcm2835_pm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm2835_pm *pm;
|
||||
+ int ret;
|
||||
|
||||
pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
|
||||
if (!pm)
|
||||
@@ -39,13 +44,36 @@ static int bcm2835_pm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(pm->base))
|
||||
return PTR_ERR(pm->base);
|
||||
|
||||
- return devm_mfd_add_devices(dev, -1,
|
||||
- bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
|
||||
- NULL, 0, NULL);
|
||||
+ ret = devm_mfd_add_devices(dev, -1,
|
||||
+ bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs),
|
||||
+ NULL, 0, NULL);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* 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.
|
||||
+ */
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
+ if (res) {
|
||||
+ pm->asb = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(pm->asb))
|
||||
+ return PTR_ERR(pm->asb);
|
||||
+
|
||||
+ ret = devm_mfd_add_devices(dev, -1,
|
||||
+ bcm2835_power_devs,
|
||||
+ ARRAY_SIZE(bcm2835_power_devs),
|
||||
+ NULL, 0, NULL);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm2835_pm_of_match[] = {
|
||||
{ .compatible = "brcm,bcm2835-pm-wdt", },
|
||||
+ { .compatible = "brcm,bcm2835-pm", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
|
||||
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
|
||||
index 587c61998b72..c24f505ecd65 100644
|
||||
--- a/drivers/soc/bcm/Kconfig
|
||||
+++ b/drivers/soc/bcm/Kconfig
|
||||
@@ -1,5 +1,16 @@
|
||||
menu "Broadcom SoC drivers"
|
||||
|
||||
+config BCM2835_POWER
|
||||
+ bool "BCM2835 power domain driver"
|
||||
+ depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
|
||||
+ select PM_GENERIC_DOMAINS if PM
|
||||
+ select RESET_CONTROLLER
|
||||
+ help
|
||||
+ This enables support for the BCM2835 power domains and reset
|
||||
+ controller. Any usage of power domains by the Raspberry Pi
|
||||
+ firmware means that Linux usage of the same power domain
|
||||
+ must be accessed using the RASPBERRYPI_POWER driver
|
||||
+
|
||||
config RASPBERRYPI_POWER
|
||||
bool "Raspberry Pi power domain driver"
|
||||
depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
|
||||
diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile
|
||||
index dc4fced72d21..c81df4b2403c 100644
|
||||
--- a/drivers/soc/bcm/Makefile
|
||||
+++ b/drivers/soc/bcm/Makefile
|
||||
@@ -1,2 +1,3 @@
|
||||
+obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o
|
||||
obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o
|
||||
obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
|
||||
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
|
||||
new file mode 100644
|
||||
index 000000000000..48412957ec7a
|
||||
--- /dev/null
|
||||
+++ b/drivers/soc/bcm/bcm2835-power.c
|
||||
@@ -0,0 +1,661 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Power domain driver for Broadcom BCM2835
|
||||
+ *
|
||||
+ * Copyright (C) 2018 Broadcom
|
||||
+ */
|
||||
+
|
||||
+#include <dt-bindings/soc/bcm2835-pm.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/mfd/bcm2835-pm.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/pm_domain.h>
|
||||
+#include <linux/reset-controller.h>
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+#define PM_GNRIC 0x00
|
||||
+#define PM_AUDIO 0x04
|
||||
+#define PM_STATUS 0x18
|
||||
+#define PM_RSTC 0x1c
|
||||
+#define PM_RSTS 0x20
|
||||
+#define PM_WDOG 0x24
|
||||
+#define PM_PADS0 0x28
|
||||
+#define PM_PADS2 0x2c
|
||||
+#define PM_PADS3 0x30
|
||||
+#define PM_PADS4 0x34
|
||||
+#define PM_PADS5 0x38
|
||||
+#define PM_PADS6 0x3c
|
||||
+#define PM_CAM0 0x44
|
||||
+#define PM_CAM0_LDOHPEN BIT(2)
|
||||
+#define PM_CAM0_LDOLPEN BIT(1)
|
||||
+#define PM_CAM0_CTRLEN BIT(0)
|
||||
+
|
||||
+#define PM_CAM1 0x48
|
||||
+#define PM_CAM1_LDOHPEN BIT(2)
|
||||
+#define PM_CAM1_LDOLPEN BIT(1)
|
||||
+#define PM_CAM1_CTRLEN BIT(0)
|
||||
+
|
||||
+#define PM_CCP2TX 0x4c
|
||||
+#define PM_CCP2TX_LDOEN BIT(1)
|
||||
+#define PM_CCP2TX_CTRLEN BIT(0)
|
||||
+
|
||||
+#define PM_DSI0 0x50
|
||||
+#define PM_DSI0_LDOHPEN BIT(2)
|
||||
+#define PM_DSI0_LDOLPEN BIT(1)
|
||||
+#define PM_DSI0_CTRLEN BIT(0)
|
||||
+
|
||||
+#define PM_DSI1 0x54
|
||||
+#define PM_DSI1_LDOHPEN BIT(2)
|
||||
+#define PM_DSI1_LDOLPEN BIT(1)
|
||||
+#define PM_DSI1_CTRLEN BIT(0)
|
||||
+
|
||||
+#define PM_HDMI 0x58
|
||||
+#define PM_HDMI_RSTDR BIT(19)
|
||||
+#define PM_HDMI_LDOPD BIT(1)
|
||||
+#define PM_HDMI_CTRLEN BIT(0)
|
||||
+
|
||||
+#define PM_USB 0x5c
|
||||
+/* The power gates must be enabled with this bit before enabling the LDO in the
|
||||
+ * USB block.
|
||||
+ */
|
||||
+#define PM_USB_CTRLEN BIT(0)
|
||||
+
|
||||
+#define PM_PXLDO 0x60
|
||||
+#define PM_PXBG 0x64
|
||||
+#define PM_DFT 0x68
|
||||
+#define PM_SMPS 0x6c
|
||||
+#define PM_XOSC 0x70
|
||||
+#define PM_SPAREW 0x74
|
||||
+#define PM_SPARER 0x78
|
||||
+#define PM_AVS_RSTDR 0x7c
|
||||
+#define PM_AVS_STAT 0x80
|
||||
+#define PM_AVS_EVENT 0x84
|
||||
+#define PM_AVS_INTEN 0x88
|
||||
+#define PM_DUMMY 0xfc
|
||||
+
|
||||
+#define PM_IMAGE 0x108
|
||||
+#define PM_GRAFX 0x10c
|
||||
+#define PM_PROC 0x110
|
||||
+#define PM_ENAB BIT(12)
|
||||
+#define PM_ISPRSTN BIT(8)
|
||||
+#define PM_H264RSTN BIT(7)
|
||||
+#define PM_PERIRSTN BIT(6)
|
||||
+#define PM_V3DRSTN BIT(6)
|
||||
+#define PM_ISFUNC BIT(5)
|
||||
+#define PM_MRDONE BIT(4)
|
||||
+#define PM_MEMREP BIT(3)
|
||||
+#define PM_ISPOW BIT(2)
|
||||
+#define PM_POWOK BIT(1)
|
||||
+#define PM_POWUP BIT(0)
|
||||
+#define PM_INRUSH_SHIFT 13
|
||||
+#define PM_INRUSH_3_5_MA 0
|
||||
+#define PM_INRUSH_5_MA 1
|
||||
+#define PM_INRUSH_10_MA 2
|
||||
+#define PM_INRUSH_20_MA 3
|
||||
+#define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT)
|
||||
+
|
||||
+#define PM_PASSWORD 0x5a000000
|
||||
+
|
||||
+#define PM_WDOG_TIME_SET 0x000fffff
|
||||
+#define PM_RSTC_WRCFG_CLR 0xffffffcf
|
||||
+#define PM_RSTS_HADWRH_SET 0x00000040
|
||||
+#define PM_RSTC_WRCFG_SET 0x00000030
|
||||
+#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
|
||||
+#define PM_RSTC_RESET 0x00000102
|
||||
+
|
||||
+#define PM_READ(reg) readl(power->base + (reg))
|
||||
+#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
|
||||
+
|
||||
+#define ASB_BRDG_VERSION 0x00
|
||||
+#define ASB_CPR_CTRL 0x04
|
||||
+
|
||||
+#define ASB_V3D_S_CTRL 0x08
|
||||
+#define ASB_V3D_M_CTRL 0x0c
|
||||
+#define ASB_ISP_S_CTRL 0x10
|
||||
+#define ASB_ISP_M_CTRL 0x14
|
||||
+#define ASB_H264_S_CTRL 0x18
|
||||
+#define ASB_H264_M_CTRL 0x1c
|
||||
+
|
||||
+#define ASB_REQ_STOP BIT(0)
|
||||
+#define ASB_ACK BIT(1)
|
||||
+#define ASB_EMPTY BIT(2)
|
||||
+#define ASB_FULL BIT(3)
|
||||
+
|
||||
+#define ASB_AXI_BRDG_ID 0x20
|
||||
+
|
||||
+#define ASB_READ(reg) readl(power->asb + (reg))
|
||||
+#define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg))
|
||||
+
|
||||
+struct bcm2835_power_domain {
|
||||
+ struct generic_pm_domain base;
|
||||
+ struct bcm2835_power *power;
|
||||
+ u32 domain;
|
||||
+ struct clk *clk;
|
||||
+};
|
||||
+
|
||||
+struct bcm2835_power {
|
||||
+ struct device *dev;
|
||||
+ /* PM registers. */
|
||||
+ void __iomem *base;
|
||||
+ /* AXI Async bridge registers. */
|
||||
+ void __iomem *asb;
|
||||
+
|
||||
+ struct genpd_onecell_data pd_xlate;
|
||||
+ struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
|
||||
+ struct reset_controller_dev reset;
|
||||
+};
|
||||
+
|
||||
+static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
|
||||
+{
|
||||
+ u64 start = ktime_get_ns();
|
||||
+
|
||||
+ /* Enable the module's async AXI bridges. */
|
||||
+ ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
|
||||
+ while (ASB_READ(reg) & ASB_ACK) {
|
||||
+ cpu_relax();
|
||||
+ if (ktime_get_ns() - start >= 1000)
|
||||
+ return -ETIMEDOUT;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
|
||||
+{
|
||||
+ u64 start = ktime_get_ns();
|
||||
+
|
||||
+ /* Enable the module's async AXI bridges. */
|
||||
+ ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
|
||||
+ while (!(ASB_READ(reg) & ASB_ACK)) {
|
||||
+ cpu_relax();
|
||||
+ if (ktime_get_ns() - start >= 1000)
|
||||
+ return -ETIMEDOUT;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
|
||||
+{
|
||||
+ struct bcm2835_power *power = pd->power;
|
||||
+
|
||||
+ /* Enable functional isolation */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
|
||||
+
|
||||
+ /* Enable electrical isolation */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
|
||||
+
|
||||
+ /* Open the power switches. */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
|
||||
+{
|
||||
+ struct bcm2835_power *power = pd->power;
|
||||
+ struct device *dev = power->dev;
|
||||
+ u64 start;
|
||||
+ int ret;
|
||||
+ int inrush;
|
||||
+ bool powok;
|
||||
+
|
||||
+ /* If it was already powered on by the fw, leave it that way. */
|
||||
+ if (PM_READ(pm_reg) & PM_POWUP)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Enable power. Allowing too much current at once may result
|
||||
+ * in POWOK never getting set, so start low and ramp it up as
|
||||
+ * necessary to succeed.
|
||||
+ */
|
||||
+ powok = false;
|
||||
+ for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
|
||||
+ PM_WRITE(pm_reg,
|
||||
+ (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
|
||||
+ (inrush << PM_INRUSH_SHIFT) |
|
||||
+ PM_POWUP);
|
||||
+
|
||||
+ start = ktime_get_ns();
|
||||
+ while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
|
||||
+ cpu_relax();
|
||||
+ if (ktime_get_ns() - start >= 3000)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!powok) {
|
||||
+ dev_err(dev, "Timeout waiting for %s power OK\n",
|
||||
+ pd->base.name);
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ goto err_disable_powup;
|
||||
+ }
|
||||
+
|
||||
+ /* Disable electrical isolation */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
|
||||
+
|
||||
+ /* Repair memory */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
|
||||
+ start = ktime_get_ns();
|
||||
+ while (!(PM_READ(pm_reg) & PM_MRDONE)) {
|
||||
+ cpu_relax();
|
||||
+ if (ktime_get_ns() - start >= 1000) {
|
||||
+ dev_err(dev, "Timeout waiting for %s memory repair\n",
|
||||
+ pd->base.name);
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ goto err_disable_ispow;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Disable functional isolation */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_disable_ispow:
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
|
||||
+err_disable_powup:
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
|
||||
+ u32 pm_reg,
|
||||
+ u32 asb_m_reg,
|
||||
+ u32 asb_s_reg,
|
||||
+ u32 reset_flags)
|
||||
+{
|
||||
+ struct bcm2835_power *power = pd->power;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = clk_prepare_enable(pd->clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(power->dev, "Failed to enable clock for %s\n",
|
||||
+ pd->base.name);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Wait 32 clocks for reset to propagate, 1 us will be enough */
|
||||
+ udelay(1);
|
||||
+
|
||||
+ clk_disable_unprepare(pd->clk);
|
||||
+
|
||||
+ /* Deassert the resets. */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
|
||||
+
|
||||
+ ret = clk_prepare_enable(pd->clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(power->dev, "Failed to enable clock for %s\n",
|
||||
+ pd->base.name);
|
||||
+ goto err_enable_resets;
|
||||
+ }
|
||||
+
|
||||
+ ret = bcm2835_asb_enable(power, asb_m_reg);
|
||||
+ if (ret) {
|
||||
+ dev_err(power->dev, "Failed to enable ASB master for %s\n",
|
||||
+ pd->base.name);
|
||||
+ goto err_disable_clk;
|
||||
+ }
|
||||
+ ret = bcm2835_asb_enable(power, asb_s_reg);
|
||||
+ if (ret) {
|
||||
+ dev_err(power->dev, "Failed to enable ASB slave for %s\n",
|
||||
+ pd->base.name);
|
||||
+ goto err_disable_asb_master;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_disable_asb_master:
|
||||
+ bcm2835_asb_disable(power, asb_m_reg);
|
||||
+err_disable_clk:
|
||||
+ clk_disable_unprepare(pd->clk);
|
||||
+err_enable_resets:
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
|
||||
+ u32 pm_reg,
|
||||
+ u32 asb_m_reg,
|
||||
+ u32 asb_s_reg,
|
||||
+ u32 reset_flags)
|
||||
+{
|
||||
+ struct bcm2835_power *power = pd->power;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = bcm2835_asb_disable(power, asb_s_reg);
|
||||
+ if (ret) {
|
||||
+ dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
|
||||
+ pd->base.name);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ ret = bcm2835_asb_disable(power, asb_m_reg);
|
||||
+ if (ret) {
|
||||
+ dev_warn(power->dev, "Failed to disable ASB master for %s\n",
|
||||
+ pd->base.name);
|
||||
+ bcm2835_asb_enable(power, asb_s_reg);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ clk_disable_unprepare(pd->clk);
|
||||
+
|
||||
+ /* Assert the resets. */
|
||||
+ PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
|
||||
+{
|
||||
+ struct bcm2835_power_domain *pd =
|
||||
+ container_of(domain, struct bcm2835_power_domain, base);
|
||||
+ struct bcm2835_power *power = pd->power;
|
||||
+
|
||||
+ switch (pd->domain) {
|
||||
+ case BCM2835_POWER_DOMAIN_GRAFX:
|
||||
+ return bcm2835_power_power_on(pd, PM_GRAFX);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_GRAFX_V3D:
|
||||
+ return bcm2835_asb_power_on(pd, PM_GRAFX,
|
||||
+ ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
|
||||
+ PM_V3DRSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE:
|
||||
+ return bcm2835_power_power_on(pd, PM_IMAGE);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE_PERI:
|
||||
+ return bcm2835_asb_power_on(pd, PM_IMAGE,
|
||||
+ 0, 0,
|
||||
+ PM_PERIRSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE_ISP:
|
||||
+ return bcm2835_asb_power_on(pd, PM_IMAGE,
|
||||
+ ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
|
||||
+ PM_ISPRSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE_H264:
|
||||
+ return bcm2835_asb_power_on(pd, PM_IMAGE,
|
||||
+ ASB_H264_M_CTRL, ASB_H264_S_CTRL,
|
||||
+ PM_H264RSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_USB:
|
||||
+ PM_WRITE(PM_USB, PM_USB_CTRLEN);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_DSI0:
|
||||
+ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
|
||||
+ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_DSI1:
|
||||
+ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
|
||||
+ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_CCP2TX:
|
||||
+ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
|
||||
+ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_HDMI:
|
||||
+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
|
||||
+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
|
||||
+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
|
||||
+ usleep_range(100, 200);
|
||||
+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
|
||||
+ return 0;
|
||||
+
|
||||
+ default:
|
||||
+ dev_err(power->dev, "Invalid domain %d\n", pd->domain);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
|
||||
+{
|
||||
+ struct bcm2835_power_domain *pd =
|
||||
+ container_of(domain, struct bcm2835_power_domain, base);
|
||||
+ struct bcm2835_power *power = pd->power;
|
||||
+
|
||||
+ switch (pd->domain) {
|
||||
+ case BCM2835_POWER_DOMAIN_GRAFX:
|
||||
+ return bcm2835_power_power_off(pd, PM_GRAFX);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_GRAFX_V3D:
|
||||
+ return bcm2835_asb_power_off(pd, PM_GRAFX,
|
||||
+ ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
|
||||
+ PM_V3DRSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE:
|
||||
+ return bcm2835_power_power_off(pd, PM_IMAGE);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE_PERI:
|
||||
+ return bcm2835_asb_power_off(pd, PM_IMAGE,
|
||||
+ 0, 0,
|
||||
+ PM_PERIRSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE_ISP:
|
||||
+ return bcm2835_asb_power_off(pd, PM_IMAGE,
|
||||
+ ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
|
||||
+ PM_ISPRSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_IMAGE_H264:
|
||||
+ return bcm2835_asb_power_off(pd, PM_IMAGE,
|
||||
+ ASB_H264_M_CTRL, ASB_H264_S_CTRL,
|
||||
+ PM_H264RSTN);
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_USB:
|
||||
+ PM_WRITE(PM_USB, 0);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_DSI0:
|
||||
+ PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
|
||||
+ PM_WRITE(PM_DSI0, 0);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_DSI1:
|
||||
+ PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
|
||||
+ PM_WRITE(PM_DSI1, 0);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_CCP2TX:
|
||||
+ PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
|
||||
+ PM_WRITE(PM_CCP2TX, 0);
|
||||
+ return 0;
|
||||
+
|
||||
+ case BCM2835_POWER_DOMAIN_HDMI:
|
||||
+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
|
||||
+ PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
|
||||
+ return 0;
|
||||
+
|
||||
+ default:
|
||||
+ dev_err(power->dev, "Invalid domain %d\n", pd->domain);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+bcm2835_init_power_domain(struct bcm2835_power *power,
|
||||
+ int pd_xlate_index, const char *name)
|
||||
+{
|
||||
+ struct device *dev = power->dev;
|
||||
+ struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
|
||||
+
|
||||
+ dom->clk = devm_clk_get(dev->parent, name);
|
||||
+
|
||||
+ dom->base.name = name;
|
||||
+ dom->base.power_on = bcm2835_power_pd_power_on;
|
||||
+ dom->base.power_off = bcm2835_power_pd_power_off;
|
||||
+
|
||||
+ dom->domain = pd_xlate_index;
|
||||
+ dom->power = power;
|
||||
+
|
||||
+ /* XXX: on/off at boot? */
|
||||
+ pm_genpd_init(&dom->base, NULL, true);
|
||||
+
|
||||
+ power->pd_xlate.domains[pd_xlate_index] = &dom->base;
|
||||
+}
|
||||
+
|
||||
+/** bcm2835_reset_reset - Resets a block that has a reset line in the
|
||||
+ * PM block.
|
||||
+ *
|
||||
+ * The consumer of the reset controller must have the power domain up
|
||||
+ * -- there's no reset ability with the power domain down. To reset
|
||||
+ * the sub-block, we just disable its access to memory through the
|
||||
+ * ASB, reset, and re-enable.
|
||||
+ */
|
||||
+static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
|
||||
+ unsigned long id)
|
||||
+{
|
||||
+ struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
|
||||
+ reset);
|
||||
+ struct bcm2835_power_domain *pd;
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (id) {
|
||||
+ case BCM2835_RESET_V3D:
|
||||
+ pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
|
||||
+ break;
|
||||
+ case BCM2835_RESET_H264:
|
||||
+ pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
|
||||
+ break;
|
||||
+ case BCM2835_RESET_ISP:
|
||||
+ pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(power->dev, "Bad reset id %ld\n", id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ ret = bcm2835_power_pd_power_off(&pd->base);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return bcm2835_power_pd_power_on(&pd->base);
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
|
||||
+ unsigned long id)
|
||||
+{
|
||||
+ struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
|
||||
+ reset);
|
||||
+
|
||||
+ switch (id) {
|
||||
+ case BCM2835_RESET_V3D:
|
||||
+ return !PM_READ(PM_GRAFX & PM_V3DRSTN);
|
||||
+ case BCM2835_RESET_H264:
|
||||
+ return !PM_READ(PM_IMAGE & PM_H264RSTN);
|
||||
+ case BCM2835_RESET_ISP:
|
||||
+ return !PM_READ(PM_IMAGE & PM_ISPRSTN);
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+const struct reset_control_ops bcm2835_reset_ops = {
|
||||
+ .reset = bcm2835_reset_reset,
|
||||
+ .status = bcm2835_reset_status,
|
||||
+};
|
||||
+
|
||||
+static const char *const power_domain_names[] = {
|
||||
+ [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
|
||||
+ [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
|
||||
+
|
||||
+ [BCM2835_POWER_DOMAIN_IMAGE] = "image",
|
||||
+ [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
|
||||
+ [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
|
||||
+ [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
|
||||
+
|
||||
+ [BCM2835_POWER_DOMAIN_USB] = "usb",
|
||||
+ [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
|
||||
+ [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
|
||||
+ [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
|
||||
+ [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
|
||||
+ [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
|
||||
+ [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
|
||||
+};
|
||||
+
|
||||
+static int bcm2835_power_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct bcm2835_power *power;
|
||||
+ static const struct {
|
||||
+ int parent, child;
|
||||
+ } domain_deps[] = {
|
||||
+ { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
|
||||
+ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
|
||||
+ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
|
||||
+ { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
|
||||
+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
|
||||
+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
|
||||
+ { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
|
||||
+ };
|
||||
+ int ret, i;
|
||||
+ u32 id;
|
||||
+
|
||||
+ power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
|
||||
+ if (!power)
|
||||
+ return -ENOMEM;
|
||||
+ platform_set_drvdata(pdev, power);
|
||||
+
|
||||
+ power->dev = dev;
|
||||
+ power->base = pm->base;
|
||||
+ power->asb = pm->asb;
|
||||
+
|
||||
+ id = ASB_READ(ASB_AXI_BRDG_ID);
|
||||
+ if (id != 0x62726467 /* "BRDG" */) {
|
||||
+ dev_err(dev, "ASB register ID returned 0x%08x\n", id);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ power->pd_xlate.domains = devm_kcalloc(dev,
|
||||
+ ARRAY_SIZE(power_domain_names),
|
||||
+ sizeof(*power->pd_xlate.domains),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!power->pd_xlate.domains)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++)
|
||||
+ bcm2835_init_power_domain(power, i, power_domain_names[i]);
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
|
||||
+ pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
|
||||
+ &power->domains[domain_deps[i].child].base);
|
||||
+ }
|
||||
+
|
||||
+ power->reset.owner = THIS_MODULE;
|
||||
+ power->reset.nr_resets = BCM2835_RESET_COUNT;
|
||||
+ power->reset.ops = &bcm2835_reset_ops;
|
||||
+ power->reset.of_node = dev->parent->of_node;
|
||||
+
|
||||
+ ret = devm_reset_controller_register(dev, &power->reset);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
|
||||
+
|
||||
+ dev_info(dev, "Broadcom BCM2835 power domains driver");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_power_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver bcm2835_power_driver = {
|
||||
+ .probe = bcm2835_power_probe,
|
||||
+ .remove = bcm2835_power_remove,
|
||||
+ .driver = {
|
||||
+ .name = "bcm2835-power",
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(bcm2835_power_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
|
||||
+MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/include/dt-bindings/soc/bcm2835-pm.h b/include/dt-bindings/soc/bcm2835-pm.h
|
||||
new file mode 100644
|
||||
index 000000000000..153d75b8d99f
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/soc/bcm2835-pm.h
|
||||
@@ -0,0 +1,28 @@
|
||||
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||
+
|
||||
+#ifndef _DT_BINDINGS_ARM_BCM2835_PM_H
|
||||
+#define _DT_BINDINGS_ARM_BCM2835_PM_H
|
||||
+
|
||||
+#define BCM2835_POWER_DOMAIN_GRAFX 0
|
||||
+#define BCM2835_POWER_DOMAIN_GRAFX_V3D 1
|
||||
+#define BCM2835_POWER_DOMAIN_IMAGE 2
|
||||
+#define BCM2835_POWER_DOMAIN_IMAGE_PERI 3
|
||||
+#define BCM2835_POWER_DOMAIN_IMAGE_ISP 4
|
||||
+#define BCM2835_POWER_DOMAIN_IMAGE_H264 5
|
||||
+#define BCM2835_POWER_DOMAIN_USB 6
|
||||
+#define BCM2835_POWER_DOMAIN_DSI0 7
|
||||
+#define BCM2835_POWER_DOMAIN_DSI1 8
|
||||
+#define BCM2835_POWER_DOMAIN_CAM0 9
|
||||
+#define BCM2835_POWER_DOMAIN_CAM1 10
|
||||
+#define BCM2835_POWER_DOMAIN_CCP2TX 11
|
||||
+#define BCM2835_POWER_DOMAIN_HDMI 12
|
||||
+
|
||||
+#define BCM2835_POWER_DOMAIN_COUNT 13
|
||||
+
|
||||
+#define BCM2835_RESET_V3D 0
|
||||
+#define BCM2835_RESET_ISP 1
|
||||
+#define BCM2835_RESET_H264 2
|
||||
+
|
||||
+#define BCM2835_RESET_COUNT 3
|
||||
+
|
||||
+#endif /* _DT_BINDINGS_ARM_BCM2835_PM_H */
|
||||
diff --git a/include/linux/mfd/bcm2835-pm.h b/include/linux/mfd/bcm2835-pm.h
|
||||
index b7d0ee1feffa..ed37dc40e82a 100644
|
||||
--- a/include/linux/mfd/bcm2835-pm.h
|
||||
+++ b/include/linux/mfd/bcm2835-pm.h
|
||||
@@ -8,6 +8,7 @@
|
||||
struct bcm2835_pm {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
+ void __iomem *asb;
|
||||
};
|
||||
|
||||
#endif /* BCM2835_MFD_PM_H */
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From 332fd3975fec374d1b84b3523f610d70c674d120 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 11 Jan 2019 17:29:10 -0800
|
||||
Subject: [PATCH 566/678] soc: bcm: bcm2835-pm: Fix PM_IMAGE_PERI power domain
|
||||
support.
|
||||
|
||||
We don't have ASB master/slave regs for this domain, so just skip that
|
||||
step.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Fixes: 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
|
||||
---
|
||||
drivers/soc/bcm/bcm2835-power.c | 14 ++++++++++++--
|
||||
1 file changed, 12 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
|
||||
index 48412957ec7a..4a1b99b773c0 100644
|
||||
--- a/drivers/soc/bcm/bcm2835-power.c
|
||||
+++ b/drivers/soc/bcm/bcm2835-power.c
|
||||
@@ -150,7 +150,12 @@ struct bcm2835_power {
|
||||
|
||||
static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
|
||||
{
|
||||
- u64 start = ktime_get_ns();
|
||||
+ u64 start;
|
||||
+
|
||||
+ if (!reg)
|
||||
+ return 0;
|
||||
+
|
||||
+ start = ktime_get_ns();
|
||||
|
||||
/* Enable the module's async AXI bridges. */
|
||||
ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP);
|
||||
@@ -165,7 +170,12 @@ static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
|
||||
|
||||
static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
|
||||
{
|
||||
- u64 start = ktime_get_ns();
|
||||
+ u64 start;
|
||||
+
|
||||
+ if (!reg)
|
||||
+ return 0;
|
||||
+
|
||||
+ start = ktime_get_ns();
|
||||
|
||||
/* Enable the module's async AXI bridges. */
|
||||
ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP);
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
From 3c369e68d729714343f2bc322eda0e36ce963607 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Sat, 12 Jan 2019 08:07:43 -0800
|
||||
Subject: [PATCH 567/678] soc: bcm: bcm2835-pm: Fix error paths of
|
||||
initialization.
|
||||
|
||||
The clock driver may probe after ours and so we need to pass the
|
||||
-EPROBE_DEFER out. Fix the other error path while we're here.
|
||||
|
||||
v2: Use dom->name instead of dom->gov as the flag for initialized
|
||||
domains, since we aren't setting up a governor. Make sure to
|
||||
clear ->clk when no clk is present in the DT.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Fixes: 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
|
||||
---
|
||||
drivers/soc/bcm/bcm2835-power.c | 35 ++++++++++++++++++++++++++++-----
|
||||
1 file changed, 30 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
|
||||
index 4a1b99b773c0..241c4ed80899 100644
|
||||
--- a/drivers/soc/bcm/bcm2835-power.c
|
||||
+++ b/drivers/soc/bcm/bcm2835-power.c
|
||||
@@ -485,7 +485,7 @@ static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
|
||||
}
|
||||
}
|
||||
|
||||
-static void
|
||||
+static int
|
||||
bcm2835_init_power_domain(struct bcm2835_power *power,
|
||||
int pd_xlate_index, const char *name)
|
||||
{
|
||||
@@ -493,6 +493,17 @@ bcm2835_init_power_domain(struct bcm2835_power *power,
|
||||
struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
|
||||
|
||||
dom->clk = devm_clk_get(dev->parent, name);
|
||||
+ if (IS_ERR(dom->clk)) {
|
||||
+ int ret = PTR_ERR(dom->clk);
|
||||
+
|
||||
+ if (ret == -EPROBE_DEFER)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Some domains don't have a clk, so make sure that we
|
||||
+ * don't deref an error pointer later.
|
||||
+ */
|
||||
+ dom->clk = NULL;
|
||||
+ }
|
||||
|
||||
dom->base.name = name;
|
||||
dom->base.power_on = bcm2835_power_pd_power_on;
|
||||
@@ -505,6 +516,8 @@ bcm2835_init_power_domain(struct bcm2835_power *power,
|
||||
pm_genpd_init(&dom->base, NULL, true);
|
||||
|
||||
power->pd_xlate.domains[pd_xlate_index] = &dom->base;
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/** bcm2835_reset_reset - Resets a block that has a reset line in the
|
||||
@@ -602,7 +615,7 @@ static int bcm2835_power_probe(struct platform_device *pdev)
|
||||
{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
|
||||
{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
|
||||
};
|
||||
- int ret, i;
|
||||
+ int ret = 0, i;
|
||||
u32 id;
|
||||
|
||||
power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
|
||||
@@ -629,8 +642,11 @@ static int bcm2835_power_probe(struct platform_device *pdev)
|
||||
|
||||
power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(power_domain_names); i++)
|
||||
- bcm2835_init_power_domain(power, i, power_domain_names[i]);
|
||||
+ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
|
||||
+ ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
|
||||
+ if (ret)
|
||||
+ goto fail;
|
||||
+ }
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
|
||||
pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
|
||||
@@ -644,12 +660,21 @@ static int bcm2835_power_probe(struct platform_device *pdev)
|
||||
|
||||
ret = devm_reset_controller_register(dev, &power->reset);
|
||||
if (ret)
|
||||
- return ret;
|
||||
+ goto fail;
|
||||
|
||||
of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
|
||||
|
||||
dev_info(dev, "Broadcom BCM2835 power domains driver");
|
||||
return 0;
|
||||
+
|
||||
+fail:
|
||||
+ for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
|
||||
+ struct generic_pm_domain *dom = &power->domains[i].base;
|
||||
+
|
||||
+ if (dom->name)
|
||||
+ pm_genpd_remove(dom);
|
||||
+ }
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static int bcm2835_power_remove(struct platform_device *pdev)
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
From f1793128b677a963b7521ec0ca0845b98869fde9 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 11 Jan 2019 17:31:07 -0800
|
||||
Subject: [PATCH 568/678] 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 <eric@anholt.net>
|
||||
---
|
||||
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(+)
|
||||
|
||||
diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c
|
||||
index 42fe67f1538e..ab1e9cbc50b1 100644
|
||||
--- a/drivers/mfd/bcm2835-pm.c
|
||||
+++ b/drivers/mfd/bcm2835-pm.c
|
||||
@@ -50,6 +50,17 @@ static int bcm2835_pm_probe(struct platform_device *pdev)
|
||||
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.
|
||||
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
|
||||
index 241c4ed80899..918cf54ab9ef 100644
|
||||
--- 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(struct bcm2835_power_domain *pd, u32 pm_reg)
|
||||
{
|
||||
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 bcm2835_power_domain *pd, u32 pm_reg)
|
||||
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 platform_device *pdev)
|
||||
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);
|
||||
diff --git a/include/linux/mfd/bcm2835-pm.h b/include/linux/mfd/bcm2835-pm.h
|
||||
index ed37dc40e82a..b2d157091e12 100644
|
||||
--- 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 */
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
From 0ae366ee1b94caf7abfd0e07505b14d9dde56bcc Mon Sep 17 00:00:00 2001
|
||||
From: Chunming Zhou <david1.zhou@amd.com>
|
||||
Date: Thu, 30 Aug 2018 14:48:29 +0800
|
||||
Subject: [PATCH 569/678] drm: expand drm_syncobj_find_fence to support
|
||||
timeline point v2
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
we can fetch timeline point fence after expanded.
|
||||
v2: The parameter fence is the result of the function and should come last.
|
||||
|
||||
Signed-off-by: Chunming Zhou <david1.zhou@amd.com>
|
||||
Reviewed-by: Christian König <christian.koenig@amd.com>
|
||||
Signed-off-by: Christian König <christian.koenig@amd.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/246541/
|
||||
(cherry picked from commit 0a6730ea27b68c7ac4171c29a816c29d26a9637a)
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +-
|
||||
drivers/gpu/drm/drm_syncobj.c | 5 +++--
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 4 ++--
|
||||
drivers/gpu/drm/vc4/vc4_gem.c | 2 +-
|
||||
include/drm/drm_syncobj.h | 2 +-
|
||||
5 files changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
|
||||
index 81001d879322..b5753d7802d3 100644
|
||||
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
|
||||
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
|
||||
@@ -1105,7 +1105,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
|
||||
{
|
||||
int r;
|
||||
struct dma_fence *fence;
|
||||
- r = drm_syncobj_find_fence(p->filp, handle, &fence);
|
||||
+ r = drm_syncobj_find_fence(p->filp, handle, 0, &fence);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
|
||||
index 759278fef35a..4ab6e78559e3 100644
|
||||
--- a/drivers/gpu/drm/drm_syncobj.c
|
||||
+++ b/drivers/gpu/drm/drm_syncobj.c
|
||||
@@ -235,6 +235,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
|
||||
* drm_syncobj_find_fence - lookup and reference the fence in a sync object
|
||||
* @file_private: drm file private pointer
|
||||
* @handle: sync object handle to lookup.
|
||||
+ * @point: timeline point
|
||||
* @fence: out parameter for the fence
|
||||
*
|
||||
* This is just a convenience function that combines drm_syncobj_find() and
|
||||
@@ -245,7 +246,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
|
||||
* dma_fence_put().
|
||||
*/
|
||||
int drm_syncobj_find_fence(struct drm_file *file_private,
|
||||
- u32 handle,
|
||||
+ u32 handle, u64 point,
|
||||
struct dma_fence **fence)
|
||||
{
|
||||
struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
|
||||
@@ -516,7 +517,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
- ret = drm_syncobj_find_fence(file_private, handle, &fence);
|
||||
+ ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
|
||||
if (ret)
|
||||
goto err_put_fd;
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 5ce24098a5fd..9b9ab34fb461 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -521,12 +521,12 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
kref_init(&exec->refcount);
|
||||
|
||||
ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
|
||||
- &exec->bin.in_fence);
|
||||
+ 0, &exec->bin.in_fence);
|
||||
if (ret == -EINVAL)
|
||||
goto fail;
|
||||
|
||||
ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
|
||||
- &exec->render.in_fence);
|
||||
+ 0, &exec->render.in_fence);
|
||||
if (ret == -EINVAL)
|
||||
goto fail;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
index 7910b9acedd6..928718b467bd 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
if (args->in_sync) {
|
||||
ret = drm_syncobj_find_fence(file_priv, args->in_sync,
|
||||
- &in_fence);
|
||||
+ 0, &in_fence);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
|
||||
index 3980602472c0..da4a4ddd32bd 100644
|
||||
--- a/include/drm/drm_syncobj.h
|
||||
+++ b/include/drm/drm_syncobj.h
|
||||
@@ -139,7 +139,7 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
|
||||
void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
|
||||
struct dma_fence *fence);
|
||||
int drm_syncobj_find_fence(struct drm_file *file_private,
|
||||
- u32 handle,
|
||||
+ u32 handle, u64 point,
|
||||
struct dma_fence **fence);
|
||||
void drm_syncobj_free(struct kref *kref);
|
||||
int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
From 047c917b9b1309e24bedc5f6a794e40b2b544da3 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 28 Sep 2018 16:21:23 -0700
|
||||
Subject: [PATCH 570/678] drm/v3d: Fix a use-after-free race accessing the
|
||||
scheduler's fences.
|
||||
|
||||
Once we push the job, the scheduler could run it and free it. So, if
|
||||
we want to reference their fences, we need to grab them before then.
|
||||
I haven't seen this happen in many days of conformance test runtime,
|
||||
but let's still close the race.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
|
||||
Link: https://patchwork.freedesktop.org/patch/254119/
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
(cherry picked from commit 34c2c4f632f232ed2fdb66d4e42cc72d322273fe)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 5 +++++
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++++--
|
||||
2 files changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index 0ad73f4b7509..eb32ff45a085 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -198,6 +198,11 @@ struct v3d_exec_info {
|
||||
*/
|
||||
struct dma_fence *bin_done_fence;
|
||||
|
||||
+ /* Fence for when the scheduler considers the render to be
|
||||
+ * done, for when the BOs reservations should be complete.
|
||||
+ */
|
||||
+ struct dma_fence *render_done_fence;
|
||||
+
|
||||
struct kref refcount;
|
||||
|
||||
/* This is the array of BOs that were looked up at the start of exec. */
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 9b9ab34fb461..5c13b0807879 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -209,7 +209,7 @@ v3d_flush_caches(struct v3d_dev *v3d)
|
||||
static void
|
||||
v3d_attach_object_fences(struct v3d_exec_info *exec)
|
||||
{
|
||||
- struct dma_fence *out_fence = &exec->render.base.s_fence->finished;
|
||||
+ struct dma_fence *out_fence = exec->render_done_fence;
|
||||
struct v3d_bo *bo;
|
||||
int i;
|
||||
|
||||
@@ -409,6 +409,7 @@ v3d_exec_cleanup(struct kref *ref)
|
||||
dma_fence_put(exec->render.done_fence);
|
||||
|
||||
dma_fence_put(exec->bin_done_fence);
|
||||
+ dma_fence_put(exec->render_done_fence);
|
||||
|
||||
for (i = 0; i < exec->bo_count; i++)
|
||||
drm_gem_object_put_unlocked(&exec->bo[i]->base);
|
||||
@@ -572,6 +573,9 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
if (ret)
|
||||
goto fail_unreserve;
|
||||
|
||||
+ exec->render_done_fence =
|
||||
+ dma_fence_get(&exec->render.base.s_fence->finished);
|
||||
+
|
||||
kref_get(&exec->refcount); /* put by scheduler job completion */
|
||||
drm_sched_entity_push_job(&exec->render.base,
|
||||
&v3d_priv->sched_entity[V3D_RENDER]);
|
||||
@@ -585,7 +589,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
sync_out = drm_syncobj_find(file_priv, args->out_sync);
|
||||
if (sync_out) {
|
||||
drm_syncobj_replace_fence(sync_out,
|
||||
- &exec->render.base.s_fence->finished);
|
||||
+ exec->render_done_fence);
|
||||
drm_syncobj_put(sync_out);
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
From 8545eb3f198f69c1575c6c731f98e0ce2885a61d Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 28 Sep 2018 16:21:24 -0700
|
||||
Subject: [PATCH 571/678] drm/v3d: Add a little debugfs entry for measuring the
|
||||
core clock.
|
||||
|
||||
This adds just enough performance counter support to measure the
|
||||
clock. We don't have linux kernel drivers for the clock driving the
|
||||
HW, and this was useful for determining that the V3D HW is running on
|
||||
a slow clock, not that the driver was slow.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20180928232126.4332-2-eric@anholt.net
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
(cherry picked from commit 6915c9a525e575732429c22b28eb11871a29374b)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_debugfs.c | 35 +++++++++++++++++++++++++++++++
|
||||
drivers/gpu/drm/v3d/v3d_regs.h | 30 ++++++++++++++++++++++++++
|
||||
2 files changed, 65 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
index 26470c77eb6e..eb2b2d2f8553 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
@@ -179,9 +179,44 @@ static int v3d_debugfs_bo_stats(struct seq_file *m, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int v3d_measure_clock(struct seq_file *m, void *unused)
|
||||
+{
|
||||
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
+ struct drm_device *dev = node->minor->dev;
|
||||
+ struct v3d_dev *v3d = to_v3d_dev(dev);
|
||||
+ uint32_t cycles;
|
||||
+ int core = 0;
|
||||
+ int measure_ms = 1000;
|
||||
+
|
||||
+ if (v3d->ver >= 40) {
|
||||
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
|
||||
+ V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
|
||||
+ V3D_PCTR_S0));
|
||||
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
|
||||
+ V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
|
||||
+ } else {
|
||||
+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_PCTRS0,
|
||||
+ V3D_PCTR_CYCLE_COUNT);
|
||||
+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_CLR, 1);
|
||||
+ V3D_CORE_WRITE(core, V3D_V3_PCTR_0_EN,
|
||||
+ V3D_V3_PCTR_0_EN_ENABLE |
|
||||
+ 1);
|
||||
+ }
|
||||
+ msleep(measure_ms);
|
||||
+ cycles = V3D_CORE_READ(core, V3D_PCTR_0_PCTR0);
|
||||
+
|
||||
+ seq_printf(m, "cycles: %d (%d.%d Mhz)\n",
|
||||
+ cycles,
|
||||
+ cycles / (measure_ms * 1000),
|
||||
+ (cycles / (measure_ms * 100)) % 10);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static const struct drm_info_list v3d_debugfs_list[] = {
|
||||
{"v3d_ident", v3d_v3d_debugfs_ident, 0},
|
||||
{"v3d_regs", v3d_v3d_debugfs_regs, 0},
|
||||
+ {"measure_clock", v3d_measure_clock, 0},
|
||||
{"bo_stats", v3d_debugfs_bo_stats, 0},
|
||||
};
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
index 854046565989..c3a5e4e44f73 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
@@ -267,6 +267,36 @@
|
||||
# define V3D_PTB_BXCF_RWORDERDISA BIT(1)
|
||||
# define V3D_PTB_BXCF_CLIPDISA BIT(0)
|
||||
|
||||
+#define V3D_V3_PCTR_0_EN 0x00674
|
||||
+#define V3D_V3_PCTR_0_EN_ENABLE BIT(31)
|
||||
+#define V3D_V4_PCTR_0_EN 0x00650
|
||||
+/* When a bit is set, resets the counter to 0. */
|
||||
+#define V3D_V3_PCTR_0_CLR 0x00670
|
||||
+#define V3D_V4_PCTR_0_CLR 0x00654
|
||||
+#define V3D_PCTR_0_OVERFLOW 0x00658
|
||||
+
|
||||
+#define V3D_V3_PCTR_0_PCTRS0 0x00684
|
||||
+#define V3D_V3_PCTR_0_PCTRS15 0x00660
|
||||
+#define V3D_V3_PCTR_0_PCTRSX(x) (V3D_V3_PCTR_0_PCTRS0 + \
|
||||
+ 4 * (x))
|
||||
+/* Each src reg muxes four counters each. */
|
||||
+#define V3D_V4_PCTR_0_SRC_0_3 0x00660
|
||||
+#define V3D_V4_PCTR_0_SRC_28_31 0x0067c
|
||||
+# define V3D_PCTR_S0_MASK V3D_MASK(6, 0)
|
||||
+# define V3D_PCTR_S0_SHIFT 0
|
||||
+# define V3D_PCTR_S1_MASK V3D_MASK(14, 8)
|
||||
+# define V3D_PCTR_S1_SHIFT 8
|
||||
+# define V3D_PCTR_S2_MASK V3D_MASK(22, 16)
|
||||
+# define V3D_PCTR_S2_SHIFT 16
|
||||
+# define V3D_PCTR_S3_MASK V3D_MASK(30, 24)
|
||||
+# define V3D_PCTR_S3_SHIFT 24
|
||||
+# define V3D_PCTR_CYCLE_COUNT 32
|
||||
+
|
||||
+/* Output values of the counters. */
|
||||
+#define V3D_PCTR_0_PCTR0 0x00680
|
||||
+#define V3D_PCTR_0_PCTR31 0x006fc
|
||||
+#define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \
|
||||
+ 4 * (x))
|
||||
#define V3D_GMP_STATUS 0x00800
|
||||
# define V3D_GMP_STATUS_GMPRST BIT(31)
|
||||
# define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24)
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From 44c52631e0a3e0a0d7a3326fb295bab564abd070 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 8 Nov 2018 08:16:52 -0800
|
||||
Subject: [PATCH 572/678] drm/v3d: Update a comment about what uses
|
||||
v3d_job_dependency().
|
||||
|
||||
I merged bin and render's paths in a late refactoring.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181108161654.19888-3-eric@anholt.net
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
(cherry picked from commit e90e45f6bd45cc494a6f4cd1853c5e7cd4be7f68)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_sched.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
index a5501581d96b..7aafcc6f5446 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
@@ -39,7 +39,7 @@ v3d_job_free(struct drm_sched_job *sched_job)
|
||||
}
|
||||
|
||||
/**
|
||||
- * Returns the fences that the bin job depends on, one by one.
|
||||
+ * Returns the fences that the bin or render job depends on, one by one.
|
||||
* v3d_job_run() won't be called until all of them have been signaled.
|
||||
*/
|
||||
static struct dma_fence *
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
From 7e09c10741324062d50fe48922baaa0dd9fa83ac Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 8 Nov 2018 08:16:53 -0800
|
||||
Subject: [PATCH 573/678] drm/v3d: Clean up the reservation object setup.
|
||||
|
||||
The extra to_v3d_bo() calls came from copying this from the vc4
|
||||
driver, which stored the cma gem object in the structs.
|
||||
|
||||
v2: Fix an unused var warning
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181108161654.19888-4-eric@anholt.net
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com> (v1)
|
||||
(cherry picked from commit 8f1cd826641d677d0f7494253ecfc3335f0bcd4e)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 33 +++++++++++----------------------
|
||||
1 file changed, 11 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 5c13b0807879..7296a3a5f84a 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -210,14 +210,11 @@ static void
|
||||
v3d_attach_object_fences(struct v3d_exec_info *exec)
|
||||
{
|
||||
struct dma_fence *out_fence = exec->render_done_fence;
|
||||
- struct v3d_bo *bo;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < exec->bo_count; i++) {
|
||||
- bo = to_v3d_bo(&exec->bo[i]->base);
|
||||
-
|
||||
/* XXX: Use shared fences for read-only objects. */
|
||||
- reservation_object_add_excl_fence(bo->resv, out_fence);
|
||||
+ reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,11 +225,8 @@ v3d_unlock_bo_reservations(struct drm_device *dev,
|
||||
{
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < exec->bo_count; i++) {
|
||||
- struct v3d_bo *bo = to_v3d_bo(&exec->bo[i]->base);
|
||||
-
|
||||
- ww_mutex_unlock(&bo->resv->lock);
|
||||
- }
|
||||
+ for (i = 0; i < exec->bo_count; i++)
|
||||
+ ww_mutex_unlock(&exec->bo[i]->resv->lock);
|
||||
|
||||
ww_acquire_fini(acquire_ctx);
|
||||
}
|
||||
@@ -251,13 +245,13 @@ v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
{
|
||||
int contended_lock = -1;
|
||||
int i, ret;
|
||||
- struct v3d_bo *bo;
|
||||
|
||||
ww_acquire_init(acquire_ctx, &reservation_ww_class);
|
||||
|
||||
retry:
|
||||
if (contended_lock != -1) {
|
||||
- bo = to_v3d_bo(&exec->bo[contended_lock]->base);
|
||||
+ struct v3d_bo *bo = exec->bo[contended_lock];
|
||||
+
|
||||
ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
|
||||
acquire_ctx);
|
||||
if (ret) {
|
||||
@@ -270,19 +264,16 @@ v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
if (i == contended_lock)
|
||||
continue;
|
||||
|
||||
- bo = to_v3d_bo(&exec->bo[i]->base);
|
||||
-
|
||||
- ret = ww_mutex_lock_interruptible(&bo->resv->lock, acquire_ctx);
|
||||
+ ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock,
|
||||
+ acquire_ctx);
|
||||
if (ret) {
|
||||
int j;
|
||||
|
||||
- for (j = 0; j < i; j++) {
|
||||
- bo = to_v3d_bo(&exec->bo[j]->base);
|
||||
- ww_mutex_unlock(&bo->resv->lock);
|
||||
- }
|
||||
+ for (j = 0; j < i; j++)
|
||||
+ ww_mutex_unlock(&exec->bo[j]->resv->lock);
|
||||
|
||||
if (contended_lock != -1 && contended_lock >= i) {
|
||||
- bo = to_v3d_bo(&exec->bo[contended_lock]->base);
|
||||
+ struct v3d_bo *bo = exec->bo[contended_lock];
|
||||
|
||||
ww_mutex_unlock(&bo->resv->lock);
|
||||
}
|
||||
@@ -303,9 +294,7 @@ v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
* before we commit the CL to the hardware.
|
||||
*/
|
||||
for (i = 0; i < exec->bo_count; i++) {
|
||||
- bo = to_v3d_bo(&exec->bo[i]->base);
|
||||
-
|
||||
- ret = reservation_object_reserve_shared(bo->resv);
|
||||
+ ret = reservation_object_reserve_shared(exec->bo[i]->resv);
|
||||
if (ret) {
|
||||
v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
|
||||
return ret;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,822 @@
|
|||
From 73fcf3b17c66b87b1ff2dc52c855cf44b7838f7f Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 28 Nov 2018 15:09:25 -0800
|
||||
Subject: [PATCH 574/678] drm/v3d: Add support for submitting jobs to the TFU.
|
||||
|
||||
The TFU can copy from raster, UIF, and SAND input images to UIF output
|
||||
images, with optional mipmap generation. This will certainly be
|
||||
useful for media EGL image input, but is also useful immediately for
|
||||
mipmap generation without bogging the V3D core down.
|
||||
|
||||
For now we only run the queue 1 job deep, and don't have any hang
|
||||
recovery (though I don't think we should need it, with TFU). Queuing
|
||||
multiple jobs in the HW will require synchronizing the YUV coefficient
|
||||
regs updates since they don't get FIFOed with the job.
|
||||
|
||||
v2: Change the ioctl to IOW instead of IOWR, always set COEF0, explain
|
||||
why TFU is AUTH, clarify the syncing docs, drop the unused TFU
|
||||
interrupt regs (you're expected to use the hub's), don't take
|
||||
&bo->base for NULL bos.
|
||||
v3: Fix a little whitespace alignment (noticed by checkpatch), rebase
|
||||
on drm_sched_job_cleanup() changes.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com> (v2)
|
||||
Link: https://patchwork.freedesktop.org/patch/264607/
|
||||
(cherry picked from commit 1584f16ca96ef124aad79efa3303cff5f3530e2c)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 15 ++-
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 32 +++++-
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 178 ++++++++++++++++++++++++++++----
|
||||
drivers/gpu/drm/v3d/v3d_irq.c | 12 ++-
|
||||
drivers/gpu/drm/v3d/v3d_regs.h | 49 +++++++++
|
||||
drivers/gpu/drm/v3d/v3d_sched.c | 148 ++++++++++++++++++++++----
|
||||
drivers/gpu/drm/v3d/v3d_trace.h | 20 ++++
|
||||
include/uapi/drm/v3d_drm.h | 25 +++++
|
||||
8 files changed, 426 insertions(+), 53 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 2a4c6187e675..30ae1c74edaa 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -112,10 +112,15 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
- /* Any params that aren't just register reads would go here. */
|
||||
|
||||
- DRM_DEBUG("Unknown parameter %d\n", args->param);
|
||||
- return -EINVAL;
|
||||
+ switch (args->param) {
|
||||
+ case DRM_V3D_PARAM_SUPPORTS_TFU:
|
||||
+ args->value = 1;
|
||||
+ return 0;
|
||||
+ default:
|
||||
+ DRM_DEBUG("Unknown parameter %d\n", args->param);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -170,7 +175,8 @@ static const struct file_operations v3d_drm_fops = {
|
||||
/* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP
|
||||
* protection between clients. Note that render nodes would be be
|
||||
* able to submit CLs that could access BOs from clients authenticated
|
||||
- * with the master node.
|
||||
+ * with the master node. The TFU doesn't use the GMP, so it would
|
||||
+ * need to stay DRM_AUTH until we do buffer size/offset validation.
|
||||
*/
|
||||
static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CL, v3d_submit_cl_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
|
||||
@@ -179,6 +185,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(V3D_MMAP_BO, v3d_mmap_bo_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
|
||||
+ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
|
||||
};
|
||||
|
||||
static const struct vm_operations_struct v3d_vm_ops = {
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index eb32ff45a085..f2937a1da581 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -7,19 +7,18 @@
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
+#include "uapi/drm/v3d_drm.h"
|
||||
|
||||
#define GMP_GRANULARITY (128 * 1024)
|
||||
|
||||
-/* Enum for each of the V3D queues. We maintain various queue
|
||||
- * tracking as an array because at some point we'll want to support
|
||||
- * the TFU (texture formatting unit) as another queue.
|
||||
- */
|
||||
+/* Enum for each of the V3D queues. */
|
||||
enum v3d_queue {
|
||||
V3D_BIN,
|
||||
V3D_RENDER,
|
||||
+ V3D_TFU,
|
||||
};
|
||||
|
||||
-#define V3D_MAX_QUEUES (V3D_RENDER + 1)
|
||||
+#define V3D_MAX_QUEUES (V3D_TFU + 1)
|
||||
|
||||
struct v3d_queue_state {
|
||||
struct drm_gpu_scheduler sched;
|
||||
@@ -68,6 +67,7 @@ struct v3d_dev {
|
||||
|
||||
struct v3d_exec_info *bin_job;
|
||||
struct v3d_exec_info *render_job;
|
||||
+ struct v3d_tfu_job *tfu_job;
|
||||
|
||||
struct v3d_queue_state queue[V3D_MAX_QUEUES];
|
||||
|
||||
@@ -218,6 +218,25 @@ struct v3d_exec_info {
|
||||
u32 qma, qms, qts;
|
||||
};
|
||||
|
||||
+struct v3d_tfu_job {
|
||||
+ struct drm_sched_job base;
|
||||
+
|
||||
+ struct drm_v3d_submit_tfu args;
|
||||
+
|
||||
+ /* An optional fence userspace can pass in for the job to depend on. */
|
||||
+ struct dma_fence *in_fence;
|
||||
+
|
||||
+ /* v3d fence to be signaled by IRQ handler when the job is complete. */
|
||||
+ struct dma_fence *done_fence;
|
||||
+
|
||||
+ struct v3d_dev *v3d;
|
||||
+
|
||||
+ struct kref refcount;
|
||||
+
|
||||
+ /* This is the array of BOs that were looked up at the start of exec. */
|
||||
+ struct v3d_bo *bo[4];
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* _wait_for - magic (register) wait macro
|
||||
*
|
||||
@@ -281,9 +300,12 @@ int v3d_gem_init(struct drm_device *dev);
|
||||
void v3d_gem_destroy(struct drm_device *dev);
|
||||
int v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
+int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
+ struct drm_file *file_priv);
|
||||
int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
void v3d_exec_put(struct v3d_exec_info *exec);
|
||||
+void v3d_tfu_job_put(struct v3d_tfu_job *exec);
|
||||
void v3d_reset(struct v3d_dev *v3d);
|
||||
void v3d_invalidate_caches(struct v3d_dev *v3d);
|
||||
void v3d_flush_caches(struct v3d_dev *v3d);
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 7296a3a5f84a..7fbbe24c583a 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -207,26 +207,27 @@ v3d_flush_caches(struct v3d_dev *v3d)
|
||||
}
|
||||
|
||||
static void
|
||||
-v3d_attach_object_fences(struct v3d_exec_info *exec)
|
||||
+v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
|
||||
+ struct dma_fence *fence)
|
||||
{
|
||||
- struct dma_fence *out_fence = exec->render_done_fence;
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < exec->bo_count; i++) {
|
||||
+ for (i = 0; i < bo_count; i++) {
|
||||
/* XXX: Use shared fences for read-only objects. */
|
||||
- reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence);
|
||||
+ reservation_object_add_excl_fence(bos[i]->resv, fence);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
v3d_unlock_bo_reservations(struct drm_device *dev,
|
||||
- struct v3d_exec_info *exec,
|
||||
+ struct v3d_bo **bos,
|
||||
+ int bo_count,
|
||||
struct ww_acquire_ctx *acquire_ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < exec->bo_count; i++)
|
||||
- ww_mutex_unlock(&exec->bo[i]->resv->lock);
|
||||
+ for (i = 0; i < bo_count; i++)
|
||||
+ ww_mutex_unlock(&bos[i]->resv->lock);
|
||||
|
||||
ww_acquire_fini(acquire_ctx);
|
||||
}
|
||||
@@ -240,7 +241,8 @@ v3d_unlock_bo_reservations(struct drm_device *dev,
|
||||
*/
|
||||
static int
|
||||
v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
- struct v3d_exec_info *exec,
|
||||
+ struct v3d_bo **bos,
|
||||
+ int bo_count,
|
||||
struct ww_acquire_ctx *acquire_ctx)
|
||||
{
|
||||
int contended_lock = -1;
|
||||
@@ -250,7 +252,7 @@ v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
|
||||
retry:
|
||||
if (contended_lock != -1) {
|
||||
- struct v3d_bo *bo = exec->bo[contended_lock];
|
||||
+ struct v3d_bo *bo = bos[contended_lock];
|
||||
|
||||
ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
|
||||
acquire_ctx);
|
||||
@@ -260,20 +262,20 @@ v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
- for (i = 0; i < exec->bo_count; i++) {
|
||||
+ for (i = 0; i < bo_count; i++) {
|
||||
if (i == contended_lock)
|
||||
continue;
|
||||
|
||||
- ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock,
|
||||
+ ret = ww_mutex_lock_interruptible(&bos[i]->resv->lock,
|
||||
acquire_ctx);
|
||||
if (ret) {
|
||||
int j;
|
||||
|
||||
for (j = 0; j < i; j++)
|
||||
- ww_mutex_unlock(&exec->bo[j]->resv->lock);
|
||||
+ ww_mutex_unlock(&bos[j]->resv->lock);
|
||||
|
||||
if (contended_lock != -1 && contended_lock >= i) {
|
||||
- struct v3d_bo *bo = exec->bo[contended_lock];
|
||||
+ struct v3d_bo *bo = bos[contended_lock];
|
||||
|
||||
ww_mutex_unlock(&bo->resv->lock);
|
||||
}
|
||||
@@ -293,10 +295,11 @@ v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
/* Reserve space for our shared (read-only) fence references,
|
||||
* before we commit the CL to the hardware.
|
||||
*/
|
||||
- for (i = 0; i < exec->bo_count; i++) {
|
||||
- ret = reservation_object_reserve_shared(exec->bo[i]->resv);
|
||||
+ for (i = 0; i < bo_count; i++) {
|
||||
+ ret = reservation_object_reserve_shared(bos[i]->resv);
|
||||
if (ret) {
|
||||
- v3d_unlock_bo_reservations(dev, exec, acquire_ctx);
|
||||
+ v3d_unlock_bo_reservations(dev, bos, bo_count,
|
||||
+ acquire_ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -419,6 +422,33 @@ void v3d_exec_put(struct v3d_exec_info *exec)
|
||||
kref_put(&exec->refcount, v3d_exec_cleanup);
|
||||
}
|
||||
|
||||
+static void
|
||||
+v3d_tfu_job_cleanup(struct kref *ref)
|
||||
+{
|
||||
+ struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
|
||||
+ refcount);
|
||||
+ struct v3d_dev *v3d = job->v3d;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ dma_fence_put(job->in_fence);
|
||||
+ dma_fence_put(job->done_fence);
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
|
||||
+ if (job->bo[i])
|
||||
+ drm_gem_object_put_unlocked(&job->bo[i]->base);
|
||||
+ }
|
||||
+
|
||||
+ pm_runtime_mark_last_busy(v3d->dev);
|
||||
+ pm_runtime_put_autosuspend(v3d->dev);
|
||||
+
|
||||
+ kfree(job);
|
||||
+}
|
||||
+
|
||||
+void v3d_tfu_job_put(struct v3d_tfu_job *job)
|
||||
+{
|
||||
+ kref_put(&job->refcount, v3d_tfu_job_cleanup);
|
||||
+}
|
||||
+
|
||||
int
|
||||
v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
@@ -536,7 +566,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
- ret = v3d_lock_bo_reservations(dev, exec, &acquire_ctx);
|
||||
+ ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count,
|
||||
+ &acquire_ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
@@ -570,9 +601,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
&v3d_priv->sched_entity[V3D_RENDER]);
|
||||
mutex_unlock(&v3d->sched_lock);
|
||||
|
||||
- v3d_attach_object_fences(exec);
|
||||
+ v3d_attach_object_fences(exec->bo, exec->bo_count,
|
||||
+ exec->render_done_fence);
|
||||
|
||||
- v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
|
||||
+ v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
|
||||
|
||||
/* Update the return sync object for the */
|
||||
sync_out = drm_syncobj_find(file_priv, args->out_sync);
|
||||
@@ -588,13 +620,119 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
fail_unreserve:
|
||||
mutex_unlock(&v3d->sched_lock);
|
||||
- v3d_unlock_bo_reservations(dev, exec, &acquire_ctx);
|
||||
+ v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
|
||||
fail:
|
||||
v3d_exec_put(exec);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D.
|
||||
+ * @dev: DRM device
|
||||
+ * @data: ioctl argument
|
||||
+ * @file_priv: DRM file for this fd
|
||||
+ *
|
||||
+ * Userspace provides the register setup for the TFU, which we don't
|
||||
+ * need to validate since the TFU is behind the MMU.
|
||||
+ */
|
||||
+int
|
||||
+v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
+ struct drm_file *file_priv)
|
||||
+{
|
||||
+ struct v3d_dev *v3d = to_v3d_dev(dev);
|
||||
+ struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
|
||||
+ struct drm_v3d_submit_tfu *args = data;
|
||||
+ struct v3d_tfu_job *job;
|
||||
+ struct ww_acquire_ctx acquire_ctx;
|
||||
+ struct drm_syncobj *sync_out;
|
||||
+ struct dma_fence *sched_done_fence;
|
||||
+ int ret = 0;
|
||||
+ int bo_count;
|
||||
+
|
||||
+ job = kcalloc(1, sizeof(*job), GFP_KERNEL);
|
||||
+ if (!job)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ret = pm_runtime_get_sync(v3d->dev);
|
||||
+ if (ret < 0) {
|
||||
+ kfree(job);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ kref_init(&job->refcount);
|
||||
+
|
||||
+ ret = drm_syncobj_find_fence(file_priv, args->in_sync,
|
||||
+ 0, &job->in_fence);
|
||||
+ if (ret == -EINVAL)
|
||||
+ goto fail;
|
||||
+
|
||||
+ job->args = *args;
|
||||
+ job->v3d = v3d;
|
||||
+
|
||||
+ spin_lock(&file_priv->table_lock);
|
||||
+ for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) {
|
||||
+ struct drm_gem_object *bo;
|
||||
+
|
||||
+ if (!args->bo_handles[bo_count])
|
||||
+ break;
|
||||
+
|
||||
+ bo = idr_find(&file_priv->object_idr,
|
||||
+ args->bo_handles[bo_count]);
|
||||
+ if (!bo) {
|
||||
+ DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
|
||||
+ bo_count, args->bo_handles[bo_count]);
|
||||
+ ret = -ENOENT;
|
||||
+ spin_unlock(&file_priv->table_lock);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ drm_gem_object_get(bo);
|
||||
+ job->bo[bo_count] = to_v3d_bo(bo);
|
||||
+ }
|
||||
+ spin_unlock(&file_priv->table_lock);
|
||||
+
|
||||
+ ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
|
||||
+ if (ret)
|
||||
+ goto fail;
|
||||
+
|
||||
+ mutex_lock(&v3d->sched_lock);
|
||||
+ ret = drm_sched_job_init(&job->base,
|
||||
+ &v3d_priv->sched_entity[V3D_TFU],
|
||||
+ v3d_priv);
|
||||
+ if (ret)
|
||||
+ goto fail_unreserve;
|
||||
+
|
||||
+ sched_done_fence = dma_fence_get(&job->base.s_fence->finished);
|
||||
+
|
||||
+ kref_get(&job->refcount); /* put by scheduler job completion */
|
||||
+ drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]);
|
||||
+ mutex_unlock(&v3d->sched_lock);
|
||||
+
|
||||
+ v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
|
||||
+
|
||||
+ v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
|
||||
+
|
||||
+ /* Update the return sync object */
|
||||
+ sync_out = drm_syncobj_find(file_priv, args->out_sync);
|
||||
+ if (sync_out) {
|
||||
+ drm_syncobj_replace_fence(sync_out, sched_done_fence);
|
||||
+ drm_syncobj_put(sync_out);
|
||||
+ }
|
||||
+ dma_fence_put(sched_done_fence);
|
||||
+
|
||||
+ v3d_tfu_job_put(job);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+fail_unreserve:
|
||||
+ mutex_unlock(&v3d->sched_lock);
|
||||
+ v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
|
||||
+fail:
|
||||
+ v3d_tfu_job_put(job);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int
|
||||
v3d_gem_init(struct drm_device *dev)
|
||||
{
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
index 22be0f2dff99..e33bca1a494b 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
@@ -4,8 +4,8 @@
|
||||
/**
|
||||
* DOC: Interrupt management for the V3D engine
|
||||
*
|
||||
- * When we take a binning or rendering flush done interrupt, we need
|
||||
- * to signal the fence for that job so that the scheduler can queue up
|
||||
+ * When we take a bin, render, or TFU done interrupt, we need to
|
||||
+ * signal the fence for that job so that the scheduler can queue up
|
||||
* the next one and unblock any waiters.
|
||||
*
|
||||
* When we take the binner out of memory interrupt, we need to
|
||||
@@ -23,7 +23,8 @@
|
||||
|
||||
#define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
|
||||
V3D_HUB_INT_MMU_PTI | \
|
||||
- V3D_HUB_INT_MMU_CAP))
|
||||
+ V3D_HUB_INT_MMU_CAP | \
|
||||
+ V3D_HUB_INT_TFUC))
|
||||
|
||||
static void
|
||||
v3d_overflow_mem_work(struct work_struct *work)
|
||||
@@ -117,6 +118,11 @@ v3d_hub_irq(int irq, void *arg)
|
||||
/* Acknowledge the interrupts we're handling here. */
|
||||
V3D_WRITE(V3D_HUB_INT_CLR, intsts);
|
||||
|
||||
+ if (intsts & V3D_HUB_INT_TFUC) {
|
||||
+ dma_fence_signal(v3d->tfu_job->done_fence);
|
||||
+ status = IRQ_HANDLED;
|
||||
+ }
|
||||
+
|
||||
if (intsts & (V3D_HUB_INT_MMU_WRV |
|
||||
V3D_HUB_INT_MMU_PTI |
|
||||
V3D_HUB_INT_MMU_CAP)) {
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
index c3a5e4e44f73..6ccdee9d47bd 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
@@ -86,6 +86,55 @@
|
||||
# define V3D_TOP_GR_BRIDGE_SW_INIT_1 0x0000c
|
||||
# define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0)
|
||||
|
||||
+#define V3D_TFU_CS 0x00400
|
||||
+/* Stops current job, empties input fifo. */
|
||||
+# define V3D_TFU_CS_TFURST BIT(31)
|
||||
+# define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16)
|
||||
+# define V3D_TFU_CS_CVTCT_SHIFT 16
|
||||
+# define V3D_TFU_CS_NFREE_MASK V3D_MASK(13, 8)
|
||||
+# define V3D_TFU_CS_NFREE_SHIFT 8
|
||||
+# define V3D_TFU_CS_BUSY BIT(0)
|
||||
+
|
||||
+#define V3D_TFU_SU 0x00404
|
||||
+/* Interrupt when FINTTHR input slots are free (0 = disabled) */
|
||||
+# define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8)
|
||||
+# define V3D_TFU_SU_FINTTHR_SHIFT 8
|
||||
+/* Skips resetting the CRC at the start of CRC generation. */
|
||||
+# define V3D_TFU_SU_CRCCHAIN BIT(4)
|
||||
+/* skips writes, computes CRC of the image. miplevels must be 0. */
|
||||
+# define V3D_TFU_SU_CRC BIT(3)
|
||||
+# define V3D_TFU_SU_THROTTLE_MASK V3D_MASK(1, 0)
|
||||
+# define V3D_TFU_SU_THROTTLE_SHIFT 0
|
||||
+
|
||||
+#define V3D_TFU_ICFG 0x00408
|
||||
+/* Interrupt when the conversion is complete. */
|
||||
+# define V3D_TFU_ICFG_IOC BIT(0)
|
||||
+
|
||||
+/* Input Image Address */
|
||||
+#define V3D_TFU_IIA 0x0040c
|
||||
+/* Input Chroma Address */
|
||||
+#define V3D_TFU_ICA 0x00410
|
||||
+/* Input Image Stride */
|
||||
+#define V3D_TFU_IIS 0x00414
|
||||
+/* Input Image U-Plane Address */
|
||||
+#define V3D_TFU_IUA 0x00418
|
||||
+/* Output Image Address */
|
||||
+#define V3D_TFU_IOA 0x0041c
|
||||
+/* Image Output Size */
|
||||
+#define V3D_TFU_IOS 0x00420
|
||||
+/* TFU YUV Coefficient 0 */
|
||||
+#define V3D_TFU_COEF0 0x00424
|
||||
+/* Use these regs instead of the defaults. */
|
||||
+# define V3D_TFU_COEF0_USECOEF BIT(31)
|
||||
+/* TFU YUV Coefficient 1 */
|
||||
+#define V3D_TFU_COEF1 0x00428
|
||||
+/* TFU YUV Coefficient 2 */
|
||||
+#define V3D_TFU_COEF2 0x0042c
|
||||
+/* TFU YUV Coefficient 3 */
|
||||
+#define V3D_TFU_COEF3 0x00430
|
||||
+
|
||||
+#define V3D_TFU_CRC 0x00434
|
||||
+
|
||||
/* Per-MMU registers. */
|
||||
|
||||
#define V3D_MMUC_CONTROL 0x01000
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
index 7aafcc6f5446..2ab1bbdb100a 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
@@ -30,6 +30,12 @@ to_v3d_job(struct drm_sched_job *sched_job)
|
||||
return container_of(sched_job, struct v3d_job, base);
|
||||
}
|
||||
|
||||
+static struct v3d_tfu_job *
|
||||
+to_tfu_job(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ return container_of(sched_job, struct v3d_tfu_job, base);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
v3d_job_free(struct drm_sched_job *sched_job)
|
||||
{
|
||||
@@ -38,6 +44,14 @@ v3d_job_free(struct drm_sched_job *sched_job)
|
||||
v3d_exec_put(job->exec);
|
||||
}
|
||||
|
||||
+static void
|
||||
+v3d_tfu_job_free(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
|
||||
+
|
||||
+ v3d_tfu_job_put(job);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* Returns the fences that the bin or render job depends on, one by one.
|
||||
* v3d_job_run() won't be called until all of them have been signaled.
|
||||
@@ -76,6 +90,27 @@ v3d_job_dependency(struct drm_sched_job *sched_job,
|
||||
return fence;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * Returns the fences that the TFU job depends on, one by one.
|
||||
+ * v3d_tfu_job_run() won't be called until all of them have been
|
||||
+ * signaled.
|
||||
+ */
|
||||
+static struct dma_fence *
|
||||
+v3d_tfu_job_dependency(struct drm_sched_job *sched_job,
|
||||
+ struct drm_sched_entity *s_entity)
|
||||
+{
|
||||
+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
|
||||
+ struct dma_fence *fence;
|
||||
+
|
||||
+ fence = job->in_fence;
|
||||
+ if (fence) {
|
||||
+ job->in_fence = NULL;
|
||||
+ return fence;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
|
||||
{
|
||||
struct v3d_job *job = to_v3d_job(sched_job);
|
||||
@@ -147,31 +182,47 @@ static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
|
||||
return fence;
|
||||
}
|
||||
|
||||
-static void
|
||||
-v3d_job_timedout(struct drm_sched_job *sched_job)
|
||||
+static struct dma_fence *
|
||||
+v3d_tfu_job_run(struct drm_sched_job *sched_job)
|
||||
{
|
||||
- struct v3d_job *job = to_v3d_job(sched_job);
|
||||
- struct v3d_exec_info *exec = job->exec;
|
||||
- struct v3d_dev *v3d = exec->v3d;
|
||||
- enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
|
||||
- enum v3d_queue q;
|
||||
- u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
|
||||
- u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
|
||||
+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
|
||||
+ struct v3d_dev *v3d = job->v3d;
|
||||
+ struct drm_device *dev = &v3d->drm;
|
||||
+ struct dma_fence *fence;
|
||||
|
||||
- /* If the current address or return address have changed, then
|
||||
- * the GPU has probably made progress and we should delay the
|
||||
- * reset. This could fail if the GPU got in an infinite loop
|
||||
- * in the CL, but that is pretty unlikely outside of an i-g-t
|
||||
- * testcase.
|
||||
- */
|
||||
- if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
|
||||
- job->timedout_ctca = ctca;
|
||||
- job->timedout_ctra = ctra;
|
||||
+ fence = v3d_fence_create(v3d, V3D_TFU);
|
||||
+ if (IS_ERR(fence))
|
||||
+ return NULL;
|
||||
|
||||
- schedule_delayed_work(&job->base.work_tdr,
|
||||
- job->base.sched->timeout);
|
||||
- return;
|
||||
+ v3d->tfu_job = job;
|
||||
+ if (job->done_fence)
|
||||
+ dma_fence_put(job->done_fence);
|
||||
+ job->done_fence = dma_fence_get(fence);
|
||||
+
|
||||
+ trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
|
||||
+
|
||||
+ V3D_WRITE(V3D_TFU_IIA, job->args.iia);
|
||||
+ V3D_WRITE(V3D_TFU_IIS, job->args.iis);
|
||||
+ V3D_WRITE(V3D_TFU_ICA, job->args.ica);
|
||||
+ V3D_WRITE(V3D_TFU_IUA, job->args.iua);
|
||||
+ V3D_WRITE(V3D_TFU_IOA, job->args.ioa);
|
||||
+ V3D_WRITE(V3D_TFU_IOS, job->args.ios);
|
||||
+ V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]);
|
||||
+ if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) {
|
||||
+ V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]);
|
||||
+ V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]);
|
||||
+ V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]);
|
||||
}
|
||||
+ /* ICFG kicks off the job. */
|
||||
+ V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC);
|
||||
+
|
||||
+ return fence;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ enum v3d_queue q;
|
||||
|
||||
mutex_lock(&v3d->reset_lock);
|
||||
|
||||
@@ -196,6 +247,41 @@ v3d_job_timedout(struct drm_sched_job *sched_job)
|
||||
mutex_unlock(&v3d->reset_lock);
|
||||
}
|
||||
|
||||
+static void
|
||||
+v3d_job_timedout(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ struct v3d_job *job = to_v3d_job(sched_job);
|
||||
+ struct v3d_exec_info *exec = job->exec;
|
||||
+ struct v3d_dev *v3d = exec->v3d;
|
||||
+ enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
|
||||
+ u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));
|
||||
+ u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));
|
||||
+
|
||||
+ /* If the current address or return address have changed, then
|
||||
+ * the GPU has probably made progress and we should delay the
|
||||
+ * reset. This could fail if the GPU got in an infinite loop
|
||||
+ * in the CL, but that is pretty unlikely outside of an i-g-t
|
||||
+ * testcase.
|
||||
+ */
|
||||
+ if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
|
||||
+ job->timedout_ctca = ctca;
|
||||
+ job->timedout_ctra = ctra;
|
||||
+ schedule_delayed_work(&job->base.work_tdr,
|
||||
+ job->base.sched->timeout);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ v3d_gpu_reset_for_timeout(v3d, sched_job);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ struct v3d_tfu_job *job = to_tfu_job(sched_job);
|
||||
+
|
||||
+ v3d_gpu_reset_for_timeout(job->v3d, sched_job);
|
||||
+}
|
||||
+
|
||||
static const struct drm_sched_backend_ops v3d_sched_ops = {
|
||||
.dependency = v3d_job_dependency,
|
||||
.run_job = v3d_job_run,
|
||||
@@ -203,6 +289,13 @@ static const struct drm_sched_backend_ops v3d_sched_ops = {
|
||||
.free_job = v3d_job_free
|
||||
};
|
||||
|
||||
+static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
|
||||
+ .dependency = v3d_tfu_job_dependency,
|
||||
+ .run_job = v3d_tfu_job_run,
|
||||
+ .timedout_job = v3d_tfu_job_timedout,
|
||||
+ .free_job = v3d_tfu_job_free
|
||||
+};
|
||||
+
|
||||
int
|
||||
v3d_sched_init(struct v3d_dev *v3d)
|
||||
{
|
||||
@@ -233,6 +326,19 @@ v3d_sched_init(struct v3d_dev *v3d)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
|
||||
+ &v3d_tfu_sched_ops,
|
||||
+ hw_jobs_limit, job_hang_limit,
|
||||
+ msecs_to_jiffies(hang_limit_ms),
|
||||
+ "v3d_tfu");
|
||||
+ if (ret) {
|
||||
+ dev_err(v3d->dev, "Failed to create TFU scheduler: %d.",
|
||||
+ ret);
|
||||
+ drm_sched_fini(&v3d->queue[V3D_RENDER].sched);
|
||||
+ drm_sched_fini(&v3d->queue[V3D_BIN].sched);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_trace.h b/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
index 85dd351e1e09..f54ed9cd3444 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
@@ -42,6 +42,26 @@ TRACE_EVENT(v3d_submit_cl,
|
||||
__entry->ctnqea)
|
||||
);
|
||||
|
||||
+TRACE_EVENT(v3d_submit_tfu,
|
||||
+ TP_PROTO(struct drm_device *dev,
|
||||
+ uint64_t seqno),
|
||||
+ TP_ARGS(dev, seqno),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u64, seqno)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->seqno = seqno;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, seqno=%llu",
|
||||
+ __entry->dev,
|
||||
+ __entry->seqno)
|
||||
+);
|
||||
+
|
||||
TRACE_EVENT(v3d_reset_begin,
|
||||
TP_PROTO(struct drm_device *dev),
|
||||
TP_ARGS(dev),
|
||||
diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h
|
||||
index 7b6627783608..c4b67eab7e59 100644
|
||||
--- a/include/uapi/drm/v3d_drm.h
|
||||
+++ b/include/uapi/drm/v3d_drm.h
|
||||
@@ -36,6 +36,7 @@ extern "C" {
|
||||
#define DRM_V3D_MMAP_BO 0x03
|
||||
#define DRM_V3D_GET_PARAM 0x04
|
||||
#define DRM_V3D_GET_BO_OFFSET 0x05
|
||||
+#define DRM_V3D_SUBMIT_TFU 0x06
|
||||
|
||||
#define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
|
||||
#define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
|
||||
@@ -43,6 +44,7 @@ extern "C" {
|
||||
#define DRM_IOCTL_V3D_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_MMAP_BO, struct drm_v3d_mmap_bo)
|
||||
#define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param)
|
||||
#define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
|
||||
+#define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
|
||||
|
||||
/**
|
||||
* struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
|
||||
@@ -169,6 +171,7 @@ enum drm_v3d_param {
|
||||
DRM_V3D_PARAM_V3D_CORE0_IDENT0,
|
||||
DRM_V3D_PARAM_V3D_CORE0_IDENT1,
|
||||
DRM_V3D_PARAM_V3D_CORE0_IDENT2,
|
||||
+ DRM_V3D_PARAM_SUPPORTS_TFU,
|
||||
};
|
||||
|
||||
struct drm_v3d_get_param {
|
||||
@@ -187,6 +190,28 @@ struct drm_v3d_get_bo_offset {
|
||||
__u32 offset;
|
||||
};
|
||||
|
||||
+struct drm_v3d_submit_tfu {
|
||||
+ __u32 icfg;
|
||||
+ __u32 iia;
|
||||
+ __u32 iis;
|
||||
+ __u32 ica;
|
||||
+ __u32 iua;
|
||||
+ __u32 ioa;
|
||||
+ __u32 ios;
|
||||
+ __u32 coef[4];
|
||||
+ /* First handle is the output BO, following are other inputs.
|
||||
+ * 0 for unused.
|
||||
+ */
|
||||
+ __u32 bo_handles[4];
|
||||
+ /* sync object to block on before running the TFU job. Each TFU
|
||||
+ * job will execute in the order submitted to its FD. Synchronization
|
||||
+ * against rendering jobs requires using sync objects.
|
||||
+ */
|
||||
+ __u32 in_sync;
|
||||
+ /* Sync object to signal when the TFU job is done. */
|
||||
+ __u32 out_sync;
|
||||
+};
|
||||
+
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
From a65d035914638414d9dff57b200dbacb9baebc6e Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 28 Nov 2018 15:09:26 -0800
|
||||
Subject: [PATCH 575/678] drm/v3d: Drop the "dev" argument to lock/unlock of BO
|
||||
reservations.
|
||||
|
||||
They were unused, as Dave Emett noticed in TFU review.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Cc: Dave Emett <david.emett@broadcom.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181128230927.10951-2-eric@anholt.net
|
||||
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
(cherry picked from commit e14a07fc4b961a75f6c275d6bd670ba54fbdae14)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 7fbbe24c583a..46ef27fab2c5 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -219,8 +219,7 @@ v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
|
||||
}
|
||||
|
||||
static void
|
||||
-v3d_unlock_bo_reservations(struct drm_device *dev,
|
||||
- struct v3d_bo **bos,
|
||||
+v3d_unlock_bo_reservations(struct v3d_bo **bos,
|
||||
int bo_count,
|
||||
struct ww_acquire_ctx *acquire_ctx)
|
||||
{
|
||||
@@ -240,8 +239,7 @@ v3d_unlock_bo_reservations(struct drm_device *dev,
|
||||
* to v3d, so we don't attach dma-buf fences to them.
|
||||
*/
|
||||
static int
|
||||
-v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
- struct v3d_bo **bos,
|
||||
+v3d_lock_bo_reservations(struct v3d_bo **bos,
|
||||
int bo_count,
|
||||
struct ww_acquire_ctx *acquire_ctx)
|
||||
{
|
||||
@@ -298,7 +296,7 @@ v3d_lock_bo_reservations(struct drm_device *dev,
|
||||
for (i = 0; i < bo_count; i++) {
|
||||
ret = reservation_object_reserve_shared(bos[i]->resv);
|
||||
if (ret) {
|
||||
- v3d_unlock_bo_reservations(dev, bos, bo_count,
|
||||
+ v3d_unlock_bo_reservations(bos, bo_count,
|
||||
acquire_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -566,7 +564,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
- ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count,
|
||||
+ ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count,
|
||||
&acquire_ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
@@ -604,7 +602,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
v3d_attach_object_fences(exec->bo, exec->bo_count,
|
||||
exec->render_done_fence);
|
||||
|
||||
- v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
|
||||
+ v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
|
||||
|
||||
/* Update the return sync object for the */
|
||||
sync_out = drm_syncobj_find(file_priv, args->out_sync);
|
||||
@@ -620,7 +618,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
fail_unreserve:
|
||||
mutex_unlock(&v3d->sched_lock);
|
||||
- v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx);
|
||||
+ v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx);
|
||||
fail:
|
||||
v3d_exec_put(exec);
|
||||
|
||||
@@ -691,7 +689,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
}
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
|
||||
- ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
|
||||
+ ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
@@ -710,7 +708,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);
|
||||
|
||||
- v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
|
||||
+ v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
|
||||
|
||||
/* Update the return sync object */
|
||||
sync_out = drm_syncobj_find(file_priv, args->out_sync);
|
||||
@@ -726,7 +724,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
fail_unreserve:
|
||||
mutex_unlock(&v3d->sched_lock);
|
||||
- v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx);
|
||||
+ v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx);
|
||||
fail:
|
||||
v3d_tfu_job_put(job);
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
From da45105ee6ab068262f4273e3fdd91a6e27dc8d3 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 30 Nov 2018 16:57:59 -0800
|
||||
Subject: [PATCH 576/678] drm/v3d: Add missing fence timeline name for TFU.
|
||||
|
||||
We shouldn't be returning v3d-render for our new queue.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Fixes: 83d5139982db ("drm/v3d: Add support for submitting jobs to the TFU.")
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181201005759.28093-6-eric@anholt.net
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com>
|
||||
(cherry picked from commit db176f6ba1da39ad0016c77b9775a6bb3d0ce88a)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_fence.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_fence.c b/drivers/gpu/drm/v3d/v3d_fence.c
|
||||
index 50bfcf9a8a1a..b0a2a1ae2eb1 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_fence.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_fence.c
|
||||
@@ -29,10 +29,16 @@ static const char *v3d_fence_get_timeline_name(struct dma_fence *fence)
|
||||
{
|
||||
struct v3d_fence *f = to_v3d_fence(fence);
|
||||
|
||||
- if (f->queue == V3D_BIN)
|
||||
+ switch (f->queue) {
|
||||
+ case V3D_BIN:
|
||||
return "v3d-bin";
|
||||
- else
|
||||
+ case V3D_RENDER:
|
||||
return "v3d-render";
|
||||
+ case V3D_TFU:
|
||||
+ return "v3d-tfu";
|
||||
+ default:
|
||||
+ return NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
const struct dma_fence_ops v3d_fence_ops = {
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
From 5ecb950808c32a75a63a97e4a3c73c9c2667046a Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 30 Nov 2018 16:57:58 -0800
|
||||
Subject: [PATCH 577/678] drm/v3d: Add more tracepoints for V3D GPU rendering.
|
||||
|
||||
The core scheduler tells us when the job is pushed to the scheduler's
|
||||
queue, and I had the job_run functions saying when they actually queue
|
||||
the job to the hardware. By adding tracepoints for the very top of
|
||||
the ioctls and the IRQs signaling job completion, "perf record -a -e
|
||||
v3d:.\* -e gpu_scheduler:.\* <job>; perf script" gets you a pretty
|
||||
decent timeline.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181201005759.28093-5-eric@anholt.net
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com>
|
||||
(cherry picked from commit 55a9b74846ed5e6219c7d81a8e1bf96f25d8ad5e)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 4 ++
|
||||
drivers/gpu/drm/v3d/v3d_irq.c | 19 +++++-
|
||||
drivers/gpu/drm/v3d/v3d_trace.h | 101 ++++++++++++++++++++++++++++++++
|
||||
3 files changed, 121 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 46ef27fab2c5..21f8ad559832 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -521,6 +521,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_syncobj *sync_out;
|
||||
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);
|
||||
return -EINVAL;
|
||||
@@ -648,6 +650,8 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
int ret = 0;
|
||||
int bo_count;
|
||||
|
||||
+ trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);
|
||||
+
|
||||
job = kcalloc(1, sizeof(*job), GFP_KERNEL);
|
||||
if (!job)
|
||||
return -ENOMEM;
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
index e33bca1a494b..29d746cfce57 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "v3d_drv.h"
|
||||
#include "v3d_regs.h"
|
||||
+#include "v3d_trace.h"
|
||||
|
||||
#define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
|
||||
V3D_INT_FLDONE | \
|
||||
@@ -88,12 +89,20 @@ v3d_irq(int irq, void *arg)
|
||||
}
|
||||
|
||||
if (intsts & V3D_INT_FLDONE) {
|
||||
- dma_fence_signal(v3d->bin_job->bin.done_fence);
|
||||
+ struct v3d_fence *fence =
|
||||
+ to_v3d_fence(v3d->bin_job->bin.done_fence);
|
||||
+
|
||||
+ trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
|
||||
+ dma_fence_signal(&fence->base);
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (intsts & V3D_INT_FRDONE) {
|
||||
- dma_fence_signal(v3d->render_job->render.done_fence);
|
||||
+ struct v3d_fence *fence =
|
||||
+ to_v3d_fence(v3d->render_job->render.done_fence);
|
||||
+
|
||||
+ trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
|
||||
+ dma_fence_signal(&fence->base);
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -119,7 +128,11 @@ v3d_hub_irq(int irq, void *arg)
|
||||
V3D_WRITE(V3D_HUB_INT_CLR, intsts);
|
||||
|
||||
if (intsts & V3D_HUB_INT_TFUC) {
|
||||
- dma_fence_signal(v3d->tfu_job->done_fence);
|
||||
+ struct v3d_fence *fence =
|
||||
+ to_v3d_fence(v3d->tfu_job->done_fence);
|
||||
+
|
||||
+ trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
|
||||
+ dma_fence_signal(&fence->base);
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_trace.h b/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
index f54ed9cd3444..edd984afa33f 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
@@ -12,6 +12,28 @@
|
||||
#define TRACE_SYSTEM v3d
|
||||
#define TRACE_INCLUDE_FILE v3d_trace
|
||||
|
||||
+TRACE_EVENT(v3d_submit_cl_ioctl,
|
||||
+ TP_PROTO(struct drm_device *dev, u32 ct1qba, u32 ct1qea),
|
||||
+ TP_ARGS(dev, ct1qba, ct1qea),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u32, ct1qba)
|
||||
+ __field(u32, ct1qea)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->ct1qba = ct1qba;
|
||||
+ __entry->ct1qea = ct1qea;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, RCL 0x%08x..0x%08x",
|
||||
+ __entry->dev,
|
||||
+ __entry->ct1qba,
|
||||
+ __entry->ct1qea)
|
||||
+);
|
||||
+
|
||||
TRACE_EVENT(v3d_submit_cl,
|
||||
TP_PROTO(struct drm_device *dev, bool is_render,
|
||||
uint64_t seqno,
|
||||
@@ -42,6 +64,85 @@ TRACE_EVENT(v3d_submit_cl,
|
||||
__entry->ctnqea)
|
||||
);
|
||||
|
||||
+TRACE_EVENT(v3d_bcl_irq,
|
||||
+ TP_PROTO(struct drm_device *dev,
|
||||
+ uint64_t seqno),
|
||||
+ TP_ARGS(dev, seqno),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u64, seqno)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->seqno = seqno;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, seqno=%llu",
|
||||
+ __entry->dev,
|
||||
+ __entry->seqno)
|
||||
+);
|
||||
+
|
||||
+TRACE_EVENT(v3d_rcl_irq,
|
||||
+ TP_PROTO(struct drm_device *dev,
|
||||
+ uint64_t seqno),
|
||||
+ TP_ARGS(dev, seqno),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u64, seqno)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->seqno = seqno;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, seqno=%llu",
|
||||
+ __entry->dev,
|
||||
+ __entry->seqno)
|
||||
+);
|
||||
+
|
||||
+TRACE_EVENT(v3d_tfu_irq,
|
||||
+ TP_PROTO(struct drm_device *dev,
|
||||
+ uint64_t seqno),
|
||||
+ TP_ARGS(dev, seqno),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u64, seqno)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->seqno = seqno;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, seqno=%llu",
|
||||
+ __entry->dev,
|
||||
+ __entry->seqno)
|
||||
+);
|
||||
+
|
||||
+TRACE_EVENT(v3d_submit_tfu_ioctl,
|
||||
+ TP_PROTO(struct drm_device *dev, u32 iia),
|
||||
+ TP_ARGS(dev, iia),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u32, iia)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->iia = iia;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, IIA 0x%08x",
|
||||
+ __entry->dev,
|
||||
+ __entry->iia)
|
||||
+);
|
||||
+
|
||||
TRACE_EVENT(v3d_submit_tfu,
|
||||
TP_PROTO(struct drm_device *dev,
|
||||
uint64_t seqno),
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
From 59d677155028619a96b400d85b758308fa3d0934 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 3 Dec 2018 14:24:34 -0800
|
||||
Subject: [PATCH 578/678] drm/v3d: Drop unused v3d_flush_caches().
|
||||
|
||||
Now that I've specified how the end-of-pipeline flushing should work,
|
||||
we're never going to use this function.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181203222438.25417-2-eric@anholt.net
|
||||
(cherry picked from commit 2aa34fd5c7754824cf5488b61ac644f30d3c5c85)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 1 -
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 21 ---------------------
|
||||
2 files changed, 22 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index f2937a1da581..2fdb456b72d3 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -308,7 +308,6 @@ void v3d_exec_put(struct v3d_exec_info *exec);
|
||||
void v3d_tfu_job_put(struct v3d_tfu_job *exec);
|
||||
void v3d_reset(struct v3d_dev *v3d);
|
||||
void v3d_invalidate_caches(struct v3d_dev *v3d);
|
||||
-void v3d_flush_caches(struct v3d_dev *v3d);
|
||||
|
||||
/* v3d_irq.c */
|
||||
int v3d_irq_init(struct v3d_dev *v3d);
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 21f8ad559832..bb5a0ec29fde 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -175,20 +175,6 @@ v3d_invalidate_slices(struct v3d_dev *v3d, int core)
|
||||
V3D_SET_FIELD(0xf, V3D_SLCACTL_ICC));
|
||||
}
|
||||
|
||||
-/* Invalidates texture L2 cachelines */
|
||||
-static void
|
||||
-v3d_invalidate_l2t(struct v3d_dev *v3d, int core)
|
||||
-{
|
||||
- V3D_CORE_WRITE(core,
|
||||
- V3D_CTL_L2TCACTL,
|
||||
- V3D_L2TCACTL_L2TFLS |
|
||||
- V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAR, V3D_L2TCACTL_FLM));
|
||||
- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
- V3D_L2TCACTL_L2TFLS), 100)) {
|
||||
- DRM_ERROR("Timeout waiting for L2T invalidate\n");
|
||||
- }
|
||||
-}
|
||||
-
|
||||
void
|
||||
v3d_invalidate_caches(struct v3d_dev *v3d)
|
||||
{
|
||||
@@ -199,13 +185,6 @@ v3d_invalidate_caches(struct v3d_dev *v3d)
|
||||
v3d_flush_l2t(v3d, 0);
|
||||
}
|
||||
|
||||
-void
|
||||
-v3d_flush_caches(struct v3d_dev *v3d)
|
||||
-{
|
||||
- v3d_invalidate_l1td(v3d, 0);
|
||||
- v3d_invalidate_l2t(v3d, 0);
|
||||
-}
|
||||
-
|
||||
static void
|
||||
v3d_attach_object_fences(struct v3d_bo **bos, int bo_count,
|
||||
struct dma_fence *fence)
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
From 69dabb23ccbd930032e0c5aecadf439937cf1f6c Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 3 Dec 2018 14:24:35 -0800
|
||||
Subject: [PATCH 579/678] drm/v3d: Don't bother flushing L1TD at job start.
|
||||
|
||||
This is the write combiner for TMU writes. You're supposed to flush
|
||||
that at job end if you had dirtied any cachelines. Flushing it at job
|
||||
start then doesn't make any sense.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181203222438.25417-3-eric@anholt.net
|
||||
(cherry picked from commit 2e6dc3bd80478212e84addf1cafd6ec60674b884)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 12 ------------
|
||||
1 file changed, 12 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index bb5a0ec29fde..15065d11f781 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -139,22 +139,10 @@ v3d_invalidate_l2(struct v3d_dev *v3d, int core)
|
||||
V3D_L2CACTL_L2CENA);
|
||||
}
|
||||
|
||||
-static void
|
||||
-v3d_invalidate_l1td(struct v3d_dev *v3d, int core)
|
||||
-{
|
||||
- V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
|
||||
- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
- V3D_L2TCACTL_L2TFLS), 100)) {
|
||||
- DRM_ERROR("Timeout waiting for L1T write combiner flush\n");
|
||||
- }
|
||||
-}
|
||||
-
|
||||
/* Invalidates texture L2 cachelines */
|
||||
static void
|
||||
v3d_flush_l2t(struct v3d_dev *v3d, int core)
|
||||
{
|
||||
- v3d_invalidate_l1td(v3d, core);
|
||||
-
|
||||
V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
|
||||
V3D_L2TCACTL_L2TFLS |
|
||||
V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
From d6f6accead7bacbe594d7b59729f8a25225f8267 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 3 Dec 2018 14:24:36 -0800
|
||||
Subject: [PATCH 580/678] drm/v3d: Drop the wait for L2T flush to complete.
|
||||
|
||||
According to Dave, once you've started an L2T flush, all L2T accesses
|
||||
will be blocked until the flush completes. This fixes a consistent
|
||||
3-4ms stall between the ioctl and running the job, and 3DMMES Taiji
|
||||
goes from 27fps to 110fps.
|
||||
|
||||
v2: Leave a note about why we don't need to wait for completion.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181203222438.25417-4-eric@anholt.net
|
||||
(cherry picked from commit 51c1b6f9eb3dbdec91b0e3c89f623e634c996bbb)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 15065d11f781..8c4380ef2b04 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -143,13 +143,13 @@ v3d_invalidate_l2(struct v3d_dev *v3d, int core)
|
||||
static void
|
||||
v3d_flush_l2t(struct v3d_dev *v3d, int core)
|
||||
{
|
||||
+ /* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't
|
||||
+ * need to wait for completion before dispatching the job --
|
||||
+ * L2T accesses will be stalled until the flush has completed.
|
||||
+ */
|
||||
V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
|
||||
V3D_L2TCACTL_L2TFLS |
|
||||
V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
|
||||
- if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
- V3D_L2TCACTL_L2TFLS), 100)) {
|
||||
- DRM_ERROR("Timeout waiting for L2T flush\n");
|
||||
- }
|
||||
}
|
||||
|
||||
/* Invalidates the slice caches. These are read-only caches. */
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From f45d756bd701ca9a4dac853f85cf72cbbce213dd Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 3 Dec 2018 14:24:37 -0800
|
||||
Subject: [PATCH 581/678] drm/v3d: Stop trying to flush L2C on V3D 3.3+
|
||||
|
||||
This cache was replaced with the slice accessing the L2T in the newer
|
||||
generations. Noted by Dave during review.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181203222438.25417-5-eric@anholt.net
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com>
|
||||
(cherry picked from commit 7b9d2fe4350a9c12f66ad8cc78c1098226f6c3c2)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 11 ++++++++---
|
||||
1 file changed, 8 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 8c4380ef2b04..15998a77960c 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -130,10 +130,15 @@ v3d_flush_l3(struct v3d_dev *v3d)
|
||||
}
|
||||
}
|
||||
|
||||
-/* Invalidates the (read-only) L2 cache. */
|
||||
+/* Invalidates the (read-only) L2C cache. This was the L2 cache for
|
||||
+ * uniforms and instructions on V3D 3.2.
|
||||
+ */
|
||||
static void
|
||||
-v3d_invalidate_l2(struct v3d_dev *v3d, int core)
|
||||
+v3d_invalidate_l2c(struct v3d_dev *v3d, int core)
|
||||
{
|
||||
+ if (v3d->ver > 32)
|
||||
+ return;
|
||||
+
|
||||
V3D_CORE_WRITE(core, V3D_CTL_L2CACTL,
|
||||
V3D_L2CACTL_L2CCLR |
|
||||
V3D_L2CACTL_L2CENA);
|
||||
@@ -168,7 +173,7 @@ v3d_invalidate_caches(struct v3d_dev *v3d)
|
||||
{
|
||||
v3d_flush_l3(v3d);
|
||||
|
||||
- v3d_invalidate_l2(v3d, 0);
|
||||
+ v3d_invalidate_l2c(v3d, 0);
|
||||
v3d_invalidate_slices(v3d, 0);
|
||||
v3d_flush_l2t(v3d, 0);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
From 0f3d303253879c812646371ff32e634286d56dc2 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 3 Dec 2018 14:24:38 -0800
|
||||
Subject: [PATCH 582/678] drm/v3d: Invalidate the caches from the outside in.
|
||||
|
||||
This would be a fairly obscure race, but let's make sure we don't ever
|
||||
lose it.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20181203222438.25417-6-eric@anholt.net
|
||||
Reviewed-by: Dave Emett <david.emett@broadcom.com>
|
||||
(cherry picked from commit aa5beec32e8b78bfcf621e3c3daebfb1644b6365)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 15998a77960c..2cef279dc36a 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -171,11 +171,15 @@ v3d_invalidate_slices(struct v3d_dev *v3d, int core)
|
||||
void
|
||||
v3d_invalidate_caches(struct v3d_dev *v3d)
|
||||
{
|
||||
+ /* Invalidate the caches from the outside in. That way if
|
||||
+ * another CL's concurrent use of nearby memory were to pull
|
||||
+ * an invalidated cacheline back in, we wouldn't leave stale
|
||||
+ * data in the inner cache.
|
||||
+ */
|
||||
v3d_flush_l3(v3d);
|
||||
-
|
||||
v3d_invalidate_l2c(v3d, 0);
|
||||
- v3d_invalidate_slices(v3d, 0);
|
||||
v3d_flush_l2t(v3d, 0);
|
||||
+ v3d_invalidate_slices(v3d, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
From 179c5bdbc11fd012e766ac71138bd9a794e2bf39 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 7 Feb 2019 15:26:13 -0800
|
||||
Subject: [PATCH 583/678] drm/v3d: Fix BO stats accounting for dma-buf-imported
|
||||
buffers.
|
||||
|
||||
We always decrement at GEM free, so make sure we increment at GEM
|
||||
creation for dma-bufs.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20190207232613.24981-1-eric@anholt.net
|
||||
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
(cherry picked from commit cc3f60cfd4f2752f1bad7eaa3839855c15347abc)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_bo.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
|
||||
index a08766d39eab..b1766f096c4b 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_bo.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_bo.c
|
||||
@@ -282,6 +282,7 @@ v3d_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt)
|
||||
{
|
||||
+ struct v3d_dev *v3d = to_v3d_dev(dev);
|
||||
struct drm_gem_object *obj;
|
||||
struct v3d_bo *bo;
|
||||
|
||||
@@ -296,6 +297,11 @@ v3d_prime_import_sg_table(struct drm_device *dev,
|
||||
obj->import_attach = attach;
|
||||
v3d_bo_get_pages(bo);
|
||||
|
||||
+ mutex_lock(&v3d->bo_lock);
|
||||
+ v3d->bo_stats.num_allocated++;
|
||||
+ v3d->bo_stats.pages_allocated += obj->size >> PAGE_SHIFT;
|
||||
+ mutex_unlock(&v3d->bo_lock);
|
||||
+
|
||||
v3d_mmu_insert_ptes(bo);
|
||||
|
||||
return obj;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
From d367d15e495238b7a2199231ebb187900c1396bd Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 7 Feb 2019 12:09:58 -0800
|
||||
Subject: [PATCH 584/678] drm/v3d: Update top-level kerneldoc for the addition
|
||||
of TFU.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20190207201001.5730-1-eric@anholt.net
|
||||
Reviewed-by: Thomas Spurden <thomas.spurden@broadcom.com>
|
||||
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
(cherry picked from commit fd347df16d4ed2eef565344b8f16a1134bddf185)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 30ae1c74edaa..41659f981f44 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -7,9 +7,9 @@
|
||||
* This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs.
|
||||
* For V3D 2.x support, see the VC4 driver.
|
||||
*
|
||||
- * Currently only single-core rendering using the binner and renderer
|
||||
- * is supported. The TFU (texture formatting unit) and V3D 4.x's CSD
|
||||
- * (compute shader dispatch) are not yet supported.
|
||||
+ * Currently only single-core rendering using the binner and renderer,
|
||||
+ * along with TFU (texture formatting unit) rendering is supported.
|
||||
+ * V3D 4.x's CSD (compute shader dispatch) is not yet supported.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
From 00503d7ce8fe07e4971185b4f93a628028eaece3 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 4 Mar 2019 11:59:34 -0800
|
||||
Subject: [PATCH 585/678] drm/vc4: Fix oops at boot with firmwarekms on 4.19.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index f8c6cafff14a..14ccd676b2e9 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -107,6 +107,9 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
|
||||
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]),
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
From 5135ce6a4eb3c13c91ce537143696bf732ca94c8 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 20 Feb 2019 13:03:41 -0800
|
||||
Subject: [PATCH 586/678] drm/vc4: Disable V3D interactions if the v3d
|
||||
component didn't probe.
|
||||
|
||||
One might want to use the VC4 display stack without using Mesa.
|
||||
Similar to the debugfs fixes for not having all of the possible
|
||||
display bits enabled, make sure you can't oops in vc4 if v3d isn't
|
||||
enabled.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.c | 11 +++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_gem.c | 10 ++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_irq.c | 9 +++++++++
|
||||
drivers/gpu/drm/vc4/vc4_perfmon.c | 18 ++++++++++++++++++
|
||||
4 files changed, 48 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
index 5b2f60b0e904..9f692253ae3d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
@@ -71,6 +71,9 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data,
|
||||
if (args->pad != 0)
|
||||
return -EINVAL;
|
||||
|
||||
+ if (!vc4->v3d)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
switch (args->param) {
|
||||
case DRM_VC4_PARAM_V3D_IDENT0:
|
||||
ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
|
||||
@@ -271,6 +274,7 @@ static int vc4_drm_bind(struct device *dev)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct drm_device *drm;
|
||||
struct vc4_dev *vc4;
|
||||
+ struct device_node *node;
|
||||
int ret = 0;
|
||||
|
||||
dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
@@ -279,6 +283,13 @@ static int vc4_drm_bind(struct device *dev)
|
||||
if (!vc4)
|
||||
return -ENOMEM;
|
||||
|
||||
+ /* If VC4 V3D is missing, don't advertise render nodes. */
|
||||
+ node = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-v3d");
|
||||
+ if (node)
|
||||
+ of_node_put(node);
|
||||
+ else
|
||||
+ vc4_drm_driver.driver_features &= ~DRIVER_RENDER;
|
||||
+
|
||||
drm = drm_dev_alloc(&vc4_drm_driver, dev);
|
||||
if (IS_ERR(drm))
|
||||
return PTR_ERR(drm);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
index 928718b467bd..e174f972beb1 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
@@ -74,6 +74,11 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
|
||||
u32 i;
|
||||
int ret = 0;
|
||||
|
||||
+ if (!vc4->v3d) {
|
||||
+ DRM_DEBUG("VC4_GET_HANG_STATE with no VC4 V3D probed\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
kernel_state = vc4->hang_state;
|
||||
if (!kernel_state) {
|
||||
@@ -1124,6 +1129,11 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
struct dma_fence *in_fence;
|
||||
int ret = 0;
|
||||
|
||||
+ if (!vc4->v3d) {
|
||||
+ DRM_DEBUG("VC4_SUBMIT_CL with no VC4 V3D probed\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
if ((args->flags & ~(VC4_SUBMIT_CL_USE_CLEAR_COLOR |
|
||||
VC4_SUBMIT_CL_FIXED_RCL_ORDER |
|
||||
VC4_SUBMIT_CL_RCL_ORDER_INCREASING_X |
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
|
||||
index 4cd2ccfe15f4..ffd0a4388752 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_irq.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
|
||||
@@ -229,6 +229,9 @@ vc4_irq_preinstall(struct drm_device *dev)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
+ if (!vc4->v3d)
|
||||
+ return;
|
||||
+
|
||||
init_waitqueue_head(&vc4->job_wait_queue);
|
||||
INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
|
||||
|
||||
@@ -243,6 +246,9 @@ vc4_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
+ if (!vc4->v3d)
|
||||
+ return 0;
|
||||
+
|
||||
/* Enable both the render done and out of memory interrupts. */
|
||||
V3D_WRITE(V3D_INTENA, V3D_DRIVER_IRQS);
|
||||
|
||||
@@ -254,6 +260,9 @@ vc4_irq_uninstall(struct drm_device *dev)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
+ if (!vc4->v3d)
|
||||
+ return;
|
||||
+
|
||||
/* Disable sending interrupts for our driver's IRQs. */
|
||||
V3D_WRITE(V3D_INTDIS, V3D_DRIVER_IRQS);
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c
|
||||
index 437e7a27f21d..4ef9802df830 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_perfmon.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_perfmon.c
|
||||
@@ -100,12 +100,18 @@ void vc4_perfmon_close_file(struct vc4_file *vc4file)
|
||||
int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_file *vc4file = file_priv->driver_priv;
|
||||
struct drm_vc4_perfmon_create *req = data;
|
||||
struct vc4_perfmon *perfmon;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
+ if (!vc4->v3d) {
|
||||
+ DRM_DEBUG("Creating perfmon no VC4 V3D probed\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
/* Number of monitored counters cannot exceed HW limits. */
|
||||
if (req->ncounters > DRM_VC4_MAX_PERF_COUNTERS ||
|
||||
!req->ncounters)
|
||||
@@ -146,10 +152,16 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
|
||||
int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_file *vc4file = file_priv->driver_priv;
|
||||
struct drm_vc4_perfmon_destroy *req = data;
|
||||
struct vc4_perfmon *perfmon;
|
||||
|
||||
+ if (!vc4->v3d) {
|
||||
+ DRM_DEBUG("Destroying perfmon no VC4 V3D probed\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
mutex_lock(&vc4file->perfmon.lock);
|
||||
perfmon = idr_remove(&vc4file->perfmon.idr, req->id);
|
||||
mutex_unlock(&vc4file->perfmon.lock);
|
||||
@@ -164,11 +176,17 @@ int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
int vc4_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_file *vc4file = file_priv->driver_priv;
|
||||
struct drm_vc4_perfmon_get_values *req = data;
|
||||
struct vc4_perfmon *perfmon;
|
||||
int ret;
|
||||
|
||||
+ if (!vc4->v3d) {
|
||||
+ DRM_DEBUG("Getting perfmon no VC4 V3D probed\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
mutex_lock(&vc4file->perfmon.lock);
|
||||
perfmon = idr_find(&vc4file->perfmon.idr, req->id);
|
||||
vc4_perfmon_get(perfmon);
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
From a319dc7a8eea4e53cde4f2e8feb85e574aeaf0de Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 4 Oct 2018 17:22:43 -0700
|
||||
Subject: [PATCH 587/678] drm/v3d: Add support for V3D v4.2.
|
||||
|
||||
No compatible string for it yet, just the version-dependent changes.
|
||||
They've now tied the hub and the core interrupt lines into a single
|
||||
interrupt line coming out of the block. It also turns out I made a
|
||||
mistake in modeling the V3D v3.3 and v4.1 bridge as a part of V3D
|
||||
itself -- the bridge is going away in favor of an external reset
|
||||
controller in a larger HW module.
|
||||
|
||||
v2: Use consistent checks for whether we're on 4.2, and fix a leak in
|
||||
an error path.
|
||||
v3: Use more general means of determining if the current 4.2 changes
|
||||
are in place, as apparently other platforms may switch back (noted
|
||||
by Dave). Update the binding doc.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
.../devicetree/bindings/gpu/brcm,bcm-v3d.txt | 11 ++++--
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 21 +++++++++---
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 2 ++
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 12 ++++++-
|
||||
drivers/gpu/drm/v3d/v3d_irq.c | 34 ++++++++++++++-----
|
||||
5 files changed, 63 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
|
||||
index c907aa8dd755..b2df82b44625 100644
|
||||
--- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
|
||||
+++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.txt
|
||||
@@ -6,15 +6,20 @@ For V3D 2.x, see brcm,bcm-vc4.txt.
|
||||
Required properties:
|
||||
- compatible: Should be "brcm,7268-v3d" or "brcm,7278-v3d"
|
||||
- reg: Physical base addresses and lengths of the register areas
|
||||
-- reg-names: Names for the register areas. The "hub", "bridge", and "core0"
|
||||
+- reg-names: Names for the register areas. The "hub" and "core0"
|
||||
register areas are always required. The "gca" register area
|
||||
- is required if the GCA cache controller is present.
|
||||
+ is required if the GCA cache controller is present. The
|
||||
+ "bridge" register area is required if an external reset
|
||||
+ controller is not present.
|
||||
- interrupts: The interrupt numbers. The first interrupt is for the hub,
|
||||
- while the following interrupts are for the cores.
|
||||
+ while the following interrupts are separate interrupt lines
|
||||
+ for the cores (if they don't share the hub's interrupt).
|
||||
See bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
Optional properties:
|
||||
- clocks: The core clock the unit runs on
|
||||
+- resets: The reset line for v3d, if not using a mapping of the bridge
|
||||
+ See bindings/reset/reset.txt
|
||||
|
||||
v3d {
|
||||
compatible = "brcm,7268-v3d";
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 41659f981f44..4cf01092936e 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
+#include <linux/reset.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
|
||||
@@ -265,10 +266,6 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
|
||||
v3d->pdev = pdev;
|
||||
drm = &v3d->drm;
|
||||
|
||||
- ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
|
||||
- if (ret)
|
||||
- goto dev_free;
|
||||
-
|
||||
ret = map_regs(v3d, &v3d->hub_regs, "hub");
|
||||
if (ret)
|
||||
goto dev_free;
|
||||
@@ -283,6 +280,22 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
|
||||
v3d->cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
|
||||
WARN_ON(v3d->cores > 1); /* multicore not yet implemented */
|
||||
|
||||
+ v3d->reset = devm_reset_control_get_exclusive(dev, NULL);
|
||||
+ if (IS_ERR(v3d->reset)) {
|
||||
+ ret = PTR_ERR(v3d->reset);
|
||||
+
|
||||
+ if (ret == -EPROBE_DEFER)
|
||||
+ goto dev_free;
|
||||
+
|
||||
+ v3d->reset = NULL;
|
||||
+ ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
|
||||
+ if (ret) {
|
||||
+ dev_err(dev,
|
||||
+ "Failed to get reset control or bridge regs\n");
|
||||
+ goto dev_free;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (v3d->ver < 41) {
|
||||
ret = map_regs(v3d, &v3d->gca_regs, "gca");
|
||||
if (ret)
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index 2fdb456b72d3..7952fb99ca01 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -34,6 +34,7 @@ struct v3d_dev {
|
||||
* and revision.
|
||||
*/
|
||||
int ver;
|
||||
+ bool single_irq_line;
|
||||
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
@@ -42,6 +43,7 @@ struct v3d_dev {
|
||||
void __iomem *bridge_regs;
|
||||
void __iomem *gca_regs;
|
||||
struct clk *clk;
|
||||
+ struct reset_control *reset;
|
||||
|
||||
/* Virtual and DMA addresses of the single shared page table. */
|
||||
volatile u32 *pt;
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 2cef279dc36a..e557a7130cae 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
+#include <linux/reset.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sched/signal.h>
|
||||
@@ -69,7 +70,7 @@ v3d_idle_gca(struct v3d_dev *v3d)
|
||||
}
|
||||
|
||||
static void
|
||||
-v3d_reset_v3d(struct v3d_dev *v3d)
|
||||
+v3d_reset_by_bridge(struct v3d_dev *v3d)
|
||||
{
|
||||
int version = V3D_BRIDGE_READ(V3D_TOP_GR_BRIDGE_REVISION);
|
||||
|
||||
@@ -89,6 +90,15 @@ v3d_reset_v3d(struct v3d_dev *v3d)
|
||||
V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT);
|
||||
V3D_BRIDGE_WRITE(V3D_TOP_GR_BRIDGE_SW_INIT_1, 0);
|
||||
}
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+v3d_reset_v3d(struct v3d_dev *v3d)
|
||||
+{
|
||||
+ if (v3d->reset)
|
||||
+ reset_control_reset(v3d->reset);
|
||||
+ else
|
||||
+ v3d_reset_by_bridge(v3d);
|
||||
|
||||
v3d_init_hw_state(v3d);
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
index 29d746cfce57..feb086026d9e 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
@@ -27,6 +27,9 @@
|
||||
V3D_HUB_INT_MMU_CAP | \
|
||||
V3D_HUB_INT_TFUC))
|
||||
|
||||
+static irqreturn_t
|
||||
+v3d_hub_irq(int irq, void *arg);
|
||||
+
|
||||
static void
|
||||
v3d_overflow_mem_work(struct work_struct *work)
|
||||
{
|
||||
@@ -112,6 +115,12 @@ v3d_irq(int irq, void *arg)
|
||||
if (intsts & V3D_INT_GMPV)
|
||||
dev_err(v3d->dev, "GMP violation\n");
|
||||
|
||||
+ /* V3D 4.2 wires the hub and core IRQs together, so if we &
|
||||
+ * didn't see the common one then check hub for MMU IRQs.
|
||||
+ */
|
||||
+ if (v3d->single_irq_line && status == IRQ_NONE)
|
||||
+ return v3d_hub_irq(irq, arg);
|
||||
+
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -170,15 +179,22 @@ 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);
|
||||
|
||||
- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
|
||||
- v3d_hub_irq, IRQF_SHARED,
|
||||
- "v3d_hub", v3d);
|
||||
- if (ret)
|
||||
- goto fail;
|
||||
-
|
||||
- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
|
||||
- v3d_irq, IRQF_SHARED,
|
||||
- "v3d_core0", v3d);
|
||||
+ if (platform_get_irq(v3d->pdev, 1) < 0) {
|
||||
+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
|
||||
+ v3d_irq, IRQF_SHARED,
|
||||
+ "v3d", v3d);
|
||||
+ v3d->single_irq_line = true;
|
||||
+ } else {
|
||||
+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
|
||||
+ v3d_hub_irq, IRQF_SHARED,
|
||||
+ "v3d_hub", v3d);
|
||||
+ if (ret)
|
||||
+ goto fail;
|
||||
+
|
||||
+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
|
||||
+ v3d_irq, IRQF_SHARED,
|
||||
+ "v3d_core0", v3d);
|
||||
+ }
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
From b9d6a655af87d50562657ea621e7112c88400a3b Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Tue, 16 Oct 2018 10:13:41 -0700
|
||||
Subject: [PATCH 588/678] drm/v3d: Don't try to set OVRTMUOUT on V3D 4.x.
|
||||
|
||||
The old field is gone and the register now has a different field,
|
||||
QRMAXCNT for how many TMU requests get serviced before thread switch.
|
||||
We were accidentally reducing it from its default of 0x3 (4 requests)
|
||||
to 0x0 (1).
|
||||
|
||||
v2: Skip setting the reg at all on 4.x, instead of trying to update
|
||||
only the old field.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 3 ++-
|
||||
drivers/gpu/drm/v3d/v3d_regs.h | 2 ++
|
||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index e557a7130cae..762b5709fcd4 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -25,7 +25,8 @@ v3d_init_core(struct v3d_dev *v3d, int core)
|
||||
* type. If you want the default behavior, you can still put
|
||||
* "2" in the indirect texture state's output_type field.
|
||||
*/
|
||||
- V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT);
|
||||
+ if (v3d->ver < 40)
|
||||
+ V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT);
|
||||
|
||||
/* Whenever we flush the L2T cache, we always want to flush
|
||||
* the whole thing.
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
index 6ccdee9d47bd..8e88af237610 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
@@ -216,6 +216,8 @@
|
||||
# define V3D_IDENT2_BCG_INT BIT(28)
|
||||
|
||||
#define V3D_CTL_MISCCFG 0x00018
|
||||
+# define V3D_CTL_MISCCFG_QRMAXCNT_MASK V3D_MASK(3, 1)
|
||||
+# define V3D_CTL_MISCCFG_QRMAXCNT_SHIFT 1
|
||||
# define V3D_MISCCFG_OVRTMUOUT BIT(0)
|
||||
|
||||
#define V3D_CTL_L2CACTL 0x00020
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From 8fec9f0134e40e54ff5b5289c01e564102dd6bee Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 14 Jan 2019 17:26:04 -0800
|
||||
Subject: [PATCH 589/678] drm/v3d: Make sure the GPU is on when measuring
|
||||
clocks.
|
||||
|
||||
You'll get garbage measurements if the registers always read back
|
||||
0xdeadbeef
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_debugfs.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
index eb2b2d2f8553..a24af2d2f574 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
@@ -187,6 +187,11 @@ static int v3d_measure_clock(struct seq_file *m, void *unused)
|
||||
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,
|
||||
@@ -210,6 +215,9 @@ static int v3d_measure_clock(struct seq_file *m, void *unused)
|
||||
cycles / (measure_ms * 1000),
|
||||
(cycles / (measure_ms * 100)) % 10);
|
||||
|
||||
+ pm_runtime_mark_last_busy(v3d->dev);
|
||||
+ pm_runtime_put_autosuspend(v3d->dev);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
From df9aee4540b1b81cec1a2f0942aab8b7e0c79c3c Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 4 Oct 2018 17:22:43 -0700
|
||||
Subject: [PATCH 590/678] drm/v3d: Add support for 2711.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 4cf01092936e..156ba517e6f3 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -235,6 +235,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);
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
From 1b9ad8d7052a12794d34e49ec9e63e1693498256 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 14 Jan 2019 12:35:43 -0800
|
||||
Subject: [PATCH 591/678] 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 <eric@anholt.net>
|
||||
(cherry picked from commit 3ee4e2e0a9e9587eacbb69b067bbc72ab2cdc47b)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_mmu.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_mmu.c b/drivers/gpu/drm/v3d/v3d_mmu.c
|
||||
index b00f97c31b70..796eed177fd9 100644
|
||||
--- 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 <linux/pm_runtime.h>
|
||||
+
|
||||
#include "v3d_drv.h"
|
||||
#include "v3d_regs.h"
|
||||
|
||||
@@ -34,6 +36,14 @@ static int v3d_mmu_flush_all(struct v3d_dev *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_dev *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;
|
||||
}
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
From c43662345b49c802eca04703612be431668aa109 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 14 Jan 2019 14:47:57 -0800
|
||||
Subject: [PATCH 592/678] 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 <eric@anholt.net>
|
||||
(cherry picked from commit ca197699af29baa8236c74c53d4904ca8957ee06)
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 156ba517e6f3..9838c65bb8ec 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -66,7 +66,7 @@ static int v3d_runtime_resume(struct device *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)
|
||||
};
|
||||
|
||||
@@ -371,6 +371,7 @@ static struct platform_driver v3d_platform_driver = {
|
||||
.driver = {
|
||||
.name = "v3d",
|
||||
.of_match_table = v3d_of_match,
|
||||
+ .pm = &v3d_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
From ff042fa1445df8b3879aec847120abb443625d05 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 14 Jan 2019 15:13:17 -0800
|
||||
Subject: [PATCH 593/678] 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 <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_debugfs.c | 16 +---------------
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 7 -------
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 20 --------------------
|
||||
3 files changed, 1 insertion(+), 42 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
index a24af2d2f574..b15051df2dbb 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/debugfs.h>
|
||||
-#include <linux/pm_runtime.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
@@ -100,11 +99,8 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused)
|
||||
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);
|
||||
@@ -157,9 +153,6 @@ static int v3d_v3d_debugfs_ident(struct seq_file *m, void *unused)
|
||||
(misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
|
||||
}
|
||||
|
||||
- pm_runtime_mark_last_busy(v3d->dev);
|
||||
- pm_runtime_put_autosuspend(v3d->dev);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -187,11 +180,6 @@ static int v3d_measure_clock(struct seq_file *m, void *unused)
|
||||
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,
|
||||
@@ -215,8 +203,6 @@ static int v3d_measure_clock(struct seq_file *m, void *unused)
|
||||
cycles / (measure_ms * 1000),
|
||||
(cycles / (measure_ms * 100)) % 10);
|
||||
|
||||
- pm_runtime_mark_last_busy(v3d->dev);
|
||||
- pm_runtime_put_autosuspend(v3d->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 9838c65bb8ec..1f2c3555c038 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -75,7 +75,6 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
|
||||
{
|
||||
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,
|
||||
@@ -101,15 +100,12 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
|
||||
if (args->value != 0)
|
||||
return -EINVAL;
|
||||
|
||||
- ret = pm_runtime_get_sync(v3d->dev);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -311,9 +307,6 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
|
||||
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/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 762b5709fcd4..341411e2e292 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -375,7 +375,6 @@ v3d_exec_cleanup(struct kref *ref)
|
||||
{
|
||||
struct v3d_exec_info *exec = container_of(ref, struct v3d_exec_info,
|
||||
refcount);
|
||||
- struct v3d_dev *v3d = exec->v3d;
|
||||
unsigned int i;
|
||||
struct v3d_bo *bo, *save;
|
||||
|
||||
@@ -396,9 +395,6 @@ v3d_exec_cleanup(struct kref *ref)
|
||||
drm_gem_object_put_unlocked(&bo->base);
|
||||
}
|
||||
|
||||
- pm_runtime_mark_last_busy(v3d->dev);
|
||||
- pm_runtime_put_autosuspend(v3d->dev);
|
||||
-
|
||||
kfree(exec);
|
||||
}
|
||||
|
||||
@@ -412,7 +408,6 @@ v3d_tfu_job_cleanup(struct kref *ref)
|
||||
{
|
||||
struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,
|
||||
refcount);
|
||||
- struct v3d_dev *v3d = job->v3d;
|
||||
unsigned int i;
|
||||
|
||||
dma_fence_put(job->in_fence);
|
||||
@@ -423,9 +418,6 @@ v3d_tfu_job_cleanup(struct kref *ref)
|
||||
drm_gem_object_put_unlocked(&job->bo[i]->base);
|
||||
}
|
||||
|
||||
- pm_runtime_mark_last_busy(v3d->dev);
|
||||
- pm_runtime_put_autosuspend(v3d->dev);
|
||||
-
|
||||
kfree(job);
|
||||
}
|
||||
|
||||
@@ -519,12 +511,6 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
if (!exec)
|
||||
return -ENOMEM;
|
||||
|
||||
- ret = pm_runtime_get_sync(v3d->dev);
|
||||
- if (ret < 0) {
|
||||
- kfree(exec);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
kref_init(&exec->refcount);
|
||||
|
||||
ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
|
||||
@@ -643,12 +629,6 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
if (!job)
|
||||
return -ENOMEM;
|
||||
|
||||
- ret = pm_runtime_get_sync(v3d->dev);
|
||||
- if (ret < 0) {
|
||||
- kfree(job);
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
kref_init(&job->refcount);
|
||||
|
||||
ret = drm_syncobj_find_fence(file_priv, args->in_sync,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
From d8d63e3c15e68224bedddd1ff8dcf702cadc89b0 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Tue, 12 Mar 2019 09:08:10 -0700
|
||||
Subject: [PATCH 594/678] drm/v3d: Update to upstream IRQ code.
|
||||
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_irq.c | 25 +++++++++++++++----------
|
||||
1 file changed, 15 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
index feb086026d9e..b8aea2dfbe82 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
@@ -168,7 +168,7 @@ v3d_hub_irq(int irq, void *arg)
|
||||
int
|
||||
v3d_irq_init(struct v3d_dev *v3d)
|
||||
{
|
||||
- int ret, core;
|
||||
+ int irq1, ret, core;
|
||||
|
||||
INIT_WORK(&v3d->overflow_mem_work, v3d_overflow_mem_work);
|
||||
|
||||
@@ -179,24 +179,29 @@ 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);
|
||||
|
||||
- if (platform_get_irq(v3d->pdev, 1) < 0) {
|
||||
- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
|
||||
+ irq1 = platform_get_irq(v3d->pdev, 1);
|
||||
+ if (irq1 == -EPROBE_DEFER)
|
||||
+ return irq1;
|
||||
+ if (irq1 > 0) {
|
||||
+ ret = devm_request_irq(v3d->dev, irq1,
|
||||
v3d_irq, IRQF_SHARED,
|
||||
- "v3d", v3d);
|
||||
- v3d->single_irq_line = true;
|
||||
- } else {
|
||||
+ "v3d_core0", v3d);
|
||||
+ if (ret)
|
||||
+ goto fail;
|
||||
ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
|
||||
v3d_hub_irq, IRQF_SHARED,
|
||||
"v3d_hub", v3d);
|
||||
if (ret)
|
||||
goto fail;
|
||||
+ } else {
|
||||
+ v3d->single_irq_line = true;
|
||||
|
||||
- ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 1),
|
||||
+ ret = devm_request_irq(v3d->dev, platform_get_irq(v3d->pdev, 0),
|
||||
v3d_irq, IRQF_SHARED,
|
||||
- "v3d_core0", v3d);
|
||||
+ "v3d", v3d);
|
||||
+ if (ret)
|
||||
+ goto fail;
|
||||
}
|
||||
- if (ret)
|
||||
- goto fail;
|
||||
|
||||
v3d_irq_enable(v3d);
|
||||
return 0;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
From 429d3726086f32d483fe7b575b476fea7b985a6b Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 27 Dec 2018 14:04:44 -0800
|
||||
Subject: [PATCH 595/678] drm/v3d: Rename the fence signaled from IRQs to
|
||||
"irq_fence".
|
||||
|
||||
We have another thing called the "done fence" that tracks when the
|
||||
scheduler considers the job done, and having the shared name was
|
||||
confusing.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 4 ++--
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 6 +++---
|
||||
drivers/gpu/drm/v3d/v3d_irq.c | 6 +++---
|
||||
drivers/gpu/drm/v3d/v3d_sched.c | 12 ++++++------
|
||||
4 files changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index 7952fb99ca01..ee51a13c7f9a 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -182,7 +182,7 @@ struct v3d_job {
|
||||
struct dma_fence *in_fence;
|
||||
|
||||
/* v3d fence to be signaled by IRQ handler when the job is complete. */
|
||||
- struct dma_fence *done_fence;
|
||||
+ struct dma_fence *irq_fence;
|
||||
|
||||
/* GPU virtual addresses of the start/end of the CL job. */
|
||||
u32 start, end;
|
||||
@@ -229,7 +229,7 @@ struct v3d_tfu_job {
|
||||
struct dma_fence *in_fence;
|
||||
|
||||
/* v3d fence to be signaled by IRQ handler when the job is complete. */
|
||||
- struct dma_fence *done_fence;
|
||||
+ struct dma_fence *irq_fence;
|
||||
|
||||
struct v3d_dev *v3d;
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 341411e2e292..2e920e4cad0f 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -381,8 +381,8 @@ v3d_exec_cleanup(struct kref *ref)
|
||||
dma_fence_put(exec->bin.in_fence);
|
||||
dma_fence_put(exec->render.in_fence);
|
||||
|
||||
- dma_fence_put(exec->bin.done_fence);
|
||||
- dma_fence_put(exec->render.done_fence);
|
||||
+ dma_fence_put(exec->bin.irq_fence);
|
||||
+ dma_fence_put(exec->render.irq_fence);
|
||||
|
||||
dma_fence_put(exec->bin_done_fence);
|
||||
dma_fence_put(exec->render_done_fence);
|
||||
@@ -411,7 +411,7 @@ v3d_tfu_job_cleanup(struct kref *ref)
|
||||
unsigned int i;
|
||||
|
||||
dma_fence_put(job->in_fence);
|
||||
- dma_fence_put(job->done_fence);
|
||||
+ dma_fence_put(job->irq_fence);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(job->bo); i++) {
|
||||
if (job->bo[i])
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
index b8aea2dfbe82..791a4c20a959 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
@@ -93,7 +93,7 @@ v3d_irq(int irq, void *arg)
|
||||
|
||||
if (intsts & V3D_INT_FLDONE) {
|
||||
struct v3d_fence *fence =
|
||||
- to_v3d_fence(v3d->bin_job->bin.done_fence);
|
||||
+ to_v3d_fence(v3d->bin_job->bin.irq_fence);
|
||||
|
||||
trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
|
||||
dma_fence_signal(&fence->base);
|
||||
@@ -102,7 +102,7 @@ v3d_irq(int irq, void *arg)
|
||||
|
||||
if (intsts & V3D_INT_FRDONE) {
|
||||
struct v3d_fence *fence =
|
||||
- to_v3d_fence(v3d->render_job->render.done_fence);
|
||||
+ to_v3d_fence(v3d->render_job->render.irq_fence);
|
||||
|
||||
trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
|
||||
dma_fence_signal(&fence->base);
|
||||
@@ -138,7 +138,7 @@ v3d_hub_irq(int irq, void *arg)
|
||||
|
||||
if (intsts & V3D_HUB_INT_TFUC) {
|
||||
struct v3d_fence *fence =
|
||||
- to_v3d_fence(v3d->tfu_job->done_fence);
|
||||
+ to_v3d_fence(v3d->tfu_job->irq_fence);
|
||||
|
||||
trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
|
||||
dma_fence_signal(&fence->base);
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
index 2ab1bbdb100a..3827f7f291aa 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
@@ -152,9 +152,9 @@ static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)
|
||||
if (IS_ERR(fence))
|
||||
return NULL;
|
||||
|
||||
- if (job->done_fence)
|
||||
- dma_fence_put(job->done_fence);
|
||||
- job->done_fence = dma_fence_get(fence);
|
||||
+ if (job->irq_fence)
|
||||
+ dma_fence_put(job->irq_fence);
|
||||
+ job->irq_fence = dma_fence_get(fence);
|
||||
|
||||
trace_v3d_submit_cl(dev, q == V3D_RENDER, to_v3d_fence(fence)->seqno,
|
||||
job->start, job->end);
|
||||
@@ -195,9 +195,9 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)
|
||||
return NULL;
|
||||
|
||||
v3d->tfu_job = job;
|
||||
- if (job->done_fence)
|
||||
- dma_fence_put(job->done_fence);
|
||||
- job->done_fence = dma_fence_get(fence);
|
||||
+ if (job->irq_fence)
|
||||
+ dma_fence_put(job->irq_fence);
|
||||
+ job->irq_fence = dma_fence_get(fence);
|
||||
|
||||
trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
|
||||
|
||||
--
|
||||
2.19.1
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,288 @@
|
|||
From 81a2ca9dd14751c05632f96d3375824862c4364a Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 27 Mar 2019 17:44:40 -0700
|
||||
Subject: [PATCH 597/678] drm/v3d: Add missing implicit synchronization.
|
||||
|
||||
It is the expectation of existing userspace (X11 + Mesa, in
|
||||
particular) that jobs submitted to the kernel against a shared BO will
|
||||
get implicitly synchronized by their submission order. If we want to
|
||||
allow clever userspace to disable implicit synchronization, we should
|
||||
do that under its own submit flag (as amdgpu and lima do).
|
||||
|
||||
Note that we currently only implicitly sync for the rendering pass,
|
||||
not binning -- if you texture-from-pixmap in the binning vertex shader
|
||||
(vertex coordinate generation), you'll miss out on synchronization.
|
||||
|
||||
Fixes flickering when multiple clients are running in parallel,
|
||||
particularly GL apps and compositors.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 10 +---
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 98 ++++++++++++++++++++++++++++++---
|
||||
drivers/gpu/drm/v3d/v3d_sched.c | 45 ++-------------
|
||||
3 files changed, 96 insertions(+), 57 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index 6ecd25631094..2807fe702524 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -186,8 +186,9 @@ struct v3d_job {
|
||||
struct v3d_bo **bo;
|
||||
u32 bo_count;
|
||||
|
||||
- /* An optional fence userspace can pass in for the job to depend on. */
|
||||
- struct dma_fence *in_fence;
|
||||
+ struct dma_fence **deps;
|
||||
+ int deps_count;
|
||||
+ int deps_size;
|
||||
|
||||
/* v3d fence to be signaled by IRQ handler when the job is complete. */
|
||||
struct dma_fence *irq_fence;
|
||||
@@ -219,11 +220,6 @@ struct v3d_bin_job {
|
||||
struct v3d_render_job {
|
||||
struct v3d_job base;
|
||||
|
||||
- /* Optional fence for the binner, to depend on before starting
|
||||
- * our job.
|
||||
- */
|
||||
- struct dma_fence *bin_done_fence;
|
||||
-
|
||||
/* GPU virtual addresses of the start/end of the CL job. */
|
||||
u32 start, end;
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 9a3930696c7e..40a72ef72099 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -218,6 +218,71 @@ v3d_unlock_bo_reservations(struct v3d_bo **bos,
|
||||
ww_acquire_fini(acquire_ctx);
|
||||
}
|
||||
|
||||
+static int
|
||||
+v3d_add_dep(struct v3d_job *job, struct dma_fence *fence)
|
||||
+{
|
||||
+ if (!fence)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (job->deps_size == job->deps_count) {
|
||||
+ int new_deps_size = max(job->deps_size * 2, 4);
|
||||
+ struct dma_fence **new_deps =
|
||||
+ krealloc(job->deps, new_deps_size * sizeof(*new_deps),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!new_deps) {
|
||||
+ dma_fence_put(fence);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ job->deps = new_deps;
|
||||
+ job->deps_size = new_deps_size;
|
||||
+ }
|
||||
+
|
||||
+ job->deps[job->deps_count++] = fence;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Adds the required implicit fences before executing the job
|
||||
+ *
|
||||
+ * Userspace (X11 + Mesa) requires that a job submitted against a shared BO
|
||||
+ * from one fd will implicitly synchronize against previous jobs submitted
|
||||
+ * against that BO from other fds.
|
||||
+ *
|
||||
+ * Currently we don't bother trying to track the shared BOs, and instead just
|
||||
+ * sync everything. However, our synchronization is only for the render pass
|
||||
+ * -- the binning stage (VS coordinate calculations) ignores implicit sync,
|
||||
+ * since using shared buffers for texture coordinates seems unlikely, and
|
||||
+ * implicitly syncing them would break bin/render parallelism. If we want to
|
||||
+ * fix that, we should introduce a flag when VS texturing has been used in the
|
||||
+ * binning stage, or a set of flags for which BOs are sampled during binning.
|
||||
+ */
|
||||
+static int
|
||||
+v3d_add_implicit_fences(struct v3d_job *job, struct v3d_bo *bo)
|
||||
+{
|
||||
+ int i, ret, nr_fences;
|
||||
+ struct dma_fence **fences;
|
||||
+
|
||||
+ ret = reservation_object_get_fences_rcu(bo->resv, NULL,
|
||||
+ &nr_fences, &fences);
|
||||
+ if (ret || !nr_fences)
|
||||
+ return ret;
|
||||
+
|
||||
+ for (i = 0; i < nr_fences; i++) {
|
||||
+ ret = v3d_add_dep(job, fences[i]);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Free any remaining fences after error. */
|
||||
+ for (; i < nr_fences; i++)
|
||||
+ dma_fence_put(fences[i]);
|
||||
+ kfree(fences);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/* Takes the reservation lock on all the BOs being referenced, so that
|
||||
* at queue submit time we can update the reservations.
|
||||
*
|
||||
@@ -226,10 +291,11 @@ v3d_unlock_bo_reservations(struct v3d_bo **bos,
|
||||
* to v3d, so we don't attach dma-buf fences to them.
|
||||
*/
|
||||
static int
|
||||
-v3d_lock_bo_reservations(struct v3d_bo **bos,
|
||||
- int bo_count,
|
||||
+v3d_lock_bo_reservations(struct v3d_job *job,
|
||||
struct ww_acquire_ctx *acquire_ctx)
|
||||
{
|
||||
+ struct v3d_bo **bos = job->bo;
|
||||
+ int bo_count = job->bo_count;
|
||||
int contended_lock = -1;
|
||||
int i, ret;
|
||||
|
||||
@@ -281,6 +347,13 @@ v3d_lock_bo_reservations(struct v3d_bo **bos,
|
||||
* before we commit the CL to the hardware.
|
||||
*/
|
||||
for (i = 0; i < bo_count; i++) {
|
||||
+ ret = v3d_add_implicit_fences(job, bos[i]);
|
||||
+ if (ret) {
|
||||
+ v3d_unlock_bo_reservations(bos, bo_count,
|
||||
+ acquire_ctx);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
ret = reservation_object_reserve_shared(bos[i]->resv);
|
||||
if (ret) {
|
||||
v3d_unlock_bo_reservations(bos, bo_count,
|
||||
@@ -383,7 +456,10 @@ v3d_job_free(struct kref *ref)
|
||||
}
|
||||
kvfree(job->bo);
|
||||
|
||||
- dma_fence_put(job->in_fence);
|
||||
+ for (i = 0; i < job->deps_count; i++)
|
||||
+ dma_fence_put(job->deps[i]);
|
||||
+ kfree(job->deps);
|
||||
+
|
||||
dma_fence_put(job->irq_fence);
|
||||
dma_fence_put(job->done_fence);
|
||||
|
||||
@@ -464,15 +540,20 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
|
||||
struct v3d_job *job, void (*free)(struct kref *ref),
|
||||
u32 in_sync)
|
||||
{
|
||||
+ struct dma_fence *in_fence = NULL;
|
||||
int ret;
|
||||
|
||||
job->v3d = v3d;
|
||||
job->free = free;
|
||||
|
||||
- ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &job->in_fence);
|
||||
+ ret = drm_syncobj_find_fence(file_priv, in_sync, 0, &in_fence);
|
||||
if (ret == -EINVAL)
|
||||
return ret;
|
||||
|
||||
+ ret = v3d_add_dep(job, in_fence);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
kref_init(&job->refcount);
|
||||
|
||||
return 0;
|
||||
@@ -590,8 +671,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
- ret = v3d_lock_bo_reservations(render->base.bo, render->base.bo_count,
|
||||
- &acquire_ctx);
|
||||
+ ret = v3d_lock_bo_reservations(&render->base, &acquire_ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
@@ -601,7 +681,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
if (ret)
|
||||
goto fail_unreserve;
|
||||
|
||||
- render->bin_done_fence = dma_fence_get(bin->base.done_fence);
|
||||
+ ret = v3d_add_dep(&render->base,
|
||||
+ dma_fence_get(bin->base.done_fence));
|
||||
}
|
||||
|
||||
ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
|
||||
@@ -692,8 +773,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
}
|
||||
spin_unlock(&file_priv->table_lock);
|
||||
|
||||
- ret = v3d_lock_bo_reservations(job->base.bo, job->base.bo_count,
|
||||
- &acquire_ctx);
|
||||
+ ret = v3d_lock_bo_reservations(&job->base, &acquire_ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
index 26290b6caaa4..e47f13bec114 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
@@ -67,47 +67,10 @@ v3d_job_dependency(struct drm_sched_job *sched_job,
|
||||
struct drm_sched_entity *s_entity)
|
||||
{
|
||||
struct v3d_job *job = to_v3d_job(sched_job);
|
||||
- struct dma_fence *fence;
|
||||
-
|
||||
- fence = job->in_fence;
|
||||
- if (fence) {
|
||||
- job->in_fence = NULL;
|
||||
- return fence;
|
||||
- }
|
||||
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * Returns the fences that the render job depends on, one by one.
|
||||
- * v3d_job_run() won't be called until all of them have been signaled.
|
||||
- */
|
||||
-static struct dma_fence *
|
||||
-v3d_render_job_dependency(struct drm_sched_job *sched_job,
|
||||
- struct drm_sched_entity *s_entity)
|
||||
-{
|
||||
- struct v3d_render_job *job = to_render_job(sched_job);
|
||||
- struct dma_fence *fence;
|
||||
-
|
||||
- fence = v3d_job_dependency(sched_job, s_entity);
|
||||
- if (fence)
|
||||
- return fence;
|
||||
-
|
||||
- /* If we had a bin job, the render job definitely depends on
|
||||
- * it. We first have to wait for bin to be scheduled, so that
|
||||
- * its done_fence is created.
|
||||
- */
|
||||
- fence = job->bin_done_fence;
|
||||
- if (fence) {
|
||||
- job->bin_done_fence = NULL;
|
||||
- return fence;
|
||||
- }
|
||||
-
|
||||
- /* XXX: Wait on a fence for switching the GMP if necessary,
|
||||
- * and then do so.
|
||||
- */
|
||||
-
|
||||
- return fence;
|
||||
+ if (!job->deps_count)
|
||||
+ return NULL;
|
||||
+ return job->deps[--job->deps_count];
|
||||
}
|
||||
|
||||
static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
|
||||
@@ -329,7 +292,7 @@ static const struct drm_sched_backend_ops v3d_bin_sched_ops = {
|
||||
};
|
||||
|
||||
static const struct drm_sched_backend_ops v3d_render_sched_ops = {
|
||||
- .dependency = v3d_render_job_dependency,
|
||||
+ .dependency = v3d_job_dependency,
|
||||
.run_job = v3d_render_job_run,
|
||||
.timedout_job = v3d_render_job_timedout,
|
||||
.free_job = v3d_job_free,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
From 7e2f4a3382d651bccc95b872383f35ce91feb23f Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 28 Mar 2019 11:58:51 -0700
|
||||
Subject: [PATCH 598/678] 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 <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 4701f6850551..d4f6ff1c410d 100644
|
||||
--- 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_plane_funcs = {
|
||||
};
|
||||
|
||||
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_funcs vc4_primary_plane_helper_funcs = {
|
||||
};
|
||||
|
||||
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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From 3e846eeaeb95360bf2f99193b41dcbb839a9b5b6 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 29 Mar 2019 12:04:36 -0700
|
||||
Subject: [PATCH 599/678] drm/vc4: Make sure that vblank waits work without v3d
|
||||
loaded.
|
||||
|
||||
This flag exists to protect legacy drivers, but when vc4's v3d doesn't
|
||||
probe, it doesn't get set up by vc4_v3d.c's call of drm_irq_install.
|
||||
This resulted in applications running as fast as possible, and laggy
|
||||
performance from compton as it had to wait for the latest rendering by
|
||||
the application for its presentation.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 14ccd676b2e9..432f9daa676c 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -422,6 +422,7 @@ int vc4_kms_load(struct drm_device *dev)
|
||||
/* Set support for vblank irq fast disable, before drm_vblank_init() */
|
||||
dev->vblank_disable_immediate = true;
|
||||
|
||||
+ dev->irq_enabled = true;
|
||||
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "failed to initialize vblank\n");
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
From c8d87d2bc5b53c89174cff52cf045eb5e76547bc Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 18 Mar 2019 16:38:32 -0700
|
||||
Subject: [PATCH 600/678] 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 <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 33 +++++++++++++++++++++++++-
|
||||
1 file changed, 32 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index d4f6ff1c410d..fe23983524cc 100644
|
||||
--- 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_plane *plane)
|
||||
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_plane_funcs = {
|
||||
.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_init(struct drm_device *dev,
|
||||
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_init(struct drm_device *dev,
|
||||
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) {
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
From 6da63d9e4bd78b9db8fcf07c7322d0a92696f0b1 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Tue, 2 Apr 2019 13:29:00 -0700
|
||||
Subject: [PATCH 601/678] 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 <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 3 ---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ++++++
|
||||
2 files changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 5a286801faa5..5615ceb15708 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -133,9 +133,6 @@ bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
|
||||
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. */
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index fe23983524cc..eed391f1d160 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -673,6 +673,12 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
|
||||
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;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
From d635657254789e386fcef321ed6f71961c637311 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Tue, 26 Mar 2019 14:43:06 +0000
|
||||
Subject: [PATCH 602/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 109 +++++++++++----------
|
||||
include/soc/bcm2835/raspberrypi-firmware.h | 10 ++
|
||||
2 files changed, 67 insertions(+), 52 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index eed391f1d160..6e90be13338c 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -28,6 +28,25 @@
|
||||
#include "vc4_regs.h"
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
+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.
|
||||
*/
|
||||
@@ -121,45 +140,39 @@ static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
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,
|
||||
@@ -168,14 +181,13 @@ static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
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.
|
||||
@@ -332,10 +344,10 @@ static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
|
||||
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[] = {
|
||||
@@ -357,22 +369,15 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
|
||||
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/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
index 23b9d356537f..b54035b15b57 100644
|
||||
--- a/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
@@ -111,9 +111,15 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_LAYER = 0x0004000c,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TRANSFORM = 0x0004000d,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VSYNC = 0x0004000e,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
|
||||
@@ -122,6 +128,8 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_LAYER = 0x0004400c,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_TRANSFORM = 0x0004400d,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
|
||||
@@ -134,6 +142,8 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER = 0x0004800c,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_TRANSFORM = 0x0004800d,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
|
||||
|
||||
RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,865 @@
|
|||
From 400fb9f6f59db3abd80716a8f116b9ab9e08814b Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Wed, 27 Mar 2019 17:45:01 +0000
|
||||
Subject: [PATCH 603/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
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
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 6e90be13338c..ccfe72926f5a 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -26,8 +26,46 @@
|
||||
#include "linux/of_device.h"
|
||||
#include "vc4_drv.h"
|
||||
#include "vc4_regs.h"
|
||||
+#include "vc_image_types.h"
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
+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;
|
||||
@@ -47,6 +85,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.
|
||||
*/
|
||||
@@ -113,6 +224,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)
|
||||
@@ -120,165 +232,183 @@ static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
|
||||
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;
|
||||
+
|
||||
+ 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];
|
||||
+
|
||||
+ /* 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 (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
|
||||
- fbinfo.bpp |= BIT(31);
|
||||
+ 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] primary update %dx%d@%d +%d,%d 0x%pad/%d\n",
|
||||
+ 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,
|
||||
@@ -301,6 +431,7 @@ static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
|
||||
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:
|
||||
@@ -309,8 +440,22 @@ static bool vc4_fkms_format_mod_supported(struct drm_plane *plane,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,31 +470,24 @@ static const struct drm_plane_funcs vc4_plane_funcs = {
|
||||
.format_mod_supported = vc4_fkms_format_mod_supported,
|
||||
};
|
||||
|
||||
-static const struct drm_plane_helper_funcs vc4_primary_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_primary_plane_atomic_update,
|
||||
- .atomic_disable = vc4_primary_plane_atomic_disable,
|
||||
-};
|
||||
-
|
||||
-static const struct drm_plane_helper_funcs vc4_cursor_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;
|
||||
+ 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
|
||||
@@ -358,6 +496,7 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
|
||||
DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
|
||||
DRM_FORMAT_MOD_INVALID,
|
||||
};
|
||||
+ int i;
|
||||
|
||||
vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
|
||||
GFP_KERNEL);
|
||||
@@ -366,19 +505,48 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
|
||||
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)
|
||||
@@ -400,19 +568,23 @@ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_s
|
||||
* 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,
|
||||
@@ -672,8 +844,10 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
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;
|
||||
@@ -702,20 +876,26 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
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);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 432f9daa676c..a16d9822abd1 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -435,6 +435,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);
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc_image_types.h b/drivers/gpu/drm/vc4/vc_image_types.h
|
||||
new file mode 100644
|
||||
index 000000000000..669a70fdb891
|
||||
--- /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,
|
||||
+};
|
||||
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
index b54035b15b57..025550ab2c76 100644
|
||||
--- a/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
@@ -148,6 +148,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,
|
||||
};
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
From d65bb322a65128c4381e8e4bd3d62454ba917b44 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Wed, 3 Apr 2019 15:20:05 +0100
|
||||
Subject: [PATCH 604/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index a16d9822abd1..a5dcfe38ffea 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -429,8 +429,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;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
From 798ace8bcba09936f605edce998435b7a935b78d Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Wed, 3 Apr 2019 17:15:45 +0100
|
||||
Subject: [PATCH 605/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 160 +++++++++++++++++--------
|
||||
1 file changed, 113 insertions(+), 47 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index ccfe72926f5a..79d21efafa69 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "vc_image_types.h"
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
+#define PLANES_PER_CRTC 3
|
||||
+
|
||||
struct set_plane {
|
||||
u8 display;
|
||||
u8 plane_id;
|
||||
@@ -175,6 +177,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)
|
||||
@@ -480,6 +483,7 @@ static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
|
||||
|
||||
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;
|
||||
@@ -543,7 +547,7 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
|
||||
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;
|
||||
|
||||
@@ -630,16 +634,20 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
|
||||
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;
|
||||
@@ -836,66 +844,55 @@ static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
|
||||
.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);
|
||||
@@ -922,13 +919,6 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
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,
|
||||
@@ -938,7 +928,7 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
memset(&vc4_crtc->overscan, 0, sizeof(vc4_crtc->overscan));
|
||||
}
|
||||
|
||||
- platform_set_drvdata(pdev, vc4_crtc);
|
||||
+ *ret_crtc = vc4_crtc;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -955,15 +945,91 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
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 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_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);
|
||||
}
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
From 6daf6ba6a766d585b6e7256b472aa70146e79a21 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Fri, 5 Apr 2019 17:21:56 +0100
|
||||
Subject: [PATCH 606/678] drm: vc4: Fix build warning
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 79d21efafa69..408a34122f04 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -932,8 +932,6 @@ static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
|
||||
|
||||
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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
From 9f7bc733a8381facdd4ae4c44a11cd735333d245 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Fri, 5 Apr 2019 17:23:15 +0100
|
||||
Subject: [PATCH 607/678] drm: vc4: Select display to blank during
|
||||
initialisation
|
||||
|
||||
Otherwise the rainbow splash screen remained in the display list
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 18 ++++++++++++++----
|
||||
1 file changed, 14 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 408a34122f04..45636bd69b54 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -87,6 +87,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_* */
|
||||
@@ -854,7 +861,12 @@ static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
|
||||
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);
|
||||
@@ -865,9 +877,7 @@ static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
|
||||
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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
From 5b49bd791a7afee0afa0fe1cbfffbd5c54639f7f Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Fri, 5 Apr 2019 17:24:20 +0100
|
||||
Subject: [PATCH 608/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 19 -------------------
|
||||
1 file changed, 19 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 45636bd69b54..24dfda3129b1 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -68,25 +68,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;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
From 478cc7e3da7eace420d752f24f7e74416a131867 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Tue, 9 Apr 2019 12:37:28 +0100
|
||||
Subject: [PATCH 609/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 16 +++++++++++++---
|
||||
include/soc/bcm2835/raspberrypi-firmware.h | 1 +
|
||||
2 files changed, 14 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 24dfda3129b1..56484046ead2 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -943,7 +943,7 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
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;
|
||||
|
||||
@@ -982,8 +982,18 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
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",
|
||||
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
index 025550ab2c76..5d55d1d7105a 100644
|
||||
--- a/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
@@ -117,6 +117,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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
From be92da644d5dee3b9f396396e352913fd85817f6 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Tue, 9 Apr 2019 14:00:07 +0100
|
||||
Subject: [PATCH 610/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 37 +++++++++++++++++++-------
|
||||
1 file changed, 27 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 56484046ead2..88844a9ffce9 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -75,6 +75,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_* */
|
||||
@@ -192,6 +199,7 @@ struct vc4_fkms_connector {
|
||||
* hook.
|
||||
*/
|
||||
struct drm_encoder *encoder;
|
||||
+ u32 display_idx;
|
||||
};
|
||||
|
||||
static inline struct vc4_fkms_connector *
|
||||
@@ -723,21 +731,27 @@ vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
|
||||
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);
|
||||
|
||||
@@ -772,8 +786,9 @@ static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs =
|
||||
.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;
|
||||
@@ -788,6 +803,7 @@ static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev,
|
||||
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);
|
||||
@@ -904,7 +920,8 @@ static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
|
||||
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;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
From 77db9bd6daa52708b5d3bdd1093581d7ceb5df2c Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Tue, 9 Apr 2019 18:14:44 +0100
|
||||
Subject: [PATCH 611/678] drm: vc4: Need to call drm_crtc_vblank_[on|off] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 88844a9ffce9..adadf4d253b0 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -562,6 +562,8 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
|
||||
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
|
||||
@@ -577,6 +579,7 @@ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_s
|
||||
|
||||
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)
|
||||
@@ -673,6 +676,9 @@ static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
|
||||
|
||||
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 = {
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
From 0d67b2e2218753eb15c0221194513d4f01a9585f Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Tue, 9 Apr 2019 17:19:51 +0100
|
||||
Subject: [PATCH 612/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 36 ++++++++++++++++++++++++++
|
||||
1 file changed, 36 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index adadf4d253b0..06865d45ba1d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -61,8 +61,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;
|
||||
@@ -274,6 +287,7 @@ static void vc4_plane_atomic_update(struct drm_plane *plane,
|
||||
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;
|
||||
@@ -294,6 +308,24 @@ static void vc4_plane_atomic_update(struct drm_plane *plane,
|
||||
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.
|
||||
*/
|
||||
@@ -514,9 +546,13 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
|
||||
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
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
From 4fc20cfb6c971d23aac31682206e5d6418ed4405 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Wed, 10 Apr 2019 17:35:05 +0100
|
||||
Subject: [PATCH 613/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 1 -
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 --------------------
|
||||
2 files changed, 21 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index b4c3bc982d32..6ab999a03914 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -724,7 +724,6 @@ extern const struct dma_fence_ops vc4_fence_ops;
|
||||
|
||||
/* 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);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 06865d45ba1d..d22e25426b37 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -739,26 +739,6 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
|
||||
.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" },
|
||||
{}
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
From 068dfbe33ce302bde78aa2232743f1428a2e9739 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Wed, 10 Apr 2019 17:42:37 +0100
|
||||
Subject: [PATCH 614/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 20 +++++++++++---------
|
||||
1 file changed, 11 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index d22e25426b37..0bfc4f54d4cc 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -598,6 +598,8 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
|
||||
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
|
||||
@@ -607,23 +609,23 @@ static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_s
|
||||
* 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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
From 21264f10c69376ce578a75c75e12fdb997d63cb9 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Wed, 10 Apr 2019 17:43:57 +0100
|
||||
Subject: [PATCH 615/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 15 +++++++++++++--
|
||||
1 file changed, 13 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 0bfc4f54d4cc..6a657f44a6a1 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -625,7 +625,17 @@ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_st
|
||||
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,
|
||||
@@ -735,10 +745,11 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
|
||||
|
||||
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[] = {
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From 644e1030528dee45312b93cd017ec3132243ebfd Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Mon, 29 Apr 2019 18:45:00 +0100
|
||||
Subject: [PATCH 616/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index a5dcfe38ffea..0fc0e901f786 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -429,8 +429,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;
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,564 @@
|
|||
From d4a7db404f22a7dafc963b3d72f14dc19c80be5f Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
Date: Tue, 9 Apr 2019 18:23:41 +0100
|
||||
Subject: [PATCH 617/678] 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 <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 334 ++++++++++++++++++---
|
||||
include/soc/bcm2835/raspberrypi-firmware.h | 2 +
|
||||
2 files changed, 302 insertions(+), 34 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_firmware_kms.c b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
index 6a657f44a6a1..30d1a5048eb2 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -88,11 +88,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 {
|
||||
@@ -186,6 +235,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)
|
||||
@@ -195,6 +245,8 @@ static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
|
||||
|
||||
struct vc4_fkms_encoder {
|
||||
struct drm_encoder base;
|
||||
+ bool hdmi_monitor;
|
||||
+ bool rgb_range_selectable;
|
||||
};
|
||||
|
||||
static inline struct vc4_fkms_encoder *
|
||||
@@ -212,7 +264,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 *
|
||||
@@ -221,6 +275,26 @@ to_vc4_fkms_connector(struct drm_connector *connector)
|
||||
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;
|
||||
@@ -255,10 +329,15 @@ static int vc4_plane_set_blank(struct drm_plane *plane, bool blank)
|
||||
.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)
|
||||
@@ -593,13 +672,102 @@ static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
|
||||
|
||||
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, mode, false);
|
||||
+ 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
|
||||
@@ -617,6 +785,8 @@ static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_st
|
||||
{
|
||||
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). */
|
||||
@@ -635,12 +805,20 @@ vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -650,6 +828,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
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;
|
||||
|
||||
@@ -717,6 +897,8 @@ static int vc4_fkms_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
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;
|
||||
@@ -726,6 +908,8 @@ static void vc4_fkms_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -760,36 +944,92 @@ static const struct of_device_id vc4_firmware_kms_dt_match[] = {
|
||||
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, &wh, sizeof(wh));
|
||||
+ ret = rpi_firmware_property_list(vc4->firmware, &mb, sizeof(mb));
|
||||
|
||||
- if (ret) {
|
||||
- DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
|
||||
- ret, wh.wh[0], wh.wh[1]);
|
||||
- return 0;
|
||||
+ 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);
|
||||
+
|
||||
+ 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;
|
||||
+
|
||||
+ 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;
|
||||
}
|
||||
|
||||
@@ -798,11 +1038,14 @@ vc4_fkms_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -821,14 +1064,22 @@ static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs =
|
||||
.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) {
|
||||
@@ -838,11 +1089,21 @@ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
|
||||
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);
|
||||
@@ -863,6 +1124,7 @@ vc4_fkms_connector_init(struct drm_device *dev, struct drm_encoder *encoder,
|
||||
|
||||
static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
+ DRM_DEBUG_KMS("Encoder_destroy\n");
|
||||
drm_encoder_cleanup(encoder);
|
||||
}
|
||||
|
||||
@@ -872,10 +1134,12 @@ static const struct drm_encoder_funcs vc4_fkms_encoder_funcs = {
|
||||
|
||||
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 = {
|
||||
@@ -907,6 +1171,7 @@ static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
|
||||
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));
|
||||
@@ -950,13 +1215,14 @@ static int vc4_fkms_create_screen(struct device *dev, struct drm_device *drm,
|
||||
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;
|
||||
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
index 5d55d1d7105a..50ed6dc6ded1 100644
|
||||
--- a/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
@@ -78,6 +78,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,
|
||||
@@ -150,6 +151,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,
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
From 637561e48b1885b7eb66a6f64eaa012e48a3f9c4 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 2 May 2019 15:11:05 -0700
|
||||
Subject: [PATCH 618/678] 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 <eric@anholt.net>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 22 +++++++++++++---------
|
||||
1 file changed, 13 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index b8da17a6e6cd..9dfaf221aca3 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -1097,15 +1097,19 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
|
||||
|
||||
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);
|
||||
|
||||
@@ -1475,7 +1479,7 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
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.
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
From 3240ab1fe84b3743beff0276dbac97e6bfa82187 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 2 May 2019 15:24:04 -0700
|
||||
Subject: [PATCH 619/678] 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 <eric@anholt.net>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 19 ++++++++++++++++---
|
||||
1 file changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index 9dfaf221aca3..07ddfc02ac95 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -1086,8 +1086,10 @@ static int bcm2835_clock_on(struct clk_hw *hw)
|
||||
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;
|
||||
@@ -1109,6 +1111,11 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
|
||||
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);
|
||||
@@ -1120,6 +1127,12 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
|
||||
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)
|
||||
{
|
||||
@@ -1303,6 +1316,7 @@ static const struct clk_ops bcm2835_clock_clk_ops = {
|
||||
.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,
|
||||
@@ -1479,7 +1493,6 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
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.
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,920 @@
|
|||
From c1a40a21b2637d2ce7f71a71cc9c7fe101a14fef Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Tue, 16 Apr 2019 15:58:54 -0700
|
||||
Subject: [PATCH 620/678] drm/v3d: Add support for compute shader dispatch.
|
||||
|
||||
The compute shader dispatch interface is pretty simple -- just pass in
|
||||
the regs that userspace has passed us, with no CLs to run. However,
|
||||
with no CL to run it means that we need to do manual cache flushing of
|
||||
the L2 after the HW execution completes (for SSBO, atomic, and
|
||||
image_load_store writes that are the output of compute shaders).
|
||||
|
||||
This doesn't yet expose the L2 cache's ability to have a region of the
|
||||
address space not write back to memory (which could be used for
|
||||
shared_var storage).
|
||||
|
||||
So far, the Mesa side has been tested on V3D v4.2 simpenrose (passing
|
||||
the ES31 tests), and on the kernel side on 7278 (failing atomic
|
||||
compswap tests in a way that doesn't reproduce on simpenrose).
|
||||
|
||||
v2: Fix excessive allocation for the clean_job (reported by Dan
|
||||
Carpenter). Keep refs on jobs until clean_job is finished, to
|
||||
avoid spurious MMU errors if the output BOs are freed by userspace
|
||||
before L2 cleaning is finished.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20190416225856.20264-4-eric@anholt.net
|
||||
Acked-by: Rob Clark <robdclark@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_debugfs.c | 22 +++++
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 10 +-
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 28 +++++-
|
||||
drivers/gpu/drm/v3d/v3d_fence.c | 2 +
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 156 +++++++++++++++++++++++++++++-
|
||||
drivers/gpu/drm/v3d/v3d_irq.c | 16 ++-
|
||||
drivers/gpu/drm/v3d/v3d_regs.h | 73 ++++++++++++++
|
||||
drivers/gpu/drm/v3d/v3d_sched.c | 121 +++++++++++++++++++++--
|
||||
drivers/gpu/drm/v3d/v3d_trace.h | 94 ++++++++++++++++++
|
||||
include/uapi/drm/v3d_drm.h | 28 ++++++
|
||||
10 files changed, 531 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
index b15051df2dbb..089fde87b2fc 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
@@ -57,6 +57,17 @@ static const struct v3d_reg_def v3d_core_reg_defs[] = {
|
||||
REGDEF(V3D_GMP_VIO_ADDR),
|
||||
};
|
||||
|
||||
+static const struct v3d_reg_def v3d_csd_reg_defs[] = {
|
||||
+ REGDEF(V3D_CSD_STATUS),
|
||||
+ REGDEF(V3D_CSD_CURRENT_CFG0),
|
||||
+ REGDEF(V3D_CSD_CURRENT_CFG1),
|
||||
+ REGDEF(V3D_CSD_CURRENT_CFG2),
|
||||
+ REGDEF(V3D_CSD_CURRENT_CFG3),
|
||||
+ REGDEF(V3D_CSD_CURRENT_CFG4),
|
||||
+ REGDEF(V3D_CSD_CURRENT_CFG5),
|
||||
+ REGDEF(V3D_CSD_CURRENT_CFG6),
|
||||
+};
|
||||
+
|
||||
static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
@@ -88,6 +99,17 @@ static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
|
||||
V3D_CORE_READ(core,
|
||||
v3d_core_reg_defs[i].reg));
|
||||
}
|
||||
+
|
||||
+ if (v3d_has_csd(v3d)) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
|
||||
+ seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
|
||||
+ core,
|
||||
+ v3d_csd_reg_defs[i].name,
|
||||
+ v3d_csd_reg_defs[i].reg,
|
||||
+ V3D_CORE_READ(core,
|
||||
+ v3d_csd_reg_defs[i].reg));
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 1f2c3555c038..05978cd7c8c6 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -7,9 +7,9 @@
|
||||
* This driver supports the Broadcom V3D 3.3 and 4.1 OpenGL ES GPUs.
|
||||
* For V3D 2.x support, see the VC4 driver.
|
||||
*
|
||||
- * Currently only single-core rendering using the binner and renderer,
|
||||
- * along with TFU (texture formatting unit) rendering is supported.
|
||||
- * V3D 4.x's CSD (compute shader dispatch) is not yet supported.
|
||||
+ * The V3D GPU includes a tiled render (composed of a bin and render
|
||||
+ * pipelines), the TFU (texture formatting unit), and the CSD (compute
|
||||
+ * shader dispatch).
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -114,6 +114,9 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
|
||||
case DRM_V3D_PARAM_SUPPORTS_TFU:
|
||||
args->value = 1;
|
||||
return 0;
|
||||
+ case DRM_V3D_PARAM_SUPPORTS_CSD:
|
||||
+ args->value = v3d_has_csd(v3d);
|
||||
+ return 0;
|
||||
default:
|
||||
DRM_DEBUG("Unknown parameter %d\n", args->param);
|
||||
return -EINVAL;
|
||||
@@ -183,6 +186,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
|
||||
DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
|
||||
+ DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CSD, v3d_submit_csd_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
|
||||
};
|
||||
|
||||
static const struct vm_operations_struct v3d_vm_ops = {
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index 2807fe702524..2de04ada4d3b 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -16,9 +16,11 @@ enum v3d_queue {
|
||||
V3D_BIN,
|
||||
V3D_RENDER,
|
||||
V3D_TFU,
|
||||
+ V3D_CSD,
|
||||
+ V3D_CACHE_CLEAN,
|
||||
};
|
||||
|
||||
-#define V3D_MAX_QUEUES (V3D_TFU + 1)
|
||||
+#define V3D_MAX_QUEUES (V3D_CACHE_CLEAN + 1)
|
||||
|
||||
struct v3d_queue_state {
|
||||
struct drm_gpu_scheduler sched;
|
||||
@@ -70,6 +72,7 @@ struct v3d_dev {
|
||||
struct v3d_bin_job *bin_job;
|
||||
struct v3d_render_job *render_job;
|
||||
struct v3d_tfu_job *tfu_job;
|
||||
+ struct v3d_csd_job *csd_job;
|
||||
|
||||
struct v3d_queue_state queue[V3D_MAX_QUEUES];
|
||||
|
||||
@@ -92,6 +95,12 @@ struct v3d_dev {
|
||||
*/
|
||||
struct mutex sched_lock;
|
||||
|
||||
+ /* Lock taken during a cache clean and when initiating an L2
|
||||
+ * flush, to keep L2 flushes from interfering with the
|
||||
+ * synchronous L2 cleans.
|
||||
+ */
|
||||
+ struct mutex cache_clean_lock;
|
||||
+
|
||||
struct {
|
||||
u32 num_allocated;
|
||||
u32 pages_allocated;
|
||||
@@ -104,6 +113,12 @@ to_v3d_dev(struct drm_device *dev)
|
||||
return (struct v3d_dev *)dev->dev_private;
|
||||
}
|
||||
|
||||
+static inline bool
|
||||
+v3d_has_csd(struct v3d_dev *v3d)
|
||||
+{
|
||||
+ return v3d->ver >= 41;
|
||||
+}
|
||||
+
|
||||
/* The per-fd struct, which tracks the MMU mappings. */
|
||||
struct v3d_file_priv {
|
||||
struct v3d_dev *v3d;
|
||||
@@ -237,6 +252,14 @@ struct v3d_tfu_job {
|
||||
struct drm_v3d_submit_tfu args;
|
||||
};
|
||||
|
||||
+struct v3d_csd_job {
|
||||
+ struct v3d_job base;
|
||||
+
|
||||
+ u32 timedout_batches;
|
||||
+
|
||||
+ struct drm_v3d_submit_csd args;
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* _wait_for - magic (register) wait macro
|
||||
*
|
||||
@@ -302,11 +325,14 @@ int v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
+int v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
|
||||
+ struct drm_file *file_priv);
|
||||
int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
void v3d_job_put(struct v3d_job *job);
|
||||
void v3d_reset(struct v3d_dev *v3d);
|
||||
void v3d_invalidate_caches(struct v3d_dev *v3d);
|
||||
+void v3d_clean_caches(struct v3d_dev *v3d);
|
||||
|
||||
/* v3d_irq.c */
|
||||
int v3d_irq_init(struct v3d_dev *v3d);
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_fence.c b/drivers/gpu/drm/v3d/v3d_fence.c
|
||||
index b0a2a1ae2eb1..89840ed212c0 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_fence.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_fence.c
|
||||
@@ -36,6 +36,8 @@ static const char *v3d_fence_get_timeline_name(struct dma_fence *fence)
|
||||
return "v3d-render";
|
||||
case V3D_TFU:
|
||||
return "v3d-tfu";
|
||||
+ case V3D_CSD:
|
||||
+ return "v3d-csd";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index 40a72ef72099..fe14777c3c20 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -162,10 +162,52 @@ v3d_flush_l2t(struct v3d_dev *v3d, int core)
|
||||
/* While there is a busy bit (V3D_L2TCACTL_L2TFLS), we don't
|
||||
* need to wait for completion before dispatching the job --
|
||||
* L2T accesses will be stalled until the flush has completed.
|
||||
+ * However, we do need to make sure we don't try to trigger a
|
||||
+ * new flush while the L2_CLEAN queue is trying to
|
||||
+ * synchronously clean after a job.
|
||||
*/
|
||||
+ mutex_lock(&v3d->cache_clean_lock);
|
||||
V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
|
||||
V3D_L2TCACTL_L2TFLS |
|
||||
V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM));
|
||||
+ mutex_unlock(&v3d->cache_clean_lock);
|
||||
+}
|
||||
+
|
||||
+/* Cleans texture L1 and L2 cachelines (writing back dirty data).
|
||||
+ *
|
||||
+ * For cleaning, which happens from the CACHE_CLEAN queue after CSD has
|
||||
+ * executed, we need to make sure that the clean is done before
|
||||
+ * signaling job completion. So, we synchronously wait before
|
||||
+ * returning, and we make sure that L2 invalidates don't happen in the
|
||||
+ * meantime to confuse our are-we-done checks.
|
||||
+ */
|
||||
+void
|
||||
+v3d_clean_caches(struct v3d_dev *v3d)
|
||||
+{
|
||||
+ struct drm_device *dev = &v3d->drm;
|
||||
+ int core = 0;
|
||||
+
|
||||
+ trace_v3d_cache_clean_begin(dev);
|
||||
+
|
||||
+ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
|
||||
+ if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
+ V3D_L2TCACTL_L2TFLS), 100)) {
|
||||
+ DRM_ERROR("Timeout waiting for L1T write combiner flush\n");
|
||||
+ }
|
||||
+
|
||||
+ mutex_lock(&v3d->cache_clean_lock);
|
||||
+ V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL,
|
||||
+ V3D_L2TCACTL_L2TFLS |
|
||||
+ V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAN, V3D_L2TCACTL_FLM));
|
||||
+
|
||||
+ if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
+ V3D_L2TCACTL_L2TFLS), 100)) {
|
||||
+ DRM_ERROR("Timeout waiting for L2T clean\n");
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&v3d->cache_clean_lock);
|
||||
+
|
||||
+ trace_v3d_cache_clean_end(dev);
|
||||
}
|
||||
|
||||
/* Invalidates the slice caches. These are read-only caches. */
|
||||
@@ -584,7 +626,8 @@ static void
|
||||
v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv,
|
||||
struct v3d_job *job,
|
||||
struct ww_acquire_ctx *acquire_ctx,
|
||||
- u32 out_sync)
|
||||
+ u32 out_sync,
|
||||
+ struct dma_fence *done_fence)
|
||||
{
|
||||
struct drm_syncobj *sync_out;
|
||||
|
||||
@@ -594,7 +637,7 @@ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv,
|
||||
/* Update the return sync object for the job */
|
||||
sync_out = drm_syncobj_find(file_priv, out_sync);
|
||||
if (sync_out) {
|
||||
- drm_syncobj_replace_fence(sync_out, job->done_fence);
|
||||
+ drm_syncobj_replace_fence(sync_out, done_fence);
|
||||
drm_syncobj_put(sync_out);
|
||||
}
|
||||
}
|
||||
@@ -691,8 +734,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
|
||||
mutex_unlock(&v3d->sched_lock);
|
||||
|
||||
v3d_attach_fences_and_unlock_reservation(file_priv,
|
||||
- &render->base, &acquire_ctx,
|
||||
- args->out_sync);
|
||||
+ &render->base,
|
||||
+ &acquire_ctx,
|
||||
+ args->out_sync,
|
||||
+ render->base.done_fence);
|
||||
|
||||
if (bin)
|
||||
v3d_job_put(&bin->base);
|
||||
@@ -785,7 +830,8 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
|
||||
v3d_attach_fences_and_unlock_reservation(file_priv,
|
||||
&job->base, &acquire_ctx,
|
||||
- args->out_sync);
|
||||
+ args->out_sync,
|
||||
+ job->base.done_fence);
|
||||
|
||||
v3d_job_put(&job->base);
|
||||
|
||||
@@ -801,6 +847,105 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * v3d_submit_csd_ioctl() - Submits a CSD (texture formatting) job to the V3D.
|
||||
+ * @dev: DRM device
|
||||
+ * @data: ioctl argument
|
||||
+ * @file_priv: DRM file for this fd
|
||||
+ *
|
||||
+ * Userspace provides the register setup for the CSD, which we don't
|
||||
+ * need to validate since the CSD is behind the MMU.
|
||||
+ */
|
||||
+int
|
||||
+v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
|
||||
+ struct drm_file *file_priv)
|
||||
+{
|
||||
+ struct v3d_dev *v3d = to_v3d_dev(dev);
|
||||
+ struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
|
||||
+ struct drm_v3d_submit_csd *args = data;
|
||||
+ struct v3d_csd_job *job;
|
||||
+ struct v3d_job *clean_job;
|
||||
+ struct ww_acquire_ctx acquire_ctx;
|
||||
+ int ret;
|
||||
+
|
||||
+ trace_v3d_submit_csd_ioctl(&v3d->drm, args->cfg[5], args->cfg[6]);
|
||||
+
|
||||
+ if (!v3d_has_csd(v3d)) {
|
||||
+ DRM_DEBUG("Attempting CSD submit on non-CSD hardware\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ job = kcalloc(1, sizeof(*job), GFP_KERNEL);
|
||||
+ if (!job)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ret = v3d_job_init(v3d, file_priv, &job->base,
|
||||
+ v3d_job_free, args->in_sync);
|
||||
+ if (ret) {
|
||||
+ kfree(job);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ clean_job = kcalloc(1, sizeof(*clean_job), GFP_KERNEL);
|
||||
+ if (!clean_job) {
|
||||
+ v3d_job_put(&job->base);
|
||||
+ kfree(job);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ ret = v3d_job_init(v3d, file_priv, clean_job, v3d_job_free, 0);
|
||||
+ if (ret) {
|
||||
+ v3d_job_put(&job->base);
|
||||
+ kfree(clean_job);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ job->args = *args;
|
||||
+
|
||||
+ ret = v3d_lookup_bos(dev, file_priv, clean_job,
|
||||
+ args->bo_handles, args->bo_handle_count);
|
||||
+ if (ret)
|
||||
+ goto fail;
|
||||
+
|
||||
+ ret = v3d_lock_bo_reservations(clean_job, &acquire_ctx);
|
||||
+ if (ret)
|
||||
+ goto fail;
|
||||
+
|
||||
+ mutex_lock(&v3d->sched_lock);
|
||||
+ ret = v3d_push_job(v3d_priv, &job->base, V3D_CSD);
|
||||
+ if (ret)
|
||||
+ goto fail_unreserve;
|
||||
+
|
||||
+ ret = v3d_add_dep(clean_job, dma_fence_get(job->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,
|
||||
+ clean_job,
|
||||
+ &acquire_ctx,
|
||||
+ args->out_sync,
|
||||
+ clean_job->done_fence);
|
||||
+
|
||||
+ v3d_job_put(&job->base);
|
||||
+ v3d_job_put(clean_job);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+fail_unreserve:
|
||||
+ mutex_unlock(&v3d->sched_lock);
|
||||
+ v3d_unlock_bo_reservations(clean_job->bo, clean_job->bo_count,
|
||||
+ &acquire_ctx);
|
||||
+fail:
|
||||
+ v3d_job_put(&job->base);
|
||||
+ v3d_job_put(clean_job);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
int
|
||||
v3d_gem_init(struct drm_device *dev)
|
||||
{
|
||||
@@ -816,6 +961,7 @@ v3d_gem_init(struct drm_device *dev)
|
||||
mutex_init(&v3d->bo_lock);
|
||||
mutex_init(&v3d->reset_lock);
|
||||
mutex_init(&v3d->sched_lock);
|
||||
+ mutex_init(&v3d->cache_clean_lock);
|
||||
|
||||
/* Note: We don't allocate address 0. Various bits of HW
|
||||
* treat 0 as special, such as the occlusion query counters
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
index 751332747b12..1d39697e610e 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
@@ -4,9 +4,9 @@
|
||||
/**
|
||||
* DOC: Interrupt management for the V3D engine
|
||||
*
|
||||
- * When we take a bin, render, or TFU done interrupt, we need to
|
||||
- * signal the fence for that job so that the scheduler can queue up
|
||||
- * the next one and unblock any waiters.
|
||||
+ * When we take a bin, render, TFU done, or CSD done interrupt, we
|
||||
+ * need to signal the fence for that job so that the scheduler can
|
||||
+ * queue up the next one and unblock any waiters.
|
||||
*
|
||||
* When we take the binner out of memory interrupt, we need to
|
||||
* allocate some new memory and pass it to the binner so that the
|
||||
@@ -20,6 +20,7 @@
|
||||
#define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
|
||||
V3D_INT_FLDONE | \
|
||||
V3D_INT_FRDONE | \
|
||||
+ V3D_INT_CSDDONE | \
|
||||
V3D_INT_GMPV))
|
||||
|
||||
#define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
|
||||
@@ -109,6 +110,15 @@ v3d_irq(int irq, void *arg)
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+ if (intsts & V3D_INT_CSDDONE) {
|
||||
+ struct v3d_fence *fence =
|
||||
+ to_v3d_fence(v3d->csd_job->base.irq_fence);
|
||||
+
|
||||
+ trace_v3d_csd_irq(&v3d->drm, fence->seqno);
|
||||
+ dma_fence_signal(&fence->base);
|
||||
+ status = IRQ_HANDLED;
|
||||
+ }
|
||||
+
|
||||
/* We shouldn't be triggering these if we have GMP in
|
||||
* always-allowed mode.
|
||||
*/
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
index 8e88af237610..9a8ff0ce648e 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
@@ -238,8 +238,11 @@
|
||||
#define V3D_CTL_L2TCACTL 0x00030
|
||||
# define V3D_L2TCACTL_TMUWCF BIT(8)
|
||||
# define V3D_L2TCACTL_L2T_NO_WM BIT(4)
|
||||
+/* Invalidates cache lines. */
|
||||
# define V3D_L2TCACTL_FLM_FLUSH 0
|
||||
+/* Removes cachelines without writing dirty lines back. */
|
||||
# define V3D_L2TCACTL_FLM_CLEAR 1
|
||||
+/* Writes out dirty cachelines and marks them clean, but doesn't invalidate. */
|
||||
# define V3D_L2TCACTL_FLM_CLEAN 2
|
||||
# define V3D_L2TCACTL_FLM_MASK V3D_MASK(2, 1)
|
||||
# define V3D_L2TCACTL_FLM_SHIFT 1
|
||||
@@ -255,6 +258,8 @@
|
||||
#define V3D_CTL_INT_MSK_CLR 0x00064
|
||||
# define V3D_INT_QPU_MASK V3D_MASK(27, 16)
|
||||
# define V3D_INT_QPU_SHIFT 16
|
||||
+# define V3D_INT_CSDDONE BIT(7)
|
||||
+# define V3D_INT_PCTR BIT(6)
|
||||
# define V3D_INT_GMPV BIT(5)
|
||||
# define V3D_INT_TRFB BIT(4)
|
||||
# define V3D_INT_SPILLUSE BIT(3)
|
||||
@@ -374,4 +379,72 @@
|
||||
#define V3D_GMP_PRESERVE_LOAD 0x00818
|
||||
#define V3D_GMP_VALID_LINES 0x00820
|
||||
|
||||
+#define V3D_CSD_STATUS 0x00900
|
||||
+# define V3D_CSD_STATUS_NUM_COMPLETED_MASK V3D_MASK(11, 4)
|
||||
+# define V3D_CSD_STATUS_NUM_COMPLETED_SHIFT 4
|
||||
+# define V3D_CSD_STATUS_NUM_ACTIVE_MASK V3D_MASK(3, 2)
|
||||
+# define V3D_CSD_STATUS_NUM_ACTIVE_SHIFT 2
|
||||
+# define V3D_CSD_STATUS_HAVE_CURRENT_DISPATCH BIT(1)
|
||||
+# define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0)
|
||||
+
|
||||
+#define V3D_CSD_QUEUED_CFG0 0x00904
|
||||
+# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16)
|
||||
+# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16
|
||||
+# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0)
|
||||
+# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0
|
||||
+
|
||||
+#define V3D_CSD_QUEUED_CFG1 0x00908
|
||||
+# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16)
|
||||
+# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16
|
||||
+# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0)
|
||||
+# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0
|
||||
+
|
||||
+#define V3D_CSD_QUEUED_CFG2 0x0090c
|
||||
+# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16)
|
||||
+# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16
|
||||
+# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0)
|
||||
+# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0
|
||||
+
|
||||
+#define V3D_CSD_QUEUED_CFG3 0x00910
|
||||
+# define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26)
|
||||
+# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20)
|
||||
+# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20
|
||||
+# define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_MASK V3D_MASK(19, 12)
|
||||
+# define V3D_CSD_QUEUED_CFG3_BATCHES_PER_SG_M1_SHIFT 12
|
||||
+# define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_MASK V3D_MASK(11, 8)
|
||||
+# define V3D_CSD_QUEUED_CFG3_WGS_PER_SG_SHIFT 8
|
||||
+# define V3D_CSD_QUEUED_CFG3_WG_SIZE_MASK V3D_MASK(7, 0)
|
||||
+# define V3D_CSD_QUEUED_CFG3_WG_SIZE_SHIFT 0
|
||||
+
|
||||
+/* Number of batches, minus 1 */
|
||||
+#define V3D_CSD_QUEUED_CFG4 0x00914
|
||||
+
|
||||
+/* Shader address, pnan, singleseg, threading, like a shader record. */
|
||||
+#define V3D_CSD_QUEUED_CFG5 0x00918
|
||||
+
|
||||
+/* Uniforms address (4 byte aligned) */
|
||||
+#define V3D_CSD_QUEUED_CFG6 0x0091c
|
||||
+
|
||||
+#define V3D_CSD_CURRENT_CFG0 0x00920
|
||||
+#define V3D_CSD_CURRENT_CFG1 0x00924
|
||||
+#define V3D_CSD_CURRENT_CFG2 0x00928
|
||||
+#define V3D_CSD_CURRENT_CFG3 0x0092c
|
||||
+#define V3D_CSD_CURRENT_CFG4 0x00930
|
||||
+#define V3D_CSD_CURRENT_CFG5 0x00934
|
||||
+#define V3D_CSD_CURRENT_CFG6 0x00938
|
||||
+
|
||||
+#define V3D_CSD_CURRENT_ID0 0x0093c
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16)
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8)
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_IN_SG_SHIFT 8
|
||||
+# define V3D_CSD_CURRENT_ID0_L_IDX_MASK V3D_MASK(7, 0)
|
||||
+# define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0
|
||||
+
|
||||
+#define V3D_CSD_CURRENT_ID1 0x00940
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16)
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0)
|
||||
+# define V3D_CSD_CURRENT_ID0_WG_Y_SHIFT 0
|
||||
+
|
||||
#endif /* V3D_REGS_H */
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
index e47f13bec114..f7c61e4991d3 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
@@ -48,6 +48,12 @@ to_tfu_job(struct drm_sched_job *sched_job)
|
||||
return container_of(sched_job, struct v3d_tfu_job, base.base);
|
||||
}
|
||||
|
||||
+static struct v3d_csd_job *
|
||||
+to_csd_job(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ return container_of(sched_job, struct v3d_csd_job, base.base);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
v3d_job_free(struct drm_sched_job *sched_job)
|
||||
{
|
||||
@@ -205,6 +211,48 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)
|
||||
return fence;
|
||||
}
|
||||
|
||||
+static struct dma_fence *
|
||||
+v3d_csd_job_run(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ struct v3d_csd_job *job = to_csd_job(sched_job);
|
||||
+ struct v3d_dev *v3d = job->base.v3d;
|
||||
+ struct drm_device *dev = &v3d->drm;
|
||||
+ struct dma_fence *fence;
|
||||
+ int i;
|
||||
+
|
||||
+ v3d->csd_job = job;
|
||||
+
|
||||
+ v3d_invalidate_caches(v3d);
|
||||
+
|
||||
+ fence = v3d_fence_create(v3d, V3D_CSD);
|
||||
+ if (IS_ERR(fence))
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (job->base.irq_fence)
|
||||
+ dma_fence_put(job->base.irq_fence);
|
||||
+ job->base.irq_fence = dma_fence_get(fence);
|
||||
+
|
||||
+ trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno);
|
||||
+
|
||||
+ for (i = 1; i <= 6; i++)
|
||||
+ V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]);
|
||||
+ /* CFG0 write kicks off the job. */
|
||||
+ V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg[0]);
|
||||
+
|
||||
+ return fence;
|
||||
+}
|
||||
+
|
||||
+static struct dma_fence *
|
||||
+v3d_cache_clean_job_run(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ struct v3d_job *job = to_v3d_job(sched_job);
|
||||
+ struct v3d_dev *v3d = job->v3d;
|
||||
+
|
||||
+ v3d_clean_caches(v3d);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job)
|
||||
{
|
||||
@@ -277,13 +325,31 @@ v3d_render_job_timedout(struct drm_sched_job *sched_job)
|
||||
}
|
||||
|
||||
static void
|
||||
-v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
|
||||
+v3d_generic_job_timedout(struct drm_sched_job *sched_job)
|
||||
{
|
||||
struct v3d_job *job = to_v3d_job(sched_job);
|
||||
|
||||
v3d_gpu_reset_for_timeout(job->v3d, sched_job);
|
||||
}
|
||||
|
||||
+static void
|
||||
+v3d_csd_job_timedout(struct drm_sched_job *sched_job)
|
||||
+{
|
||||
+ struct v3d_csd_job *job = to_csd_job(sched_job);
|
||||
+ struct v3d_dev *v3d = job->base.v3d;
|
||||
+ u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4);
|
||||
+
|
||||
+ /* If we've made progress, skip reset and let the timer get
|
||||
+ * rearmed.
|
||||
+ */
|
||||
+ if (job->timedout_batches != batches) {
|
||||
+ job->timedout_batches = batches;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ v3d_gpu_reset_for_timeout(v3d, sched_job);
|
||||
+}
|
||||
+
|
||||
static const struct drm_sched_backend_ops v3d_bin_sched_ops = {
|
||||
.dependency = v3d_job_dependency,
|
||||
.run_job = v3d_bin_job_run,
|
||||
@@ -301,10 +367,24 @@ static const struct drm_sched_backend_ops v3d_render_sched_ops = {
|
||||
static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
|
||||
.dependency = v3d_job_dependency,
|
||||
.run_job = v3d_tfu_job_run,
|
||||
- .timedout_job = v3d_tfu_job_timedout,
|
||||
+ .timedout_job = v3d_generic_job_timedout,
|
||||
.free_job = v3d_job_free,
|
||||
};
|
||||
|
||||
+static const struct drm_sched_backend_ops v3d_csd_sched_ops = {
|
||||
+ .dependency = v3d_job_dependency,
|
||||
+ .run_job = v3d_csd_job_run,
|
||||
+ .timedout_job = v3d_csd_job_timedout,
|
||||
+ .free_job = v3d_job_free
|
||||
+};
|
||||
+
|
||||
+static const struct drm_sched_backend_ops v3d_cache_clean_sched_ops = {
|
||||
+ .dependency = v3d_job_dependency,
|
||||
+ .run_job = v3d_cache_clean_job_run,
|
||||
+ .timedout_job = v3d_generic_job_timedout,
|
||||
+ .free_job = v3d_job_free
|
||||
+};
|
||||
+
|
||||
int
|
||||
v3d_sched_init(struct v3d_dev *v3d)
|
||||
{
|
||||
@@ -331,7 +411,7 @@ v3d_sched_init(struct v3d_dev *v3d)
|
||||
if (ret) {
|
||||
dev_err(v3d->dev, "Failed to create render scheduler: %d.",
|
||||
ret);
|
||||
- drm_sched_fini(&v3d->queue[V3D_BIN].sched);
|
||||
+ v3d_sched_fini(v3d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -343,11 +423,36 @@ v3d_sched_init(struct v3d_dev *v3d)
|
||||
if (ret) {
|
||||
dev_err(v3d->dev, "Failed to create TFU scheduler: %d.",
|
||||
ret);
|
||||
- drm_sched_fini(&v3d->queue[V3D_RENDER].sched);
|
||||
- drm_sched_fini(&v3d->queue[V3D_BIN].sched);
|
||||
+ v3d_sched_fini(v3d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ if (v3d_has_csd(v3d)) {
|
||||
+ ret = drm_sched_init(&v3d->queue[V3D_CSD].sched,
|
||||
+ &v3d_csd_sched_ops,
|
||||
+ hw_jobs_limit, job_hang_limit,
|
||||
+ msecs_to_jiffies(hang_limit_ms),
|
||||
+ "v3d_csd");
|
||||
+ if (ret) {
|
||||
+ dev_err(v3d->dev, "Failed to create CSD scheduler: %d.",
|
||||
+ ret);
|
||||
+ v3d_sched_fini(v3d);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched,
|
||||
+ &v3d_cache_clean_sched_ops,
|
||||
+ hw_jobs_limit, job_hang_limit,
|
||||
+ msecs_to_jiffies(hang_limit_ms),
|
||||
+ "v3d_cache_clean");
|
||||
+ if (ret) {
|
||||
+ dev_err(v3d->dev, "Failed to create CACHE_CLEAN scheduler: %d.",
|
||||
+ ret);
|
||||
+ v3d_sched_fini(v3d);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -356,6 +461,8 @@ v3d_sched_fini(struct v3d_dev *v3d)
|
||||
{
|
||||
enum v3d_queue q;
|
||||
|
||||
- for (q = 0; q < V3D_MAX_QUEUES; q++)
|
||||
- drm_sched_fini(&v3d->queue[q].sched);
|
||||
+ for (q = 0; q < V3D_MAX_QUEUES; q++) {
|
||||
+ if (v3d->queue[q].sched.ops)
|
||||
+ drm_sched_fini(&v3d->queue[q].sched);
|
||||
+ }
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_trace.h b/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
index edd984afa33f..7aa8dc356e54 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_trace.h
|
||||
@@ -124,6 +124,26 @@ TRACE_EVENT(v3d_tfu_irq,
|
||||
__entry->seqno)
|
||||
);
|
||||
|
||||
+TRACE_EVENT(v3d_csd_irq,
|
||||
+ TP_PROTO(struct drm_device *dev,
|
||||
+ uint64_t seqno),
|
||||
+ TP_ARGS(dev, seqno),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u64, seqno)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->seqno = seqno;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, seqno=%llu",
|
||||
+ __entry->dev,
|
||||
+ __entry->seqno)
|
||||
+);
|
||||
+
|
||||
TRACE_EVENT(v3d_submit_tfu_ioctl,
|
||||
TP_PROTO(struct drm_device *dev, u32 iia),
|
||||
TP_ARGS(dev, iia),
|
||||
@@ -163,6 +183,80 @@ TRACE_EVENT(v3d_submit_tfu,
|
||||
__entry->seqno)
|
||||
);
|
||||
|
||||
+TRACE_EVENT(v3d_submit_csd_ioctl,
|
||||
+ TP_PROTO(struct drm_device *dev, u32 cfg5, u32 cfg6),
|
||||
+ TP_ARGS(dev, cfg5, cfg6),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u32, cfg5)
|
||||
+ __field(u32, cfg6)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->cfg5 = cfg5;
|
||||
+ __entry->cfg6 = cfg6;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, CFG5 0x%08x, CFG6 0x%08x",
|
||||
+ __entry->dev,
|
||||
+ __entry->cfg5,
|
||||
+ __entry->cfg6)
|
||||
+);
|
||||
+
|
||||
+TRACE_EVENT(v3d_submit_csd,
|
||||
+ TP_PROTO(struct drm_device *dev,
|
||||
+ uint64_t seqno),
|
||||
+ TP_ARGS(dev, seqno),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ __field(u64, seqno)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ __entry->seqno = seqno;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u, seqno=%llu",
|
||||
+ __entry->dev,
|
||||
+ __entry->seqno)
|
||||
+);
|
||||
+
|
||||
+TRACE_EVENT(v3d_cache_clean_begin,
|
||||
+ TP_PROTO(struct drm_device *dev),
|
||||
+ TP_ARGS(dev),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u",
|
||||
+ __entry->dev)
|
||||
+);
|
||||
+
|
||||
+TRACE_EVENT(v3d_cache_clean_end,
|
||||
+ TP_PROTO(struct drm_device *dev),
|
||||
+ TP_ARGS(dev),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __field(u32, dev)
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __entry->dev = dev->primary->index;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("dev=%u",
|
||||
+ __entry->dev)
|
||||
+);
|
||||
+
|
||||
TRACE_EVENT(v3d_reset_begin,
|
||||
TP_PROTO(struct drm_device *dev),
|
||||
TP_ARGS(dev),
|
||||
diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h
|
||||
index c4b67eab7e59..c8a508a5e9da 100644
|
||||
--- a/include/uapi/drm/v3d_drm.h
|
||||
+++ b/include/uapi/drm/v3d_drm.h
|
||||
@@ -37,6 +37,7 @@ extern "C" {
|
||||
#define DRM_V3D_GET_PARAM 0x04
|
||||
#define DRM_V3D_GET_BO_OFFSET 0x05
|
||||
#define DRM_V3D_SUBMIT_TFU 0x06
|
||||
+#define DRM_V3D_SUBMIT_CSD 0x07
|
||||
|
||||
#define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
|
||||
#define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
|
||||
@@ -45,6 +46,7 @@ extern "C" {
|
||||
#define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param)
|
||||
#define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
|
||||
#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)
|
||||
|
||||
/**
|
||||
* struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D
|
||||
@@ -172,6 +174,7 @@ enum drm_v3d_param {
|
||||
DRM_V3D_PARAM_V3D_CORE0_IDENT1,
|
||||
DRM_V3D_PARAM_V3D_CORE0_IDENT2,
|
||||
DRM_V3D_PARAM_SUPPORTS_TFU,
|
||||
+ DRM_V3D_PARAM_SUPPORTS_CSD,
|
||||
};
|
||||
|
||||
struct drm_v3d_get_param {
|
||||
@@ -212,6 +215,31 @@ struct drm_v3d_submit_tfu {
|
||||
__u32 out_sync;
|
||||
};
|
||||
|
||||
+/* Submits a compute shader for dispatch. This job will block on any
|
||||
+ * previous compute shaders submitted on this fd, and any other
|
||||
+ * synchronization must be performed with in_sync/out_sync.
|
||||
+ */
|
||||
+struct drm_v3d_submit_csd {
|
||||
+ __u32 cfg[7];
|
||||
+ __u32 coef[4];
|
||||
+
|
||||
+ /* Pointer to a u32 array of the BOs that are referenced by the job.
|
||||
+ */
|
||||
+ __u64 bo_handles;
|
||||
+
|
||||
+ /* Number of BO handles passed in (size is that times 4). */
|
||||
+ __u32 bo_handle_count;
|
||||
+
|
||||
+ /* sync object to block on before running the CSD job. Each
|
||||
+ * CSD job will execute in the order submitted to its FD.
|
||||
+ * Synchronization against rendering/TFU jobs or CSD from
|
||||
+ * other fds requires using sync objects.
|
||||
+ */
|
||||
+ __u32 in_sync;
|
||||
+ /* Sync object to signal when the CSD job is done. */
|
||||
+ __u32 out_sync;
|
||||
+};
|
||||
+
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
From b051adf80d02f51507c5c198e49f0e54ac5f9e13 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Thu, 2 May 2019 13:22:53 -0700
|
||||
Subject: [PATCH 621/678] 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 <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 18 +++++++++++++
|
||||
drivers/gpu/drm/v3d/v3d_drv.h | 6 +++++
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 49 +++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 73 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
index 05978cd7c8c6..cffd69464b17 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -297,6 +297,21 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
+ 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)
|
||||
@@ -331,6 +346,9 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto irq_disable;
|
||||
|
||||
+ ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
|
||||
+ WARN_ON_ONCE(ret != 0);
|
||||
+
|
||||
return 0;
|
||||
|
||||
irq_disable:
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
index 2de04ada4d3b..7b4f3b5a086e 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
|
||||
@@ -45,6 +45,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. */
|
||||
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
index fe14777c3c20..ce72a4d08fe6 100644
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_syncobj.h>
|
||||
+#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@@ -16,6 +17,47 @@
|
||||
#include "v3d_regs.h"
|
||||
#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)
|
||||
{
|
||||
@@ -490,6 +532,7 @@ static void
|
||||
v3d_job_free(struct kref *ref)
|
||||
{
|
||||
struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
|
||||
+ struct v3d_dev *v3d = job->v3d;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < job->bo_count; i++) {
|
||||
@@ -505,6 +548,8 @@ v3d_job_free(struct kref *ref)
|
||||
dma_fence_put(job->irq_fence);
|
||||
dma_fence_put(job->done_fence);
|
||||
|
||||
+ v3d_clock_up_put(v3d);
|
||||
+
|
||||
kfree(job);
|
||||
}
|
||||
|
||||
@@ -596,6 +641,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ v3d_clock_up_get(v3d);
|
||||
kref_init(&job->refcount);
|
||||
|
||||
return 0;
|
||||
@@ -963,6 +1009,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".
|
||||
--
|
||||
2.19.1
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
From 1ac954a8c5dd939dffd3b256be50253082297d9a Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <wahrenst@gmx.net>
|
||||
Date: Thu, 2 May 2019 23:42:29 +0200
|
||||
Subject: [PATCH 622/678] HACK: clk-bcm2835: Add BCM2838_CLOCK_EMMC2 support
|
||||
|
||||
The new BCM2838 supports an additional emmc2 clock. So add a new
|
||||
compatible to register this clock only for BCM2838.
|
||||
|
||||
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 20 ++++++++++++++++++--
|
||||
include/dt-bindings/clock/bcm2835.h | 2 ++
|
||||
2 files changed, 20 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index 07ddfc02ac95..a885c2faa7b0 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -124,6 +124,8 @@
|
||||
#define CM_AVEODIV 0x1bc
|
||||
#define CM_EMMCCTL 0x1c0
|
||||
#define CM_EMMCDIV 0x1c4
|
||||
+#define CM_EMMC2CTL 0x1d0
|
||||
+#define CM_EMMC2DIV 0x1d4
|
||||
|
||||
/* General bits for the CM_*CTL regs */
|
||||
# define CM_ENABLE BIT(4)
|
||||
@@ -2047,6 +2049,15 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
||||
.frac_bits = 8,
|
||||
.tcnt_mux = 39),
|
||||
|
||||
+ /* EMMC2 clock (only available for BCM2838) */
|
||||
+ [BCM2838_CLOCK_EMMC2] = REGISTER_PER_CLK(
|
||||
+ .name = "emmc2",
|
||||
+ .ctl_reg = CM_EMMC2CTL,
|
||||
+ .div_reg = CM_EMMC2DIV,
|
||||
+ .int_bits = 4,
|
||||
+ .frac_bits = 8,
|
||||
+ .tcnt_mux = 42),
|
||||
+
|
||||
/* General purpose (GPIO) clocks */
|
||||
[BCM2835_CLOCK_GP0] = REGISTER_PER_CLK(
|
||||
.name = "gp0",
|
||||
@@ -2276,8 +2287,12 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
|
||||
for (i = 0; i < asize; i++) {
|
||||
desc = &clk_desc_array[i];
|
||||
- if (desc->clk_register && desc->data)
|
||||
- hws[i] = desc->clk_register(cprman, desc->data);
|
||||
+ if (desc->clk_register && desc->data) {
|
||||
+ if ((i != BCM2838_CLOCK_EMMC2) ||
|
||||
+ of_device_is_compatible(fw_node, "brcm,bcm2838-cprman")) {
|
||||
+ hws[i] = desc->clk_register(cprman, desc->data);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
ret = bcm2835_mark_sdc_parent_critical(hws[BCM2835_CLOCK_SDRAM]->clk);
|
||||
@@ -2297,6 +2312,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id bcm2835_clk_of_match[] = {
|
||||
{ .compatible = "brcm,bcm2835-cprman", },
|
||||
+ { .compatible = "brcm,bcm2838-cprman", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm2835_clk_of_match);
|
||||
diff --git a/include/dt-bindings/clock/bcm2835.h b/include/dt-bindings/clock/bcm2835.h
|
||||
index a0c812b0fa39..077796e8f24b 100644
|
||||
--- a/include/dt-bindings/clock/bcm2835.h
|
||||
+++ b/include/dt-bindings/clock/bcm2835.h
|
||||
@@ -66,3 +66,5 @@
|
||||
#define BCM2835_CLOCK_DSI1E 48
|
||||
#define BCM2835_CLOCK_DSI0P 49
|
||||
#define BCM2835_CLOCK_DSI1P 50
|
||||
+
|
||||
+#define BCM2838_CLOCK_EMMC2 51
|
||||
--
|
||||
2.19.1
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue