1
0
Fork 0
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:
Ycarus (Yannick Chabanois) 2019-06-24 19:52:48 +02:00
parent abf18246f5
commit 5f08b288eb
155 changed files with 29237 additions and 0 deletions

5
config-rpi4 Normal file
View 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

View 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))

View file

@ -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

View 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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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(&regs);
#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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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