mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-02-12 19:31:52 +00:00
Add kernel 5.15 for RPI4 support
This commit is contained in:
parent
e961d478cd
commit
df88a19bbd
638 changed files with 239907 additions and 0 deletions
366
root/target/linux/bcm27xx/bcm2708/config-5.15
Normal file
366
root/target/linux/bcm27xx/bcm2708/config-5.15
Normal file
|
@ -0,0 +1,366 @@
|
|||
# CONFIG_AIO is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
CONFIG_ARCH_BCM=y
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
|
||||
CONFIG_ARCH_MULTIPLATFORM=y
|
||||
CONFIG_ARCH_MULTI_V6=y
|
||||
CONFIG_ARCH_MULTI_V6_V7=y
|
||||
CONFIG_ARCH_NR_GPIO=0
|
||||
CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
|
||||
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_CPU_SUSPEND=y
|
||||
CONFIG_ARM_ERRATA_411920=y
|
||||
CONFIG_ARM_HAS_SG_CHAIN=y
|
||||
CONFIG_ARM_L1_CACHE_SHIFT=5
|
||||
CONFIG_ARM_PATCH_PHYS_VIRT=y
|
||||
CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
|
||||
CONFIG_ARM_THUMB=y
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_ARM_UNWIND=y
|
||||
CONFIG_AUTO_ZRELADDR=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2711_THERMAL is not set
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_FAST_MEMCPY=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
CONFIG_BCM2835_THERMAL=y
|
||||
CONFIG_BCM2835_TIMER=y
|
||||
CONFIG_BCM2835_VCHIQ=y
|
||||
# CONFIG_BCM2835_VCHIQ_MMAL is not set
|
||||
CONFIG_BCM2835_WDT=y
|
||||
CONFIG_BCM_VCIO=y
|
||||
# CONFIG_BCM_VC_SM_CMA is not set
|
||||
CONFIG_BCM_VIDEOCORE=y
|
||||
CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=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_PM=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BRCMSTB_L2_IRQ=y
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
# CONFIG_CACHE_L2X0 is not set
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLK_BCM2711_DVP=y
|
||||
CONFIG_CLK_BCM2835=y
|
||||
CONFIG_CLK_RASPBERRYPI=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=5
|
||||
# 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_COMPAT_32BIT_TIME=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
CONFIG_CPU_32v6=y
|
||||
CONFIG_CPU_32v6K=y
|
||||
CONFIG_CPU_ABRT_EV6=y
|
||||
CONFIG_CPU_CACHE_V6=y
|
||||
CONFIG_CPU_CACHE_VIPT=y
|
||||
CONFIG_CPU_COPY_V6=y
|
||||
CONFIG_CPU_CP15=y
|
||||
CONFIG_CPU_CP15_MMU=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
|
||||
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_HAS_ASID=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
CONFIG_CPU_PABRT_V6=y
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_THUMB_CAPABLE=y
|
||||
CONFIG_CPU_TLB_V6=y
|
||||
CONFIG_CPU_V6K=y
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_GF128MUL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
|
||||
CONFIG_DMABUF_HEAPS=y
|
||||
CONFIG_DMABUF_HEAPS_CMA=y
|
||||
CONFIG_DMABUF_HEAPS_SYSTEM=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_OPS=y
|
||||
CONFIG_DMA_REMAP=y
|
||||
CONFIG_DMA_SHARED_BUFFER=y
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
CONFIG_EDAC_ATOMIC_SCRUB=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_FS=y
|
||||
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_FB_SIMPLE=y
|
||||
CONFIG_FIQ=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
CONFIG_FONT_8x16=y
|
||||
CONFIG_FONT_8x8=y
|
||||
CONFIG_FONT_SUPPORT=y
|
||||
# CONFIG_FPE_FASTFPE is not set
|
||||
# CONFIG_FPE_NWFPE is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
|
||||
CONFIG_FREEZER=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_FW_CACHE=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_GENERIC_ALLOCATOR=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IRQ_CHIP=y
|
||||
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=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_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
# CONFIG_GPIO_BCM_VIRT is not set
|
||||
# CONFIG_GPIO_FSM is not set
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=y
|
||||
CONFIG_HANDLE_DOMAIN_IRQ=y
|
||||
CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT_MAP=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_BCM2835=y
|
||||
CONFIG_HZ_FIXED=0
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
# CONFIG_I2C_BRCMSTB is not set
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=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_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JBD2=y
|
||||
CONFIG_KERNEL_GZIP=y
|
||||
# CONFIG_KERNEL_XZ is not set
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_ACTPWR=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LLD_VERSION=0
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=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_MDIO_DEVRES=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MIGHT_HAVE_CACHE_L2X0=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_REL=y
|
||||
# CONFIG_MTD is not set
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_PER_CPU_KM=y
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NVMEM=y
|
||||
# CONFIG_NVMEM_RMEM is not set
|
||||
CONFIG_OABI_COMPAT=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_RESOLVE=y
|
||||
CONFIG_OLD_SIGACTION=y
|
||||
CONFIG_OLD_SIGSUSPEND3=y
|
||||
CONFIG_PAGE_OFFSET=0xC0000000
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PGTABLE_LEVELS=2
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_BCM2835=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_CLK=y
|
||||
CONFIG_PM_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
# CONFIG_RESET_RASPBERRYPI is not set
|
||||
CONFIG_RESET_SIMPLE=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
# CONFIG_RPI_POE_POWER is not set
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS 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_DEV_BUS=y
|
||||
# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMSC_PHY=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=y
|
||||
CONFIG_SWPHY=y
|
||||
CONFIG_SYS_SUPPORTS_APM_EMULATION=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_TICK_CPU_ACCOUNTING=y
|
||||
CONFIG_TIMER_OF=y
|
||||
CONFIG_TIMER_PROBE=y
|
||||
CONFIG_TINY_SRCU=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_UEVENT_HELPER_PATH=""
|
||||
# CONFIG_UID16 is not set
|
||||
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
|
||||
CONFIG_UNWINDER_ARM=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_DWCOTG=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_USE_OF=y
|
||||
CONFIG_VFP=y
|
||||
CONFIG_VT=y
|
||||
CONFIG_VT_CONSOLE=y
|
||||
CONFIG_VT_CONSOLE_SLEEP=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_XZ_DEC_ARM=y
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
CONFIG_ZBOOT_ROM_BSS=0x0
|
||||
CONFIG_ZBOOT_ROM_TEXT=0x0
|
462
root/target/linux/bcm27xx/bcm2709/config-5.15
Normal file
462
root/target/linux/bcm27xx/bcm2709/config-5.15
Normal file
|
@ -0,0 +1,462 @@
|
|||
# CONFIG_AIO is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
CONFIG_ARCH_BCM=y
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
# CONFIG_ARCH_BCM_HR2 is not set
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
|
||||
CONFIG_ARCH_MULTIPLATFORM=y
|
||||
CONFIG_ARCH_MULTI_V6_V7=y
|
||||
CONFIG_ARCH_MULTI_V7=y
|
||||
CONFIG_ARCH_NR_GPIO=0
|
||||
CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
|
||||
CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
|
||||
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
CONFIG_ARM_CPU_SUSPEND=y
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_HAS_SG_CHAIN=y
|
||||
CONFIG_ARM_L1_CACHE_SHIFT=6
|
||||
CONFIG_ARM_L1_CACHE_SHIFT_6=y
|
||||
CONFIG_ARM_LPAE=y
|
||||
CONFIG_ARM_PATCH_IDIV=y
|
||||
CONFIG_ARM_PATCH_PHYS_VIRT=y
|
||||
CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
|
||||
CONFIG_ARM_THUMB=y
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_ARM_UNWIND=y
|
||||
CONFIG_ARM_VIRT_EXT=y
|
||||
CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUTO_ZRELADDR=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
CONFIG_BCM2711_THERMAL=y
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
CONFIG_BCM2835_THERMAL=y
|
||||
CONFIG_BCM2835_TIMER=y
|
||||
CONFIG_BCM2835_VCHIQ=y
|
||||
# CONFIG_BCM2835_VCHIQ_MMAL is not set
|
||||
CONFIG_BCM2835_WDT=y
|
||||
CONFIG_BCM7XXX_PHY=y
|
||||
CONFIG_BCMGENET=y
|
||||
CONFIG_BCM_NET_PHYLIB=y
|
||||
CONFIG_BCM_VCIO=y
|
||||
# CONFIG_BCM_VC_SM_CMA is not set
|
||||
CONFIG_BCM_VIDEOCORE=y
|
||||
CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=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_MQ_PCI=y
|
||||
CONFIG_BLK_PM=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BOUNCE=y
|
||||
CONFIG_BRCMSTB_L2_IRQ=y
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
CONFIG_BROADCOM_PHY=y
|
||||
# CONFIG_CACHE_L2X0 is not set
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLK_BCM2711_DVP=y
|
||||
CONFIG_CLK_BCM2835=y
|
||||
CONFIG_CLK_RASPBERRYPI=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=5
|
||||
# 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_COMPAT_32BIT_TIME=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
CONFIG_CPU_32v6K=y
|
||||
CONFIG_CPU_32v7=y
|
||||
CONFIG_CPU_ABRT_EV7=y
|
||||
CONFIG_CPU_CACHE_V7=y
|
||||
CONFIG_CPU_CACHE_VIPT=y
|
||||
CONFIG_CPU_COPY_V6=y
|
||||
CONFIG_CPU_CP15=y
|
||||
CONFIG_CPU_CP15_MMU=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
|
||||
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_HAS_ASID=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
CONFIG_CPU_PABRT_V7=y
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
CONFIG_CPU_SPECTRE=y
|
||||
CONFIG_CPU_THUMB_CAPABLE=y
|
||||
CONFIG_CPU_TLB_V7=y
|
||||
CONFIG_CPU_V7=y
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
CONFIG_CRYPTO_DRBG_MENU=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_GF128MUL=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_JITTERENTROPY=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
CONFIG_CRYPTO_SEQIV=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
|
||||
CONFIG_DIMLIB=y
|
||||
CONFIG_DMABUF_HEAPS=y
|
||||
CONFIG_DMABUF_HEAPS_CMA=y
|
||||
CONFIG_DMABUF_HEAPS_SYSTEM=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_OPS=y
|
||||
CONFIG_DMA_REMAP=y
|
||||
CONFIG_DMA_SHARED_BUFFER=y
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
CONFIG_EDAC_ATOMIC_SCRUB=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_EXTCON=y
|
||||
CONFIG_F2FS_FS=y
|
||||
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_FB_SIMPLE=y
|
||||
CONFIG_FIQ=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
CONFIG_FONT_8x16=y
|
||||
CONFIG_FONT_8x8=y
|
||||
CONFIG_FONT_SUPPORT=y
|
||||
# CONFIG_FPE_FASTFPE is not set
|
||||
# CONFIG_FPE_NWFPE is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
|
||||
CONFIG_FREEZER=y
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_ENCRYPTION_ALGS=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_FW_CACHE=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_GENERIC_ALLOCATOR=y
|
||||
CONFIG_GENERIC_ARCH_TOPOLOGY=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IRQ_CHIP=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_PHY=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_GENERIC_VDSO_32=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
CONFIG_GPIO_BCM_VIRT=y
|
||||
# CONFIG_GPIO_FSM is not set
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=y
|
||||
CONFIG_HANDLE_DOMAIN_IRQ=y
|
||||
CONFIG_HARDEN_BRANCH_PREDICTOR=y
|
||||
CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT_MAP=y
|
||||
CONFIG_HAVE_SMP=y
|
||||
CONFIG_HIGHMEM=y
|
||||
CONFIG_HIGHPTE=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_BCM2835=y
|
||||
CONFIG_HW_RANDOM_IPROC_RNG200=y
|
||||
CONFIG_HZ_FIXED=0
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
# CONFIG_I2C_BRCMSTB is not set
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=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_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JBD2=y
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_ACTPWR=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LLD_VERSION=0
|
||||
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_BCM_UNIMAC=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MICROCHIP_PHY=y
|
||||
CONFIG_MIGHT_HAVE_CACHE_L2X0=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_IO_ACCESSORS=y
|
||||
CONFIG_MMC_SDHCI_IPROC=y
|
||||
# CONFIG_MMC_SDHCI_PCI is not set
|
||||
CONFIG_MMC_SDHCI_PLTFM=y
|
||||
CONFIG_MODULES_USE_ELF_REL=y
|
||||
# CONFIG_MTD is not set
|
||||
CONFIG_MUTEX_SPIN_ON_OWNER=y
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEON=y
|
||||
CONFIG_NET_FLOW_LIMIT=y
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NOP_USB_XCEIV=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
# CONFIG_NVMEM_RMEM is not set
|
||||
CONFIG_OABI_COMPAT=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_RESOLVE=y
|
||||
CONFIG_OLD_SIGACTION=y
|
||||
CONFIG_OLD_SIGSUSPEND3=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PAGE_OFFSET=0xC0000000
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCIEAER=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
CONFIG_PCIE_BRCMSTB=y
|
||||
CONFIG_PCIE_PME=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCI_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PGTABLE_LEVELS=3
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_BCM2835=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_CLK=y
|
||||
CONFIG_PM_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_RAS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_REGULATOR_GPIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RESET_RASPBERRYPI=y
|
||||
CONFIG_RESET_SIMPLE=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
# CONFIG_RPI_POE_POWER is not set
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS 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_DEV_BUS=y
|
||||
# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SMP_ON_UP=y
|
||||
CONFIG_SMSC_PHY=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=y
|
||||
CONFIG_SWIOTLB=y
|
||||
CONFIG_SWPHY=y
|
||||
CONFIG_SWP_EMULATE=y
|
||||
CONFIG_SYS_SUPPORTS_APM_EMULATION=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_TICK_CPU_ACCOUNTING=y
|
||||
CONFIG_TIMER_OF=y
|
||||
CONFIG_TIMER_PROBE=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_TREE_RCU=y
|
||||
CONFIG_TREE_SRCU=y
|
||||
CONFIG_UEVENT_HELPER_PATH=""
|
||||
# CONFIG_UID16 is not set
|
||||
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
|
||||
CONFIG_UNWINDER_ARM=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_DWCOTG=y
|
||||
# CONFIG_USB_ETH is not set
|
||||
CONFIG_USB_GADGET=y
|
||||
CONFIG_USB_LAN78XX=y
|
||||
CONFIG_USB_NET_DRIVERS=y
|
||||
CONFIG_USB_NET_SMSC95XX=y
|
||||
CONFIG_USB_PCI=y
|
||||
CONFIG_USB_PHY=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_USB_UAS=y
|
||||
# CONFIG_USB_UHCI_HCD is not set
|
||||
CONFIG_USB_USBNET=y
|
||||
CONFIG_USB_XHCI_HCD=y
|
||||
CONFIG_USB_XHCI_PCI=y
|
||||
CONFIG_USB_XHCI_PLATFORM=y
|
||||
CONFIG_USE_OF=y
|
||||
CONFIG_VFP=y
|
||||
CONFIG_VFPv3=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_ZBOOT_ROM_BSS=0
|
||||
CONFIG_ZBOOT_ROM_TEXT=0
|
446
root/target/linux/bcm27xx/bcm2710/config-5.15
Normal file
446
root/target/linux/bcm27xx/bcm2710/config-5.15
Normal file
|
@ -0,0 +1,446 @@
|
|||
CONFIG_64BIT=y
|
||||
# CONFIG_AIO is not set
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=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_STACKWALK=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARM64=y
|
||||
CONFIG_ARM64_4K_PAGES=y
|
||||
CONFIG_ARM64_CNP=y
|
||||
CONFIG_ARM64_ERRATUM_1165522=y
|
||||
CONFIG_ARM64_ERRATUM_1286807=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_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_PTR_AUTH=y
|
||||
CONFIG_ARM64_SVE=y
|
||||
CONFIG_ARM64_TAGGED_ADDR_ABI=y
|
||||
CONFIG_ARM64_UAO=y
|
||||
CONFIG_ARM64_VA_BITS=39
|
||||
CONFIG_ARM64_VA_BITS_39=y
|
||||
CONFIG_ARM64_VHE=y
|
||||
CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
|
||||
CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
|
||||
CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=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_GIC=y
|
||||
CONFIG_ARM_GIC_V2M=y
|
||||
CONFIG_ARM_GIC_V3=y
|
||||
CONFIG_ARM_GIC_V3_ITS=y
|
||||
CONFIG_ARM_GIC_V3_ITS_PCI=y
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2711_THERMAL is not set
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
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 is not set
|
||||
CONFIG_BCM2835_WDT=y
|
||||
CONFIG_BCM_VCIO=y
|
||||
# CONFIG_BCM_VC_SM_CMA 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_MQ_PCI=y
|
||||
CONFIG_BLK_PM=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BOUNCE=y
|
||||
CONFIG_BRCMSTB_L2_IRQ=y
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
CONFIG_CAVIUM_ERRATUM_22375=y
|
||||
CONFIG_CAVIUM_ERRATUM_23154=y
|
||||
CONFIG_CAVIUM_ERRATUM_27456=y
|
||||
CONFIG_CAVIUM_TX2_ERRATUM_219=y
|
||||
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLK_BCM2711_DVP=y
|
||||
CONFIG_CLK_BCM2835=y
|
||||
CONFIG_CLK_RASPBERRYPI=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=5
|
||||
# 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_COMPAT_32BIT_TIME is not set
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
|
||||
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
|
||||
CONFIG_CPU_FREQ_GOV_COMMON=y
|
||||
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
|
||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
||||
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_STAT=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
CONFIG_CRYPTO_DRBG_MENU=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_GF128MUL=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_JITTERENTROPY=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
CONFIG_CRYPTO_SEQIV=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DMABUF_HEAPS=y
|
||||
CONFIG_DMABUF_HEAPS_CMA=y
|
||||
CONFIG_DMABUF_HEAPS_SYSTEM=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_DIRECT_REMAP=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_REMAP=y
|
||||
CONFIG_DMA_SHARED_BUFFER=y
|
||||
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_EXTCON=y
|
||||
CONFIG_F2FS_FS=y
|
||||
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_FB_SIMPLE=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
# CONFIG_FLATMEM_MANUAL 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=y
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_FREEZER=y
|
||||
CONFIG_FSL_ERRATUM_A008585=y
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_ENCRYPTION_ALGS=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_FUJITSU_ERRATUM_010001=y
|
||||
CONFIG_FW_CACHE=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=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_CPU_VULNERABILITIES=y
|
||||
CONFIG_GENERIC_CSUM=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IRQ_CHIP=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_FSM is not set
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=y
|
||||
CONFIG_HANDLE_DOMAIN_IRQ=y
|
||||
CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT_MAP=y
|
||||
CONFIG_HOLES_IN_ZONE=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HW_RANDOM_BCM2835=y
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
# CONFIG_I2C_BRCMSTB is not set
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
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_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JBD2=y
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_ACTPWR=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LLD_VERSION=0
|
||||
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_MDIO_DEVRES=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=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_IO_ACCESSORS=y
|
||||
CONFIG_MMC_SDHCI_IPROC=y
|
||||
# CONFIG_MMC_SDHCI_PCI is not set
|
||||
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_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
# CONFIG_NVMEM_RMEM is not set
|
||||
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_RESOLVE=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PARTITION_PERCPU=y
|
||||
CONFIG_PCI=y
|
||||
# CONFIG_PCIE_BRCMSTB is not set
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCI_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_PGTABLE_LEVELS=3
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_BCM2835=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_CLK=y
|
||||
CONFIG_PM_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_QUEUED_RWLOCKS=y
|
||||
CONFIG_QUEUED_SPINLOCKS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_REGULATOR_GPIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
# CONFIG_RESET_RASPBERRYPI is not set
|
||||
CONFIG_RESET_SIMPLE=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
# CONFIG_RPI_POE_POWER is not set
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS 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_DEV_BUS=y
|
||||
# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SMSC_PHY=y
|
||||
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_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_THERMAL_WRITABLE_TRIPS=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_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_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_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
|
465
root/target/linux/bcm27xx/bcm2711/config-5.15
Normal file
465
root/target/linux/bcm27xx/bcm2711/config-5.15
Normal file
|
@ -0,0 +1,465 @@
|
|||
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_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=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_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARM64=y
|
||||
CONFIG_ARM64_4K_PAGES=y
|
||||
CONFIG_ARM64_CNP=y
|
||||
CONFIG_ARM64_CONT_SHIFT=4
|
||||
CONFIG_ARM64_ERRATUM_1165522=y
|
||||
CONFIG_ARM64_ERRATUM_1286807=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_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_PTR_AUTH=y
|
||||
CONFIG_ARM64_SSBD=y
|
||||
CONFIG_ARM64_SVE=y
|
||||
CONFIG_ARM64_TAGGED_ADDR_ABI=y
|
||||
CONFIG_ARM64_UAO=y
|
||||
CONFIG_ARM64_VA_BITS=39
|
||||
CONFIG_ARM64_VA_BITS_39=y
|
||||
CONFIG_ARM64_VHE=y
|
||||
CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
|
||||
CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=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 is not set
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_GIC_V2M=y
|
||||
CONFIG_ARM_GIC_V3=y
|
||||
CONFIG_ARM_GIC_V3_ITS=y
|
||||
CONFIG_ARM_GIC_V3_ITS_PCI=y
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
|
||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
CONFIG_BCM2711_THERMAL=y
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
# CONFIG_BCM2835_THERMAL is not set
|
||||
CONFIG_BCM2835_VCHIQ=y
|
||||
# CONFIG_BCM2835_VCHIQ_MMAL is not set
|
||||
CONFIG_BCM2835_WDT=y
|
||||
CONFIG_BCM7XXX_PHY=y
|
||||
CONFIG_BCMGENET=y
|
||||
CONFIG_BCM_NET_PHYLIB=y
|
||||
CONFIG_BCM_VCIO=y
|
||||
# CONFIG_BCM_VC_SM is not set
|
||||
# CONFIG_BCM_VC_SM_CMA 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_MQ_PCI=y
|
||||
CONFIG_BLK_PM=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BOUNCE=y
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
CONFIG_BROADCOM_PHY=y
|
||||
CONFIG_CAVIUM_ERRATUM_22375=y
|
||||
CONFIG_CAVIUM_ERRATUM_23154=y
|
||||
CONFIG_CAVIUM_ERRATUM_27456=y
|
||||
CONFIG_CAVIUM_TX2_ERRATUM_219=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLK_BCM2835=y
|
||||
CONFIG_CLK_RASPBERRYPI=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=5
|
||||
# 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_CONTIG_ALLOC=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
|
||||
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
|
||||
CONFIG_CPU_FREQ_GOV_COMMON=y
|
||||
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
|
||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
||||
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_CPU_FREQ_STAT=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_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_CBC=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_CTR=y
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
CONFIG_CRYPTO_DRBG_MENU=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_JITTERENTROPY=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
CONFIG_CRYPTO_SEQIV=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DIMLIB=y
|
||||
CONFIG_DMABUF_HEAPS=y
|
||||
CONFIG_DMABUF_HEAPS_CMA=y
|
||||
CONFIG_DMABUF_HEAPS_SYSTEM=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_DIRECT_REMAP=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_REMAP=y
|
||||
CONFIG_DMA_SHARED_BUFFER=y
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_DRM_RCAR_WRITEBACK=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_EXTCON=y
|
||||
CONFIG_F2FS_FS=y
|
||||
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_FB_SIMPLE=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
# CONFIG_FLATMEM_MANUAL 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=y
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_FREEZER=y
|
||||
CONFIG_FSL_ERRATUM_A008585=y
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_FUJITSU_ERRATUM_010001=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=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_CPU_VULNERABILITIES=y
|
||||
CONFIG_GENERIC_CSUM=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_GETTIMEOFDAY=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_PHY=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_FSM is not set
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=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_HAS_IOPORT_MAP=y
|
||||
CONFIG_HOLES_IN_ZONE=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
# CONFIG_HW_RANDOM_BCM2835 is not set
|
||||
CONFIG_HW_RANDOM_IPROC_RNG200=y
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
# CONFIG_I2C_BRCMSTB is not set
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
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_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JBD2=y
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_ACTPWR=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
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_BCM_UNIMAC=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=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_IO_ACCESSORS=y
|
||||
CONFIG_MMC_SDHCI_IPROC=y
|
||||
# CONFIG_MMC_SDHCI_PCI is not set
|
||||
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_NOP_USB_XCEIV=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
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_RESOLVE=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PARTITION_PERCPU=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCIEAER=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
CONFIG_PCIE_BRCMSTB=y
|
||||
CONFIG_PCIE_PME=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCI_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_PGTABLE_LEVELS=3
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYS_ADDR_T_64BIT=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_BCM2835=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_CLK=y
|
||||
CONFIG_PM_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_QUEUED_RWLOCKS=y
|
||||
CONFIG_QUEUED_SPINLOCKS=y
|
||||
CONFIG_RAS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
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_REGULATOR_GPIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RESET_SIMPLE=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS 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_DEV_BUS=y
|
||||
# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMP=y
|
||||
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_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_THERMAL_WRITABLE_TRIPS=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_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_GADGET=y
|
||||
CONFIG_USB_PCI=y
|
||||
CONFIG_USB_PHY=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_USB_UAS=y
|
||||
# CONFIG_USB_UHCI_HCD is not set
|
||||
CONFIG_USB_XHCI_HCD=y
|
||||
CONFIG_USB_XHCI_PCI=y
|
||||
CONFIG_USB_XHCI_PLATFORM=y
|
||||
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
|
|
@ -0,0 +1,77 @@
|
|||
From 4b7a4389846c44ff6a3590027d25aefd796b50f4 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:16 +0200
|
||||
Subject: [PATCH 001/634] clk: bcm-2835: Remove rounding up the dividers
|
||||
|
||||
The driver, once it found a divider, tries to round it up by increasing
|
||||
the least significant bit of the fractional part by one when the
|
||||
round_up argument is set and there's a remainder.
|
||||
|
||||
However, since it increases the divider it will actually reduce the
|
||||
clock rate below what we were asking for, leading to issues with
|
||||
clk_set_min_rate() that will complain that our rounded clock rate is
|
||||
below the minimum of the rate.
|
||||
|
||||
Since the dividers are fairly precise already, let's remove that part so
|
||||
that we can have clk_set_min_rate() working.
|
||||
|
||||
This is effectively a revert of 9c95b32ca093 ("clk: bcm2835: add a round
|
||||
up ability to the clock divisor").
|
||||
|
||||
Fixes: 9c95b32ca093 ("clk: bcm2835: add a round up ability to the clock divisor")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Acked-by: Stephen Boyd <sboyd@kernel.org>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org> # boot and basic functionality
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-3-maxime@cerno.tech
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 11 +++--------
|
||||
1 file changed, 3 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index bf97b2b2a63f..3667b4d731e7 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -932,8 +932,7 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)
|
||||
|
||||
static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
- unsigned long parent_rate,
|
||||
- bool round_up)
|
||||
+ unsigned long parent_rate)
|
||||
{
|
||||
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
||||
const struct bcm2835_clock_data *data = clock->data;
|
||||
@@ -945,10 +944,6 @@ static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
|
||||
|
||||
rem = do_div(temp, rate);
|
||||
div = temp;
|
||||
-
|
||||
- /* Round up and mask off the unused bits */
|
||||
- if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
|
||||
- div += unused_frac_mask + 1;
|
||||
div &= ~unused_frac_mask;
|
||||
|
||||
/* different clamping limits apply for a mash clock */
|
||||
@@ -1079,7 +1074,7 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
|
||||
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
||||
struct bcm2835_cprman *cprman = clock->cprman;
|
||||
const struct bcm2835_clock_data *data = clock->data;
|
||||
- u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
|
||||
+ u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
|
||||
u32 ctl;
|
||||
|
||||
spin_lock(&cprman->regs_lock);
|
||||
@@ -1130,7 +1125,7 @@ static unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw,
|
||||
|
||||
if (!(BIT(parent_idx) & data->set_rate_parent)) {
|
||||
*prate = clk_hw_get_rate(parent);
|
||||
- *div = bcm2835_clock_choose_div(hw, rate, *prate, true);
|
||||
+ *div = bcm2835_clock_choose_div(hw, rate, *prate);
|
||||
|
||||
*avgrate = bcm2835_clock_rate_from_divisor(clock, *prate, *div);
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
From b6b62f912d8aa4bd47780b3de56dc35ee820aad9 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:17 +0200
|
||||
Subject: [PATCH 002/634] drm/vc4: hdmi: Set a default HSM rate
|
||||
|
||||
When the firmware doesn't setup the HSM rate (such as when booting
|
||||
without an HDMI cable plugged in), its rate is 0 and thus any register
|
||||
access results in a CPU stall, even though HSM is enabled.
|
||||
|
||||
Let's enforce a minimum rate at boot to avoid this issue.
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-4-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index ed8a4b7f8b6e..623a4699bd21 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -94,6 +94,7 @@
|
||||
# define VC4_HD_M_SW_RST BIT(2)
|
||||
# define VC4_HD_M_ENABLE BIT(0)
|
||||
|
||||
+#define HSM_MIN_CLOCK_FREQ 120000000
|
||||
#define CEC_CLOCK_FREQ 40000
|
||||
|
||||
#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
|
||||
@@ -2161,6 +2162,19 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi->disable_4kp60 = true;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * If we boot without any cable connected to the HDMI connector,
|
||||
+ * the firmware will skip the HSM initialization and leave it
|
||||
+ * with a rate of 0, resulting in a bus lockup when we're
|
||||
+ * accessing the registers even if it's enabled.
|
||||
+ *
|
||||
+ * Let's put a sensible default at runtime_resume so that we
|
||||
+ * don't end up in this situation.
|
||||
+ */
|
||||
+ ret = clk_set_min_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ);
|
||||
+ if (ret)
|
||||
+ goto err_put_ddc;
|
||||
+
|
||||
if (vc4_hdmi->variant->reset)
|
||||
vc4_hdmi->variant->reset(vc4_hdmi);
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
From bfb78996b5fb1fb937541a17f58afdcbf7e6a8a5 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:18 +0200
|
||||
Subject: [PATCH 003/634] drm/vc4: hdmi: Move the HSM clock enable to
|
||||
runtime_pm
|
||||
|
||||
In order to access the HDMI controller, we need to make sure the HSM
|
||||
clock is enabled. If we were to access it with the clock disabled, the
|
||||
CPU would completely hang, resulting in an hard crash.
|
||||
|
||||
Since we have different code path that would require it, let's move that
|
||||
clock enable / disable to runtime_pm that will take care of the
|
||||
reference counting for us.
|
||||
|
||||
Since we also want to change the HSM clock rate and it's only valid
|
||||
while the clock is disabled, we need to move the clk_set_min_rate() call
|
||||
on the HSM clock above pm_runtime_get_and_sync().
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-5-maxime@cerno.tech
|
||||
Link: https://lore.kernel.org/linux-arm-kernel/20210924152334.1342630-1-maxime@cerno.tech/
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 70 +++++++++++++++++++++-------------
|
||||
1 file changed, 44 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 623a4699bd21..6b0700d0b408 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -628,7 +628,6 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
vc4_hdmi->variant->phy_disable(vc4_hdmi);
|
||||
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
|
||||
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
|
||||
ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
@@ -894,28 +893,10 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
conn_state_to_vc4_hdmi_conn_state(conn_state);
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
- unsigned long bvb_rate, pixel_rate, hsm_rate;
|
||||
+ unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
||||
+ unsigned long bvb_rate, hsm_rate;
|
||||
int ret;
|
||||
|
||||
- ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
- if (ret < 0) {
|
||||
- DRM_ERROR("Failed to retain power domain: %d\n", ret);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- pixel_rate = vc4_conn_state->pixel_rate;
|
||||
- ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
- if (ret) {
|
||||
- DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
|
||||
- if (ret) {
|
||||
- DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
/*
|
||||
* As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
|
||||
* be faster than pixel clock, infinitesimally faster, tested in
|
||||
@@ -939,10 +920,21 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
- ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
|
||||
+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret < 0) {
|
||||
+ DRM_ERROR("Failed to retain power domain: %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
if (ret) {
|
||||
- DRM_ERROR("Failed to turn on HSM clock: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
+ DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
|
||||
+ if (ret) {
|
||||
+ DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -958,7 +950,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
return;
|
||||
}
|
||||
@@ -966,7 +957,6 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
return;
|
||||
}
|
||||
@@ -2099,6 +2089,27 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int __maybe_unused vc4_hdmi_runtime_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
+
|
||||
+ clk_disable_unprepare(vc4_hdmi->hsm_clock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vc4_hdmi_runtime_resume(struct device *dev)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
|
||||
@@ -2366,11 +2377,18 @@ static const struct of_device_id vc4_hdmi_dt_match[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
+static const struct dev_pm_ops vc4_hdmi_pm_ops = {
|
||||
+ SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
|
||||
+ vc4_hdmi_runtime_resume,
|
||||
+ NULL)
|
||||
+};
|
||||
+
|
||||
struct platform_driver vc4_hdmi_driver = {
|
||||
.probe = vc4_hdmi_dev_probe,
|
||||
.remove = vc4_hdmi_dev_remove,
|
||||
.driver = {
|
||||
.name = "vc4_hdmi",
|
||||
.of_match_table = vc4_hdmi_dt_match,
|
||||
+ .pm = &vc4_hdmi_pm_ops,
|
||||
},
|
||||
};
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
From 4bfb738710a3ea66e51eefbc8cd8e8673c84a5b3 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 22 Sep 2021 14:54:19 +0200
|
||||
Subject: [PATCH 004/634] drm/vc4: hdmi: Make sure the controller is powered in
|
||||
detect
|
||||
|
||||
If the HPD GPIO is not available and drm_probe_ddc fails, we end up
|
||||
reading the HDMI_HOTPLUG register, but the controller might be powered
|
||||
off resulting in a CPU hang. Make sure we have the power domain and the
|
||||
HSM clock powered during the detect cycle to prevent the hang from
|
||||
happening.
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Michael Stapelberg <michael@stapelberg.ch>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210922125419.4125779-6-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 6b0700d0b408..21510ae31a9e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -168,6 +168,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
|
||||
bool connected = false;
|
||||
|
||||
+ WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
|
||||
+
|
||||
if (vc4_hdmi->hpd_gpio &&
|
||||
gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
|
||||
connected = true;
|
||||
@@ -188,10 +190,12 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
From 977d70a849d52a89e8b9fd949b0339ff8e5c88f8 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:27 +0200
|
||||
Subject: [PATCH 005/634] drm/vc4: hdmi: Make sure the controller is powered up
|
||||
during bind
|
||||
|
||||
In the bind hook, we actually need the device to have the HSM clock
|
||||
running during the final part of the display initialisation where we
|
||||
reset the controller and initialise the CEC component.
|
||||
|
||||
Failing to do so will result in a complete, silent, hang of the CPU.
|
||||
|
||||
Fixes: 411efa18e4b0 ("drm/vc4: hdmi: Move the HSM clock enable to runtime_pm")
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-3-maxime@cerno.tech
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 17 +++++++++++++++--
|
||||
1 file changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 21510ae31a9e..2087717f1cce 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -2190,6 +2190,18 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
if (ret)
|
||||
goto err_put_ddc;
|
||||
|
||||
+ /*
|
||||
+ * We need to have the device powered up at this point to call
|
||||
+ * our reset hook and for the CEC init.
|
||||
+ */
|
||||
+ ret = vc4_hdmi_runtime_resume(dev);
|
||||
+ if (ret)
|
||||
+ goto err_put_ddc;
|
||||
+
|
||||
+ pm_runtime_get_noresume(dev);
|
||||
+ pm_runtime_set_active(dev);
|
||||
+ pm_runtime_enable(dev);
|
||||
+
|
||||
if (vc4_hdmi->variant->reset)
|
||||
vc4_hdmi->variant->reset(vc4_hdmi);
|
||||
|
||||
@@ -2201,8 +2213,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
|
||||
}
|
||||
|
||||
- pm_runtime_enable(dev);
|
||||
-
|
||||
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs);
|
||||
|
||||
@@ -2226,6 +2236,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi_debugfs_regs,
|
||||
vc4_hdmi);
|
||||
|
||||
+ pm_runtime_put_sync(dev);
|
||||
+
|
||||
return 0;
|
||||
|
||||
err_free_cec:
|
||||
@@ -2236,6 +2248,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
|
||||
err_destroy_encoder:
|
||||
drm_encoder_cleanup(encoder);
|
||||
+ pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
err_put_ddc:
|
||||
put_device(&vc4_hdmi->ddc->dev);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
From 98fa097e699cf1f9aeab523e109b06465b2e456a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:28 +0200
|
||||
Subject: [PATCH 006/634] drm/vc4: hdmi: Rework the pre_crtc_configure error
|
||||
handling
|
||||
|
||||
Since our pre_crtc_configure hook returned void, we didn't implement a
|
||||
goto-based error path handling, leading to errors like failing to put
|
||||
back the device in pm_runtime in all the error paths, but also failing
|
||||
to disable the pixel clock if clk_set_min_rate on the HSM clock fails.
|
||||
|
||||
Move to a goto-based implementation to have an easier consitency.
|
||||
|
||||
Fixes: 4f6e3d66ac52 ("drm/vc4: Add runtime PM support to the HDMI encoder driver")
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-4-maxime@cerno.tech
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 20 ++++++++++++++------
|
||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 2087717f1cce..49944644a9b3 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -933,15 +933,16 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel clock rate: %d\n", ret);
|
||||
- return;
|
||||
+ goto err_put_runtime_pm;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(vc4_hdmi->pixel_clock);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to turn on pixel clock: %d\n", ret);
|
||||
- return;
|
||||
+ goto err_put_runtime_pm;
|
||||
}
|
||||
|
||||
+
|
||||
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
||||
|
||||
if (pixel_rate > 297000000)
|
||||
@@ -954,15 +955,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_min_rate(vc4_hdmi->pixel_bvb_clock, bvb_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set pixel bvb clock rate: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
- return;
|
||||
+ goto err_disable_pixel_clock;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(vc4_hdmi->pixel_bvb_clock);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to turn on pixel bvb clock: %d\n", ret);
|
||||
- clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
- return;
|
||||
+ goto err_disable_pixel_clock;
|
||||
}
|
||||
|
||||
if (vc4_hdmi->variant->phy_init)
|
||||
@@ -975,6 +974,15 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
|
||||
if (vc4_hdmi->variant->set_timings)
|
||||
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+err_disable_pixel_clock:
|
||||
+ clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
+err_put_runtime_pm:
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+
|
||||
+ return;
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
From 9ae0103555f84dce8bf29859fb3f5820da07e34a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:29 +0200
|
||||
Subject: [PATCH 007/634] drm/vc4: hdmi: Split the CEC disable / enable
|
||||
functions in two
|
||||
|
||||
In order to ease further additions to the CEC enable and disable, let's
|
||||
split the function into two functions, one to enable and the other to
|
||||
disable.
|
||||
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-5-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 75 ++++++++++++++++++++--------------
|
||||
1 file changed, 45 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 49944644a9b3..9b3c0009b2ed 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1727,7 +1727,7 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
+static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
/* clock period in microseconds */
|
||||
@@ -1740,38 +1740,53 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
val |= ((4700 / usecs) << VC4_HDMI_CEC_CNT_TO_4700_US_SHIFT) |
|
||||
((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT);
|
||||
|
||||
- if (enable) {
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
|
||||
- VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_2,
|
||||
- ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
|
||||
- ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
|
||||
- ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
|
||||
- ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
|
||||
- ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_3,
|
||||
- ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
|
||||
- ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
|
||||
- ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
|
||||
- ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_4,
|
||||
- ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
|
||||
- ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
|
||||
- ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
|
||||
- ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
|
||||
-
|
||||
- if (!vc4_hdmi->variant->external_irq_controller)
|
||||
- HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
- } else {
|
||||
- if (!vc4_hdmi->variant->external_irq_controller)
|
||||
- HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
- HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
|
||||
- VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
- }
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_5, val |
|
||||
+ VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_5, val);
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_2,
|
||||
+ ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
|
||||
+ ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
|
||||
+ ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
|
||||
+ ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
|
||||
+ ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_3,
|
||||
+ ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
|
||||
+ ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
|
||||
+ ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
|
||||
+ ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_4,
|
||||
+ ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
|
||||
+ ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
|
||||
+ ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
|
||||
+ ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));
|
||||
+
|
||||
+ if (!vc4_hdmi->variant->external_irq_controller)
|
||||
+ HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
+
|
||||
+ if (!vc4_hdmi->variant->external_irq_controller)
|
||||
+ HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
+
|
||||
+ HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
|
||||
+ VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
+{
|
||||
+ if (enable)
|
||||
+ return vc4_hdmi_cec_enable(adap);
|
||||
+ else
|
||||
+ return vc4_hdmi_cec_disable(adap);
|
||||
+}
|
||||
+
|
||||
static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
From 086555e0bcbdf8e2e6e9f9306323cb4bf84fb807 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:30 +0200
|
||||
Subject: [PATCH 008/634] drm/vc4: hdmi: Make sure the device is powered with
|
||||
CEC
|
||||
|
||||
Similarly to what we encountered with the detect hook with DRM, nothing
|
||||
actually prevents any of the CEC callback from being run while the HDMI
|
||||
output is disabled.
|
||||
|
||||
However, this is an issue since any register access to the controller
|
||||
when it's powered down will result in a silent hang.
|
||||
|
||||
Let's make sure we run the runtime_pm hooks when the CEC adapter is
|
||||
opened and closed by the userspace to avoid that issue.
|
||||
|
||||
Fixes: 15b4511a4af6 ("drm/vc4: add HDMI CEC support")
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-6-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 9b3c0009b2ed..70101e09b245 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1732,8 +1732,14 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
/* clock period in microseconds */
|
||||
const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
|
||||
- u32 val = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
+ val = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
|
||||
VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
|
||||
VC4_HDMI_CEC_CNT_TO_4500_US_MASK);
|
||||
@@ -1776,6 +1782,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
|
||||
VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
|
||||
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
From 54a0fd6b5fd8c0eeef7f3666ef1bbc2ce00cd779 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:59:31 +0200
|
||||
Subject: [PATCH 009/634] drm/vc4: hdmi: Warn if we access the controller while
|
||||
disabled
|
||||
|
||||
We've had many silent hangs where the kernel would look like it just
|
||||
stalled due to the access to one of the HDMI registers while the
|
||||
controller was disabled.
|
||||
|
||||
Add a warning if we're about to do that so that it's at least not silent
|
||||
anymore.
|
||||
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210819135931.895976-7-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
index 19d2fdc446bc..99dde6e06a37 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef _VC4_HDMI_REGS_H_
|
||||
#define _VC4_HDMI_REGS_H_
|
||||
|
||||
+#include <linux/pm_runtime.h>
|
||||
+
|
||||
#include "vc4_hdmi.h"
|
||||
|
||||
#define VC4_HDMI_PACKET_STRIDE 0x24
|
||||
@@ -412,6 +414,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
|
||||
const struct vc4_hdmi_variant *variant = hdmi->variant;
|
||||
void __iomem *base;
|
||||
|
||||
+ WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
|
||||
+
|
||||
if (reg >= variant->num_registers) {
|
||||
dev_warn(&hdmi->pdev->dev,
|
||||
"Invalid register ID %u\n", reg);
|
||||
@@ -438,6 +442,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
|
||||
const struct vc4_hdmi_variant *variant = hdmi->variant;
|
||||
void __iomem *base;
|
||||
|
||||
+ WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
|
||||
+
|
||||
if (reg >= variant->num_registers) {
|
||||
dev_warn(&hdmi->pdev->dev,
|
||||
"Invalid register ID %u\n", reg);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
From 7d9e3fd5588ff325e87844e3bcb0d167a9456e78 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 23 Sep 2021 20:50:13 +0200
|
||||
Subject: [PATCH 010/634] drm/vc4: crtc: Make sure the HDMI controller is
|
||||
powered when disabling
|
||||
|
||||
Since commit 875a4d536842 ("drm/vc4: drv: Disable the CRTC at boot
|
||||
time"), during the initial setup of the driver we call into the VC4 HDMI
|
||||
controller hooks to make sure the controller is properly disabled.
|
||||
|
||||
However, we were never making sure that the device was properly powered
|
||||
while doing so. This never resulted in any (reported) issue in practice,
|
||||
but since the introduction of commit 4209f03fcb8e ("drm/vc4: hdmi: Warn
|
||||
if we access the controller while disabled") we get a loud complaint
|
||||
when we do that kind of access.
|
||||
|
||||
Let's make sure we have the HDMI controller properly powered while
|
||||
disabling it.
|
||||
|
||||
Fixes: 875a4d536842 ("drm/vc4: drv: Disable the CRTC at boot time")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
Reviewed-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Tested-by: Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20210923185013.826679-1-maxime@cerno.tech
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 19 ++++++++++++++++++-
|
||||
1 file changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 18f5009ce90e..c0df11e5fcf2 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_device.h>
|
||||
+#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
@@ -42,6 +43,7 @@
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include "vc4_drv.h"
|
||||
+#include "vc4_hdmi.h"
|
||||
#include "vc4_regs.h"
|
||||
|
||||
#define HVS_FIFO_LATENCY_PIX 6
|
||||
@@ -496,8 +498,10 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
|
||||
enum vc4_encoder_type encoder_type;
|
||||
const struct vc4_pv_data *pv_data;
|
||||
struct drm_encoder *encoder;
|
||||
+ struct vc4_hdmi *vc4_hdmi;
|
||||
unsigned encoder_sel;
|
||||
int channel;
|
||||
+ int ret;
|
||||
|
||||
if (!(of_device_is_compatible(vc4_crtc->pdev->dev.of_node,
|
||||
"brcm,bcm2711-pixelvalve2") ||
|
||||
@@ -525,7 +529,20 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
|
||||
if (WARN_ON(!encoder))
|
||||
return 0;
|
||||
|
||||
- return vc4_crtc_disable(crtc, encoder, NULL, channel);
|
||||
+ vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = vc4_crtc_disable(crtc, encoder, NULL, channel);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
From 8dab6a99245dd443527dce15f99707b889c21248 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 18 Oct 2021 15:19:30 +0200
|
||||
Subject: [PATCH 011/634] drm/vc4: crtc: Drop feed_txp from state
|
||||
|
||||
Accessing the crtc->state pointer from outside the modesetting context
|
||||
is not allowed. We thus need to copy whatever we need from the KMS state
|
||||
to our structure in order to access it.
|
||||
|
||||
In VC4, a number of users of that pointers have crept in over the years,
|
||||
the first one being whether or not the downstream controller of the
|
||||
pixelvalve is our writeback controller.
|
||||
|
||||
Fortunately for us, Since commit 39fcb2808376 ("drm/vc4: txp: Turn the
|
||||
TXP into a CRTC of its own") this is no longer something that can change
|
||||
from one commit to the other and is hardcoded.
|
||||
|
||||
Let's set this flag in struct vc4_crtc if we happen to be the TXP, and
|
||||
drop the flag from our private state structure.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: 008095e065a8 ("drm/vc4: Add support for the transposer block")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 3 +--
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 6 +++++-
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++----
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 3 ++-
|
||||
drivers/gpu/drm/vc4/vc4_txp.c | 3 +--
|
||||
5 files changed, 12 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index c0df11e5fcf2..b90187d2c819 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -715,7 +715,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (vc4_crtc->event &&
|
||||
(vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) ||
|
||||
- vc4_state->feed_txp)) {
|
||||
+ vc4_crtc->feeds_txp)) {
|
||||
drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
|
||||
vc4_crtc->event = NULL;
|
||||
drm_crtc_vblank_put(crtc);
|
||||
@@ -893,7 +893,6 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
|
||||
return NULL;
|
||||
|
||||
old_vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
- vc4_state->feed_txp = old_vc4_state->feed_txp;
|
||||
vc4_state->margins = old_vc4_state->margins;
|
||||
vc4_state->assigned_channel = old_vc4_state->assigned_channel;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index ef73e0aaf726..3c69b89363cb 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -495,6 +495,11 @@ struct vc4_crtc {
|
||||
struct drm_pending_vblank_event *event;
|
||||
|
||||
struct debugfs_regset32 regset;
|
||||
+
|
||||
+ /**
|
||||
+ * @feeds_txp: True if the CRTC feeds our writeback controller.
|
||||
+ */
|
||||
+ bool feeds_txp;
|
||||
};
|
||||
|
||||
static inline struct vc4_crtc *
|
||||
@@ -521,7 +526,6 @@ struct vc4_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
/* Dlist area for this CRTC configuration. */
|
||||
struct drm_mm_node mm;
|
||||
- bool feed_txp;
|
||||
bool txp_armed;
|
||||
unsigned int assigned_channel;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index c239045e05d6..9ddaee6b368d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -375,7 +375,7 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
|
||||
- if (!vc4_state->feed_txp || vc4_state->txp_armed) {
|
||||
+ if (!vc4_crtc->feeds_txp || vc4_state->txp_armed) {
|
||||
vc4_crtc->event = crtc->state->event;
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
@@ -395,10 +395,9 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
- struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(new_crtc_state);
|
||||
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
- bool oneshot = vc4_state->feed_txp;
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
+ bool oneshot = vc4_crtc->feeds_txp;
|
||||
|
||||
vc4_hvs_update_dlist(crtc);
|
||||
vc4_hvs_init_channel(vc4, crtc, mode, oneshot);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index f0b3e4cf5bce..028f19f7a5f8 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -233,6 +233,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
|
||||
unsigned int i;
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
|
||||
u32 dispctrl;
|
||||
u32 dsp3_mux;
|
||||
@@ -253,7 +254,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
|
||||
* TXP IP, and we need to disable the FIFO2 -> pixelvalve1
|
||||
* route.
|
||||
*/
|
||||
- if (vc4_state->feed_txp)
|
||||
+ if (vc4_crtc->feeds_txp)
|
||||
dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX);
|
||||
else
|
||||
dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
index 2fc7f4b5fa09..26eda7542f74 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
@@ -391,7 +391,6 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc,
|
||||
{
|
||||
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
|
||||
crtc);
|
||||
- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
|
||||
int ret;
|
||||
|
||||
ret = vc4_hvs_atomic_check(crtc, state);
|
||||
@@ -399,7 +398,6 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc,
|
||||
return ret;
|
||||
|
||||
crtc_state->no_vblank = true;
|
||||
- vc4_state->feed_txp = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -482,6 +480,7 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
|
||||
|
||||
vc4_crtc->pdev = pdev;
|
||||
vc4_crtc->data = &vc4_txp_crtc_data;
|
||||
+ vc4_crtc->feeds_txp = true;
|
||||
|
||||
txp->pdev = pdev;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
From 7c65e42492d48ed03ce6b7e2346d5f969e30a62a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 10 Jun 2021 17:48:28 +0200
|
||||
Subject: [PATCH 012/634] drm/vc4: Fix non-blocking commit getting stuck
|
||||
forever
|
||||
|
||||
In some situation, we can end up being stuck on a non-blocking that went
|
||||
through properly.
|
||||
|
||||
The situation that seems to trigger it reliably is to first start a
|
||||
non-blocking commit, and then right after, and before we had any vblank
|
||||
interrupt), start a blocking commit.
|
||||
|
||||
This will lead to the first commit workqueue to be scheduled, setup the
|
||||
display, while the second commit is waiting for the first one to be
|
||||
completed.
|
||||
|
||||
The vblank interrupt will then be raised, vc4_crtc_handle_vblank() will
|
||||
run and will compare the active dlist in the HVS channel to the one
|
||||
associated with the crtc->state.
|
||||
|
||||
However, at that point, the second commit is waiting using
|
||||
drm_atomic_helper_wait_for_dependencies that occurs after
|
||||
drm_atomic_helper_swap_state has been called, so crtc->state points to
|
||||
the second commit state. vc4_crtc_handle_vblank() will compare the two
|
||||
dlist addresses and since they don't match will ignore the interrupt.
|
||||
|
||||
The vblank event will never be reported, and the first and second commit
|
||||
will wait for the first commit completion until they timeout.
|
||||
|
||||
The underlying reason is that it was never safe to do so. Indeed,
|
||||
accessing the ->state pointer access synchronization is based on
|
||||
ownership guarantees that can only occur within the functions and hooks
|
||||
defined as part of the KMS framework, and obviously the irq handler
|
||||
isn't one of them. The rework to move to generic helpers only uncovered
|
||||
the underlying issue.
|
||||
|
||||
However, since the code path between
|
||||
drm_atomic_helper_wait_for_dependencies() and
|
||||
drm_atomic_helper_wait_for_vblanks() is serialised and we can't get two
|
||||
commits in that path at the same time, we can work around this issue by
|
||||
setting a variable associated to struct drm_crtc to the dlist we expect,
|
||||
and then using it from the vc4_crtc_handle_vblank() function.
|
||||
|
||||
Since that state is shared with the modesetting path, we also need to
|
||||
introduce a spinlock to protect the code shared between the interrupt
|
||||
handler and the modesetting path, protecting only our new variable for
|
||||
now.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: 56d1fe0979dc ("drm/vc4: Make pageflip completion handling more robust.")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 5 ++++-
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 14 ++++++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 7 +++++--
|
||||
3 files changed, 23 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index b90187d2c819..98de8b265220 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -713,8 +713,9 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
+ spin_lock(&vc4_crtc->irq_lock);
|
||||
if (vc4_crtc->event &&
|
||||
- (vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) ||
|
||||
+ (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) ||
|
||||
vc4_crtc->feeds_txp)) {
|
||||
drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
|
||||
vc4_crtc->event = NULL;
|
||||
@@ -728,6 +729,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
*/
|
||||
vc4_hvs_unmask_underrun(dev, chan);
|
||||
}
|
||||
+ spin_unlock(&vc4_crtc->irq_lock);
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
@@ -1127,6 +1129,7 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc,
|
||||
return PTR_ERR(primary_plane);
|
||||
}
|
||||
|
||||
+ spin_lock_init(&vc4_crtc->irq_lock);
|
||||
drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
|
||||
crtc_funcs, NULL);
|
||||
drm_crtc_helper_add(crtc, crtc_helper_funcs);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 3c69b89363cb..6d2480abcf08 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -500,6 +500,20 @@ struct vc4_crtc {
|
||||
* @feeds_txp: True if the CRTC feeds our writeback controller.
|
||||
*/
|
||||
bool feeds_txp;
|
||||
+
|
||||
+ /**
|
||||
+ * @irq_lock: Spinlock protecting the resources shared between
|
||||
+ * the atomic code and our vblank handler.
|
||||
+ */
|
||||
+ spinlock_t irq_lock;
|
||||
+
|
||||
+ /**
|
||||
+ * @current_dlist: Start offset of the display list currently
|
||||
+ * set in the HVS for that CRTC. Protected by @irq_lock, and
|
||||
+ * copied in vc4_hvs_update_dlist() for the CRTC interrupt
|
||||
+ * handler to have access to that value.
|
||||
+ */
|
||||
+ unsigned int current_dlist;
|
||||
};
|
||||
|
||||
static inline struct vc4_crtc *
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index 9ddaee6b368d..f8ed0f6a57e0 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -365,10 +365,9 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
+ unsigned long flags;
|
||||
|
||||
if (crtc->state->event) {
|
||||
- unsigned long flags;
|
||||
-
|
||||
crtc->state->event->pipe = drm_crtc_index(crtc);
|
||||
|
||||
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
|
||||
@@ -388,6 +387,10 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
|
||||
vc4_state->mm.start);
|
||||
}
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_crtc->irq_lock, flags);
|
||||
+ vc4_crtc->current_dlist = vc4_state->mm.start;
|
||||
+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
From ed2955f9cdaf873fd2b470febe3da024e3aa3f11 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 18 Oct 2021 15:56:44 +0200
|
||||
Subject: [PATCH 013/634] drm/vc4: crtc: Copy assigned channel to the CRTC
|
||||
|
||||
Accessing the crtc->state pointer from outside the modesetting context
|
||||
is not allowed. We thus need to copy whatever we need from the KMS state
|
||||
to our structure in order to access it.
|
||||
|
||||
In VC4, a number of users of that pointers have crept in over the years,
|
||||
and the previous commits removed them all but the HVS channel a CRTC has
|
||||
been assigned.
|
||||
|
||||
Let's move this channel in struct vc4_crtc at atomic_begin() time, drop
|
||||
it from our private state structure, and remove our use of crtc->state
|
||||
from our vblank handler entirely.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: 87ebcd42fb7b ("drm/vc4: crtc: Assign output to channel automatically")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 4 ++--
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 9 +++++++++
|
||||
drivers/gpu/drm/vc4/vc4_hvs.c | 12 ++++++++++++
|
||||
drivers/gpu/drm/vc4/vc4_txp.c | 1 +
|
||||
4 files changed, 24 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 98de8b265220..e3ed52d96f42 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -708,8 +708,7 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
struct drm_crtc *crtc = &vc4_crtc->base;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
- struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
- u32 chan = vc4_state->assigned_channel;
|
||||
+ u32 chan = vc4_crtc->current_hvs_channel;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
@@ -955,6 +954,7 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = {
|
||||
static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
|
||||
.mode_valid = vc4_crtc_mode_valid,
|
||||
.atomic_check = vc4_crtc_atomic_check,
|
||||
+ .atomic_begin = vc4_hvs_atomic_begin,
|
||||
.atomic_flush = vc4_hvs_atomic_flush,
|
||||
.atomic_enable = vc4_crtc_atomic_enable,
|
||||
.atomic_disable = vc4_crtc_atomic_disable,
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 6d2480abcf08..4b550ebd9572 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -514,6 +514,14 @@ struct vc4_crtc {
|
||||
* handler to have access to that value.
|
||||
*/
|
||||
unsigned int current_dlist;
|
||||
+
|
||||
+ /**
|
||||
+ * @current_hvs_channel: HVS channel currently assigned to the
|
||||
+ * CRTC. Protected by @irq_lock, and copied in
|
||||
+ * vc4_hvs_atomic_begin() for the CRTC interrupt handler to have
|
||||
+ * access to that value.
|
||||
+ */
|
||||
+ unsigned int current_hvs_channel;
|
||||
};
|
||||
|
||||
static inline struct vc4_crtc *
|
||||
@@ -926,6 +934,7 @@ extern struct platform_driver vc4_hvs_driver;
|
||||
void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int output);
|
||||
int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output);
|
||||
int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
+void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
index f8ed0f6a57e0..604933e20e6a 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
|
||||
@@ -393,6 +393,18 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
|
||||
spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags);
|
||||
}
|
||||
|
||||
+void vc4_hvs_atomic_begin(struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_crtc->irq_lock, flags);
|
||||
+ vc4_crtc->current_hvs_channel = vc4_state->assigned_channel;
|
||||
+ spin_unlock_irqrestore(&vc4_crtc->irq_lock, flags);
|
||||
+}
|
||||
+
|
||||
void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
index 26eda7542f74..9809ca3e2945 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
|
||||
@@ -435,6 +435,7 @@ static void vc4_txp_atomic_disable(struct drm_crtc *crtc,
|
||||
|
||||
static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = {
|
||||
.atomic_check = vc4_txp_atomic_check,
|
||||
+ .atomic_begin = vc4_hvs_atomic_begin,
|
||||
.atomic_flush = vc4_hvs_atomic_flush,
|
||||
.atomic_enable = vc4_txp_atomic_enable,
|
||||
.atomic_disable = vc4_txp_atomic_disable,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,916 @@
|
|||
From a17ad9dc735724a186d8618c56e27467dbb1451b Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 12:25:17 +0200
|
||||
Subject: [PATCH 014/634] drm/vc4: hdmi: Add a spinlock to protect register
|
||||
access
|
||||
|
||||
The vc4 HDMI driver has multiple path shared between the CEC, ALSA and
|
||||
KMS frameworks, plus two interrupt handlers (CEC and hotplug) that will
|
||||
read and modify a number of registers.
|
||||
|
||||
Even though not bug has been reported so far, it's definitely unsafe, so
|
||||
let's just add a spinlock to protect the register access of the HDMI
|
||||
controller.
|
||||
|
||||
Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 202 ++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 5 +
|
||||
drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 37 +++++
|
||||
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 2 +
|
||||
4 files changed, 236 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 70101e09b245..6a9d5d423cf8 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -118,6 +118,10 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
|
||||
|
||||
static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_M_CTL, VC4_HD_M_SW_RST);
|
||||
udelay(1);
|
||||
HDMI_WRITE(HDMI_M_CTL, 0);
|
||||
@@ -129,24 +133,36 @@ static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
VC4_HDMI_SW_RESET_FORMAT_DETECT);
|
||||
|
||||
HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
reset_control_reset(vc4_hdmi->reset);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_DVP_CTL, 0);
|
||||
|
||||
HDMI_WRITE(HDMI_CLOCK_STOP,
|
||||
HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_VC4_HDMI_CEC
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long cec_rate = clk_get_rate(vc4_hdmi->cec_clock);
|
||||
+ unsigned long flags;
|
||||
u16 clk_cnt;
|
||||
u32 value;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
|
||||
|
||||
@@ -154,9 +170,11 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
||||
* Set the clock divider: the hsm_clock rate and this divider
|
||||
* setting will give a 40 kHz CEC clock.
|
||||
*/
|
||||
- clk_cnt = clk_get_rate(vc4_hdmi->cec_clock) / CEC_CLOCK_FREQ;
|
||||
+ clk_cnt = cec_rate / CEC_CLOCK_FREQ;
|
||||
value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
#else
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
|
||||
@@ -175,8 +193,16 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
connected = true;
|
||||
} else if (drm_probe_ddc(vc4_hdmi->ddc)) {
|
||||
connected = true;
|
||||
- } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) {
|
||||
- connected = true;
|
||||
+ } else {
|
||||
+ unsigned long flags;
|
||||
+ u32 hotplug;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+ hotplug = HDMI_READ(HDMI_HOTPLUG);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
+ if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED)
|
||||
+ connected = true;
|
||||
}
|
||||
|
||||
if (connected) {
|
||||
@@ -369,9 +395,12 @@ static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
u32 packet_id = type - 0x80;
|
||||
+ unsigned long flags;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
||||
HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (!poll)
|
||||
return 0;
|
||||
@@ -391,6 +420,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
void __iomem *base = __vc4_hdmi_get_field_base(vc4_hdmi,
|
||||
ram_packet_start->reg);
|
||||
uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
|
||||
+ unsigned long flags;
|
||||
ssize_t len, i;
|
||||
int ret;
|
||||
|
||||
@@ -408,6 +438,8 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
return;
|
||||
}
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
for (i = 0; i < len; i += 7) {
|
||||
writel(buffer[i + 0] << 0 |
|
||||
buffer[i + 1] << 8 |
|
||||
@@ -425,6 +457,9 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
|
||||
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
||||
HDMI_READ(HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for((HDMI_READ(HDMI_RAM_PACKET_STATUS) &
|
||||
BIT(packet_id)), 100);
|
||||
if (ret)
|
||||
@@ -544,6 +579,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
|
||||
if (!vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
return;
|
||||
@@ -554,8 +590,10 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
|
||||
drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
|
||||
VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
|
||||
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
|
||||
@@ -565,6 +603,7 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
+ unsigned long flags;
|
||||
|
||||
/*
|
||||
* At boot, encoder->crtc will be NULL. Since we don't know the
|
||||
@@ -580,8 +619,10 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
|
||||
cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
|
||||
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
|
||||
drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
|
||||
@@ -607,15 +648,23 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
|
||||
|
||||
HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_CLRRGB);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
mdelay(1);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
vc4_hdmi_disable_scrambling(encoder);
|
||||
}
|
||||
|
||||
@@ -623,10 +672,13 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (vc4_hdmi->variant->phy_disable)
|
||||
vc4_hdmi->variant->phy_disable(vc4_hdmi);
|
||||
@@ -645,8 +697,11 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
|
||||
static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
u32 csc_ctl;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
|
||||
VC4_HD_CSC_CTL_ORDER);
|
||||
|
||||
@@ -676,14 +731,19 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
|
||||
/* The RGB order applies even when CSC is disabled. */
|
||||
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
u32 csc_ctl;
|
||||
|
||||
csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
if (enable) {
|
||||
/* CEA VICs other than #1 requre limited range RGB
|
||||
* output unless overridden by an AVI infoframe.
|
||||
@@ -715,6 +775,8 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
}
|
||||
|
||||
HDMI_WRITE(HDMI_CSC_CTL, csc_ctl);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
@@ -738,6 +800,9 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
mode->crtc_vsync_end -
|
||||
interlaced,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_HORZA,
|
||||
(vsync_pos ? VC4_HDMI_HORZA_VPOS : 0) |
|
||||
@@ -761,6 +826,8 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
|
||||
HDMI_WRITE(HDMI_VERTB0, vertb_even);
|
||||
HDMI_WRITE(HDMI_VERTB1, vertb);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
@@ -784,10 +851,13 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
mode->crtc_vsync_end -
|
||||
interlaced,
|
||||
VC4_HDMI_VERTB_VBP));
|
||||
+ unsigned long flags;
|
||||
unsigned char gcp;
|
||||
bool gcp_en;
|
||||
u32 reg;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
|
||||
HDMI_WRITE(HDMI_HORZA,
|
||||
(vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) |
|
||||
@@ -846,13 +916,18 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
|
||||
HDMI_WRITE(HDMI_GCP_CONFIG, reg);
|
||||
|
||||
HDMI_WRITE(HDMI_CLOCK_STOP, 0);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
u32 drift;
|
||||
int ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
drift = HDMI_READ(HDMI_FIFO_CTL);
|
||||
drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
|
||||
|
||||
@@ -860,12 +935,20 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
|
||||
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL,
|
||||
drift | VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
usleep_range(1000, 1100);
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_FIFO_CTL,
|
||||
drift & ~VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL,
|
||||
drift | VC4_HDMI_FIFO_CTL_RECENTER);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for(HDMI_READ(HDMI_FIFO_CTL) &
|
||||
VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1);
|
||||
WARN_ONCE(ret, "Timeout waiting for "
|
||||
@@ -899,6 +982,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
||||
unsigned long bvb_rate, hsm_rate;
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -967,11 +1051,15 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
if (vc4_hdmi->variant->phy_init)
|
||||
vc4_hdmi->variant->phy_init(vc4_hdmi, vc4_conn_state);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
|
||||
HDMI_READ(HDMI_SCHEDULER_CONTROL) |
|
||||
VC4_HDMI_SCHEDULER_CONTROL_MANUAL_FORMAT |
|
||||
VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
if (vc4_hdmi->variant->set_timings)
|
||||
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
|
||||
|
||||
@@ -991,6 +1079,7 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ unsigned long flags;
|
||||
|
||||
if (vc4_encoder->hdmi_monitor &&
|
||||
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
|
||||
@@ -1005,7 +1094,9 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
vc4_encoder->limited_rgb_range = false;
|
||||
}
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
@@ -1016,8 +1107,11 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
|
||||
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
VC4_HD_VID_CTL_ENABLE |
|
||||
VC4_HD_VID_CTL_CLRRGB |
|
||||
@@ -1034,6 +1128,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
HDMI_READ(HDMI_SCHEDULER_CONTROL) |
|
||||
VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
|
||||
WARN_ONCE(ret, "Timeout waiting for "
|
||||
@@ -1046,6 +1142,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
ret = wait_for(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
|
||||
WARN_ONCE(ret, "Timeout waiting for "
|
||||
@@ -1053,6 +1151,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
}
|
||||
|
||||
if (vc4_encoder->hdmi_monitor) {
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
|
||||
VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE));
|
||||
HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
|
||||
@@ -1062,6 +1162,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
|
||||
VC4_HDMI_RAM_PACKET_ENABLE);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
vc4_hdmi_set_infoframes(encoder);
|
||||
}
|
||||
|
||||
@@ -1183,6 +1285,7 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
|
||||
unsigned int samplerate)
|
||||
{
|
||||
u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock);
|
||||
+ unsigned long flags;
|
||||
unsigned long n, m;
|
||||
|
||||
rational_best_approximation(hsm_clock, samplerate,
|
||||
@@ -1192,9 +1295,11 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
|
||||
VC4_HD_MAI_SMP_M_SHIFT) + 1,
|
||||
&n, &m);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_MAI_SMP,
|
||||
VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) |
|
||||
VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M));
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)
|
||||
@@ -1205,6 +1310,8 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerat
|
||||
u32 n, cts;
|
||||
u64 tmp;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
n = 128 * samplerate / 1000;
|
||||
tmp = (u64)(mode->clock * 1000) * n;
|
||||
do_div(tmp, 128 * samplerate);
|
||||
@@ -1234,6 +1341,7 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
+ unsigned long flags;
|
||||
|
||||
/*
|
||||
* If the HDMI encoder hasn't probed, or the encoder is
|
||||
@@ -1245,12 +1353,14 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
|
||||
vc4_hdmi->audio.streaming = true;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
VC4_HD_MAI_CTL_RESET |
|
||||
VC4_HD_MAI_CTL_FLUSH |
|
||||
VC4_HD_MAI_CTL_DLATE |
|
||||
VC4_HD_MAI_CTL_ERRORE |
|
||||
VC4_HD_MAI_CTL_ERRORF);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (vc4_hdmi->variant->phy_rng_enable)
|
||||
vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
|
||||
@@ -1262,6 +1372,7 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
struct device *dev = &vc4_hdmi->pdev->dev;
|
||||
+ unsigned long flags;
|
||||
int ret;
|
||||
|
||||
vc4_hdmi->audio.streaming = false;
|
||||
@@ -1269,20 +1380,29 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to stop audio infoframe: %d\n", ret);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_RESET);
|
||||
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_ERRORF);
|
||||
HDMI_WRITE(HDMI_MAI_CTL, VC4_HD_MAI_CTL_FLUSH);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
VC4_HD_MAI_CTL_DLATE |
|
||||
VC4_HD_MAI_CTL_ERRORE |
|
||||
VC4_HD_MAI_CTL_ERRORF);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
if (vc4_hdmi->variant->phy_rng_disable)
|
||||
vc4_hdmi->variant->phy_rng_disable(vc4_hdmi);
|
||||
|
||||
@@ -1337,6 +1457,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
unsigned int sample_rate = params->sample_rate;
|
||||
unsigned int channels = params->channels;
|
||||
+ unsigned long flags;
|
||||
u32 audio_packet_config, channel_mask;
|
||||
u32 channel_map;
|
||||
u32 mai_audio_format;
|
||||
@@ -1345,14 +1466,15 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
|
||||
sample_rate, params->sample_width, channels);
|
||||
|
||||
+ vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
VC4_SET_FIELD(channels, VC4_HD_MAI_CTL_CHNUM) |
|
||||
VC4_HD_MAI_CTL_WHOLSMP |
|
||||
VC4_HD_MAI_CTL_CHALIGN |
|
||||
VC4_HD_MAI_CTL_ENABLE);
|
||||
|
||||
- vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
-
|
||||
mai_sample_rate = sample_rate_to_mai_fmt(sample_rate);
|
||||
if (params->iec.status[0] & IEC958_AES0_NONAUDIO &&
|
||||
params->channels == 8)
|
||||
@@ -1390,8 +1512,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
channel_map = vc4_hdmi->variant->channel_map(vc4_hdmi, channel_mask);
|
||||
HDMI_WRITE(HDMI_MAI_CHANNEL_MAP, channel_map);
|
||||
HDMI_WRITE(HDMI_AUDIO_PACKET_CONFIG, audio_packet_config);
|
||||
+
|
||||
vc4_hdmi_set_n_cts(vc4_hdmi, sample_rate);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea));
|
||||
vc4_hdmi_set_audio_infoframe(encoder);
|
||||
|
||||
@@ -1658,6 +1783,8 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
|
||||
struct cec_msg *msg = &vc4_hdmi->cec_rx_msg;
|
||||
unsigned int i;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
|
||||
VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
|
||||
|
||||
@@ -1676,11 +1803,12 @@ static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
|
||||
}
|
||||
}
|
||||
|
||||
-static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
||||
+static irqreturn_t vc4_cec_irq_handler_tx_bare_locked(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
- struct vc4_hdmi *vc4_hdmi = priv;
|
||||
u32 cntrl1;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
|
||||
cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
|
||||
@@ -1689,11 +1817,24 @@ static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
-static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
||||
+static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
+ irqreturn_t ret;
|
||||
+
|
||||
+ spin_lock(&vc4_hdmi->hw_lock);
|
||||
+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi);
|
||||
+ spin_unlock(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t vc4_cec_irq_handler_rx_bare_locked(struct vc4_hdmi *vc4_hdmi)
|
||||
+{
|
||||
u32 cntrl1;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
vc4_hdmi->cec_rx_msg.len = 0;
|
||||
cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
vc4_cec_read_msg(vc4_hdmi, cntrl1);
|
||||
@@ -1706,6 +1847,18 @@ static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
+static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = priv;
|
||||
+ irqreturn_t ret;
|
||||
+
|
||||
+ spin_lock(&vc4_hdmi->hw_lock);
|
||||
+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi);
|
||||
+ spin_unlock(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
@@ -1716,14 +1869,17 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
|
||||
if (!(stat & VC4_HDMI_CPU_CEC))
|
||||
return IRQ_NONE;
|
||||
|
||||
+ spin_lock(&vc4_hdmi->hw_lock);
|
||||
cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
|
||||
if (vc4_hdmi->cec_irq_was_rx)
|
||||
- ret = vc4_cec_irq_handler_rx_bare(irq, priv);
|
||||
+ ret = vc4_cec_irq_handler_rx_bare_locked(vc4_hdmi);
|
||||
else
|
||||
- ret = vc4_cec_irq_handler_tx_bare(irq, priv);
|
||||
+ ret = vc4_cec_irq_handler_tx_bare_locked(vc4_hdmi);
|
||||
|
||||
HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
+ spin_unlock(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1732,6 +1888,7 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
/* clock period in microseconds */
|
||||
const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
|
||||
+ unsigned long flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
@@ -1739,6 +1896,8 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
val = HDMI_READ(HDMI_CEC_CNTRL_5);
|
||||
val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
|
||||
VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
|
||||
@@ -1769,12 +1928,17 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
|
||||
@@ -1782,6 +1946,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_5, HDMI_READ(HDMI_CEC_CNTRL_5) |
|
||||
VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
|
||||
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
|
||||
return 0;
|
||||
@@ -1798,10 +1964,14 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
+ unsigned long flags;
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1,
|
||||
(HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
|
||||
(log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1810,6 +1980,7 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
struct drm_device *dev = vc4_hdmi->connector.dev;
|
||||
+ unsigned long flags;
|
||||
u32 val;
|
||||
unsigned int i;
|
||||
|
||||
@@ -1818,6 +1989,8 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
for (i = 0; i < msg->len; i += 4)
|
||||
HDMI_WRITE(HDMI_CEC_TX_DATA_1 + (i >> 2),
|
||||
(msg->msg[i]) |
|
||||
@@ -1833,6 +2006,9 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
val |= VC4_HDMI_CEC_START_XMIT_BEGIN;
|
||||
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, val);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1847,6 +2023,7 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
struct cec_connector_info conn_info;
|
||||
struct platform_device *pdev = vc4_hdmi->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
+ unsigned long flags;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
@@ -1866,10 +2043,12 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
|
||||
cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
value = HDMI_READ(HDMI_CEC_CNTRL_1);
|
||||
/* Set the logical address to Unregistered */
|
||||
value |= VC4_HDMI_CEC_ADDR_MASK;
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1, value);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
vc4_hdmi_cec_update_clk_div(vc4_hdmi);
|
||||
|
||||
@@ -1888,7 +2067,9 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
|
||||
if (ret)
|
||||
goto err_remove_cec_rx_handler;
|
||||
} else {
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
ret = request_threaded_irq(platform_get_irq(pdev, 0),
|
||||
vc4_cec_irq_handler,
|
||||
@@ -2158,6 +2339,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
|
||||
if (!vc4_hdmi)
|
||||
return -ENOMEM;
|
||||
+ spin_lock_init(&vc4_hdmi->hw_lock);
|
||||
INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
|
||||
|
||||
dev_set_drvdata(dev, vc4_hdmi);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index 33e9f665ab8e..006142fe8d4e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -178,6 +178,11 @@ struct vc4_hdmi {
|
||||
|
||||
struct debugfs_regset32 hdmi_regset;
|
||||
struct debugfs_regset32 hd_regset;
|
||||
+
|
||||
+ /**
|
||||
+ * @hw_lock: Spinlock protecting device register access.
|
||||
+ */
|
||||
+ spinlock_t hw_lock;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
||||
index 36535480f8e2..62148f0dc284 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c
|
||||
@@ -130,31 +130,49 @@
|
||||
void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
||||
struct vc4_hdmi_connector_state *conn_state)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
/* PHY should be in reset, like
|
||||
* vc4_hdmi_encoder_disable() does.
|
||||
*/
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_CTL_0,
|
||||
HDMI_READ(HDMI_TX_PHY_CTL_0) &
|
||||
~VC4_HDMI_TX_PHY_RNG_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_CTL_0,
|
||||
HDMI_READ(HDMI_TX_PHY_CTL_0) |
|
||||
VC4_HDMI_TX_PHY_RNG_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
static unsigned long long
|
||||
@@ -336,6 +354,8 @@ phy_get_channel_settings(enum vc4_hdmi_phy_channel chan,
|
||||
|
||||
static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
+
|
||||
HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x0f);
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10));
|
||||
}
|
||||
@@ -348,10 +368,13 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
||||
unsigned long long pixel_freq = conn_state->pixel_rate;
|
||||
unsigned long long vco_freq;
|
||||
unsigned char word_sel;
|
||||
+ unsigned long flags;
|
||||
u8 vco_sel, vco_div;
|
||||
|
||||
vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div);
|
||||
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
vc5_hdmi_reset_phy(vc4_hdmi);
|
||||
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
||||
@@ -501,23 +524,37 @@ void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
||||
HDMI_READ(HDMI_TX_PHY_RESET_CTL) |
|
||||
VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB |
|
||||
VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
vc5_hdmi_reset_phy(vc4_hdmi);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
||||
HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) &
|
||||
~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
|
||||
void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL,
|
||||
HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) |
|
||||
VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN);
|
||||
+ spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
index 99dde6e06a37..fc971506bd4f 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
|
||||
@@ -442,6 +442,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
|
||||
const struct vc4_hdmi_variant *variant = hdmi->variant;
|
||||
void __iomem *base;
|
||||
|
||||
+ lockdep_assert_held(&hdmi->hw_lock);
|
||||
+
|
||||
WARN_ON(!pm_runtime_active(&hdmi->pdev->dev));
|
||||
|
||||
if (reg >= variant->num_registers) {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,449 @@
|
|||
From a2cadb4575045b8503169302f3b18011c7e09c77 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 14:19:04 +0200
|
||||
Subject: [PATCH 015/634] drm/vc4: hdmi: Use a mutex to prevent concurrent
|
||||
framework access
|
||||
|
||||
The vc4 HDMI controller registers into the KMS, CEC and ALSA
|
||||
frameworks.
|
||||
|
||||
However, no particular care is done to prevent the concurrent execution
|
||||
of different framework hooks from happening at the same time.
|
||||
|
||||
In order to protect against that scenario, let's introduce a mutex that
|
||||
relevant ALSA and KMS hooks will need to take to prevent concurrent
|
||||
execution.
|
||||
|
||||
CEC is left out at the moment though, since the .get_modes and .detect
|
||||
KMS hooks, when running cec_s_phys_addr_from_edid, can end up calling
|
||||
CEC's .adap_enable hook. This introduces some reentrancy that isn't easy
|
||||
to deal with properly.
|
||||
|
||||
The CEC hooks also don't share much state with the rest of the driver:
|
||||
the registers are entirely separate, we don't share any variable, the
|
||||
only thing that can conflict is the CEC clock divider setup that can be
|
||||
affected by a mode set.
|
||||
|
||||
However, after discussing it, it looks like CEC should be able to
|
||||
recover from this if it was to happen.
|
||||
|
||||
Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 118 +++++++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 14 ++++
|
||||
2 files changed, 126 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 6a9d5d423cf8..a3f25efe60e9 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -186,6 +186,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
|
||||
bool connected = false;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
|
||||
|
||||
if (vc4_hdmi->hpd_gpio &&
|
||||
@@ -217,11 +219,13 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
@@ -238,10 +242,14 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
int ret = 0;
|
||||
struct edid *edid;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
edid = drm_get_edid(connector, vc4_hdmi->ddc);
|
||||
cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
|
||||
- if (!edid)
|
||||
- return -ENODEV;
|
||||
+ if (!edid) {
|
||||
+ ret = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
||||
|
||||
@@ -261,6 +269,9 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
}
|
||||
}
|
||||
|
||||
+out:
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -477,6 +488,8 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
|
||||
union hdmi_infoframe frame;
|
||||
int ret;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
connector, mode);
|
||||
if (ret < 0) {
|
||||
@@ -528,6 +541,8 @@ static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder)
|
||||
struct drm_connector_state *conn_state = connector->state;
|
||||
union hdmi_infoframe frame;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (!vc4_hdmi->variant->supports_hdr)
|
||||
return;
|
||||
|
||||
@@ -544,6 +559,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
vc4_hdmi_set_avi_infoframe(encoder);
|
||||
vc4_hdmi_set_spd_infoframe(encoder);
|
||||
/*
|
||||
@@ -563,6 +580,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (!vc4_encoder->hdmi_monitor)
|
||||
return false;
|
||||
|
||||
@@ -581,6 +600,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (!vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
return;
|
||||
|
||||
@@ -650,6 +671,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
|
||||
@@ -666,6 +689,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
|
||||
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
vc4_hdmi_disable_scrambling(encoder);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
@@ -675,6 +700,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
|
||||
@@ -689,6 +716,8 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
if (ret < 0)
|
||||
DRM_ERROR("Failed to release power domain: %d\n", ret);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
@@ -985,6 +1014,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
/*
|
||||
* As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
|
||||
* be faster than pixel clock, infinitesimally faster, tested in
|
||||
@@ -1005,13 +1036,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
ret = clk_set_min_rate(vc4_hdmi->hsm_clock, hsm_rate);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Failed to retain power domain: %d\n", ret);
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate);
|
||||
@@ -1063,13 +1094,16 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
if (vc4_hdmi->variant->set_timings)
|
||||
vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
|
||||
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return;
|
||||
|
||||
err_disable_pixel_clock:
|
||||
clk_disable_unprepare(vc4_hdmi->pixel_clock);
|
||||
err_put_runtime_pm:
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
-
|
||||
+out:
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1081,6 +1115,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
if (vc4_encoder->hdmi_monitor &&
|
||||
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
|
||||
if (vc4_hdmi->variant->csc_setup)
|
||||
@@ -1097,6 +1133,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
|
||||
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
@@ -1110,6 +1148,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_VID_CTL,
|
||||
@@ -1169,6 +1209,8 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
|
||||
vc4_hdmi_recenter_fifo(vc4_hdmi);
|
||||
vc4_hdmi_enable_scrambling(encoder);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
@@ -1310,6 +1352,7 @@ static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerat
|
||||
u32 n, cts;
|
||||
u64 tmp;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
|
||||
n = 128 * samplerate / 1000;
|
||||
@@ -1343,13 +1386,17 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
/*
|
||||
* If the HDMI encoder hasn't probed, or the encoder is
|
||||
* currently in DVI mode, treat the codec dai as missing.
|
||||
*/
|
||||
if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
|
||||
- VC4_HDMI_RAM_PACKET_ENABLE))
|
||||
+ VC4_HDMI_RAM_PACKET_ENABLE)) {
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
return -ENODEV;
|
||||
+ }
|
||||
|
||||
vc4_hdmi->audio.streaming = true;
|
||||
|
||||
@@ -1365,6 +1412,8 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
if (vc4_hdmi->variant->phy_rng_enable)
|
||||
vc4_hdmi->variant->phy_rng_enable(vc4_hdmi);
|
||||
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1375,6 +1424,8 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi)
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
vc4_hdmi->audio.streaming = false;
|
||||
ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO, false);
|
||||
if (ret)
|
||||
@@ -1394,6 +1445,8 @@ static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
HDMI_WRITE(HDMI_MAI_CTL,
|
||||
@@ -1408,6 +1461,8 @@ static void vc4_hdmi_audio_shutdown(struct device *dev, void *data)
|
||||
|
||||
vc4_hdmi->audio.streaming = false;
|
||||
vc4_hdmi_audio_reset(vc4_hdmi);
|
||||
+
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static int sample_rate_to_mai_fmt(int samplerate)
|
||||
@@ -1466,6 +1521,8 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
|
||||
sample_rate, params->sample_width, channels);
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+
|
||||
vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
@@ -1520,6 +1577,8 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea));
|
||||
vc4_hdmi_set_audio_infoframe(encoder);
|
||||
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1562,7 +1621,9 @@ static int vc4_hdmi_audio_get_eld(struct device *dev, void *data,
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
struct drm_connector *connector = &vc4_hdmi->connector;
|
||||
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
memcpy(buf, connector->eld, min(sizeof(connector->eld), len));
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1892,6 +1953,17 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1938,6 +2010,17 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
unsigned long flags;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
if (!vc4_hdmi->variant->external_irq_controller)
|
||||
@@ -1966,6 +2049,17 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||
struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
|
||||
unsigned long flags;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
HDMI_WRITE(HDMI_CEC_CNTRL_1,
|
||||
(HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
|
||||
@@ -1984,6 +2078,17 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
u32 val;
|
||||
unsigned int i;
|
||||
|
||||
+ /*
|
||||
+ * NOTE: This function should really take vc4_hdmi->mutex, but doing so
|
||||
+ * results in a reentrancy since cec_s_phys_addr_from_edid() called in
|
||||
+ * .detect or .get_modes might call .adap_enable, which leads to this
|
||||
+ * function being called with that mutex held.
|
||||
+ *
|
||||
+ * Concurrency is not an issue for the moment since we don't share any
|
||||
+ * state with KMS, so we can ignore the lock for now, but we need to
|
||||
+ * keep it in mind if we were to change that assumption.
|
||||
+ */
|
||||
+
|
||||
if (msg->len > 16) {
|
||||
drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len);
|
||||
return -ENOMEM;
|
||||
@@ -2339,6 +2444,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
|
||||
if (!vc4_hdmi)
|
||||
return -ENOMEM;
|
||||
+ mutex_init(&vc4_hdmi->mutex);
|
||||
spin_lock_init(&vc4_hdmi->hw_lock);
|
||||
INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index 006142fe8d4e..cf9bb21a8ef7 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -183,6 +183,20 @@ struct vc4_hdmi {
|
||||
* @hw_lock: Spinlock protecting device register access.
|
||||
*/
|
||||
spinlock_t hw_lock;
|
||||
+
|
||||
+ /**
|
||||
+ * @mutex: Mutex protecting the driver access across multiple
|
||||
+ * frameworks (KMS, ALSA).
|
||||
+ *
|
||||
+ * NOTE: While supported, CEC has been left out since
|
||||
+ * cec_s_phys_addr_from_edid() might call .adap_enable and lead to a
|
||||
+ * reentrancy issue between .get_modes (or .detect) and .adap_enable.
|
||||
+ * Since we don't share any state between the CEC hooks and KMS', it's
|
||||
+ * not a big deal. The only trouble might come from updating the CEC
|
||||
+ * clock divider which might be affected by a modeset, but CEC should
|
||||
+ * be resilient to that.
|
||||
+ */
|
||||
+ struct mutex mutex;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
From d51fcb1a3d1b478c76935b01a8788ff546727149 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 14:19:29 +0200
|
||||
Subject: [PATCH 016/634] drm/vc4: hdmi: Prevent access to crtc->state outside
|
||||
of KMS
|
||||
|
||||
Accessing the crtc->state pointer from outside the modesetting context
|
||||
is not allowed. We thus need to copy whatever we need from the KMS state
|
||||
to our structure in order to access it.
|
||||
|
||||
However, in the vc4 HDMI driver we do use that pointer in the ALSA code
|
||||
path, and potentially in the hotplug interrupt handler path.
|
||||
|
||||
These paths both need access to the CRTC adjusted mode in order for the
|
||||
proper dividers to be set for ALSA, and the scrambler state to be
|
||||
reinstated properly for hotplug.
|
||||
|
||||
Let's copy this mode into our private encoder structure and reference it
|
||||
from there when needed. Since that part is shared between KMS and other
|
||||
paths, we need to protect it using our mutex.
|
||||
|
||||
Link: https://lore.kernel.org/all/YWgteNaNeaS9uWDe@phenom.ffwll.local/
|
||||
Fixes: bb7d78568814 ("drm/vc4: Add HDMI audio support")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 38 +++++++++++++++++++++++-----------
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++
|
||||
2 files changed, 32 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index a3f25efe60e9..355f85418862 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -483,8 +483,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
struct drm_connector *connector = &vc4_hdmi->connector;
|
||||
struct drm_connector_state *cstate = connector->state;
|
||||
- struct drm_crtc *crtc = encoder->crtc;
|
||||
- const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
+ const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
union hdmi_infoframe frame;
|
||||
int ret;
|
||||
|
||||
@@ -596,8 +595,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
|
||||
|
||||
static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
unsigned long flags;
|
||||
|
||||
lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
@@ -623,18 +622,21 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
unsigned long flags;
|
||||
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
/*
|
||||
* At boot, encoder->crtc will be NULL. Since we don't know the
|
||||
* state of the scrambler and in order to avoid any
|
||||
* inconsistency, let's disable it all the time.
|
||||
*/
|
||||
- if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode))
|
||||
+ if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
return;
|
||||
|
||||
- if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))
|
||||
+ if (crtc && !vc4_hdmi_mode_needs_scrambling(mode))
|
||||
return;
|
||||
|
||||
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
|
||||
@@ -1007,8 +1009,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
vc4_hdmi_encoder_get_connector_state(encoder, state);
|
||||
struct vc4_hdmi_connector_state *vc4_conn_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(conn_state);
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
unsigned long pixel_rate = vc4_conn_state->pixel_rate;
|
||||
unsigned long bvb_rate, hsm_rate;
|
||||
unsigned long flags;
|
||||
@@ -1110,9 +1112,9 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
|
||||
static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
+ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&vc4_hdmi->mutex);
|
||||
@@ -1140,8 +1142,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
|
||||
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+ struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
|
||||
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
|
||||
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
|
||||
@@ -1217,6 +1219,19 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
+static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+ memcpy(&vc4_hdmi->saved_adjusted_mode,
|
||||
+ &crtc_state->adjusted_mode,
|
||||
+ sizeof(vc4_hdmi->saved_adjusted_mode));
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+}
|
||||
+
|
||||
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
|
||||
#define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL
|
||||
|
||||
@@ -1293,6 +1308,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
|
||||
static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
|
||||
.atomic_check = vc4_hdmi_encoder_atomic_check,
|
||||
+ .atomic_mode_set = vc4_hdmi_encoder_atomic_mode_set,
|
||||
.mode_valid = vc4_hdmi_encoder_mode_valid,
|
||||
.disable = vc4_hdmi_encoder_disable,
|
||||
.enable = vc4_hdmi_encoder_enable,
|
||||
@@ -1346,9 +1362,7 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
|
||||
|
||||
static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate)
|
||||
{
|
||||
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
- struct drm_crtc *crtc = encoder->crtc;
|
||||
- const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
+ const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
u32 n, cts;
|
||||
u64 tmp;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index cf9bb21a8ef7..a43cc5614d19 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -197,6 +197,12 @@ struct vc4_hdmi {
|
||||
* be resilient to that.
|
||||
*/
|
||||
struct mutex mutex;
|
||||
+
|
||||
+ /**
|
||||
+ * @saved_adjusted_mode: Copy of @drm_crtc_state.adjusted_mode
|
||||
+ * for use by ALSA hooks and interrupt handlers. Protected by @mutex.
|
||||
+ */
|
||||
+ struct drm_display_mode saved_adjusted_mode;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
From d78e135b703cd511621d2b396c03e8a8faa0b1a7 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 24 Sep 2021 14:27:38 +0200
|
||||
Subject: [PATCH 017/634] drm/vc4: hdmi: Check the device state in prepare()
|
||||
|
||||
Even though we already check that the encoder->crtc pointer is there
|
||||
during in startup(), which is part of the open() path in ASoC, nothing
|
||||
guarantees that our encoder state won't change between the time when we
|
||||
open the device and the time we prepare it.
|
||||
|
||||
Move the sanity checks we do in startup() to a helper and call it from
|
||||
prepare().
|
||||
|
||||
Fixes: 91e99e113929 ("drm/vc4: hdmi: Register HDMI codec")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 35 +++++++++++++++++++++++++++-------
|
||||
1 file changed, 28 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 355f85418862..8ea2291fe784 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1394,20 +1394,36 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
|
||||
return snd_soc_card_get_drvdata(card);
|
||||
}
|
||||
|
||||
+static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi)
|
||||
+{
|
||||
+ struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
+
|
||||
+ lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
+
|
||||
+ /*
|
||||
+ * The encoder doesn't have a CRTC until the first modeset.
|
||||
+ */
|
||||
+ if (!encoder->crtc)
|
||||
+ return false;
|
||||
+
|
||||
+ /*
|
||||
+ * If the encoder is currently in DVI mode, treat the codec DAI
|
||||
+ * as missing.
|
||||
+ */
|
||||
+ if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE))
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
static int vc4_hdmi_audio_startup(struct device *dev, void *data)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
|
||||
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&vc4_hdmi->mutex);
|
||||
|
||||
- /*
|
||||
- * If the HDMI encoder hasn't probed, or the encoder is
|
||||
- * currently in DVI mode, treat the codec dai as missing.
|
||||
- */
|
||||
- if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
|
||||
- VC4_HDMI_RAM_PACKET_ENABLE)) {
|
||||
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
|
||||
mutex_unlock(&vc4_hdmi->mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1537,6 +1553,11 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
|
||||
|
||||
mutex_lock(&vc4_hdmi->mutex);
|
||||
|
||||
+ if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) {
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate);
|
||||
|
||||
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
From b3fa147e2b8ec4b9acf242a589e464ed49b54ffe Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 17:31:58 +0200
|
||||
Subject: [PATCH 018/634] drm/vc4: hdmi: Introduce an output_enabled flag
|
||||
|
||||
We currently poke at encoder->crtc in the ALSA code path to determine
|
||||
whether the HDMI output is enabled or not, and thus whether we should
|
||||
allow the audio output.
|
||||
|
||||
However, that pointer is deprecated and shouldn't really be used by
|
||||
atomic drivers anymore. Since we have the infrastructure in place now,
|
||||
let's just create a flag that we toggle to report whether the controller
|
||||
is currently enabled and use that instead of encoder->crtc in ALSA.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++++++++++----
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++
|
||||
2 files changed, 18 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 8ea2291fe784..d31fd7e1fb17 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -724,6 +724,11 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
|
||||
|
||||
static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+ vc4_hdmi->output_enabled = false;
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
|
||||
@@ -1217,6 +1222,11 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
|
||||
|
||||
static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
+
|
||||
+ mutex_lock(&vc4_hdmi->mutex);
|
||||
+ vc4_hdmi->output_enabled = true;
|
||||
+ mutex_unlock(&vc4_hdmi->mutex);
|
||||
}
|
||||
|
||||
static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
|
||||
@@ -1396,14 +1406,12 @@ static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai)
|
||||
|
||||
static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
- struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base;
|
||||
-
|
||||
lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
|
||||
/*
|
||||
- * The encoder doesn't have a CRTC until the first modeset.
|
||||
+ * If the controller is disabled, prevent any ALSA output.
|
||||
*/
|
||||
- if (!encoder->crtc)
|
||||
+ if (!vc4_hdmi->output_enabled)
|
||||
return false;
|
||||
|
||||
/*
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index a43cc5614d19..5d3e97703e8d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -203,6 +203,12 @@ struct vc4_hdmi {
|
||||
* for use by ALSA hooks and interrupt handlers. Protected by @mutex.
|
||||
*/
|
||||
struct drm_display_mode saved_adjusted_mode;
|
||||
+
|
||||
+ /**
|
||||
+ * @output_enabled: Is the HDMI controller currently active?
|
||||
+ * Protected by @mutex.
|
||||
+ */
|
||||
+ bool output_enabled;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
From 9aa26a91fcad0b72ff20dbc5dbce2a39eaf73d41 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 19 Oct 2021 19:13:46 +0200
|
||||
Subject: [PATCH 019/634] drm/vc4: hdmi: Introduce a scdc_enabled flag
|
||||
|
||||
We currently rely on two functions, vc4_hdmi_supports_scrambling() and
|
||||
vc4_hdmi_mode_needs_scrambling() to determine if we should enable and
|
||||
disable the scrambler for any given mode.
|
||||
|
||||
Since we might need to disable the controller at boot, we also always
|
||||
run vc4_hdmi_disable_scrambling() and thus call those functions without
|
||||
a mode yet, which in turns need to make some special casing in order for
|
||||
it to work.
|
||||
|
||||
Instead of duplicating the check for whether or not we need to take care
|
||||
of the scrambler in both vc4_hdmi_enable_scrambling() and
|
||||
vc4_hdmi_disable_scrambling(), we can do that check only when we enable
|
||||
it and store whether or not it's been enabled in our private structure.
|
||||
|
||||
We also need to initialize that flag at true to make sure we disable the
|
||||
scrambler at boot since we can't really know its state yet.
|
||||
|
||||
This allows to simplify a bit that part of the driver, and removes one
|
||||
user of our copy of the CRTC adjusted mode outside of KMS (since
|
||||
vc4_hdmi_disable_scrambling() might be called from the hotplug interrupt
|
||||
handler).
|
||||
|
||||
It also removes our last user of the legacy encoder->crtc pointer.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 22 ++++++++++++----------
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 ++++++
|
||||
2 files changed, 18 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index d31fd7e1fb17..5cca1dacc933 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -615,6 +615,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
VC5_HDMI_SCRAMBLER_CTL_ENABLE);
|
||||
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
|
||||
|
||||
+ vc4_hdmi->scdc_enabled = true;
|
||||
+
|
||||
queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
|
||||
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
|
||||
}
|
||||
@@ -622,22 +624,14 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
|
||||
static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
|
||||
- struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
- struct drm_crtc *crtc = encoder->crtc;
|
||||
unsigned long flags;
|
||||
|
||||
lockdep_assert_held(&vc4_hdmi->mutex);
|
||||
|
||||
- /*
|
||||
- * At boot, encoder->crtc will be NULL. Since we don't know the
|
||||
- * state of the scrambler and in order to avoid any
|
||||
- * inconsistency, let's disable it all the time.
|
||||
- */
|
||||
- if (crtc && !vc4_hdmi_supports_scrambling(encoder, mode))
|
||||
+ if (!vc4_hdmi->scdc_enabled)
|
||||
return;
|
||||
|
||||
- if (crtc && !vc4_hdmi_mode_needs_scrambling(mode))
|
||||
- return;
|
||||
+ vc4_hdmi->scdc_enabled = false;
|
||||
|
||||
if (delayed_work_pending(&vc4_hdmi->scrambling_work))
|
||||
cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
|
||||
@@ -2502,6 +2496,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
vc4_hdmi->pdev = pdev;
|
||||
vc4_hdmi->variant = variant;
|
||||
|
||||
+ /*
|
||||
+ * Since we don't know the state of the controller and its
|
||||
+ * display (if any), let's assume it's always enabled.
|
||||
+ * vc4_hdmi_disable_scrambling() will thus run at boot, make
|
||||
+ * sure it's disabled, and avoid any inconsistency.
|
||||
+ */
|
||||
+ vc4_hdmi->scdc_enabled = true;
|
||||
+
|
||||
ret = variant->init_resources(vc4_hdmi);
|
||||
if (ret)
|
||||
return ret;
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
index 5d3e97703e8d..36c0b082a43b 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
||||
@@ -209,6 +209,12 @@ struct vc4_hdmi {
|
||||
* Protected by @mutex.
|
||||
*/
|
||||
bool output_enabled;
|
||||
+
|
||||
+ /**
|
||||
+ * @scdc_enabled: Is the HDMI controller currently running with
|
||||
+ * the scrambler on? Protected by @mutex.
|
||||
+ */
|
||||
+ bool scdc_enabled;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From 46ea9d1cd67819a8ecdd75893290cbb259f7a71f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Tue, 11 May 2021 17:05:11 +0200
|
||||
Subject: [PATCH 020/634] drm/vc4: hdmi: Remove the DDC probing for status
|
||||
detection
|
||||
|
||||
Commit 9d44abbbb8d5 ("drm/vc4: Fall back to using an EDID probe in the
|
||||
absence of a GPIO.") added some code to read the EDID through DDC in the
|
||||
HDMI driver detect hook since the Pi3 had no HPD GPIO back then.
|
||||
However, commit b1b8f45b3130 ("ARM: dts: bcm2837: Add missing GPIOs of
|
||||
Expander") changed that a couple of years later.
|
||||
|
||||
This causes an issue though since some TV (like the LG 55C8) when it
|
||||
comes out of standy will deassert the HPD line, but the EDID will
|
||||
remain readable.
|
||||
|
||||
It causes an issues nn platforms without an HPD GPIO, like the Pi4,
|
||||
where the DDC probing will be our primary mean to detect a display, and
|
||||
thus we will never detect the HPD pulse. This was fine before since the
|
||||
pulse was small enough that we would never detect it, and we also didn't
|
||||
have anything (like the scrambler) that needed to be set up in the
|
||||
display.
|
||||
|
||||
However, now that we have both, the display during the HPD pulse will
|
||||
clear its scrambler status, and since we won't detect the
|
||||
disconnect/reconnect cycle we will never enable the scrambler back.
|
||||
|
||||
As our main reason for that DDC probing is gone, let's just remove it.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 5cca1dacc933..918941a2bc58 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -193,8 +193,6 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
if (vc4_hdmi->hpd_gpio &&
|
||||
gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
|
||||
connected = true;
|
||||
- } else if (drm_probe_ddc(vc4_hdmi->ddc)) {
|
||||
- connected = true;
|
||||
} else {
|
||||
unsigned long flags;
|
||||
u32 hotplug;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From 84da606fe60662e046d6f7982d8a9281245b09f5 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 25 Jun 2021 17:16:51 +0200
|
||||
Subject: [PATCH 021/634] drm/vc4: hdmi: Fix HPD GPIO detection
|
||||
|
||||
Prior to commit 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod"), in the
|
||||
detect hook, if we had an HPD GPIO we would only rely on it and return
|
||||
whatever state it was in.
|
||||
|
||||
However, that commit changed that by mistake to only consider the case
|
||||
where we have a GPIO and it returns a logical high, and would fall back
|
||||
to the other methods otherwise.
|
||||
|
||||
Since we can read the EDIDs when the HPD signal is low on some displays,
|
||||
we changed the detection status from disconnected to connected, and we
|
||||
would ignore an HPD pulse.
|
||||
|
||||
Fixes: 6800234ceee0 ("drm/vc4: hdmi: Convert to gpiod")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 918941a2bc58..50e9e1f3ac47 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -190,9 +190,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
|
||||
WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
|
||||
|
||||
- if (vc4_hdmi->hpd_gpio &&
|
||||
- gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
|
||||
- connected = true;
|
||||
+ if (vc4_hdmi->hpd_gpio) {
|
||||
+ if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
|
||||
+ connected = true;
|
||||
} else {
|
||||
unsigned long flags;
|
||||
u32 hotplug;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
From 6ca024fdd37a7953f7f6ee301fef026cf9446272 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 26 May 2021 16:07:01 +0200
|
||||
Subject: [PATCH 022/634] drm/vc4: Make vc4_crtc_get_encoder public
|
||||
|
||||
We'll need that function in vc4_kms to compute the core clock rate
|
||||
requirements.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 8 ++++----
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 5 +++++
|
||||
2 files changed, 9 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index e3ed52d96f42..7cfd4a097847 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -281,10 +281,10 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc,
|
||||
* allows drivers to push pixels to more than one encoder from the
|
||||
* same CRTC.
|
||||
*/
|
||||
-static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
- struct drm_atomic_state *state,
|
||||
- struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
- struct drm_connector *connector))
|
||||
+struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state,
|
||||
+ struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
+ struct drm_connector *connector))
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 4b550ebd9572..f5e678491502 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -544,6 +544,11 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc)
|
||||
return container_of(data, struct vc4_pv_data, base);
|
||||
}
|
||||
|
||||
+struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
+ struct drm_atomic_state *state,
|
||||
+ struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
+ struct drm_connector *connector));
|
||||
+
|
||||
struct vc4_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
/* Dlist area for this CRTC configuration. */
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
From c2092ee4811081bab692db0ccf4893797df54b13 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 14 Jun 2021 15:27:24 +0200
|
||||
Subject: [PATCH 023/634] drm/vc4: crtc: Add encoder to vc4_crtc_config_pv
|
||||
prototype
|
||||
|
||||
vc4_crtc_config_pv() retrieves the encoder again, even though its only
|
||||
caller, vc4_crtc_atomic_enable(), already did.
|
||||
|
||||
Pass the encoder pointer as an argument instead of going through all the
|
||||
connectors to retrieve it again.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 7cfd4a097847..e5c2e29a6f01 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -315,12 +315,11 @@ static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc)
|
||||
CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_FIFO_CLR);
|
||||
}
|
||||
|
||||
-static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_atomic_state *state)
|
||||
+static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encoder,
|
||||
+ struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
- struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, state,
|
||||
- drm_atomic_get_new_connector_state);
|
||||
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
const struct vc4_pv_data *pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
|
||||
@@ -597,7 +596,7 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
if (vc4_encoder->pre_crtc_configure)
|
||||
vc4_encoder->pre_crtc_configure(encoder, state);
|
||||
|
||||
- vc4_crtc_config_pv(crtc, state);
|
||||
+ vc4_crtc_config_pv(crtc, encoder, state);
|
||||
|
||||
CRTC_WRITE(PV_CONTROL, CRTC_READ(PV_CONTROL) | PV_CONTROL_EN);
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
From af2318d413f366931b7efaf179c326d67557e64b Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 21 Jun 2021 16:07:22 +0200
|
||||
Subject: [PATCH 024/634] drm/vc4: crtc: Rework the encoder retrieval code
|
||||
(again)
|
||||
|
||||
It turns out the encoder retrieval code, in addition to being
|
||||
unnecessarily complicated, has a bug when only the planes and crtcs are
|
||||
affected by a given atomic commit.
|
||||
|
||||
Indeed, in such a case, either drm_atomic_get_old_connector_state or
|
||||
drm_atomic_get_new_connector_state will return NULL and thus our encoder
|
||||
retrieval code will not match on anything.
|
||||
|
||||
We can however simplify the code by using drm_for_each_encoder_mask, the
|
||||
drm_crtc_state storing the encoders a given CRTC is connected to
|
||||
directly and without relying on any other state.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 30 +++++++++---------------------
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 4 +---
|
||||
2 files changed, 10 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index e5c2e29a6f01..fbc1d4638650 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -282,26 +282,14 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc,
|
||||
* same CRTC.
|
||||
*/
|
||||
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
- struct drm_atomic_state *state,
|
||||
- struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
- struct drm_connector *connector))
|
||||
+ struct drm_crtc_state *state)
|
||||
{
|
||||
- struct drm_connector *connector;
|
||||
- struct drm_connector_list_iter conn_iter;
|
||||
-
|
||||
- drm_connector_list_iter_begin(crtc->dev, &conn_iter);
|
||||
- drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
- struct drm_connector_state *conn_state = get_state(state, connector);
|
||||
+ struct drm_encoder *encoder;
|
||||
|
||||
- if (!conn_state)
|
||||
- continue;
|
||||
+ WARN_ON(hweight32(state->encoder_mask) > 1);
|
||||
|
||||
- if (conn_state->crtc == crtc) {
|
||||
- drm_connector_list_iter_end(&conn_iter);
|
||||
- return connector->encoder;
|
||||
- }
|
||||
- }
|
||||
- drm_connector_list_iter_end(&conn_iter);
|
||||
+ drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask)
|
||||
+ return encoder;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -550,8 +538,7 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
|
||||
crtc);
|
||||
struct vc4_crtc_state *old_vc4_state = to_vc4_crtc_state(old_state);
|
||||
- struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, state,
|
||||
- drm_atomic_get_old_connector_state);
|
||||
+ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, old_state);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
require_hvs_enabled(dev);
|
||||
@@ -578,10 +565,11 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
+ struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state,
|
||||
+ crtc);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
- struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, state,
|
||||
- drm_atomic_get_new_connector_state);
|
||||
+ struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, new_state);
|
||||
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
|
||||
require_hvs_enabled(dev);
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index f5e678491502..60826aca9e5b 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -545,9 +545,7 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc)
|
||||
}
|
||||
|
||||
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
- struct drm_atomic_state *state,
|
||||
- struct drm_connector_state *(*get_state)(struct drm_atomic_state *state,
|
||||
- struct drm_connector *connector));
|
||||
+ struct drm_crtc_state *state);
|
||||
|
||||
struct vc4_crtc_state {
|
||||
struct drm_crtc_state base;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From f13f8a8233fdec553f3788edba1ebf5a6090b330 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 21 Jun 2021 16:13:02 +0200
|
||||
Subject: [PATCH 025/634] drm/vc4: crtc: Add some logging
|
||||
|
||||
The encoder retrieval code has been a source of bugs and glitches in the
|
||||
past and the crtc <-> encoder association been wrong in a number of
|
||||
different ways.
|
||||
|
||||
Add some logging to quickly spot issues if they occur.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index fbc1d4638650..6decaa12a078 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -541,6 +541,9 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, old_state);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
+ drm_dbg(dev, "Disabling CRTC %s (%u) connected to Encoder %s (%u)",
|
||||
+ crtc->name, crtc->base.id, encoder->name, encoder->base.id);
|
||||
+
|
||||
require_hvs_enabled(dev);
|
||||
|
||||
/* Disable vblank irq handling before crtc is disabled. */
|
||||
@@ -572,6 +575,9 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc, new_state);
|
||||
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
|
||||
+ drm_dbg(dev, "Enabling CRTC %s (%u) connected to Encoder %s (%u)",
|
||||
+ crtc->name, crtc->base.id, encoder->name, encoder->base.id);
|
||||
+
|
||||
require_hvs_enabled(dev);
|
||||
|
||||
/* Enable vblank irq handling before crtc is started otherwise
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
From b678d84ff877cf7f4264707f30f5e26c643f8414 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Mon, 21 Jun 2021 17:19:22 +0200
|
||||
Subject: [PATCH 026/634] drm/vc4: Leverage the load tracker on the BCM2711
|
||||
|
||||
The load tracker was initially designed to report and warn about a load
|
||||
too high for the HVS. To do so, it computes for each plane the impact
|
||||
it's going to have on the HVS, and will warn (if it's enabled) if we go
|
||||
over what the hardware can process.
|
||||
|
||||
While the limits being used are a bit irrelevant to the BCM2711, the
|
||||
algorithm to compute the HVS load will be one component used in order to
|
||||
compute the core clock rate on the BCM2711.
|
||||
|
||||
Let's remove the hooks to prevent the load tracker to do its
|
||||
computation, but since we don't have the same limits, don't check them
|
||||
against them, and prevent the debugfs file to enable it from being
|
||||
created.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_debugfs.c | 7 +++++--
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 3 ---
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 16 +++++-----------
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 5 -----
|
||||
4 files changed, 10 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
|
||||
index 6da22af4ee91..ba2d8ea562af 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/debugfs.h>
|
||||
+#include <linux/platform_device.h>
|
||||
|
||||
#include "vc4_drv.h"
|
||||
#include "vc4_regs.h"
|
||||
@@ -26,8 +27,10 @@ vc4_debugfs_init(struct drm_minor *minor)
|
||||
struct vc4_dev *vc4 = to_vc4_dev(minor->dev);
|
||||
struct vc4_debugfs_info_entry *entry;
|
||||
|
||||
- debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
|
||||
- minor->debugfs_root, &vc4->load_tracker_enabled);
|
||||
+ if (!of_device_is_compatible(vc4->hvs->pdev->dev.of_node,
|
||||
+ "brcm,bcm2711-vc5"))
|
||||
+ debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR,
|
||||
+ minor->debugfs_root, &vc4->load_tracker_enabled);
|
||||
|
||||
list_for_each_entry(entry, &vc4->debugfs_list, link) {
|
||||
drm_debugfs_create_files(&entry->info, 1,
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 60826aca9e5b..813c5d0ea98e 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -202,9 +202,6 @@ struct vc4_dev {
|
||||
|
||||
int power_refcount;
|
||||
|
||||
- /* Set to true when the load tracker is supported. */
|
||||
- bool load_tracker_available;
|
||||
-
|
||||
/* Set to true when the load tracker is active. */
|
||||
bool load_tracker_enabled;
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 028f19f7a5f8..41cb4869da50 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -552,9 +552,6 @@ static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state)
|
||||
struct drm_plane *plane;
|
||||
int i;
|
||||
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return 0;
|
||||
-
|
||||
priv_state = drm_atomic_get_private_obj_state(state,
|
||||
&vc4->load_tracker);
|
||||
if (IS_ERR(priv_state))
|
||||
@@ -629,9 +626,6 @@ static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return;
|
||||
-
|
||||
drm_atomic_private_obj_fini(&vc4->load_tracker);
|
||||
}
|
||||
|
||||
@@ -639,9 +633,6 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
|
||||
{
|
||||
struct vc4_load_tracker_state *load_state;
|
||||
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return 0;
|
||||
-
|
||||
load_state = kzalloc(sizeof(*load_state), GFP_KERNEL);
|
||||
if (!load_state)
|
||||
return -ENOMEM;
|
||||
@@ -869,9 +860,12 @@ int vc4_kms_load(struct drm_device *dev)
|
||||
"brcm,bcm2711-vc5");
|
||||
int ret;
|
||||
|
||||
+ /*
|
||||
+ * The limits enforced by the load tracker aren't relevant for
|
||||
+ * the BCM2711, but the load tracker computations are used for
|
||||
+ * the core clock rate calculation.
|
||||
+ */
|
||||
if (!is_vc5) {
|
||||
- vc4->load_tracker_available = true;
|
||||
-
|
||||
/* Start with the load tracker enabled. Can be
|
||||
* disabled through the debugfs load_tracker file.
|
||||
*/
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
index 19161b6ab27f..ac761c683663 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -529,11 +529,6 @@ static void vc4_plane_calc_load(struct drm_plane_state *state)
|
||||
struct vc4_plane_state *vc4_state;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
unsigned int vscale_factor;
|
||||
- struct vc4_dev *vc4;
|
||||
-
|
||||
- vc4 = to_vc4_dev(state->plane->dev);
|
||||
- if (!vc4->load_tracker_available)
|
||||
- return;
|
||||
|
||||
vc4_state = to_vc4_plane_state(state);
|
||||
crtc_state = drm_atomic_get_existing_crtc_state(state->state,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
From cd009dc7e47225c5736cae1d706adcb30b8d4ef5 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 8 Oct 2020 16:08:06 +0200
|
||||
Subject: [PATCH 027/634] drm/vc4: hdmi: Raise the maximum clock rate
|
||||
|
||||
Now that we have the infrastructure in place, we can raise the maximum
|
||||
pixel rate we can reach for HDMI0 on the BCM2711.
|
||||
|
||||
HDMI1 is left untouched since its pixelvalve has a smaller FIFO and
|
||||
would need a clock faster than what we can provide to support the same
|
||||
modes.
|
||||
|
||||
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
|
||||
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 50e9e1f3ac47..80ce69e0ead5 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -2697,7 +2697,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
|
||||
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
|
||||
.debugfs_name = "hdmi0_regs",
|
||||
.card_name = "vc4-hdmi-0",
|
||||
- .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
|
||||
+ .max_pixel_clock = 600000000,
|
||||
.registers = vc5_hdmi_hdmi0_fields,
|
||||
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
|
||||
.phy_lane_mapping = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From 4c78953fff281d78eabbd336a17bcded00d6316f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Fri, 25 Jun 2021 16:22:39 +0200
|
||||
Subject: [PATCH 028/634] drm/vc4: hdmi: Enable the scrambler on reconnection
|
||||
|
||||
If we have a state already and disconnect/reconnect the display, the
|
||||
SCDC messages won't be sent again since we didn't go through a disable /
|
||||
enable cycle.
|
||||
|
||||
In order to fix this, let's call the vc4_hdmi_enable_scrambling function
|
||||
in the detect callback if there is a mode and it needs the scrambler to
|
||||
be enabled.
|
||||
|
||||
Fixes: c85695a2016e ("drm/vc4: hdmi: Enable the scrambler")
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 80ce69e0ead5..87870775471d 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -180,6 +180,8 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
|
||||
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
|
||||
#endif
|
||||
|
||||
+static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder);
|
||||
+
|
||||
static enum drm_connector_status
|
||||
vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
@@ -216,6 +218,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
|
||||
}
|
||||
}
|
||||
|
||||
+ vc4_hdmi_enable_scrambling(&vc4_hdmi->encoder.base.base);
|
||||
pm_runtime_put(&vc4_hdmi->pdev->dev);
|
||||
mutex_unlock(&vc4_hdmi->mutex);
|
||||
return connector_status_connected;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
From 32ab2dd5dc63120f1e006e4a3a6beaafbd5dd550 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Wed, 26 May 2021 16:13:02 +0200
|
||||
Subject: [PATCH 029/634] drm/vc4: Increase the core clock based on HVS load
|
||||
|
||||
Depending on a given HVS output (HVS to PixelValves) and input (planes
|
||||
attached to a channel) load, the HVS needs for the core clock to be
|
||||
raised above its boot time default.
|
||||
|
||||
Failing to do so will result in a vblank timeout and a stalled display
|
||||
pipeline.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 15 +++++
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 2 +
|
||||
drivers/gpu/drm/vc4/vc4_kms.c | 110 ++++++++++++++++++++++++++++++---
|
||||
3 files changed, 118 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
index 6decaa12a078..287dbc89ad64 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -659,12 +659,27 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
|
||||
struct drm_connector *conn;
|
||||
struct drm_connector_state *conn_state;
|
||||
+ struct drm_encoder *encoder;
|
||||
int ret, i;
|
||||
|
||||
ret = vc4_hvs_atomic_check(crtc, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ encoder = vc4_get_crtc_encoder(crtc, crtc_state);
|
||||
+ if (encoder) {
|
||||
+ const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
|
||||
+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
|
||||
+
|
||||
+ mode = &crtc_state->adjusted_mode;
|
||||
+ if (vc4_encoder->type == VC4_ENCODER_TYPE_HDMI0) {
|
||||
+ vc4_state->hvs_load = max(mode->clock * mode->hdisplay / mode->htotal + 1000,
|
||||
+ mode->clock * 9 / 10) * 1000;
|
||||
+ } else {
|
||||
+ vc4_state->hvs_load = mode->clock * 1000;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
for_each_new_connector_in_state(state, conn, conn_state,
|
||||
i) {
|
||||
if (conn_state->crtc != crtc)
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
index 813c5d0ea98e..4329e09d357c 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -558,6 +558,8 @@ struct vc4_crtc_state {
|
||||
unsigned int bottom;
|
||||
} margins;
|
||||
|
||||
+ unsigned long hvs_load;
|
||||
+
|
||||
/* Transitional state below, only valid during atomic commits */
|
||||
bool update_muxing;
|
||||
};
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
index 41cb4869da50..79d4d9dd1394 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
|
||||
@@ -39,9 +39,11 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv)
|
||||
|
||||
struct vc4_hvs_state {
|
||||
struct drm_private_state base;
|
||||
+ unsigned long core_clock_rate;
|
||||
|
||||
struct {
|
||||
unsigned in_use: 1;
|
||||
+ unsigned long fifo_load;
|
||||
struct drm_crtc_commit *pending_commit;
|
||||
} fifo_state[HVS_NUM_CHANNELS];
|
||||
};
|
||||
@@ -340,10 +342,19 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
struct vc4_hvs *hvs = vc4->hvs;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
+ struct vc4_hvs_state *new_hvs_state;
|
||||
struct drm_crtc *crtc;
|
||||
struct vc4_hvs_state *old_hvs_state;
|
||||
int i;
|
||||
|
||||
+ old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
+ if (WARN_ON(!old_hvs_state))
|
||||
+ return;
|
||||
+
|
||||
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
|
||||
+ if (WARN_ON(!new_hvs_state))
|
||||
+ return;
|
||||
+
|
||||
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state;
|
||||
|
||||
@@ -354,12 +365,13 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel);
|
||||
}
|
||||
|
||||
- if (vc4->hvs->hvs5)
|
||||
- clk_set_min_rate(hvs->core_clk, 500000000);
|
||||
+ if (vc4->hvs->hvs5) {
|
||||
+ unsigned long core_rate = max_t(unsigned long,
|
||||
+ 500000000,
|
||||
+ new_hvs_state->core_clock_rate);
|
||||
|
||||
- old_hvs_state = vc4_hvs_get_old_global_state(state);
|
||||
- if (!old_hvs_state)
|
||||
- return;
|
||||
+ clk_set_min_rate(hvs->core_clk, core_rate);
|
||||
+ }
|
||||
|
||||
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
||||
struct vc4_crtc_state *vc4_crtc_state =
|
||||
@@ -399,8 +411,12 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
|
||||
drm_atomic_helper_cleanup_planes(dev, state);
|
||||
|
||||
- if (vc4->hvs->hvs5)
|
||||
- clk_set_min_rate(hvs->core_clk, 0);
|
||||
+ if (vc4->hvs->hvs5) {
|
||||
+ drm_dbg(dev, "Running the core clock at %lu Hz\n",
|
||||
+ new_hvs_state->core_clock_rate);
|
||||
+
|
||||
+ clk_set_min_rate(hvs->core_clk, new_hvs_state->core_clock_rate);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
|
||||
@@ -657,9 +673,9 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
|
||||
|
||||
__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
|
||||
|
||||
-
|
||||
for (i = 0; i < HVS_NUM_CHANNELS; i++) {
|
||||
state->fifo_state[i].in_use = old_state->fifo_state[i].in_use;
|
||||
+ state->fifo_state[i].fifo_load = old_state->fifo_state[i].fifo_load;
|
||||
|
||||
if (!old_state->fifo_state[i].pending_commit)
|
||||
continue;
|
||||
@@ -668,6 +684,8 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
|
||||
drm_crtc_commit_get(old_state->fifo_state[i].pending_commit);
|
||||
}
|
||||
|
||||
+ state->core_clock_rate = old_state->core_clock_rate;
|
||||
+
|
||||
return &state->base;
|
||||
}
|
||||
|
||||
@@ -822,6 +840,76 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+vc4_core_clock_atomic_check(struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(state->dev);
|
||||
+ struct drm_private_state *priv_state;
|
||||
+ struct vc4_hvs_state *hvs_new_state;
|
||||
+ struct vc4_load_tracker_state *load_state;
|
||||
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
|
||||
+ struct drm_crtc *crtc;
|
||||
+ unsigned int num_outputs;
|
||||
+ unsigned long pixel_rate;
|
||||
+ unsigned long cob_rate;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ priv_state = drm_atomic_get_private_obj_state(state,
|
||||
+ &vc4->load_tracker);
|
||||
+ if (IS_ERR(priv_state))
|
||||
+ return PTR_ERR(priv_state);
|
||||
+
|
||||
+ load_state = to_vc4_load_tracker_state(priv_state);
|
||||
+
|
||||
+ hvs_new_state = vc4_hvs_get_global_state(state);
|
||||
+ if (!hvs_new_state)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ for_each_oldnew_crtc_in_state(state, crtc,
|
||||
+ old_crtc_state,
|
||||
+ new_crtc_state,
|
||||
+ i) {
|
||||
+ if (old_crtc_state->active) {
|
||||
+ struct vc4_crtc_state *old_vc4_state =
|
||||
+ to_vc4_crtc_state(old_crtc_state);
|
||||
+ unsigned int channel = old_vc4_state->assigned_channel;
|
||||
+
|
||||
+ hvs_new_state->fifo_state[channel].fifo_load = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (new_crtc_state->active) {
|
||||
+ struct vc4_crtc_state *new_vc4_state =
|
||||
+ to_vc4_crtc_state(new_crtc_state);
|
||||
+ unsigned int channel = new_vc4_state->assigned_channel;
|
||||
+
|
||||
+ hvs_new_state->fifo_state[channel].fifo_load =
|
||||
+ new_vc4_state->hvs_load;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ cob_rate = 0;
|
||||
+ num_outputs = 0;
|
||||
+ for (i = 0; i < HVS_NUM_CHANNELS; i++) {
|
||||
+ if (!hvs_new_state->fifo_state[i].in_use)
|
||||
+ continue;
|
||||
+
|
||||
+ num_outputs++;
|
||||
+ cob_rate += hvs_new_state->fifo_state[i].fifo_load;
|
||||
+ }
|
||||
+
|
||||
+ pixel_rate = load_state->hvs_load;
|
||||
+ if (num_outputs > 1) {
|
||||
+ pixel_rate = (pixel_rate * 40) / 100;
|
||||
+ } else {
|
||||
+ pixel_rate = (pixel_rate * 60) / 100;
|
||||
+ }
|
||||
+
|
||||
+ hvs_new_state->core_clock_rate = max(cob_rate, pixel_rate);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int
|
||||
vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
|
||||
{
|
||||
@@ -839,7 +927,11 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return vc4_load_tracker_atomic_check(state);
|
||||
+ ret = vc4_load_tracker_atomic_check(state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return vc4_core_clock_atomic_check(state);
|
||||
}
|
||||
|
||||
static struct drm_mode_config_helper_funcs vc4_mode_config_helpers = {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
From 13fd7f615657b8b300e1840a1ec393079126f53f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 15:53:03 +0200
|
||||
Subject: [PATCH 030/634] drm/vc4: select PM
|
||||
|
||||
We already depend on runtime PM to get the power domains and clocks for
|
||||
most of the devices supported by the vc4 driver, so let's just select it
|
||||
to make sure it's there, and remove the ifdef.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/Kconfig | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
|
||||
index 345a5570a3da..52a1c309cb4a 100644
|
||||
--- a/drivers/gpu/drm/vc4/Kconfig
|
||||
+++ b/drivers/gpu/drm/vc4/Kconfig
|
||||
@@ -9,6 +9,7 @@ config DRM_VC4
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_PANEL_BRIDGE
|
||||
+ select PM
|
||||
select SND_PCM
|
||||
select SND_PCM_ELD
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
From 05bc2a114f7ee3caeb87377748bcf368d760b436 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 14:37:04 +0200
|
||||
Subject: [PATCH 031/634] drm/probe-helper: Create a HPD IRQ event helper for a
|
||||
single connector
|
||||
|
||||
The drm_helper_hpd_irq_event() function is iterating over all the
|
||||
connectors when an hotplug event is detected.
|
||||
|
||||
During that iteration, it will call each connector detect function and
|
||||
figure out if its status changed.
|
||||
|
||||
Finally, if any connector changed, it will notify the user-space and the
|
||||
clients that something changed on the DRM device.
|
||||
|
||||
This is supposed to be used for drivers that don't have a hotplug
|
||||
interrupt for individual connectors. However, drivers that can use an
|
||||
interrupt for a single connector are left in the dust and can either
|
||||
reimplement the logic used during the iteration for each connector or
|
||||
use that helper and iterate over all connectors all the time.
|
||||
|
||||
Since both are suboptimal, let's create a helper that will only perform
|
||||
the status detection on a single connector.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
|
||||
---
|
||||
|
||||
Changes from v1:
|
||||
- Rename the shared function
|
||||
- Move the hotplug event notification out of the shared function
|
||||
- Added missing locks
|
||||
- Improve the documentation
|
||||
- Switched to drm_dbg_kms
|
||||
---
|
||||
drivers/gpu/drm/drm_probe_helper.c | 120 ++++++++++++++++++++---------
|
||||
include/drm/drm_probe_helper.h | 1 +
|
||||
2 files changed, 86 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
|
||||
index 5606bca3caa8..fcf32ec0b0c8 100644
|
||||
--- a/drivers/gpu/drm/drm_probe_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_probe_helper.c
|
||||
@@ -795,6 +795,86 @@ void drm_kms_helper_poll_fini(struct drm_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
|
||||
|
||||
+static bool check_connector_changed(struct drm_connector *connector)
|
||||
+{
|
||||
+ struct drm_device *dev = connector->dev;
|
||||
+ enum drm_connector_status old_status;
|
||||
+ u64 old_epoch_counter;
|
||||
+ bool changed = false;
|
||||
+
|
||||
+ /* Only handle HPD capable connectors. */
|
||||
+ drm_WARN_ON(dev, !(connector->polled & DRM_CONNECTOR_POLL_HPD));
|
||||
+
|
||||
+ drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex));
|
||||
+
|
||||
+ old_status = connector->status;
|
||||
+ old_epoch_counter = connector->epoch_counter;
|
||||
+
|
||||
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Old epoch counter %llu\n",
|
||||
+ connector->base.id,
|
||||
+ connector->name,
|
||||
+ old_epoch_counter);
|
||||
+
|
||||
+ connector->status = drm_helper_probe_detect(connector, NULL, false);
|
||||
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] status updated from %s to %s\n",
|
||||
+ connector->base.id,
|
||||
+ connector->name,
|
||||
+ drm_get_connector_status_name(old_status),
|
||||
+ drm_get_connector_status_name(connector->status));
|
||||
+
|
||||
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] New epoch counter %llu\n",
|
||||
+ connector->base.id,
|
||||
+ connector->name,
|
||||
+ connector->epoch_counter);
|
||||
+
|
||||
+ /*
|
||||
+ * Check if epoch counter had changed, meaning that we need
|
||||
+ * to send a uevent.
|
||||
+ */
|
||||
+ if (old_epoch_counter != connector->epoch_counter)
|
||||
+ changed = true;
|
||||
+
|
||||
+ return changed;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * drm_connector_helper_hpd_irq_event - hotplug processing
|
||||
+ * @connector: drm_connector
|
||||
+ *
|
||||
+ * Drivers can use this helper function to run a detect cycle on a connector
|
||||
+ * which has the DRM_CONNECTOR_POLL_HPD flag set in its &polled member.
|
||||
+ *
|
||||
+ * This helper function is useful for drivers which can track hotplug
|
||||
+ * interrupts for a single connector. Drivers that want to send a
|
||||
+ * hotplug event for all connectors or can't track hotplug interrupts
|
||||
+ * per connector need to use drm_helper_hpd_irq_event().
|
||||
+ *
|
||||
+ * This function must be called from process context with no mode
|
||||
+ * setting locks held.
|
||||
+ *
|
||||
+ * Note that a connector can be both polled and probed from the hotplug
|
||||
+ * handler, in case the hotplug interrupt is known to be unreliable.
|
||||
+ */
|
||||
+bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector)
|
||||
+{
|
||||
+ struct drm_device *dev = connector->dev;
|
||||
+ bool changed;
|
||||
+
|
||||
+ mutex_lock(&dev->mode_config.mutex);
|
||||
+ changed = check_connector_changed(connector);
|
||||
+ mutex_unlock(&dev->mode_config.mutex);
|
||||
+
|
||||
+ if (changed) {
|
||||
+ drm_kms_helper_hotplug_event(dev);
|
||||
+ drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Sent hotplug event\n",
|
||||
+ connector->base.id,
|
||||
+ connector->name);
|
||||
+ }
|
||||
+
|
||||
+ return changed;
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_connector_helper_hpd_irq_event);
|
||||
+
|
||||
/**
|
||||
* drm_helper_hpd_irq_event - hotplug processing
|
||||
* @dev: drm_device
|
||||
@@ -808,9 +888,10 @@ EXPORT_SYMBOL(drm_kms_helper_poll_fini);
|
||||
* interrupts for each connector.
|
||||
*
|
||||
* Drivers which support hotplug interrupts for each connector individually and
|
||||
- * which have a more fine-grained detect logic should bypass this code and
|
||||
- * directly call drm_kms_helper_hotplug_event() in case the connector state
|
||||
- * changed.
|
||||
+ * which have a more fine-grained detect logic can use
|
||||
+ * drm_connector_helper_hpd_irq_event(). Alternatively, they should bypass this
|
||||
+ * code and directly call drm_kms_helper_hotplug_event() in case the connector
|
||||
+ * state changed.
|
||||
*
|
||||
* This function must be called from process context with no mode
|
||||
* setting locks held.
|
||||
@@ -822,9 +903,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
- enum drm_connector_status old_status;
|
||||
bool changed = false;
|
||||
- u64 old_epoch_counter;
|
||||
|
||||
if (!dev->mode_config.poll_enabled)
|
||||
return false;
|
||||
@@ -832,37 +911,8 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
- /* Only handle HPD capable connectors. */
|
||||
- if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
|
||||
- continue;
|
||||
-
|
||||
- old_status = connector->status;
|
||||
-
|
||||
- old_epoch_counter = connector->epoch_counter;
|
||||
-
|
||||
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n", connector->base.id,
|
||||
- connector->name,
|
||||
- old_epoch_counter);
|
||||
-
|
||||
- connector->status = drm_helper_probe_detect(connector, NULL, false);
|
||||
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
|
||||
- connector->base.id,
|
||||
- connector->name,
|
||||
- drm_get_connector_status_name(old_status),
|
||||
- drm_get_connector_status_name(connector->status));
|
||||
-
|
||||
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n",
|
||||
- connector->base.id,
|
||||
- connector->name,
|
||||
- connector->epoch_counter);
|
||||
-
|
||||
- /*
|
||||
- * Check if epoch counter had changed, meaning that we need
|
||||
- * to send a uevent.
|
||||
- */
|
||||
- if (old_epoch_counter != connector->epoch_counter)
|
||||
+ if (check_connector_changed(connector))
|
||||
changed = true;
|
||||
-
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
|
||||
index 8d3ed2834d34..04c57564c397 100644
|
||||
--- a/include/drm/drm_probe_helper.h
|
||||
+++ b/include/drm/drm_probe_helper.h
|
||||
@@ -18,6 +18,7 @@ int drm_helper_probe_detect(struct drm_connector *connector,
|
||||
void drm_kms_helper_poll_init(struct drm_device *dev);
|
||||
void drm_kms_helper_poll_fini(struct drm_device *dev);
|
||||
bool drm_helper_hpd_irq_event(struct drm_device *dev);
|
||||
+bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector);
|
||||
void drm_kms_helper_hotplug_event(struct drm_device *dev);
|
||||
|
||||
void drm_kms_helper_poll_disable(struct drm_device *dev);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
From 9219926b71a1c16eb77ef9d96b14913b7f03757d Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Ripard <maxime@cerno.tech>
|
||||
Date: Thu, 19 Aug 2021 13:50:12 +0200
|
||||
Subject: [PATCH 032/634] drm/vc4: hdmi: Actually check for the connector
|
||||
status in hotplug
|
||||
|
||||
The drm_helper_hpd_irq_event() documentation states that this function
|
||||
is "useful for drivers which can't or don't track hotplug interrupts for
|
||||
each connector." and that "Drivers which support hotplug interrupts for
|
||||
each connector individually and which have a more fine-grained detect
|
||||
logic should bypass this code and directly call
|
||||
drm_kms_helper_hotplug_event()". This is thus what we ended-up doing.
|
||||
|
||||
However, what this actually means, and is further explained in the
|
||||
drm_kms_helper_hotplug_event() documentation, is that
|
||||
drm_kms_helper_hotplug_event() should be called by drivers that can
|
||||
track the connection status change, and if it has changed we should call
|
||||
that function.
|
||||
|
||||
This underlying expectation we failed to provide is that the caller of
|
||||
drm_kms_helper_hotplug_event() should call drm_helper_probe_detect() to
|
||||
probe the new status of the connector.
|
||||
|
||||
Since we didn't do it, it meant that even though we were sending the
|
||||
notification to user-space and the DRM clients that something changed we
|
||||
never probed or updated our internal connector status ourselves.
|
||||
|
||||
This went mostly unnoticed since the detect callback usually doesn't
|
||||
have any side-effect. Also, if we were using the DRM fbdev emulation
|
||||
(which is a DRM client), or any user-space application that can deal
|
||||
with hotplug events, chances are they would react to the hotplug event
|
||||
by probing the connector status eventually.
|
||||
|
||||
However, now that we have to enable the scrambler in detect() if it was
|
||||
enabled it has a side effect, and an application such as Kodi or
|
||||
modetest doesn't deal with hotplug events. This resulted with a black
|
||||
screen when Kodi or modetest was running when a screen was disconnected
|
||||
and then reconnected, or switched off and on.
|
||||
|
||||
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
index 87870775471d..053fbaf765ca 100644
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -1783,10 +1783,11 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
|
||||
static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
|
||||
{
|
||||
struct vc4_hdmi *vc4_hdmi = priv;
|
||||
- struct drm_device *dev = vc4_hdmi->connector.dev;
|
||||
+ struct drm_connector *connector = &vc4_hdmi->connector;
|
||||
+ struct drm_device *dev = connector->dev;
|
||||
|
||||
if (dev && dev->registered)
|
||||
- drm_kms_helper_hotplug_event(dev);
|
||||
+ drm_connector_helper_hpd_irq_event(connector);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
From 54c471a9b4588ba9bba0d9f3becb9ebcbf3f2c20 Mon Sep 17 00:00:00 2001
|
||||
From: Dan Pasanen <dan.pasanen@gmail.com>
|
||||
Date: Thu, 21 Sep 2017 09:55:42 -0500
|
||||
Subject: [PATCH 033/634] arm: partially revert
|
||||
702b94bff3c50542a6e4ab9a4f4cef093262fe65
|
||||
|
||||
* Re-expose some dmi APIs for use in VCSM
|
||||
---
|
||||
arch/arm/include/asm/cacheflush.h | 21 +++++++++++++++++++++
|
||||
arch/arm/include/asm/glue-cache.h | 2 ++
|
||||
arch/arm/mm/proc-macros.S | 2 ++
|
||||
arch/arm/mm/proc-syms.c | 3 +++
|
||||
4 files changed, 28 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
|
||||
index 5e56288e343b..d3672588ca84 100644
|
||||
--- a/arch/arm/include/asm/cacheflush.h
|
||||
+++ b/arch/arm/include/asm/cacheflush.h
|
||||
@@ -91,6 +91,21 @@
|
||||
* DMA Cache Coherency
|
||||
* ===================
|
||||
*
|
||||
+ * dma_inv_range(start, end)
|
||||
+ *
|
||||
+ * Invalidate (discard) the specified virtual address range.
|
||||
+ * May not write back any entries. If 'start' or 'end'
|
||||
+ * are not cache line aligned, those lines must be written
|
||||
+ * back.
|
||||
+ * - start - virtual start address
|
||||
+ * - end - virtual end address
|
||||
+ *
|
||||
+ * dma_clean_range(start, end)
|
||||
+ *
|
||||
+ * Clean (write back) the specified virtual address range.
|
||||
+ * - start - virtual start address
|
||||
+ * - end - virtual end address
|
||||
+ *
|
||||
* dma_flush_range(start, end)
|
||||
*
|
||||
* Clean and invalidate the specified virtual address range.
|
||||
@@ -112,6 +127,8 @@ struct cpu_cache_fns {
|
||||
void (*dma_map_area)(const void *, size_t, int);
|
||||
void (*dma_unmap_area)(const void *, size_t, int);
|
||||
|
||||
+ void (*dma_inv_range)(const void *, const void *);
|
||||
+ void (*dma_clean_range)(const void *, const void *);
|
||||
void (*dma_flush_range)(const void *, const void *);
|
||||
} __no_randomize_layout;
|
||||
|
||||
@@ -137,6 +154,8 @@ extern struct cpu_cache_fns cpu_cache;
|
||||
* is visible to DMA, or data written by DMA to system memory is
|
||||
* visible to the CPU.
|
||||
*/
|
||||
+#define dmac_inv_range cpu_cache.dma_inv_range
|
||||
+#define dmac_clean_range cpu_cache.dma_clean_range
|
||||
#define dmac_flush_range cpu_cache.dma_flush_range
|
||||
|
||||
#else
|
||||
@@ -156,6 +175,8 @@ extern void __cpuc_flush_dcache_area(void *, size_t);
|
||||
* is visible to DMA, or data written by DMA to system memory is
|
||||
* visible to the CPU.
|
||||
*/
|
||||
+extern void dmac_inv_range(const void *, const void *);
|
||||
+extern void dmac_clean_range(const void *, const void *);
|
||||
extern void dmac_flush_range(const void *, const void *);
|
||||
|
||||
#endif
|
||||
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
|
||||
index 724f8dac1e5b..aa74173092dd 100644
|
||||
--- a/arch/arm/include/asm/glue-cache.h
|
||||
+++ b/arch/arm/include/asm/glue-cache.h
|
||||
@@ -155,6 +155,8 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
|
||||
#define __cpuc_coherent_user_range __glue(_CACHE,_coherent_user_range)
|
||||
#define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area)
|
||||
|
||||
+#define dmac_inv_range __glue(_CACHE,_dma_inv_range)
|
||||
+#define dmac_clean_range __glue(_CACHE,_dma_clean_range)
|
||||
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
|
||||
#endif
|
||||
|
||||
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
|
||||
index d9f7dfe2a7ed..687d126d1c6c 100644
|
||||
--- a/arch/arm/mm/proc-macros.S
|
||||
+++ b/arch/arm/mm/proc-macros.S
|
||||
@@ -334,6 +334,8 @@ ENTRY(\name\()_cache_fns)
|
||||
.long \name\()_flush_kern_dcache_area
|
||||
.long \name\()_dma_map_area
|
||||
.long \name\()_dma_unmap_area
|
||||
+ .long \name\()_dma_inv_range
|
||||
+ .long \name\()_dma_clean_range
|
||||
.long \name\()_dma_flush_range
|
||||
.size \name\()_cache_fns, . - \name\()_cache_fns
|
||||
.endm
|
||||
diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
|
||||
index e21249548e9f..33e4a9b8f1ba 100644
|
||||
--- a/arch/arm/mm/proc-syms.c
|
||||
+++ b/arch/arm/mm/proc-syms.c
|
||||
@@ -27,6 +27,9 @@ EXPORT_SYMBOL(__cpuc_flush_user_all);
|
||||
EXPORT_SYMBOL(__cpuc_flush_user_range);
|
||||
EXPORT_SYMBOL(__cpuc_coherent_kern_range);
|
||||
EXPORT_SYMBOL(__cpuc_flush_dcache_area);
|
||||
+EXPORT_SYMBOL(dmac_inv_range);
|
||||
+EXPORT_SYMBOL(dmac_clean_range);
|
||||
+EXPORT_SYMBOL(dmac_flush_range);
|
||||
#else
|
||||
EXPORT_SYMBOL(cpu_cache);
|
||||
#endif
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
From 7e6b77b2bba73652ea10978bba06cde6c7af6046 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 29 Oct 2018 14:45:45 +0000
|
||||
Subject: [PATCH 034/634] Revert "rtc: pcf8523: properly handle oscillator stop
|
||||
bit"
|
||||
|
||||
This reverts commit ede44c908d44b166a5b6bd7caacd105c2ff5a70f.
|
||||
|
||||
See: https://github.com/raspberrypi/firmware/issues/1065
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/rtc/rtc-pcf8523.c | 24 ++++++++++++++++++++++--
|
||||
1 file changed, 22 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
|
||||
index 8b6fb20774bf..ad2231f1faac 100644
|
||||
--- a/drivers/rtc/rtc-pcf8523.c
|
||||
+++ b/drivers/rtc/rtc-pcf8523.c
|
||||
@@ -242,8 +242,28 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
- if (regs[0] & PCF8523_SECONDS_OS)
|
||||
- return -EINVAL;
|
||||
+ if (regs[0] & PCF8523_SECONDS_OS) {
|
||||
+ /*
|
||||
+ * If the oscillator was stopped, try to clear the flag. Upon
|
||||
+ * power-up the flag is always set, but if we cannot clear it
|
||||
+ * the oscillator isn't running properly for some reason. The
|
||||
+ * sensible thing therefore is to return an error, signalling
|
||||
+ * that the clock cannot be assumed to be correct.
|
||||
+ */
|
||||
+
|
||||
+ regs[0] &= ~PCF8523_SECONDS_OS;
|
||||
+
|
||||
+ err = pcf8523_write(client, PCF8523_REG_SECONDS, regs[0]);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ err = pcf8523_read(client, PCF8523_REG_SECONDS, ®s[0]);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ if (regs[0] & PCF8523_SECONDS_OS)
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
|
||||
tm->tm_sec = bcd2bin(regs[0] & 0x7f);
|
||||
tm->tm_min = bcd2bin(regs[1] & 0x7f);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
From e1aca9751c1ca2bb868435f32d985dc5622fb36f Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Fri, 15 Mar 2019 21:11:10 +0000
|
||||
Subject: [PATCH 035/634] Revert "staging: bcm2835-audio: Drop DT dependency"
|
||||
|
||||
This reverts commit b7491a9fca2dc2535b9dc922550a37c5baae9d3d.
|
||||
---
|
||||
.../vc04_services/bcm2835-audio/bcm2835.c | 31 +++++++++++++------
|
||||
1 file changed, 22 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
|
||||
index c250fbef2fa3..b42917c25050 100644
|
||||
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
|
||||
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
|
||||
@@ -6,13 +6,13 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
|
||||
#include "bcm2835.h"
|
||||
|
||||
static bool enable_hdmi;
|
||||
static bool enable_headphones;
|
||||
static bool enable_compat_alsa = true;
|
||||
-static int num_channels = MAX_SUBSTREAMS;
|
||||
|
||||
module_param(enable_hdmi, bool, 0444);
|
||||
MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device");
|
||||
@@ -21,8 +21,6 @@ MODULE_PARM_DESC(enable_headphones, "Enables Headphones virtual audio device");
|
||||
module_param(enable_compat_alsa, bool, 0444);
|
||||
MODULE_PARM_DESC(enable_compat_alsa,
|
||||
"Enables ALSA compatibility virtual audio device");
|
||||
-module_param(num_channels, int, 0644);
|
||||
-MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)");
|
||||
|
||||
static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
|
||||
{
|
||||
@@ -296,19 +294,28 @@ static int snd_add_child_devices(struct device *device, u32 numchans)
|
||||
static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
+ u32 numchans;
|
||||
int err;
|
||||
|
||||
- if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) {
|
||||
- num_channels = MAX_SUBSTREAMS;
|
||||
- dev_warn(dev, "Illegal num_channels value, will use %u\n",
|
||||
- num_channels);
|
||||
+ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
|
||||
+ &numchans);
|
||||
+ if (err) {
|
||||
+ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
|
||||
+ numchans = MAX_SUBSTREAMS;
|
||||
+ dev_warn(dev,
|
||||
+ "Illegal 'brcm,pwm-channels' value, will use %u\n",
|
||||
+ numchans);
|
||||
}
|
||||
|
||||
err = bcm2835_devm_add_vchi_ctx(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- err = snd_add_child_devices(dev, num_channels);
|
||||
+ err = snd_add_child_devices(dev, numchans);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -330,6 +337,12 @@ static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
|
||||
|
||||
#endif
|
||||
|
||||
+static const struct of_device_id snd_bcm2835_of_match_table[] = {
|
||||
+ { .compatible = "brcm,bcm2835-audio",},
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
|
||||
+
|
||||
static struct platform_driver bcm2835_alsa_driver = {
|
||||
.probe = snd_bcm2835_alsa_probe,
|
||||
#ifdef CONFIG_PM
|
||||
@@ -338,6 +351,7 @@ static struct platform_driver bcm2835_alsa_driver = {
|
||||
#endif
|
||||
.driver = {
|
||||
.name = "bcm2835_audio",
|
||||
+ .of_match_table = snd_bcm2835_of_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(bcm2835_alsa_driver);
|
||||
@@ -345,4 +359,3 @@ module_platform_driver(bcm2835_alsa_driver);
|
||||
MODULE_AUTHOR("Dom Cobley");
|
||||
MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
|
||||
MODULE_LICENSE("GPL");
|
||||
-MODULE_ALIAS("platform:bcm2835_audio");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
From 1913228233ca712bcf4a1798a14dae8d73a7812d Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 20 Apr 2020 13:41:10 +0100
|
||||
Subject: [PATCH 036/634] Revert "spi: spidev: Fix CS polarity if GPIO
|
||||
descriptors are used"
|
||||
|
||||
This reverts commit 83b2a8fe43bda0c11981ad6afa5dd0104d78be28.
|
||||
---
|
||||
drivers/spi/spidev.c | 5 -----
|
||||
1 file changed, 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
|
||||
index 1bd73e322b7b..795bef1efcc6 100644
|
||||
--- a/drivers/spi/spidev.c
|
||||
+++ b/drivers/spi/spidev.c
|
||||
@@ -402,7 +402,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
else
|
||||
retval = get_user(tmp, (u32 __user *)arg);
|
||||
if (retval == 0) {
|
||||
- struct spi_controller *ctlr = spi->controller;
|
||||
u32 save = spi->mode;
|
||||
|
||||
if (tmp & ~SPI_MODE_MASK) {
|
||||
@@ -410,10 +409,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
}
|
||||
|
||||
- if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
|
||||
- ctlr->cs_gpiods[spi->chip_select])
|
||||
- tmp |= SPI_CS_HIGH;
|
||||
-
|
||||
tmp |= spi->mode & ~SPI_MODE_MASK;
|
||||
spi->mode = (u16)tmp;
|
||||
retval = spi_setup(spi);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
From d5fdbbc0de13fa9a40f02e1efb2a141bed7d7c26 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 3 Nov 2020 11:49:53 +0000
|
||||
Subject: [PATCH 037/634] Revert "mailbox: avoid timer start from callback"
|
||||
|
||||
This reverts commit c7dacf5b0f32957b24ef29df1207dc2cd8307743.
|
||||
|
||||
The Pi 400 shutdown/poweroff mechanism relies on being able to set
|
||||
a GPIO on the expander in the pm_power_off handler, something that
|
||||
requires two mailbox calls - GET_GPIO_STATE and SET_GPIO_STATE. A
|
||||
recent kernel change introduces a reasonable possibility that the
|
||||
GET call doesn't completes, and bisecting led to a commit from
|
||||
October that changes the timer usage of the mailbox.
|
||||
|
||||
My theory is that there is a race condition in the new code that breaks
|
||||
the poll timer, but that it normally goes unnoticed because subsequent
|
||||
mailbox activity wakes it up again. The power-off mailbox calls happen
|
||||
at a time when other subsystems have been shut down, so if one of them
|
||||
fails then there is nothing to allow it to recover.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/3941
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/mailbox/mailbox.c | 12 +++++-------
|
||||
1 file changed, 5 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
|
||||
index 3e7d4b20ab34..0b821a5b2db8 100644
|
||||
--- a/drivers/mailbox/mailbox.c
|
||||
+++ b/drivers/mailbox/mailbox.c
|
||||
@@ -82,12 +82,9 @@ static void msg_submit(struct mbox_chan *chan)
|
||||
exit:
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
- /* kick start the timer immediately to avoid delays */
|
||||
- if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
|
||||
- /* but only if not already active */
|
||||
- if (!hrtimer_active(&chan->mbox->poll_hrt))
|
||||
- hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
|
||||
- }
|
||||
+ if (!err && (chan->txdone_method & TXDONE_BY_POLL))
|
||||
+ /* kick start the timer immediately to avoid delays */
|
||||
+ hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
static void tx_tick(struct mbox_chan *chan, int r)
|
||||
@@ -125,10 +122,11 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
|
||||
struct mbox_chan *chan = &mbox->chans[i];
|
||||
|
||||
if (chan->active_req && chan->cl) {
|
||||
- resched = true;
|
||||
txdone = chan->mbox->ops->last_tx_done(chan);
|
||||
if (txdone)
|
||||
tx_tick(chan, 0);
|
||||
+ else
|
||||
+ resched = true;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From b16229ce33d1f597585e7a9adb2797698cd70d53 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 1 Mar 2021 09:12:44 +0000
|
||||
Subject: [PATCH 038/634] Revert "Bluetooth: Always request for user
|
||||
confirmation for Just Works (LE SC)"
|
||||
|
||||
This reverts commit ffee202a78c2980688bc5d2f7d56480e69a5e0c9.
|
||||
|
||||
The commit "Bluetooth: Always request for user confirmation for Just
|
||||
Works" prevents BLE devices pairing in (at least) the Raspberry Pi OS
|
||||
GUI. After reverting it, pairing works again. Although this companion
|
||||
commit ("... (LE SC)") has not been demonstrated to be problematic,
|
||||
it follows the same logic and therefore could affect some use cases.
|
||||
|
||||
If another solution to the problem is found then this reversion will
|
||||
be removed.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/4139
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
net/bluetooth/smp.c | 5 +----
|
||||
1 file changed, 1 insertion(+), 4 deletions(-)
|
||||
|
||||
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
|
||||
index 11f853d0500f..3efb60918dda 100644
|
||||
--- a/net/bluetooth/smp.c
|
||||
+++ b/net/bluetooth/smp.c
|
||||
@@ -2207,7 +2207,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (err)
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
- if (smp->method == REQ_OOB) {
|
||||
+ if (smp->method == JUST_WORKS || smp->method == REQ_OOB) {
|
||||
if (hcon->out) {
|
||||
sc_dhkey_check(smp);
|
||||
SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
|
||||
@@ -2222,9 +2222,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
confirm_hint = 0;
|
||||
|
||||
confirm:
|
||||
- if (smp->method == JUST_WORKS)
|
||||
- confirm_hint = 1;
|
||||
-
|
||||
err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst, hcon->type,
|
||||
hcon->dst_type, passkey, confirm_hint);
|
||||
if (err)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
From 08df3cf28d296e75a24617b3f42e4074424d8723 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 1 Mar 2021 09:14:35 +0000
|
||||
Subject: [PATCH 039/634] Revert "Bluetooth: Always request for user
|
||||
confirmation for Just Works"
|
||||
|
||||
This reverts commit 92516cd97fd4d8ad5b1421a0d51771044f453a5f.
|
||||
|
||||
Thi commit "Bluetooth: Always request for user confirmation for Just
|
||||
Works" prevents BLE devices pairing in (at least) the Raspberry Pi OS
|
||||
GUI. After reverting it, pairing works again.
|
||||
|
||||
If another solution to the problem is found then this reversion will
|
||||
be removed.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/4139
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
net/bluetooth/smp.c | 11 ++---------
|
||||
1 file changed, 2 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
|
||||
index 3efb60918dda..6f555b3c96a6 100644
|
||||
--- a/net/bluetooth/smp.c
|
||||
+++ b/net/bluetooth/smp.c
|
||||
@@ -883,16 +883,9 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
|
||||
smp->method = JUST_WORKS;
|
||||
|
||||
- /* If Just Works, Continue with Zero TK and ask user-space for
|
||||
- * confirmation */
|
||||
+ /* If Just Works, Continue with Zero TK */
|
||||
if (smp->method == JUST_WORKS) {
|
||||
- ret = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
|
||||
- hcon->type,
|
||||
- hcon->dst_type,
|
||||
- passkey, 1);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- set_bit(SMP_FLAG_WAIT_USER, &smp->flags);
|
||||
+ set_bit(SMP_FLAG_TK_VALID, &smp->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
From cca91bca835263af74f73a048e15907037163f3e Mon Sep 17 00:00:00 2001
|
||||
From: Steve Glendinning <steve.glendinning@smsc.com>
|
||||
Date: Thu, 19 Feb 2015 18:47:12 +0000
|
||||
Subject: [PATCH 040/634] smsx95xx: fix crimes against truesize
|
||||
|
||||
smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings.
|
||||
|
||||
This patch stops smsc95xx from changing truesize.
|
||||
|
||||
Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
|
||||
---
|
||||
drivers/net/usb/smsc95xx.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
|
||||
index 26b1bd8e845b..befbabddb7f2 100644
|
||||
--- a/drivers/net/usb/smsc95xx.c
|
||||
+++ b/drivers/net/usb/smsc95xx.c
|
||||
@@ -67,6 +67,10 @@ static bool turbo_mode = true;
|
||||
module_param(turbo_mode, bool, 0644);
|
||||
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
|
||||
|
||||
+static bool truesize_mode = false;
|
||||
+module_param(truesize_mode, bool, 0644);
|
||||
+MODULE_PARM_DESC(truesize_mode, "Report larger truesize value");
|
||||
+
|
||||
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
|
||||
u32 *data, int in_pm)
|
||||
{
|
||||
@@ -1830,7 +1834,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||||
if (dev->net->features & NETIF_F_RXCSUM)
|
||||
smsc95xx_rx_csum_offload(skb);
|
||||
skb_trim(skb, skb->len - 4); /* remove fcs */
|
||||
- skb->truesize = size + sizeof(struct sk_buff);
|
||||
+ if (truesize_mode)
|
||||
+ skb->truesize = size + sizeof(struct sk_buff);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1848,7 +1853,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
||||
if (dev->net->features & NETIF_F_RXCSUM)
|
||||
smsc95xx_rx_csum_offload(ax_skb);
|
||||
skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
|
||||
- ax_skb->truesize = size + sizeof(struct sk_buff);
|
||||
+ if (truesize_mode)
|
||||
+ ax_skb->truesize = size + sizeof(struct sk_buff);
|
||||
|
||||
usbnet_skb_return(dev, ax_skb);
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
From 533c49dd675017d8027f555106df6c135a787c48 Mon Sep 17 00:00:00 2001
|
||||
From: Sam Nazarko <email@samnazarko.co.uk>
|
||||
Date: Fri, 1 Apr 2016 17:27:21 +0100
|
||||
Subject: [PATCH 041/634] smsc95xx: Experimental: Enable turbo_mode and
|
||||
packetsize=2560 by default
|
||||
|
||||
See: http://forum.kodi.tv/showthread.php?tid=285288
|
||||
---
|
||||
drivers/net/usb/smsc95xx.c | 14 +++++++++-----
|
||||
1 file changed, 9 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
|
||||
index befbabddb7f2..a7bb0bfa51a7 100644
|
||||
--- a/drivers/net/usb/smsc95xx.c
|
||||
+++ b/drivers/net/usb/smsc95xx.c
|
||||
@@ -71,6 +71,10 @@ static bool truesize_mode = false;
|
||||
module_param(truesize_mode, bool, 0644);
|
||||
MODULE_PARM_DESC(truesize_mode, "Report larger truesize value");
|
||||
|
||||
+static int packetsize = 2560;
|
||||
+module_param(packetsize, int, 0644);
|
||||
+MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
|
||||
+
|
||||
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
|
||||
u32 *data, int in_pm)
|
||||
{
|
||||
@@ -905,13 +909,13 @@ static int smsc95xx_reset(struct usbnet *dev)
|
||||
|
||||
if (!turbo_mode) {
|
||||
burst_cap = 0;
|
||||
- dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
|
||||
+ dev->rx_urb_size = packetsize ? packetsize : MAX_SINGLE_PACKET_SIZE;
|
||||
} else if (dev->udev->speed == USB_SPEED_HIGH) {
|
||||
- burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
|
||||
- dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
|
||||
+ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_HS_BURST_CAP_SIZE;
|
||||
+ burst_cap = dev->rx_urb_size / HS_USB_PKT_SIZE;
|
||||
} else {
|
||||
- burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
|
||||
- dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
|
||||
+ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_FS_BURST_CAP_SIZE;
|
||||
+ burst_cap = dev->rx_urb_size / FS_USB_PKT_SIZE;
|
||||
}
|
||||
|
||||
netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
From de98c2df30df39fc7ea36af74fbe791b2be5c867 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 26 Mar 2013 17:26:38 +0000
|
||||
Subject: [PATCH 042/634] Allow mac address to be set in smsc95xx
|
||||
|
||||
Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/net/usb/smsc95xx.c | 56 ++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 56 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
|
||||
index a7bb0bfa51a7..8a035345d617 100644
|
||||
--- a/drivers/net/usb/smsc95xx.c
|
||||
+++ b/drivers/net/usb/smsc95xx.c
|
||||
@@ -50,6 +50,7 @@
|
||||
#define SUSPEND_SUSPEND3 (0x08)
|
||||
#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
|
||||
SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
|
||||
+#define MAC_ADDR_LEN (6)
|
||||
|
||||
struct smsc95xx_priv {
|
||||
u32 mac_cr;
|
||||
@@ -75,6 +76,10 @@ static int packetsize = 2560;
|
||||
module_param(packetsize, int, 0644);
|
||||
MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
|
||||
|
||||
+static char *macaddr = ":";
|
||||
+module_param(macaddr, charp, 0);
|
||||
+MODULE_PARM_DESC(macaddr, "MAC address");
|
||||
+
|
||||
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
|
||||
u32 *data, int in_pm)
|
||||
{
|
||||
@@ -761,6 +766,53 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
|
||||
return phy_mii_ioctl(netdev->phydev, rq, cmd);
|
||||
}
|
||||
|
||||
+/* Check the macaddr module parameter for a MAC address */
|
||||
+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
|
||||
+{
|
||||
+ int i, j, got_num, num;
|
||||
+ u8 mtbl[MAC_ADDR_LEN];
|
||||
+
|
||||
+ if (macaddr[0] == ':')
|
||||
+ return 0;
|
||||
+
|
||||
+ i = 0;
|
||||
+ j = 0;
|
||||
+ num = 0;
|
||||
+ got_num = 0;
|
||||
+ while (j < MAC_ADDR_LEN) {
|
||||
+ if (macaddr[i] && macaddr[i] != ':') {
|
||||
+ got_num++;
|
||||
+ if ('0' <= macaddr[i] && macaddr[i] <= '9')
|
||||
+ num = num * 16 + macaddr[i] - '0';
|
||||
+ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
|
||||
+ num = num * 16 + 10 + macaddr[i] - 'A';
|
||||
+ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
|
||||
+ num = num * 16 + 10 + macaddr[i] - 'a';
|
||||
+ else
|
||||
+ break;
|
||||
+ i++;
|
||||
+ } else if (got_num == 2) {
|
||||
+ mtbl[j++] = (u8) num;
|
||||
+ num = 0;
|
||||
+ got_num = 0;
|
||||
+ i++;
|
||||
+ } else {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (j == MAC_ADDR_LEN) {
|
||||
+ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
|
||||
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
|
||||
+ mtbl[3], mtbl[4], mtbl[5]);
|
||||
+ for (i = 0; i < MAC_ADDR_LEN; i++)
|
||||
+ dev_mac[i] = mtbl[i];
|
||||
+ return 1;
|
||||
+ } else {
|
||||
+ return 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void smsc95xx_init_mac_address(struct usbnet *dev)
|
||||
{
|
||||
/* maybe the boot loader passed the MAC address in devicetree */
|
||||
@@ -783,6 +835,10 @@ static void smsc95xx_init_mac_address(struct usbnet *dev)
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Check module parameters */
|
||||
+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
|
||||
+ return;
|
||||
+
|
||||
/* no useful static MAC address found. generate a random one */
|
||||
eth_hw_addr_random(dev->net);
|
||||
netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
From 40a04a8163ad602e595998d97cd3278e85e7b398 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 27 Nov 2017 17:14:54 +0000
|
||||
Subject: [PATCH 043/634] cgroup: Disable cgroup "memory" by default
|
||||
|
||||
Some Raspberry Pis have limited RAM and most users won't use the
|
||||
cgroup memory support so it is disabled by default. Enable with:
|
||||
|
||||
cgroup_enable=memory
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1950
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
kernel/cgroup/cgroup.c | 38 ++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 38 insertions(+)
|
||||
|
||||
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
|
||||
index d6ea872b23aa..db12e07ce531 100644
|
||||
--- a/kernel/cgroup/cgroup.c
|
||||
+++ b/kernel/cgroup/cgroup.c
|
||||
@@ -5788,6 +5788,9 @@ int __init cgroup_init_early(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static u16 cgroup_enable_mask __initdata;
|
||||
+static int __init cgroup_disable(char *str);
|
||||
+
|
||||
/**
|
||||
* cgroup_init - cgroup initialization
|
||||
*
|
||||
@@ -5826,6 +5829,12 @@ int __init cgroup_init(void)
|
||||
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
|
||||
+ /*
|
||||
+ * Apply an implicit disable, knowing that an explicit enable will
|
||||
+ * prevent if from doing anything.
|
||||
+ */
|
||||
+ cgroup_disable("memory");
|
||||
+
|
||||
for_each_subsys(ss, ssid) {
|
||||
if (ss->early_init) {
|
||||
struct cgroup_subsys_state *css =
|
||||
@@ -6409,6 +6418,10 @@ static int __init cgroup_disable(char *str)
|
||||
strcmp(token, ss->legacy_name))
|
||||
continue;
|
||||
|
||||
+ /* An explicit cgroup_enable overrides a disable */
|
||||
+ if (cgroup_enable_mask & (1 << i))
|
||||
+ continue;
|
||||
+
|
||||
static_branch_disable(cgroup_subsys_enabled_key[i]);
|
||||
pr_info("Disabling %s control group subsystem\n",
|
||||
ss->name);
|
||||
@@ -6427,6 +6440,31 @@ static int __init cgroup_disable(char *str)
|
||||
}
|
||||
__setup("cgroup_disable=", cgroup_disable);
|
||||
|
||||
+static int __init cgroup_enable(char *str)
|
||||
+{
|
||||
+ struct cgroup_subsys *ss;
|
||||
+ char *token;
|
||||
+ int i;
|
||||
+
|
||||
+ while ((token = strsep(&str, ",")) != NULL) {
|
||||
+ if (!*token)
|
||||
+ continue;
|
||||
+
|
||||
+ for_each_subsys(ss, i) {
|
||||
+ if (strcmp(token, ss->name) &&
|
||||
+ strcmp(token, ss->legacy_name))
|
||||
+ continue;
|
||||
+
|
||||
+ cgroup_enable_mask |= 1 << i;
|
||||
+ static_branch_enable(cgroup_subsys_enabled_key[i]);
|
||||
+ pr_info("Enabling %s control group subsystem\n",
|
||||
+ ss->name);
|
||||
+ }
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("cgroup_enable=", cgroup_enable);
|
||||
+
|
||||
void __init __weak enable_debug_cgroup(void) { }
|
||||
|
||||
static int __init enable_cgroup_debug(char *str)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From 0f195b63e8705152d2774c6213ce3096efc8c14d Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 13 Mar 2015 12:43:36 +0000
|
||||
Subject: [PATCH 044/634] Protect __release_resource against resources without
|
||||
parents
|
||||
|
||||
Without this patch, removing a device tree overlay can crash here.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
kernel/resource.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/kernel/resource.c b/kernel/resource.c
|
||||
index ca9f5198a01f..dd5ac10ff847 100644
|
||||
--- a/kernel/resource.c
|
||||
+++ b/kernel/resource.c
|
||||
@@ -213,6 +213,12 @@ static int __release_resource(struct resource *old, bool release_child)
|
||||
{
|
||||
struct resource *tmp, **p, *chd;
|
||||
|
||||
+ if (!old->parent) {
|
||||
+ WARN(old->sibling, "sibling but no parent");
|
||||
+ if (old->sibling)
|
||||
+ return -EINVAL;
|
||||
+ return 0;
|
||||
+ }
|
||||
p = &old->parent->child;
|
||||
for (;;) {
|
||||
tmp = *p;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
From 35a4353310b87f7e10c789cd5818bd83b6787a77 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 9 Feb 2017 14:33:30 +0000
|
||||
Subject: [PATCH 045/634] irq-bcm2836: Avoid "Invalid trigger warning"
|
||||
|
||||
Initialise the level for each IRQ to avoid a warning from the
|
||||
arm arch timer code.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/irqchip/irq-bcm2836.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
|
||||
index 501facdb4570..b6a7036305d8 100644
|
||||
--- a/drivers/irqchip/irq-bcm2836.c
|
||||
+++ b/drivers/irqchip/irq-bcm2836.c
|
||||
@@ -128,7 +128,7 @@ static int bcm2836_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_set_percpu_devid(irq);
|
||||
irq_domain_set_info(d, irq, hw, chip, d->host_data,
|
||||
handle_percpu_devid_irq, NULL, NULL);
|
||||
- irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
+ irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
From 0fb5b605e449a0af9ea90b253729aa0cc05c1e9c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 12 Jun 2015 19:01:05 +0200
|
||||
Subject: [PATCH 046/634] irqchip: bcm2835: Add FIQ support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add a duplicate irq range with an offset on the hwirq's so the
|
||||
driver can detect that enable_fiq() is used.
|
||||
Tested with downstream dwc_otg USB controller driver.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
Reviewed-by: Eric Anholt <eric@anholt.net>
|
||||
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
|
||||
---
|
||||
arch/arm/mach-bcm/Kconfig | 1 +
|
||||
drivers/irqchip/irq-bcm2835.c | 51 +++++++++++++++++++++++++++++++----
|
||||
2 files changed, 47 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
|
||||
index 2890e61b2b46..0462f870ab17 100644
|
||||
--- a/arch/arm/mach-bcm/Kconfig
|
||||
+++ b/arch/arm/mach-bcm/Kconfig
|
||||
@@ -162,6 +162,7 @@ config ARCH_BCM2835
|
||||
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
|
||||
select BCM2835_TIMER
|
||||
select BRCMSTB_L2_IRQ
|
||||
+ select FIQ
|
||||
select PINCTRL
|
||||
select PINCTRL_BCM2835
|
||||
select MFD_CORE
|
||||
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
|
||||
index adc1556ed332..0ae3b5d4d2de 100644
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -45,7 +45,7 @@
|
||||
#include <asm/exception.h>
|
||||
|
||||
/* Put the bank and irq (32 bits) into the hwirq */
|
||||
-#define MAKE_HWIRQ(b, n) ((b << 5) | (n))
|
||||
+#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
|
||||
#define HWIRQ_BANK(i) (i >> 5)
|
||||
#define HWIRQ_BIT(i) BIT(i & 0x1f)
|
||||
|
||||
@@ -62,9 +62,13 @@
|
||||
|
||||
#define REG_FIQ_CONTROL 0x0c
|
||||
#define FIQ_CONTROL_ENABLE BIT(7)
|
||||
+#define REG_FIQ_ENABLE FIQ_CONTROL_ENABLE
|
||||
+#define REG_FIQ_DISABLE 0
|
||||
|
||||
#define NR_BANKS 3
|
||||
#define IRQS_PER_BANK 32
|
||||
+#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
|
||||
+#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
|
||||
|
||||
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
|
||||
static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
|
||||
@@ -89,14 +93,38 @@ static void __exception_irq_entry bcm2835_handle_irq(
|
||||
struct pt_regs *regs);
|
||||
static void bcm2836_chained_handle_irq(struct irq_desc *desc);
|
||||
|
||||
+static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
|
||||
+{
|
||||
+ hwirq -= NUMBER_IRQS;
|
||||
+ /*
|
||||
+ * The hwirq numbering used in this driver is:
|
||||
+ * BASE (0-7) GPU1 (32-63) GPU2 (64-95).
|
||||
+ * This differ from the one used in the FIQ register:
|
||||
+ * GPU1 (0-31) GPU2 (32-63) BASE (64-71)
|
||||
+ */
|
||||
+ if (hwirq >= 32)
|
||||
+ return hwirq - 32;
|
||||
+
|
||||
+ return hwirq + 64;
|
||||
+}
|
||||
+
|
||||
static void armctrl_mask_irq(struct irq_data *d)
|
||||
{
|
||||
- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
|
||||
+ if (d->hwirq >= NUMBER_IRQS)
|
||||
+ writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
|
||||
+ else
|
||||
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
|
||||
+ intc.disable[HWIRQ_BANK(d->hwirq)]);
|
||||
}
|
||||
|
||||
static void armctrl_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
|
||||
+ if (d->hwirq >= NUMBER_IRQS)
|
||||
+ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
|
||||
+ intc.base + REG_FIQ_CONTROL);
|
||||
+ else
|
||||
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
|
||||
+ intc.enable[HWIRQ_BANK(d->hwirq)]);
|
||||
}
|
||||
|
||||
static struct irq_chip armctrl_chip = {
|
||||
@@ -142,8 +170,9 @@ static int __init armctrl_of_init(struct device_node *node,
|
||||
if (!base)
|
||||
panic("%pOF: unable to map IC registers\n", node);
|
||||
|
||||
- intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
|
||||
- &armctrl_ops, NULL);
|
||||
+ intc.base = base;
|
||||
+ intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
|
||||
+ &armctrl_ops, NULL);
|
||||
if (!intc.domain)
|
||||
panic("%pOF: unable to create IRQ domain\n", node);
|
||||
|
||||
@@ -186,6 +215,18 @@ static int __init armctrl_of_init(struct device_node *node,
|
||||
set_handle_irq(bcm2835_handle_irq);
|
||||
}
|
||||
|
||||
+ /* Make a duplicate irq range which is used to enable FIQ */
|
||||
+ for (b = 0; b < NR_BANKS; b++) {
|
||||
+ for (i = 0; i < bank_irqs[b]; i++) {
|
||||
+ irq = irq_create_mapping(intc.domain,
|
||||
+ MAKE_HWIRQ(b, i) + NUMBER_IRQS);
|
||||
+ BUG_ON(irq <= 0);
|
||||
+ irq_set_chip(irq, &armctrl_chip);
|
||||
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
+ }
|
||||
+ }
|
||||
+ init_FIQ(FIQ_START);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
From 7accb7f6c01b6922415a0c866f170088e0c28594 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 23 Oct 2015 16:26:55 +0200
|
||||
Subject: [PATCH 047/634] irqchip: irq-bcm2835: Add 2836 FIQ support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/irqchip/irq-bcm2835.c | 43 +++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 41 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
|
||||
index 0ae3b5d4d2de..a6ffff76c539 100644
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -41,8 +41,11 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqdomain.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/regmap.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
+#include <asm/mach/irq.h>
|
||||
|
||||
/* Put the bank and irq (32 bits) into the hwirq */
|
||||
#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
|
||||
@@ -60,6 +63,9 @@
|
||||
#define BANK0_VALID_MASK (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
|
||||
| SHORTCUT1_MASK | SHORTCUT2_MASK)
|
||||
|
||||
+#undef ARM_LOCAL_GPU_INT_ROUTING
|
||||
+#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
|
||||
+
|
||||
#define REG_FIQ_CONTROL 0x0c
|
||||
#define FIQ_CONTROL_ENABLE BIT(7)
|
||||
#define REG_FIQ_ENABLE FIQ_CONTROL_ENABLE
|
||||
@@ -86,6 +92,7 @@ struct armctrl_ic {
|
||||
void __iomem *enable[NR_BANKS];
|
||||
void __iomem *disable[NR_BANKS];
|
||||
struct irq_domain *domain;
|
||||
+ struct regmap *local_regmap;
|
||||
};
|
||||
|
||||
static struct armctrl_ic intc __read_mostly;
|
||||
@@ -119,12 +126,35 @@ static void armctrl_mask_irq(struct irq_data *d)
|
||||
|
||||
static void armctrl_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
- if (d->hwirq >= NUMBER_IRQS)
|
||||
+ if (d->hwirq >= NUMBER_IRQS) {
|
||||
+ if (num_online_cpus() > 1) {
|
||||
+ unsigned int data;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!intc.local_regmap) {
|
||||
+ pr_err("FIQ is disabled due to missing regmap\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_read(intc.local_regmap,
|
||||
+ ARM_LOCAL_GPU_INT_ROUTING, &data);
|
||||
+ if (ret) {
|
||||
+ pr_err("Failed to read int routing %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ data &= ~0xc;
|
||||
+ data |= (1 << 2);
|
||||
+ regmap_write(intc.local_regmap,
|
||||
+ ARM_LOCAL_GPU_INT_ROUTING, data);
|
||||
+ }
|
||||
+
|
||||
writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
|
||||
intc.base + REG_FIQ_CONTROL);
|
||||
- else
|
||||
+ } else {
|
||||
writel_relaxed(HWIRQ_BIT(d->hwirq),
|
||||
intc.enable[HWIRQ_BANK(d->hwirq)]);
|
||||
+ }
|
||||
}
|
||||
|
||||
static struct irq_chip armctrl_chip = {
|
||||
@@ -215,6 +245,15 @@ static int __init armctrl_of_init(struct device_node *node,
|
||||
set_handle_irq(bcm2835_handle_irq);
|
||||
}
|
||||
|
||||
+ if (is_2836) {
|
||||
+ intc.local_regmap =
|
||||
+ syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
|
||||
+ if (IS_ERR(intc.local_regmap)) {
|
||||
+ pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
|
||||
+ intc.local_regmap = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* Make a duplicate irq range which is used to enable FIQ */
|
||||
for (b = 0; b < NR_BANKS; b++) {
|
||||
for (i = 0; i < bank_irqs[b]; i++) {
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
From 0322d4639d99a2c0e472aee8996b566699b6355d Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 14 Jul 2015 10:26:09 +0100
|
||||
Subject: [PATCH 048/634] spi: spidev: Completely disable the spidev warning
|
||||
|
||||
An alternative strategy would be to use "rpi,spidev" instead, but that
|
||||
would require many Raspberry Pi Device Tree changes.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/spi/spidev.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
|
||||
index 795bef1efcc6..9a3b8a51eaef 100644
|
||||
--- a/drivers/spi/spidev.c
|
||||
+++ b/drivers/spi/spidev.c
|
||||
@@ -746,7 +746,7 @@ static int spidev_probe(struct spi_device *spi)
|
||||
* compatible string, it is a Linux implementation thing
|
||||
* rather than a description of the hardware.
|
||||
*/
|
||||
- WARN(spi->dev.of_node &&
|
||||
+ WARN(0 && spi->dev.of_node &&
|
||||
of_device_is_compatible(spi->dev.of_node, "spidev"),
|
||||
"%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
From 1e5020ac43d2bf03efb094cf68b887de9a121a2e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Sat, 3 Oct 2015 22:22:55 +0200
|
||||
Subject: [PATCH 049/634] dmaengine: bcm2835: Load driver early and support
|
||||
legacy API
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Load driver early since at least bcm2708_fb doesn't support deferred
|
||||
probing and even if it did, we don't want the video driver deferred.
|
||||
Support the legacy DMA API which is needed by bcm2708_fb.
|
||||
Don't mask out channel 2.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/dma/Kconfig | 2 +-
|
||||
drivers/dma/bcm2835-dma.c | 26 +++++++++++++++++++++++++-
|
||||
2 files changed, 26 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
|
||||
index 80c2c03cb014..f5afe0ec4f96 100644
|
||||
--- a/drivers/dma/Kconfig
|
||||
+++ b/drivers/dma/Kconfig
|
||||
@@ -127,7 +127,7 @@ config BCM_SBA_RAID
|
||||
|
||||
config DMA_BCM2835
|
||||
tristate "BCM2835 DMA engine support"
|
||||
- depends on ARCH_BCM2835
|
||||
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
|
||||
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
|
||||
index 630dfbb01a40..bf7ba96a39f9 100644
|
||||
--- a/drivers/dma/bcm2835-dma.c
|
||||
+++ b/drivers/dma/bcm2835-dma.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/platform_data/dma-bcm2708.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
@@ -36,6 +37,7 @@
|
||||
|
||||
#define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
|
||||
#define BCM2835_DMA_CHAN_NAME_SIZE 8
|
||||
+#define BCM2835_DMA_BULK_MASK BIT(0)
|
||||
|
||||
/**
|
||||
* struct bcm2835_dmadev - BCM2835 DMA controller
|
||||
@@ -906,6 +908,9 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
+ rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
|
||||
+ if (rc)
|
||||
+ dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
|
||||
|
||||
od->base = base;
|
||||
|
||||
@@ -951,6 +956,9 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
|
||||
goto err_no_dma;
|
||||
}
|
||||
|
||||
+ /* Channel 0 is used by the legacy API */
|
||||
+ chans_available &= ~BCM2835_DMA_BULK_MASK;
|
||||
+
|
||||
/* get irqs for each channel that we support */
|
||||
for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
|
||||
/* skip masked out channels */
|
||||
@@ -1025,6 +1033,7 @@ static int bcm2835_dma_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
|
||||
|
||||
+ bcm_dmaman_remove(pdev);
|
||||
dma_async_device_unregister(&od->ddev);
|
||||
bcm2835_dma_free(od);
|
||||
|
||||
@@ -1040,7 +1049,22 @@ static struct platform_driver bcm2835_dma_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
-module_platform_driver(bcm2835_dma_driver);
|
||||
+static int bcm2835_dma_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&bcm2835_dma_driver);
|
||||
+}
|
||||
+
|
||||
+static void bcm2835_dma_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&bcm2835_dma_driver);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Load after serial driver (arch_initcall) so we see the messages if it fails,
|
||||
+ * but before drivers (module_init) that need a DMA channel.
|
||||
+ */
|
||||
+subsys_initcall(bcm2835_dma_init);
|
||||
+module_exit(bcm2835_dma_exit);
|
||||
|
||||
MODULE_ALIAS("platform:bcm2835-dma");
|
||||
MODULE_DESCRIPTION("BCM2835 DMA engine driver");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
From 2fa1a23df8dd065af38db8950c50b385cc96e583 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 15 Jun 2016 16:48:41 +0100
|
||||
Subject: [PATCH 050/634] rtc: Add SPI alias for pcf2123 driver
|
||||
|
||||
Without this alias, Device Tree won't cause the driver
|
||||
to be loaded.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/pull/1510
|
||||
---
|
||||
drivers/rtc/rtc-pcf2123.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
|
||||
index 7473e6c8a183..4b986b338654 100644
|
||||
--- a/drivers/rtc/rtc-pcf2123.c
|
||||
+++ b/drivers/rtc/rtc-pcf2123.c
|
||||
@@ -473,3 +473,4 @@ module_spi_driver(pcf2123_driver);
|
||||
MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>");
|
||||
MODULE_DESCRIPTION("NXP PCF2123 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
+MODULE_ALIAS("spi:rtc-pcf2123");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
From ee758835da30ce57abee8d3591170f0122a5b3b3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 7 Oct 2016 16:50:59 +0200
|
||||
Subject: [PATCH 051/634] watchdog: bcm2835: Support setting reboot partition
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The Raspberry Pi firmware looks at the RSTS register to know which
|
||||
partition to boot from. The reboot syscall command
|
||||
LINUX_REBOOT_CMD_RESTART2 supports passing in a string argument.
|
||||
|
||||
Add support for passing in a partition number 0..63 to boot from.
|
||||
Partition 63 is a special partiton indicating halt.
|
||||
If the partition doesn't exist, the firmware falls back to partition 0.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/watchdog/bcm2835_wdt.c | 49 +++++++++++++++++++---------------
|
||||
1 file changed, 27 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
|
||||
index 94907176a0e4..58d5a1b89584 100644
|
||||
--- a/drivers/watchdog/bcm2835_wdt.c
|
||||
+++ b/drivers/watchdog/bcm2835_wdt.c
|
||||
@@ -32,13 +32,7 @@
|
||||
#define PM_RSTC_WRCFG_SET 0x00000030
|
||||
#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
|
||||
#define PM_RSTC_RESET 0x00000102
|
||||
-
|
||||
-/*
|
||||
- * The Raspberry Pi firmware uses the RSTS register to know which partition
|
||||
- * to boot from. The partition value is spread into bits 0, 2, 4, 6, 8, 10.
|
||||
- * Partition 63 is a special partition used by the firmware to indicate halt.
|
||||
- */
|
||||
-#define PM_RSTS_RASPBERRYPI_HALT 0x555
|
||||
+#define PM_RSTS_PARTITION_CLR 0xfffffaaa
|
||||
|
||||
#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
|
||||
#define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
|
||||
@@ -97,9 +91,24 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog)
|
||||
return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
|
||||
}
|
||||
|
||||
-static void __bcm2835_restart(struct bcm2835_wdt *wdt)
|
||||
+/*
|
||||
+ * The Raspberry Pi firmware uses the RSTS register to know which partiton
|
||||
+ * to boot from. The partiton value is spread into bits 0, 2, 4, 6, 8, 10.
|
||||
+ * Partiton 63 is a special partition used by the firmware to indicate halt.
|
||||
+ */
|
||||
+
|
||||
+static void __bcm2835_restart(struct bcm2835_wdt *wdt, u8 partition)
|
||||
{
|
||||
- u32 val;
|
||||
+ u32 val, rsts;
|
||||
+
|
||||
+ rsts = (partition & BIT(0)) | ((partition & BIT(1)) << 1) |
|
||||
+ ((partition & BIT(2)) << 2) | ((partition & BIT(3)) << 3) |
|
||||
+ ((partition & BIT(4)) << 4) | ((partition & BIT(5)) << 5);
|
||||
+
|
||||
+ val = readl_relaxed(wdt->base + PM_RSTS);
|
||||
+ val &= PM_RSTS_PARTITION_CLR;
|
||||
+ val |= PM_PASSWORD | rsts;
|
||||
+ writel_relaxed(val, wdt->base + PM_RSTS);
|
||||
|
||||
/* use a timeout of 10 ticks (~150us) */
|
||||
writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
|
||||
@@ -117,7 +126,13 @@ static int bcm2835_restart(struct watchdog_device *wdog,
|
||||
{
|
||||
struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
|
||||
|
||||
- __bcm2835_restart(wdt);
|
||||
+ unsigned long long val;
|
||||
+ u8 partition = 0;
|
||||
+
|
||||
+ if (data && !kstrtoull(data, 0, &val) && val <= 63)
|
||||
+ partition = val;
|
||||
+
|
||||
+ __bcm2835_restart(wdt, partition);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -152,19 +167,9 @@ static struct watchdog_device bcm2835_wdt_wdd = {
|
||||
static void bcm2835_power_off(void)
|
||||
{
|
||||
struct bcm2835_wdt *wdt = bcm2835_power_off_wdt;
|
||||
- u32 val;
|
||||
-
|
||||
- /*
|
||||
- * We set the watchdog hard reset bit here to distinguish this reset
|
||||
- * from the normal (full) reset. bootcode.bin will not reboot after a
|
||||
- * hard reset.
|
||||
- */
|
||||
- val = readl_relaxed(wdt->base + PM_RSTS);
|
||||
- val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT;
|
||||
- writel_relaxed(val, wdt->base + PM_RSTS);
|
||||
|
||||
- /* Continue with normal reset mechanism */
|
||||
- __bcm2835_restart(wdt);
|
||||
+ /* Partition 63 tells the firmware that this is a halt */
|
||||
+ __bcm2835_restart(wdt, 63);
|
||||
}
|
||||
|
||||
static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
From 10fbf516799bb00bf5c20fa539e7a10da9378ebc Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 5 Apr 2016 19:40:12 +0100
|
||||
Subject: [PATCH 052/634] reboot: Use power off rather than busy spinning when
|
||||
halt is requested
|
||||
|
||||
---
|
||||
arch/arm/kernel/reboot.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
|
||||
index 3044fcb8d073..fe22c46d9943 100644
|
||||
--- a/arch/arm/kernel/reboot.c
|
||||
+++ b/arch/arm/kernel/reboot.c
|
||||
@@ -101,9 +101,7 @@ void machine_shutdown(void)
|
||||
*/
|
||||
void machine_halt(void)
|
||||
{
|
||||
- local_irq_disable();
|
||||
- smp_send_stop();
|
||||
- while (1);
|
||||
+ machine_power_off();
|
||||
}
|
||||
|
||||
/*
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
From e81b252831f153b6dc2b270eb66a5f002aed19ee Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 9 Nov 2016 13:02:52 +0000
|
||||
Subject: [PATCH 053/634] bcm: Make RASPBERRYPI_POWER depend on PM
|
||||
|
||||
---
|
||||
drivers/soc/bcm/Kconfig | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
|
||||
index 24f92a6e882a..a6a705ec30c7 100644
|
||||
--- a/drivers/soc/bcm/Kconfig
|
||||
+++ b/drivers/soc/bcm/Kconfig
|
||||
@@ -17,6 +17,7 @@ config RASPBERRYPI_POWER
|
||||
bool "Raspberry Pi power domain driver"
|
||||
depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
|
||||
depends on RASPBERRYPI_FIRMWARE=y
|
||||
+ depends on PM
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
help
|
||||
This enables support for the RPi power domains which can be enabled
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From 2240403332a02438761e961cc30e475001e0e971 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sperl <kernel@martin.sperl.org>
|
||||
Date: Fri, 2 Sep 2016 16:45:27 +0100
|
||||
Subject: [PATCH 054/634] Register the clocks early during the boot process, so
|
||||
that special/critical clocks can get enabled early on in the boot process
|
||||
avoiding the risk of disabling a clock, pll_divider or pll when a claiming
|
||||
driver fails to install propperly - maybe it needs to defer.
|
||||
|
||||
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 15 +++++++++++++--
|
||||
1 file changed, 13 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index 3667b4d731e7..9332379565cb 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -2289,8 +2289,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
|
||||
+ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
|
||||
&cprman->onecell);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* note that we have registered all the clocks */
|
||||
+ dev_dbg(dev, "registered %d clocks\n", asize);
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static const struct cprman_plat_data cprman_bcm2835_plat_data = {
|
||||
@@ -2316,7 +2323,11 @@ static struct platform_driver bcm2835_clk_driver = {
|
||||
.probe = bcm2835_clk_probe,
|
||||
};
|
||||
|
||||
-builtin_platform_driver(bcm2835_clk_driver);
|
||||
+static int __init __bcm2835_clk_driver_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&bcm2835_clk_driver);
|
||||
+}
|
||||
+core_initcall(__bcm2835_clk_driver_init);
|
||||
|
||||
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
|
||||
MODULE_DESCRIPTION("BCM2835 clock driver");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
From 6a478cf4989ca434f590096599fe7edf66d4c6f5 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 6 Dec 2016 17:05:39 +0000
|
||||
Subject: [PATCH 055/634] bcm2835-rng: Avoid initialising if already enabled
|
||||
|
||||
Avoids the 0x40000 cycles of warmup again if firmware has already used it
|
||||
---
|
||||
drivers/char/hw_random/bcm2835-rng.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
|
||||
index e7dd457e9b22..f9a4a89e762b 100644
|
||||
--- a/drivers/char/hw_random/bcm2835-rng.c
|
||||
+++ b/drivers/char/hw_random/bcm2835-rng.c
|
||||
@@ -106,8 +106,10 @@ static int bcm2835_rng_init(struct hwrng *rng)
|
||||
}
|
||||
|
||||
/* set warm-up count & enable */
|
||||
- rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
|
||||
- rng_writel(priv, RNG_RBGEN, RNG_CTRL);
|
||||
+ if (!(rng_readl(priv, RNG_CTRL) & RNG_RBGEN)) {
|
||||
+ rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
|
||||
+ rng_writel(priv, RNG_RBGEN, RNG_CTRL);
|
||||
+ }
|
||||
|
||||
return ret;
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From d1b7a7961814d5a60bc1e8494b2308525b42b584 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 13 Feb 2017 17:20:08 +0000
|
||||
Subject: [PATCH 056/634] clk-bcm2835: Mark used PLLs and dividers CRITICAL
|
||||
|
||||
The VPU configures and relies on several PLLs and dividers. Mark all
|
||||
enabled dividers and their PLLs as CRITICAL to prevent the kernel from
|
||||
switching them off.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index 9332379565cb..d111f7f4fc81 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -1378,6 +1378,11 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
|
||||
divider->div.hw.init = &init;
|
||||
divider->div.table = NULL;
|
||||
|
||||
+ if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) {
|
||||
+ init.flags |= CLK_IS_CRITICAL;
|
||||
+ divider->div.flags |= CLK_IS_CRITICAL;
|
||||
+ }
|
||||
+
|
||||
divider->cprman = cprman;
|
||||
divider->data = divider_data;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
From c1db994a1b6533cb5354f276fc68e95bb0a9bd67 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 13 Feb 2017 17:20:08 +0000
|
||||
Subject: [PATCH 057/634] clk-bcm2835: Add claim-clocks property
|
||||
|
||||
The claim-clocks property can be used to prevent PLLs and dividers
|
||||
from being marked as critical. It contains a vector of clock IDs,
|
||||
as defined by dt-bindings/clock/bcm2835.h.
|
||||
|
||||
Use this mechanism to claim PLLD_DSI0, PLLD_DSI1, PLLH_AUX and
|
||||
PLLH_PIX for the vc4_kms_v3d driver.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 45 ++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 42 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index d111f7f4fc81..76bf4c81316e 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -1306,6 +1306,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
|
||||
.debug_init = bcm2835_clock_debug_init,
|
||||
};
|
||||
|
||||
+static bool bcm2835_clk_is_claimed(const char *name);
|
||||
+
|
||||
static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
|
||||
const void *data)
|
||||
{
|
||||
@@ -1323,6 +1325,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
|
||||
init.ops = &bcm2835_pll_clk_ops;
|
||||
init.flags = pll_data->flags | CLK_IGNORE_UNUSED;
|
||||
|
||||
+ if (!bcm2835_clk_is_claimed(pll_data->name))
|
||||
+ init.flags |= CLK_IS_CRITICAL;
|
||||
+
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return NULL;
|
||||
@@ -1378,9 +1383,11 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
|
||||
divider->div.hw.init = &init;
|
||||
divider->div.table = NULL;
|
||||
|
||||
- if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) {
|
||||
- init.flags |= CLK_IS_CRITICAL;
|
||||
- divider->div.flags |= CLK_IS_CRITICAL;
|
||||
+ if (!(cprman_read(cprman, divider_data->cm_reg) & divider_data->hold_mask)) {
|
||||
+ if (!bcm2835_clk_is_claimed(divider_data->source_pll))
|
||||
+ init.flags |= CLK_IS_CRITICAL;
|
||||
+ if (!bcm2835_clk_is_claimed(divider_data->name))
|
||||
+ divider->div.flags |= CLK_IS_CRITICAL;
|
||||
}
|
||||
|
||||
divider->cprman = cprman;
|
||||
@@ -1436,6 +1443,15 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
|
||||
init.name = clock_data->name;
|
||||
init.flags = clock_data->flags | CLK_IGNORE_UNUSED;
|
||||
|
||||
+ /*
|
||||
+ * Some GPIO clocks for ethernet/wifi PLLs are marked as
|
||||
+ * critical (since some platforms use them), but if the
|
||||
+ * firmware didn't have them turned on then they clearly
|
||||
+ * aren't actually critical.
|
||||
+ */
|
||||
+ if ((cprman_read(cprman, clock_data->ctl_reg) & CM_ENABLE) == 0)
|
||||
+ init.flags &= ~CLK_IS_CRITICAL;
|
||||
+
|
||||
/*
|
||||
* Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
|
||||
* rate changes on at least of the parents.
|
||||
@@ -2215,6 +2231,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
|
||||
.ctl_reg = CM_PERIICTL),
|
||||
};
|
||||
|
||||
+static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)];
|
||||
+
|
||||
/*
|
||||
* Permanently take a reference on the parent of the SDRAM clock.
|
||||
*
|
||||
@@ -2234,6 +2252,19 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
|
||||
return clk_prepare_enable(parent);
|
||||
}
|
||||
|
||||
+static bool bcm2835_clk_is_claimed(const char *name)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) {
|
||||
+ const char *clk_name = *(const char **)(clk_desc_array[i].data);
|
||||
+ if (!strcmp(name, clk_name))
|
||||
+ return bcm2835_clk_claimed[i];
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -2243,6 +2274,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
const size_t asize = ARRAY_SIZE(clk_desc_array);
|
||||
const struct cprman_plat_data *pdata;
|
||||
size_t i;
|
||||
+ u32 clk_id;
|
||||
int ret;
|
||||
|
||||
pdata = of_device_get_match_data(&pdev->dev);
|
||||
@@ -2261,6 +2293,13 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(cprman->regs))
|
||||
return PTR_ERR(cprman->regs);
|
||||
|
||||
+ memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
|
||||
+ for (i = 0;
|
||||
+ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",
|
||||
+ i, &clk_id);
|
||||
+ i++)
|
||||
+ bcm2835_clk_claimed[clk_id]= true;
|
||||
+
|
||||
memcpy(cprman->real_parent_names, cprman_parent_names,
|
||||
sizeof(cprman_parent_names));
|
||||
of_clk_parent_fill(dev->of_node, cprman->real_parent_names,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
From e096dfdc7d68b3fef9f5338df8df679969b1bc8a Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 6 Mar 2017 09:06:18 +0000
|
||||
Subject: [PATCH 058/634] clk-bcm2835: Read max core clock from firmware
|
||||
|
||||
The VPU is responsible for managing the core clock, usually under
|
||||
direction from the bcm2835-cpufreq driver but not via the clk-bcm2835
|
||||
driver. Since the core frequency can change without warning, it is
|
||||
safer to report the maximum clock rate to users of the core clock -
|
||||
I2C, SPI and the mini UART - to err on the safe side when calculating
|
||||
clock divisors.
|
||||
|
||||
If the DT node for the clock driver includes a reference to the
|
||||
firmware node, use the firmware API to query the maximum core clock
|
||||
instead of reading the divider registers.
|
||||
|
||||
Prior to this patch, a "100KHz" I2C bus was sometimes clocked at about
|
||||
160KHz. In particular, switching to the 4.9 kernel was likely to break
|
||||
SenseHAT usage on a Pi3.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 39 ++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 38 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
|
||||
index 76bf4c81316e..9b9a799a487d 100644
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <dt-bindings/clock/bcm2835.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
#define CM_PASSWORD 0x5a000000
|
||||
|
||||
@@ -295,6 +296,8 @@
|
||||
#define SOC_BCM2711 BIT(1)
|
||||
#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711)
|
||||
|
||||
+#define VCMSG_ID_CORE_CLOCK 4
|
||||
+
|
||||
/*
|
||||
* Names of clocks used within the driver that need to be replaced
|
||||
* with an external parent's name. This array is in the order that
|
||||
@@ -313,6 +316,7 @@ static const char *const cprman_parent_names[] = {
|
||||
struct bcm2835_cprman {
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
+ struct rpi_firmware *fw;
|
||||
spinlock_t regs_lock; /* spinlock for all clocks */
|
||||
unsigned int soc;
|
||||
|
||||
@@ -1010,6 +1014,30 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
|
||||
return bcm2835_clock_rate_from_divisor(clock, parent_rate, div);
|
||||
}
|
||||
|
||||
+static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw,
|
||||
+ unsigned long parent_rate)
|
||||
+{
|
||||
+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
|
||||
+ struct bcm2835_cprman *cprman = clock->cprman;
|
||||
+
|
||||
+ if (cprman->fw) {
|
||||
+ struct {
|
||||
+ u32 id;
|
||||
+ u32 val;
|
||||
+ } packet;
|
||||
+
|
||||
+ packet.id = VCMSG_ID_CORE_CLOCK;
|
||||
+ packet.val = 0;
|
||||
+
|
||||
+ if (!rpi_firmware_property(cprman->fw,
|
||||
+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
|
||||
+ &packet, sizeof(packet)))
|
||||
+ return packet.val;
|
||||
+ }
|
||||
+
|
||||
+ return bcm2835_clock_get_rate(hw, parent_rate);
|
||||
+}
|
||||
+
|
||||
static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock)
|
||||
{
|
||||
struct bcm2835_cprman *cprman = clock->cprman;
|
||||
@@ -1298,7 +1326,7 @@ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
|
||||
*/
|
||||
static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
|
||||
.is_prepared = bcm2835_vpu_clock_is_on,
|
||||
- .recalc_rate = bcm2835_clock_get_rate,
|
||||
+ .recalc_rate = bcm2835_clock_get_rate_vpu,
|
||||
.set_rate = bcm2835_clock_set_rate,
|
||||
.determine_rate = bcm2835_clock_determine_rate,
|
||||
.set_parent = bcm2835_clock_set_parent,
|
||||
@@ -2273,6 +2301,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
const struct bcm2835_clk_desc *desc;
|
||||
const size_t asize = ARRAY_SIZE(clk_desc_array);
|
||||
const struct cprman_plat_data *pdata;
|
||||
+ struct device_node *fw_node;
|
||||
size_t i;
|
||||
u32 clk_id;
|
||||
int ret;
|
||||
@@ -2293,6 +2322,14 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(cprman->regs))
|
||||
return PTR_ERR(cprman->regs);
|
||||
|
||||
+ fw_node = of_parse_phandle(dev->of_node, "firmware", 0);
|
||||
+ if (fw_node) {
|
||||
+ struct rpi_firmware *fw = rpi_firmware_get(NULL);
|
||||
+ if (!fw)
|
||||
+ return -EPROBE_DEFER;
|
||||
+ cprman->fw = fw;
|
||||
+ }
|
||||
+
|
||||
memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
|
||||
for (i = 0;
|
||||
!of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
From 322604e2085fc8b6e13a211718200ebd8802fb29 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 9 Feb 2017 14:36:44 +0000
|
||||
Subject: [PATCH 059/634] sound: Demote deferral errors to INFO level
|
||||
|
||||
At present there is no mechanism to specify driver load order,
|
||||
which can lead to deferrals and repeated retries until successful.
|
||||
Since this situation is expected, reduce the dmesg level to
|
||||
INFO and mention that the operation will be retried.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
sound/soc/soc-core.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
|
||||
index 80ca260595fd..633b02b43c9f 100644
|
||||
--- a/sound/soc/soc-core.c
|
||||
+++ b/sound/soc/soc-core.c
|
||||
@@ -1017,7 +1017,7 @@ int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
|
||||
for_each_link_cpus(dai_link, i, cpu) {
|
||||
asoc_rtd_to_cpu(rtd, i) = snd_soc_find_dai(cpu);
|
||||
if (!asoc_rtd_to_cpu(rtd, i)) {
|
||||
- dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
|
||||
+ dev_info(card->dev, "ASoC: CPU DAI %s not registered - will retry\n",
|
||||
cpu->dai_name);
|
||||
goto _err_defer;
|
||||
}
|
||||
@@ -1028,7 +1028,7 @@ int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
|
||||
for_each_link_codecs(dai_link, i, codec) {
|
||||
asoc_rtd_to_codec(rtd, i) = snd_soc_find_dai(codec);
|
||||
if (!asoc_rtd_to_codec(rtd, i)) {
|
||||
- dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n",
|
||||
+ dev_info(card->dev, "ASoC: CODEC DAI %s not registered- will retry\n",
|
||||
codec->dai_name);
|
||||
goto _err_defer;
|
||||
}
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
From 87d19cf28c0d690c08b0f2d172922fd9ed14b568 Mon Sep 17 00:00:00 2001
|
||||
From: Claggy3 <stephen.maclagan@hotmail.com>
|
||||
Date: Sat, 11 Feb 2017 14:00:30 +0000
|
||||
Subject: [PATCH 060/634] Update vfpmodule.c
|
||||
|
||||
Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m.
|
||||
This patch fixes a problem with VFP state save and restore related
|
||||
to exception handling (panic with message "BUG: unsupported FP
|
||||
instruction in kernel mode") present on VFP11 floating point units
|
||||
(as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry
|
||||
Pi boards). This patch was developed and discussed on
|
||||
|
||||
https://github.com/raspberrypi/linux/issues/859
|
||||
|
||||
A precondition to see the crashes is that floating point exception
|
||||
traps are enabled. In this case, the VFP11 might determine that a FPU
|
||||
operation needs to trap at a point in time when it is not possible to
|
||||
signal this to the ARM11 core any more. The VFP11 will then set the
|
||||
FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases,
|
||||
a second opcode might have been accepted by the VFP11 before the
|
||||
exception was detected and could be reported to the ARM11 - in this
|
||||
case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in
|
||||
FPINST2.)
|
||||
|
||||
If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued
|
||||
by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode
|
||||
trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits
|
||||
to decide what actions to take, i.e., whether to emulate the opcodes
|
||||
found in FPINST and FPINST2, and whether to retry the bounced instruction.
|
||||
|
||||
If a user space application has left the VFP11 in this "pending trap"
|
||||
state, the next FPU opcode issued to the VFP11 might actually be the
|
||||
VSTMIA operation vfp_save_state() uses to store the FPU registers
|
||||
to memory (in our test cases, when building the signal stack frame).
|
||||
In this case, the kernel crashes as described above.
|
||||
|
||||
This patch fixes the problem by making sure that vfp_save_state() is
|
||||
always entered with FPEXC.EX cleared. (The current value of FPEXC has
|
||||
already been saved, so this does not corrupt the context. Clearing
|
||||
FPEXC.EX has no effects on FPINST or FPINST2. Also note that many
|
||||
callers already modify FPEXC by setting FPEXC.EN before invoking
|
||||
vfp_save_state().)
|
||||
|
||||
This patch also addresses a second problem related to FPEXC.EX: After
|
||||
returning from signal handling, the kernel reloads the VFP context
|
||||
from the user mode stack. However, the current code explicitly clears
|
||||
both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these
|
||||
bits to be preserved, this patch disables clearing them for VFP
|
||||
implementations belonging to architecture 1. There should be no
|
||||
negative side effects: the user can set both bits by executing FPU
|
||||
opcodes anyway, and while user code may now place arbitrary values
|
||||
into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support
|
||||
code knows which instructions can be emulated, and rejects other
|
||||
opcodes with "unhandled bounce" messages, so there should be no
|
||||
security impact from allowing reloading FPEXC.EX and FPEXC.FP2V.
|
||||
|
||||
Signed-off-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net>
|
||||
---
|
||||
arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------
|
||||
1 file changed, 19 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
|
||||
index 2cb355c1b5b7..1e2dcf81aefa 100644
|
||||
--- a/arch/arm/vfp/vfpmodule.c
|
||||
+++ b/arch/arm/vfp/vfpmodule.c
|
||||
@@ -176,8 +176,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
|
||||
* case the thread migrates to a different CPU. The
|
||||
* restoring is done lazily.
|
||||
*/
|
||||
- if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu])
|
||||
+ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
|
||||
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
||||
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
|
||||
vfp_save_state(vfp_current_hw_state[cpu], fpexc);
|
||||
+ }
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -454,13 +457,16 @@ static int vfp_pm_suspend(void)
|
||||
/* if vfp is on, then save state for resumption */
|
||||
if (fpexc & FPEXC_EN) {
|
||||
pr_debug("%s: saving vfp state\n", __func__);
|
||||
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
||||
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
|
||||
vfp_save_state(&ti->vfpstate, fpexc);
|
||||
|
||||
/* disable, just in case */
|
||||
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
|
||||
} else if (vfp_current_hw_state[ti->cpu]) {
|
||||
#ifndef CONFIG_SMP
|
||||
- fmxr(FPEXC, fpexc | FPEXC_EN);
|
||||
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
||||
+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
|
||||
vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
|
||||
fmxr(FPEXC, fpexc);
|
||||
#endif
|
||||
@@ -523,7 +529,8 @@ void vfp_sync_hwstate(struct thread_info *thread)
|
||||
/*
|
||||
* Save the last VFP state on this CPU.
|
||||
*/
|
||||
- fmxr(FPEXC, fpexc | FPEXC_EN);
|
||||
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
||||
+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
|
||||
vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
|
||||
fmxr(FPEXC, fpexc);
|
||||
}
|
||||
@@ -589,6 +596,7 @@ int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc)
|
||||
struct thread_info *thread = current_thread_info();
|
||||
struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
|
||||
unsigned long fpexc;
|
||||
+ u32 fpsid = fmrx(FPSID);
|
||||
|
||||
/* Disable VFP to avoid corrupting the new thread state. */
|
||||
vfp_flush_hwstate(thread);
|
||||
@@ -611,8 +619,12 @@ int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc)
|
||||
/* Ensure the VFP is enabled. */
|
||||
fpexc |= FPEXC_EN;
|
||||
|
||||
- /* Ensure FPINST2 is invalid and the exception flag is cleared. */
|
||||
- fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
|
||||
+ /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */
|
||||
+ if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) {
|
||||
+ /* Ensure FPINST2 is invalid and the exception flag is cleared. */
|
||||
+ fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
|
||||
+ }
|
||||
+
|
||||
hwstate->fpexc = fpexc;
|
||||
|
||||
hwstate->fpinst = ufp_exc->fpinst;
|
||||
@@ -726,7 +738,8 @@ void kernel_neon_begin(void)
|
||||
cpu = get_cpu();
|
||||
|
||||
fpexc = fmrx(FPEXC) | FPEXC_EN;
|
||||
- fmxr(FPEXC, fpexc);
|
||||
+ /* vfp_save_state oopses on VFP11 if EX bit set */
|
||||
+ fmxr(FPEXC, fpexc & ~FPEXC_EX);
|
||||
|
||||
/*
|
||||
* Save the userland NEON/VFP state. Under UP,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
From e8015f39c17a5a2f91cbac60cd39069220a0d2ac Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Tue, 1 Nov 2016 15:15:41 +0100
|
||||
Subject: [PATCH 061/634] i2c: bcm2835: Add debug support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds a debug module parameter to aid in debugging transfer issues
|
||||
by printing info to the kernel log. When enabled, status values are
|
||||
collected in the interrupt routine and msg info in
|
||||
bcm2835_i2c_start_transfer(). This is done in a way that tries to avoid
|
||||
affecting timing. Having printk in the isr can mask issues.
|
||||
|
||||
debug values (additive):
|
||||
1: Print info on error
|
||||
2: Print info on all transfers
|
||||
3: Print messages before transfer is started
|
||||
|
||||
The value can be changed at runtime:
|
||||
/sys/module/i2c_bcm2835/parameters/debug
|
||||
|
||||
Example output, debug=3:
|
||||
[ 747.114448] bcm2835_i2c_xfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
|
||||
[ 747.114463] bcm2835_i2c_xfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
|
||||
[ 747.117809] start_transfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
|
||||
[ 747.117825] isr: remain=2, status=0x30000055 : TA TXW TXD TXE [i2c1]
|
||||
[ 747.117839] start_transfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
|
||||
[ 747.117849] isr: remain=32, status=0xd0000039 : TA RXR TXD RXD [i2c1]
|
||||
[ 747.117861] isr: remain=20, status=0xd0000039 : TA RXR TXD RXD [i2c1]
|
||||
[ 747.117870] isr: remain=8, status=0x32 : DONE TXD RXD [i2c1]
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/i2c/busses/i2c-bcm2835.c | 99 +++++++++++++++++++++++++++++++-
|
||||
1 file changed, 98 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
|
||||
index 37443edbf754..18b2e9e3d752 100644
|
||||
--- a/drivers/i2c/busses/i2c-bcm2835.c
|
||||
+++ b/drivers/i2c/busses/i2c-bcm2835.c
|
||||
@@ -51,6 +51,18 @@
|
||||
#define BCM2835_I2C_CDIV_MIN 0x0002
|
||||
#define BCM2835_I2C_CDIV_MAX 0xFFFE
|
||||
|
||||
+static unsigned int debug;
|
||||
+module_param(debug, uint, 0644);
|
||||
+MODULE_PARM_DESC(debug, "1=err, 2=isr, 3=xfer");
|
||||
+
|
||||
+#define BCM2835_DEBUG_MAX 512
|
||||
+struct bcm2835_debug {
|
||||
+ struct i2c_msg *msg;
|
||||
+ int msg_idx;
|
||||
+ size_t remain;
|
||||
+ u32 status;
|
||||
+};
|
||||
+
|
||||
struct bcm2835_i2c_dev {
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
@@ -63,8 +75,78 @@ struct bcm2835_i2c_dev {
|
||||
u32 msg_err;
|
||||
u8 *msg_buf;
|
||||
size_t msg_buf_remaining;
|
||||
+ struct bcm2835_debug debug[BCM2835_DEBUG_MAX];
|
||||
+ unsigned int debug_num;
|
||||
+ unsigned int debug_num_msgs;
|
||||
};
|
||||
|
||||
+static inline void bcm2835_debug_add(struct bcm2835_i2c_dev *i2c_dev, u32 s)
|
||||
+{
|
||||
+ if (!i2c_dev->debug_num_msgs || i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
|
||||
+ return;
|
||||
+
|
||||
+ i2c_dev->debug[i2c_dev->debug_num].msg = i2c_dev->curr_msg;
|
||||
+ i2c_dev->debug[i2c_dev->debug_num].msg_idx =
|
||||
+ i2c_dev->debug_num_msgs - i2c_dev->num_msgs;
|
||||
+ i2c_dev->debug[i2c_dev->debug_num].remain = i2c_dev->msg_buf_remaining;
|
||||
+ i2c_dev->debug[i2c_dev->debug_num].status = s;
|
||||
+ i2c_dev->debug_num++;
|
||||
+}
|
||||
+
|
||||
+static void bcm2835_debug_print_status(struct bcm2835_i2c_dev *i2c_dev,
|
||||
+ struct bcm2835_debug *d)
|
||||
+{
|
||||
+ u32 s = d->status;
|
||||
+
|
||||
+ pr_info("isr: remain=%zu, status=0x%x : %s%s%s%s%s%s%s%s%s%s [i2c%d]\n",
|
||||
+ d->remain, s,
|
||||
+ s & BCM2835_I2C_S_TA ? "TA " : "",
|
||||
+ s & BCM2835_I2C_S_DONE ? "DONE " : "",
|
||||
+ s & BCM2835_I2C_S_TXW ? "TXW " : "",
|
||||
+ s & BCM2835_I2C_S_RXR ? "RXR " : "",
|
||||
+ s & BCM2835_I2C_S_TXD ? "TXD " : "",
|
||||
+ s & BCM2835_I2C_S_RXD ? "RXD " : "",
|
||||
+ s & BCM2835_I2C_S_TXE ? "TXE " : "",
|
||||
+ s & BCM2835_I2C_S_RXF ? "RXF " : "",
|
||||
+ s & BCM2835_I2C_S_ERR ? "ERR " : "",
|
||||
+ s & BCM2835_I2C_S_CLKT ? "CLKT " : "",
|
||||
+ i2c_dev->adapter.nr);
|
||||
+}
|
||||
+
|
||||
+static void bcm2835_debug_print_msg(struct bcm2835_i2c_dev *i2c_dev,
|
||||
+ struct i2c_msg *msg, int i, int total,
|
||||
+ const char *fname)
|
||||
+{
|
||||
+ pr_info("%s: msg(%d/%d) %s addr=0x%02x, len=%u flags=%s%s%s%s%s%s%s [i2c%d]\n",
|
||||
+ fname, i, total,
|
||||
+ msg->flags & I2C_M_RD ? "read" : "write", msg->addr, msg->len,
|
||||
+ msg->flags & I2C_M_TEN ? "TEN" : "",
|
||||
+ msg->flags & I2C_M_RECV_LEN ? "RECV_LEN" : "",
|
||||
+ msg->flags & I2C_M_NO_RD_ACK ? "NO_RD_ACK" : "",
|
||||
+ msg->flags & I2C_M_IGNORE_NAK ? "IGNORE_NAK" : "",
|
||||
+ msg->flags & I2C_M_REV_DIR_ADDR ? "REV_DIR_ADDR" : "",
|
||||
+ msg->flags & I2C_M_NOSTART ? "NOSTART" : "",
|
||||
+ msg->flags & I2C_M_STOP ? "STOP" : "",
|
||||
+ i2c_dev->adapter.nr);
|
||||
+}
|
||||
+
|
||||
+static void bcm2835_debug_print(struct bcm2835_i2c_dev *i2c_dev)
|
||||
+{
|
||||
+ struct bcm2835_debug *d;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < i2c_dev->debug_num; i++) {
|
||||
+ d = &i2c_dev->debug[i];
|
||||
+ if (d->status == ~0)
|
||||
+ bcm2835_debug_print_msg(i2c_dev, d->msg, d->msg_idx,
|
||||
+ i2c_dev->debug_num_msgs, "start_transfer");
|
||||
+ else
|
||||
+ bcm2835_debug_print_status(i2c_dev, d);
|
||||
+ }
|
||||
+ if (i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
|
||||
+ pr_info("BCM2835_DEBUG_MAX reached\n");
|
||||
+}
|
||||
+
|
||||
static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev,
|
||||
u32 reg, u32 val)
|
||||
{
|
||||
@@ -252,6 +334,7 @@ static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev)
|
||||
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
|
||||
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
|
||||
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
|
||||
+ bcm2835_debug_add(i2c_dev, ~0);
|
||||
}
|
||||
|
||||
static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev)
|
||||
@@ -278,6 +361,7 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
||||
u32 val, err;
|
||||
|
||||
val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
|
||||
+ bcm2835_debug_add(i2c_dev, val);
|
||||
|
||||
err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
|
||||
if (err) {
|
||||
@@ -344,6 +428,13 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
unsigned long time_left;
|
||||
int i;
|
||||
|
||||
+ if (debug)
|
||||
+ i2c_dev->debug_num_msgs = num;
|
||||
+
|
||||
+ if (debug > 2)
|
||||
+ for (i = 0; i < num; i++)
|
||||
+ bcm2835_debug_print_msg(i2c_dev, &msgs[i], i + 1, num, __func__);
|
||||
+
|
||||
for (i = 0; i < (num - 1); i++)
|
||||
if (msgs[i].flags & I2C_M_RD) {
|
||||
dev_warn_once(i2c_dev->dev,
|
||||
@@ -362,6 +453,10 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
|
||||
bcm2835_i2c_finish_transfer(i2c_dev);
|
||||
|
||||
+ if (debug > 1 || (debug && (!time_left || i2c_dev->msg_err)))
|
||||
+ bcm2835_debug_print(i2c_dev);
|
||||
+ i2c_dev->debug_num_msgs = 0;
|
||||
+ i2c_dev->debug_num = 0;
|
||||
if (!time_left) {
|
||||
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
|
||||
BCM2835_I2C_C_CLEAR);
|
||||
@@ -372,7 +467,9 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
if (!i2c_dev->msg_err)
|
||||
return num;
|
||||
|
||||
- dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
|
||||
+ if (debug)
|
||||
+ dev_err(i2c_dev->dev, "i2c transfer failed: %x\n",
|
||||
+ i2c_dev->msg_err);
|
||||
|
||||
if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
|
||||
return -EREMOTEIO;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
From afad4ffe2d466cadf396592d78df9cdb16041c26 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 23 Jan 2018 16:52:45 +0000
|
||||
Subject: [PATCH 062/634] irqchip: irq-bcm2836: Remove regmap and syscon use
|
||||
|
||||
The syscon node defines a register range that duplicates that used by
|
||||
the local_intc node on bcm2836/7. Since irq-bcm2835 and irq-bcm2836 are
|
||||
built in and always present together (both drivers are enabled by
|
||||
CONFIG_ARCH_BCM2835), it is possible to replace the syscon usage with a
|
||||
global variable that simplifies the code. Doing so does lose the
|
||||
locking provided by regmap, but as only one side is using the regmap
|
||||
interface (irq-bcm2835 uses readl and write) there is no loss of
|
||||
atomicity.
|
||||
|
||||
See: https://github.com/raspberrypi/firmware/issues/926
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/irqchip/irq-bcm2835.c | 32 ++++++++++++--------------------
|
||||
drivers/irqchip/irq-bcm2836.c | 5 +++++
|
||||
2 files changed, 17 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
|
||||
index a6ffff76c539..e08c209521ac 100644
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -41,8 +41,6 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqdomain.h>
|
||||
-#include <linux/mfd/syscon.h>
|
||||
-#include <linux/regmap.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
#include <asm/mach/irq.h>
|
||||
@@ -92,7 +90,7 @@ struct armctrl_ic {
|
||||
void __iomem *enable[NR_BANKS];
|
||||
void __iomem *disable[NR_BANKS];
|
||||
struct irq_domain *domain;
|
||||
- struct regmap *local_regmap;
|
||||
+ void __iomem *local_base;
|
||||
};
|
||||
|
||||
static struct armctrl_ic intc __read_mostly;
|
||||
@@ -129,24 +127,20 @@ static void armctrl_unmask_irq(struct irq_data *d)
|
||||
if (d->hwirq >= NUMBER_IRQS) {
|
||||
if (num_online_cpus() > 1) {
|
||||
unsigned int data;
|
||||
- int ret;
|
||||
|
||||
- if (!intc.local_regmap) {
|
||||
- pr_err("FIQ is disabled due to missing regmap\n");
|
||||
+ if (!intc.local_base) {
|
||||
+ pr_err("FIQ is disabled due to missing arm_local_intc\n");
|
||||
return;
|
||||
}
|
||||
|
||||
- ret = regmap_read(intc.local_regmap,
|
||||
- ARM_LOCAL_GPU_INT_ROUTING, &data);
|
||||
- if (ret) {
|
||||
- pr_err("Failed to read int routing %d\n", ret);
|
||||
- return;
|
||||
- }
|
||||
+ data = readl_relaxed(intc.local_base +
|
||||
+ ARM_LOCAL_GPU_INT_ROUTING);
|
||||
|
||||
data &= ~0xc;
|
||||
data |= (1 << 2);
|
||||
- regmap_write(intc.local_regmap,
|
||||
- ARM_LOCAL_GPU_INT_ROUTING, data);
|
||||
+ writel_relaxed(data,
|
||||
+ intc.local_base +
|
||||
+ ARM_LOCAL_GPU_INT_ROUTING);
|
||||
}
|
||||
|
||||
writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
|
||||
@@ -246,12 +240,10 @@ static int __init armctrl_of_init(struct device_node *node,
|
||||
}
|
||||
|
||||
if (is_2836) {
|
||||
- intc.local_regmap =
|
||||
- syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
|
||||
- if (IS_ERR(intc.local_regmap)) {
|
||||
- pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
|
||||
- intc.local_regmap = NULL;
|
||||
- }
|
||||
+ extern void __iomem * __attribute__((weak)) arm_local_intc;
|
||||
+ intc.local_base = arm_local_intc;
|
||||
+ if (!intc.local_base)
|
||||
+ pr_err("Failed to get local intc base. FIQ is disabled for cpus > 1\n");
|
||||
}
|
||||
|
||||
/* Make a duplicate irq range which is used to enable FIQ */
|
||||
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
|
||||
index b6a7036305d8..867c3b43490c 100644
|
||||
--- a/drivers/irqchip/irq-bcm2836.c
|
||||
+++ b/drivers/irqchip/irq-bcm2836.c
|
||||
@@ -22,6 +22,9 @@ struct bcm2836_arm_irqchip_intc {
|
||||
|
||||
static struct bcm2836_arm_irqchip_intc intc __read_mostly;
|
||||
|
||||
+void __iomem *arm_local_intc;
|
||||
+EXPORT_SYMBOL_GPL(arm_local_intc);
|
||||
+
|
||||
static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset,
|
||||
unsigned int bit,
|
||||
int cpu)
|
||||
@@ -323,6 +326,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
|
||||
panic("%pOF: unable to map local interrupt registers\n", node);
|
||||
}
|
||||
|
||||
+ arm_local_intc = intc.base;
|
||||
+
|
||||
bcm2835_init_local_timer_frequency();
|
||||
|
||||
intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
From 68c76ce879b7e970a748f8c2686f25ac3b817f7e Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 17 Oct 2017 15:04:29 +0100
|
||||
Subject: [PATCH 063/634] lan78xx: Enable LEDs and auto-negotiation
|
||||
|
||||
For applications of the LAN78xx that don't have valid programmed
|
||||
EEPROMs or OTPs, enabling both LEDs and auto-negotiation by default
|
||||
seems reasonable.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/net/usb/lan78xx.c | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
|
||||
index 63cd72c5f580..3d39f34bc641 100644
|
||||
--- a/drivers/net/usb/lan78xx.c
|
||||
+++ b/drivers/net/usb/lan78xx.c
|
||||
@@ -2714,6 +2714,11 @@ static int lan78xx_reset(struct lan78xx_net *dev)
|
||||
int ret;
|
||||
u32 buf;
|
||||
u8 sig;
|
||||
+ bool has_eeprom;
|
||||
+ bool has_otp;
|
||||
+
|
||||
+ has_eeprom = !lan78xx_read_eeprom(dev, 0, 0, NULL);
|
||||
+ has_otp = !lan78xx_read_otp(dev, 0, 0, NULL);
|
||||
|
||||
ret = lan78xx_read_reg(dev, HW_CFG, &buf);
|
||||
if (ret < 0)
|
||||
@@ -2795,6 +2800,10 @@ static int lan78xx_reset(struct lan78xx_net *dev)
|
||||
|
||||
buf |= HW_CFG_MEF_;
|
||||
|
||||
+ /* If no valid EEPROM and no valid OTP, enable the LEDs by default */
|
||||
+ if (!has_eeprom && !has_otp)
|
||||
+ buf |= HW_CFG_LED0_EN_ | HW_CFG_LED1_EN_;
|
||||
+
|
||||
ret = lan78xx_write_reg(dev, HW_CFG, buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -2893,6 +2902,9 @@ static int lan78xx_reset(struct lan78xx_net *dev)
|
||||
buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
|
||||
}
|
||||
}
|
||||
+ /* If no valid EEPROM and no valid OTP, enable AUTO negotiation */
|
||||
+ if (!has_eeprom && !has_otp)
|
||||
+ buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
|
||||
ret = lan78xx_write_reg(dev, MAC_CR, buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
From f5381879293b3019d229028a3fc30e0f6e6b9539 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 23 Feb 2016 17:26:48 +0000
|
||||
Subject: [PATCH 064/634] amba_pl011: Don't use DT aliases for numbering
|
||||
|
||||
The pl011 driver looks for DT aliases of the form "serial<n>",
|
||||
and if found uses <n> as the device ID. This can cause
|
||||
/dev/ttyAMA0 to become /dev/ttyAMA1, which is confusing if the
|
||||
other serial port is provided by the 8250 driver which doesn't
|
||||
use the same logic.
|
||||
---
|
||||
drivers/tty/serial/amba-pl011.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||||
index d361cd84ff8c..82429e05ed7d 100644
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -2752,7 +2752,12 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
+ /* Don't use DT serial<n> aliases - it causes the device to
|
||||
+ be renumbered to ttyAMA1 if it is the second serial port in the
|
||||
+ system, even though the other one is ttyS0. The 8250 driver
|
||||
+ doesn't use this logic, so always remains ttyS0.
|
||||
index = pl011_probe_dt_alias(index, dev);
|
||||
+ */
|
||||
|
||||
uap->old_cr = 0;
|
||||
uap->port.dev = dev;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
From 676d05db81365c6c247a626ad9bfec58a1fe45b1 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 1 Mar 2017 16:07:39 +0000
|
||||
Subject: [PATCH 065/634] amba_pl011: Round input clock up
|
||||
|
||||
The UART clock is initialised to be as close to the requested
|
||||
frequency as possible without exceeding it. Now that there is a
|
||||
clock manager that returns the actual frequencies, an expected
|
||||
48MHz clock is reported as 47999625. If the requested baudrate
|
||||
== requested clock/16, there is no headroom and the slight
|
||||
reduction in actual clock rate results in failure.
|
||||
|
||||
Detect cases where it looks like a "round" clock was chosen and
|
||||
adjust the reported clock to match that "round" value. As the
|
||||
code comment says:
|
||||
|
||||
/*
|
||||
* If increasing a clock by less than 0.1% changes it
|
||||
* from ..999.. to ..000.., round up.
|
||||
*/
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/tty/serial/amba-pl011.c | 23 +++++++++++++++++++++--
|
||||
1 file changed, 21 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||||
index 82429e05ed7d..83c5ab78b0d0 100644
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -1716,6 +1716,23 @@ static void pl011_put_poll_char(struct uart_port *port,
|
||||
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
+unsigned long pl011_clk_round(unsigned long clk)
|
||||
+{
|
||||
+ unsigned long scaler;
|
||||
+
|
||||
+ /*
|
||||
+ * If increasing a clock by less than 0.1% changes it
|
||||
+ * from ..999.. to ..000.., round up.
|
||||
+ */
|
||||
+ scaler = 1;
|
||||
+ while (scaler * 100000 < clk)
|
||||
+ scaler *= 10;
|
||||
+ if ((clk + scaler - 1)/scaler % 1000 == 0)
|
||||
+ clk = (clk/scaler + 1) * scaler;
|
||||
+
|
||||
+ return clk;
|
||||
+}
|
||||
+
|
||||
static int pl011_hwinit(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
@@ -1732,7 +1749,7 @@ static int pl011_hwinit(struct uart_port *port)
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
- uap->port.uartclk = clk_get_rate(uap->clk);
|
||||
+ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk));
|
||||
|
||||
/* Clear pending error and receive interrupts */
|
||||
pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
|
||||
@@ -2448,7 +2465,7 @@ static int pl011_console_setup(struct console *co, char *options)
|
||||
plat->init();
|
||||
}
|
||||
|
||||
- uap->port.uartclk = clk_get_rate(uap->clk);
|
||||
+ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk));
|
||||
|
||||
if (uap->vendor->fixed_options) {
|
||||
baud = uap->fixed_baud;
|
||||
@@ -2665,6 +2682,7 @@ static struct uart_driver amba_reg = {
|
||||
.cons = AMBA_CONSOLE,
|
||||
};
|
||||
|
||||
+#if 0
|
||||
static int pl011_probe_dt_alias(int index, struct device *dev)
|
||||
{
|
||||
struct device_node *np;
|
||||
@@ -2696,6 +2714,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
|
||||
|
||||
return ret;
|
||||
}
|
||||
+#endif
|
||||
|
||||
/* unregisters the driver also if no more ports are left */
|
||||
static void pl011_unregister_port(struct uart_amba_port *uap)
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From a62a788b8b85ec1ddcb720d9b4587a43a8a263e8 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 29 Sep 2017 10:32:19 +0100
|
||||
Subject: [PATCH 066/634] amba_pl011: Insert mb() for correct FIFO handling
|
||||
|
||||
The pl011 register accessor functions use the _relaxed versions of the
|
||||
standard readl() and writel() functions, meaning that there are no
|
||||
automatic memory barriers. When polling a FIFO status register to check
|
||||
for fullness, it is necessary to ensure that any outstanding writes have
|
||||
completed; otherwise the flags are effectively stale, making it possible
|
||||
that the next write is to a full FIFO.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/tty/serial/amba-pl011.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||||
index 83c5ab78b0d0..e940909308b0 100644
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -1418,6 +1418,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
|
||||
return false; /* unable to transmit character */
|
||||
|
||||
pl011_write(c, uap, REG_DR);
|
||||
+ mb();
|
||||
uap->port.icount.tx++;
|
||||
|
||||
return true;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
From 5c24e541edade9b7dee3d462c078199733072b23 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 29 Sep 2017 10:32:19 +0100
|
||||
Subject: [PATCH 067/634] amba_pl011: Add cts-event-workaround DT property
|
||||
|
||||
The BCM2835 PL011 implementation seems to have a bug that can lead to a
|
||||
transmission lockup if CTS changes frequently. A workaround was added to
|
||||
the driver with a vendor-specific flag to enable it, but this flag is
|
||||
currently not set for ARM implementations.
|
||||
|
||||
Add a "cts-event-workaround" property to Pi DTBs and use the presence
|
||||
of that property to force the flag to be enabled in the driver.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1280
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
Documentation/devicetree/bindings/serial/pl011.yaml | 6 ++++++
|
||||
drivers/tty/serial/amba-pl011.c | 5 +++++
|
||||
2 files changed, 11 insertions(+)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/serial/pl011.yaml b/Documentation/devicetree/bindings/serial/pl011.yaml
|
||||
index 5ea00f8a283d..8df2883abc04 100644
|
||||
--- a/Documentation/devicetree/bindings/serial/pl011.yaml
|
||||
+++ b/Documentation/devicetree/bindings/serial/pl011.yaml
|
||||
@@ -91,6 +91,12 @@ properties:
|
||||
3000ms.
|
||||
default: 3000
|
||||
|
||||
+ cts-event-workaround:
|
||||
+ description:
|
||||
+ Enables the (otherwise vendor-specific) workaround for the
|
||||
+ CTS-induced TX lockup.
|
||||
+ type: boolean
|
||||
+
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||||
index e940909308b0..44a5cbf92542 100644
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -2843,6 +2843,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
||||
if (IS_ERR(uap->clk))
|
||||
return PTR_ERR(uap->clk);
|
||||
|
||||
+ if (of_property_read_bool(dev->dev.of_node, "cts-event-workaround")) {
|
||||
+ vendor->cts_event_workaround = true;
|
||||
+ dev_info(&dev->dev, "cts_event_workaround enabled\n");
|
||||
+ }
|
||||
+
|
||||
uap->reg_offset = vendor->reg_offset;
|
||||
uap->vendor = vendor;
|
||||
uap->fifosize = vendor->get_fifosize(dev);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
From b09e7ee5c298c9a22c2018ee6d2f81f50c687b71 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 24 Jan 2020 11:38:28 +0000
|
||||
Subject: [PATCH 068/634] tty: amba-pl011: Add un/throttle support
|
||||
|
||||
The PL011 driver lacks throttle and unthrottle methods. As a result,
|
||||
sending more data to the Pi than it can immediately sink while CRTSCTS
|
||||
is enabled causes a NULL pointer to be followed.
|
||||
|
||||
Add a throttle handler that disables the RX interrupts, and an
|
||||
unthrottle handler that reenables them.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++
|
||||
1 file changed, 28 insertions(+)
|
||||
|
||||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||||
index 44a5cbf92542..5e9a789e3c15 100644
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -1355,6 +1355,32 @@ static void pl011_start_tx(struct uart_port *port)
|
||||
pl011_start_tx_pio(uap);
|
||||
}
|
||||
|
||||
+static void pl011_throttle(struct uart_port *port)
|
||||
+{
|
||||
+ struct uart_amba_port *uap =
|
||||
+ container_of(port, struct uart_amba_port, port);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&uap->port.lock, flags);
|
||||
+ uap->im &= ~(UART011_RTIM | UART011_RXIM);
|
||||
+ pl011_write(uap->im, uap, REG_IMSC);
|
||||
+ spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
+}
|
||||
+
|
||||
+static void pl011_unthrottle(struct uart_port *port)
|
||||
+{
|
||||
+ struct uart_amba_port *uap =
|
||||
+ container_of(port, struct uart_amba_port, port);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&uap->port.lock, flags);
|
||||
+ uap->im |= UART011_RTIM;
|
||||
+ if (!pl011_dma_rx_running(uap))
|
||||
+ uap->im |= UART011_RXIM;
|
||||
+ pl011_write(uap->im, uap, REG_IMSC);
|
||||
+ spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
+}
|
||||
+
|
||||
static void pl011_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
@@ -2286,6 +2312,8 @@ static const struct uart_ops amba_pl011_pops = {
|
||||
.stop_tx = pl011_stop_tx,
|
||||
.start_tx = pl011_start_tx,
|
||||
.stop_rx = pl011_stop_rx,
|
||||
+ .throttle = pl011_throttle,
|
||||
+ .unthrottle = pl011_unthrottle,
|
||||
.enable_ms = pl011_enable_ms,
|
||||
.break_ctl = pl011_break_ctl,
|
||||
.startup = pl011_startup,
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
From 4957c6f9a91339b182625ad74aee2b392aa5d148 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 29 Jan 2020 09:35:19 +0000
|
||||
Subject: [PATCH 069/634] tty: amba-pl011: Avoid rare write-when-full error
|
||||
|
||||
Under some circumstances on BCM283x processors data loss can be
|
||||
observed - a single byte missing from the TX output stream. These bytes
|
||||
are always the last byte of a batch of 8 written from pl011_tx_chars
|
||||
when from_irq is true, meaning that the FIFO full flag is not checked
|
||||
before writing.
|
||||
|
||||
The transmit optimisation relies on the FIFO being half-empty when the
|
||||
TX interrupt is raised. Instrumenting the driver further showed that
|
||||
the failure case correlated with the TX FIFO full flag being set at the
|
||||
point where the last byte was written to the data register, which
|
||||
explains the data loss but not how the FIFO appeared to be prematurely
|
||||
full. A possible explanation is that a FIFO write was in flight at the
|
||||
time the interrupt was raised, but as yet there is no hypothesis as to
|
||||
how this might occur.
|
||||
|
||||
In the absence of a clear understanding of the failure mechanism, avoid
|
||||
the problem by checking the FIFO levels before writing the last byte of
|
||||
the group, which will have minimal performance impact.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/tty/serial/amba-pl011.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
||||
index 5e9a789e3c15..979fce6a05a7 100644
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -1505,6 +1505,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
|
||||
if (likely(from_irq) && count-- == 0)
|
||||
break;
|
||||
|
||||
+ if (likely(from_irq) && count == 0 &&
|
||||
+ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
|
||||
+ break;
|
||||
+
|
||||
if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
|
||||
break;
|
||||
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
From a6e1d77c5279b86105db8c352208e20e3c1822b6 Mon Sep 17 00:00:00 2001
|
||||
From: notro <notro@tronnes.org>
|
||||
Date: Thu, 10 Jul 2014 13:59:47 +0200
|
||||
Subject: [PATCH 070/634] pinctrl-bcm2835: Set base to 0 give expected gpio
|
||||
numbering
|
||||
|
||||
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
|
||||
|
||||
SQUASH: pinctrl: bcm2835: Set base for bcm2711 GPIO to 0
|
||||
|
||||
Without this patch GPIOs don't seem to work properly, primarily
|
||||
noticeable as broken LEDs.
|
||||
|
||||
Squash with "pinctrl-bcm2835: Set base to 0 give expected gpio numbering"
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
index 6e6fefeb21ea..7167927e9f26 100644
|
||||
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
|
||||
@@ -362,7 +362,7 @@ static const struct gpio_chip bcm2835_gpio_chip = {
|
||||
.get = bcm2835_gpio_get,
|
||||
.set = bcm2835_gpio_set,
|
||||
.set_config = gpiochip_generic_config,
|
||||
- .base = -1,
|
||||
+ .base = 0,
|
||||
.ngpio = BCM2835_NUM_GPIOS,
|
||||
.can_sleep = false,
|
||||
};
|
||||
@@ -378,7 +378,7 @@ static const struct gpio_chip bcm2711_gpio_chip = {
|
||||
.get = bcm2835_gpio_get,
|
||||
.set = bcm2835_gpio_set,
|
||||
.set_config = gpiochip_generic_config,
|
||||
- .base = -1,
|
||||
+ .base = 0,
|
||||
.ngpio = BCM2711_NUM_GPIOS,
|
||||
.can_sleep = false,
|
||||
};
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
From 404cf082aed147576fb07d389aa8f92d32fee9a5 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Sun, 12 May 2013 12:24:19 +0100
|
||||
Subject: [PATCH 071/634] Main bcm2708/bcm2709 linux port
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
bcm2709: Drop platform smp and timer init code
|
||||
|
||||
irq-bcm2836 handles this through these functions:
|
||||
bcm2835_init_local_timer_frequency()
|
||||
bcm2836_arm_irqchip_smp_init()
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
bcm270x: Use watchdog for reboot/poweroff
|
||||
|
||||
The watchdog driver already has support for reboot/poweroff.
|
||||
Make use of this and remove the code from the platform files.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
board_bcm2835: Remove coherent dma pool increase - API has gone
|
||||
---
|
||||
arch/arm/mach-bcm/Kconfig | 1 +
|
||||
arch/arm/mm/proc-v6.S | 15 ++++++++++++---
|
||||
drivers/irqchip/irq-bcm2835.c | 7 ++++++-
|
||||
drivers/mailbox/bcm2835-mailbox.c | 18 ++++++++++++++++--
|
||||
4 files changed, 35 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
|
||||
index 0462f870ab17..d802ded21ed6 100644
|
||||
--- a/arch/arm/mach-bcm/Kconfig
|
||||
+++ b/arch/arm/mach-bcm/Kconfig
|
||||
@@ -166,6 +166,7 @@ config ARCH_BCM2835
|
||||
select PINCTRL
|
||||
select PINCTRL_BCM2835
|
||||
select MFD_CORE
|
||||
+ select MFD_SYSCON if ARCH_MULTI_V7
|
||||
help
|
||||
This enables support for the Broadcom BCM2711 and BCM283x SoCs.
|
||||
This SoC is used in the Raspberry Pi and Roku 2 devices.
|
||||
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
|
||||
index a0618f3e6836..b3a2fce22eac 100644
|
||||
--- a/arch/arm/mm/proc-v6.S
|
||||
+++ b/arch/arm/mm/proc-v6.S
|
||||
@@ -70,10 +70,19 @@ ENDPROC(cpu_v6_reset)
|
||||
*
|
||||
* IRQs are already disabled.
|
||||
*/
|
||||
+
|
||||
+/* See jira SW-5991 for details of this workaround */
|
||||
ENTRY(cpu_v6_do_idle)
|
||||
- mov r1, #0
|
||||
- mcr p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
|
||||
- mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt
|
||||
+ .align 5
|
||||
+ mov r1, #2
|
||||
+1: subs r1, #1
|
||||
+ nop
|
||||
+ mcreq p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
|
||||
+ mcreq p15, 0, r1, c7, c0, 4 @ wait for interrupt
|
||||
+ nop
|
||||
+ nop
|
||||
+ nop
|
||||
+ bne 1b
|
||||
ret lr
|
||||
|
||||
ENTRY(cpu_v6_dcache_clean_area)
|
||||
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
|
||||
index e08c209521ac..4dbb4b16ee6e 100644
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -43,7 +43,9 @@
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
+#ifndef CONFIG_ARM64
|
||||
#include <asm/mach/irq.h>
|
||||
+#endif
|
||||
|
||||
/* Put the bank and irq (32 bits) into the hwirq */
|
||||
#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
|
||||
@@ -72,6 +74,7 @@
|
||||
#define NR_BANKS 3
|
||||
#define IRQS_PER_BANK 32
|
||||
#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
|
||||
+#undef FIQ_START
|
||||
#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
|
||||
|
||||
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
|
||||
@@ -253,10 +256,12 @@ static int __init armctrl_of_init(struct device_node *node,
|
||||
MAKE_HWIRQ(b, i) + NUMBER_IRQS);
|
||||
BUG_ON(irq <= 0);
|
||||
irq_set_chip(irq, &armctrl_chip);
|
||||
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
+ irq_set_probe(irq);
|
||||
}
|
||||
}
|
||||
+#ifndef CONFIG_ARM64
|
||||
init_FIQ(FIQ_START);
|
||||
+#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c
|
||||
index 86b7ce3549c5..f0c2ad3d59c9 100644
|
||||
--- a/drivers/mailbox/bcm2835-mailbox.c
|
||||
+++ b/drivers/mailbox/bcm2835-mailbox.c
|
||||
@@ -45,12 +45,15 @@
|
||||
#define MAIL1_WRT (ARM_0_MAIL1 + 0x00)
|
||||
#define MAIL1_STA (ARM_0_MAIL1 + 0x18)
|
||||
|
||||
+/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
|
||||
+#ifndef ARM_MS_FULL
|
||||
/* Status register: FIFO state. */
|
||||
#define ARM_MS_FULL BIT(31)
|
||||
#define ARM_MS_EMPTY BIT(30)
|
||||
|
||||
/* Configuration register: Enable interrupts. */
|
||||
#define ARM_MC_IHAVEDATAIRQEN BIT(0)
|
||||
+#endif
|
||||
|
||||
struct bcm2835_mbox {
|
||||
void __iomem *regs;
|
||||
@@ -145,7 +148,7 @@ static int bcm2835_mbox_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&mbox->lock);
|
||||
|
||||
- ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
|
||||
+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
|
||||
bcm2835_mbox_irq, 0, dev_name(dev), mbox);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
|
||||
@@ -194,7 +197,18 @@ static struct platform_driver bcm2835_mbox_driver = {
|
||||
},
|
||||
.probe = bcm2835_mbox_probe,
|
||||
};
|
||||
-module_platform_driver(bcm2835_mbox_driver);
|
||||
+
|
||||
+static int __init bcm2835_mbox_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&bcm2835_mbox_driver);
|
||||
+}
|
||||
+arch_initcall(bcm2835_mbox_init);
|
||||
+
|
||||
+static void __init bcm2835_mbox_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&bcm2835_mbox_driver);
|
||||
+}
|
||||
+module_exit(bcm2835_mbox_exit);
|
||||
|
||||
MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
|
||||
MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");
|
||||
--
|
||||
2.33.1
|
||||
|
61822
root/target/linux/bcm27xx/patches-5.15/0072-Add-dwc_otg-driver.patch
Normal file
61822
root/target/linux/bcm27xx/patches-5.15/0072-Add-dwc_otg-driver.patch
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,834 @@
|
|||
From 441052f1c98dde7ca5b6500e41e4b844ff6f9c5e Mon Sep 17 00:00:00 2001
|
||||
From: James Hughes <james.hughes@raspberrypi.org>
|
||||
Date: Thu, 14 Mar 2019 13:27:54 +0000
|
||||
Subject: [PATCH 074/634] Pulled in the multi frame buffer support from the Pi3
|
||||
repo
|
||||
|
||||
---
|
||||
drivers/video/fbdev/bcm2708_fb.c | 457 +++++++++++++++------
|
||||
include/soc/bcm2835/raspberrypi-firmware.h | 13 +
|
||||
2 files changed, 337 insertions(+), 133 deletions(-)
|
||||
|
||||
diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c
|
||||
index 831e9a7b6818..f66957d48dc3 100644
|
||||
--- a/drivers/video/fbdev/bcm2708_fb.c
|
||||
+++ b/drivers/video/fbdev/bcm2708_fb.c
|
||||
@@ -2,6 +2,7 @@
|
||||
* linux/drivers/video/bcm2708_fb.c
|
||||
*
|
||||
* Copyright (C) 2010 Broadcom
|
||||
+ * Copyright (C) 2018 Raspberry Pi (Trading) Ltd
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
@@ -13,6 +14,7 @@
|
||||
* Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
|
||||
*
|
||||
*/
|
||||
+
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -33,6 +35,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+#include <linux/mutex.h>
|
||||
|
||||
//#define BCM2708_FB_DEBUG
|
||||
#define MODULE_NAME "bcm2708_fb"
|
||||
@@ -79,64 +82,150 @@ struct bcm2708_fb_stats {
|
||||
u32 dma_irqs;
|
||||
};
|
||||
|
||||
+struct vc4_display_settings_t {
|
||||
+ u32 display_num;
|
||||
+ u32 width;
|
||||
+ u32 height;
|
||||
+ u32 depth;
|
||||
+ u32 pitch;
|
||||
+ u32 virtual_width;
|
||||
+ u32 virtual_height;
|
||||
+ u32 virtual_width_offset;
|
||||
+ u32 virtual_height_offset;
|
||||
+ unsigned long fb_bus_address;
|
||||
+};
|
||||
+
|
||||
+struct bcm2708_fb_dev;
|
||||
+
|
||||
struct bcm2708_fb {
|
||||
struct fb_info fb;
|
||||
struct platform_device *dev;
|
||||
- struct rpi_firmware *fw;
|
||||
u32 cmap[16];
|
||||
u32 gpu_cmap[256];
|
||||
- int dma_chan;
|
||||
- int dma_irq;
|
||||
- void __iomem *dma_chan_base;
|
||||
- void *cb_base; /* DMA control blocks */
|
||||
- dma_addr_t cb_handle;
|
||||
struct dentry *debugfs_dir;
|
||||
- wait_queue_head_t dma_waitq;
|
||||
- struct bcm2708_fb_stats stats;
|
||||
+ struct dentry *debugfs_subdir;
|
||||
unsigned long fb_bus_address;
|
||||
- bool disable_arm_alloc;
|
||||
+ struct { u32 base, length; } gpu;
|
||||
+ struct vc4_display_settings_t display_settings;
|
||||
+ struct debugfs_regset32 screeninfo_regset;
|
||||
+ struct bcm2708_fb_dev *fbdev;
|
||||
unsigned int image_size;
|
||||
dma_addr_t dma_addr;
|
||||
void *cpuaddr;
|
||||
};
|
||||
|
||||
+#define MAX_FRAMEBUFFERS 3
|
||||
+
|
||||
+struct bcm2708_fb_dev {
|
||||
+ int firmware_supports_multifb;
|
||||
+ /* Protects the DMA system from multiple FB access */
|
||||
+ struct mutex dma_mutex;
|
||||
+ int dma_chan;
|
||||
+ int dma_irq;
|
||||
+ void __iomem *dma_chan_base;
|
||||
+ wait_queue_head_t dma_waitq;
|
||||
+ bool disable_arm_alloc;
|
||||
+ struct bcm2708_fb_stats dma_stats;
|
||||
+ void *cb_base; /* DMA control blocks */
|
||||
+ dma_addr_t cb_handle;
|
||||
+ int instance_count;
|
||||
+ int num_displays;
|
||||
+ struct rpi_firmware *fw;
|
||||
+ struct bcm2708_fb displays[MAX_FRAMEBUFFERS];
|
||||
+};
|
||||
+
|
||||
#define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
|
||||
|
||||
static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb)
|
||||
{
|
||||
- debugfs_remove_recursive(fb->debugfs_dir);
|
||||
- fb->debugfs_dir = NULL;
|
||||
+ debugfs_remove_recursive(fb->debugfs_subdir);
|
||||
+ fb->debugfs_subdir = NULL;
|
||||
+
|
||||
+ fb->fbdev->instance_count--;
|
||||
+
|
||||
+ if (!fb->fbdev->instance_count) {
|
||||
+ debugfs_remove_recursive(fb->debugfs_dir);
|
||||
+ fb->debugfs_dir = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb)
|
||||
{
|
||||
+ char buf[3];
|
||||
+ struct bcm2708_fb_dev *fbdev = fb->fbdev;
|
||||
+
|
||||
static struct debugfs_reg32 stats_registers[] = {
|
||||
- {
|
||||
- "dma_copies",
|
||||
- offsetof(struct bcm2708_fb_stats, dma_copies)
|
||||
- },
|
||||
- {
|
||||
- "dma_irqs",
|
||||
- offsetof(struct bcm2708_fb_stats, dma_irqs)
|
||||
- },
|
||||
+ {"dma_copies", offsetof(struct bcm2708_fb_stats, dma_copies)},
|
||||
+ {"dma_irqs", offsetof(struct bcm2708_fb_stats, dma_irqs)},
|
||||
+ };
|
||||
+
|
||||
+ static struct debugfs_reg32 screeninfo[] = {
|
||||
+ {"width", offsetof(struct fb_var_screeninfo, xres)},
|
||||
+ {"height", offsetof(struct fb_var_screeninfo, yres)},
|
||||
+ {"bpp", offsetof(struct fb_var_screeninfo, bits_per_pixel)},
|
||||
+ {"xres_virtual", offsetof(struct fb_var_screeninfo, xres_virtual)},
|
||||
+ {"yres_virtual", offsetof(struct fb_var_screeninfo, yres_virtual)},
|
||||
+ {"xoffset", offsetof(struct fb_var_screeninfo, xoffset)},
|
||||
+ {"yoffset", offsetof(struct fb_var_screeninfo, yoffset)},
|
||||
};
|
||||
|
||||
- fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
|
||||
+ fb->debugfs_dir = debugfs_lookup(DRIVER_NAME, NULL);
|
||||
+
|
||||
+ if (!fb->debugfs_dir)
|
||||
+ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
|
||||
+
|
||||
if (!fb->debugfs_dir) {
|
||||
- pr_warn("%s: could not create debugfs entry\n",
|
||||
- __func__);
|
||||
+ dev_warn(fb->fb.dev, "%s: could not create debugfs folder\n",
|
||||
+ __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
- fb->stats.regset.regs = stats_registers;
|
||||
- fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
|
||||
- fb->stats.regset.base = &fb->stats;
|
||||
+ snprintf(buf, sizeof(buf), "%u", fb->display_settings.display_num);
|
||||
+
|
||||
+ fb->debugfs_subdir = debugfs_create_dir(buf, fb->debugfs_dir);
|
||||
|
||||
debugfs_create_regset32("stats", 0444, fb->debugfs_dir,
|
||||
&fb->stats.regset);
|
||||
+
|
||||
+ if (!fb->debugfs_subdir) {
|
||||
+ dev_warn(fb->fb.dev, "%s: could not create debugfs entry %u\n",
|
||||
+ __func__, fb->display_settings.display_num);
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ fbdev->dma_stats.regset.regs = stats_registers;
|
||||
+ fbdev->dma_stats.regset.nregs = ARRAY_SIZE(stats_registers);
|
||||
+ fbdev->dma_stats.regset.base = &fbdev->dma_stats;
|
||||
+
|
||||
+ debugfs_create_regset32("dma_stats", 0444, fb->debugfs_subdir,
|
||||
+ &fbdev->dma_stats.regset);
|
||||
+
|
||||
+ fb->screeninfo_regset.regs = screeninfo;
|
||||
+ fb->screeninfo_regset.nregs = ARRAY_SIZE(screeninfo);
|
||||
+ fb->screeninfo_regset.base = &fb->fb.var;
|
||||
+
|
||||
+ debugfs_create_regset32("screeninfo", 0444, fb->debugfs_subdir,
|
||||
+ &fb->screeninfo_regset);
|
||||
+
|
||||
+ fbdev->instance_count++;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void set_display_num(struct bcm2708_fb *fb)
|
||||
+{
|
||||
+ if (fb && fb->fbdev && fb->fbdev->firmware_supports_multifb) {
|
||||
+ u32 tmp = fb->display_settings.display_num;
|
||||
+
|
||||
+ if (rpi_firmware_property(fb->fbdev->fw,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM,
|
||||
+ &tmp,
|
||||
+ sizeof(tmp)))
|
||||
+ dev_warn_once(fb->fb.dev,
|
||||
+ "Set display number call failed. Old GPU firmware?");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -214,11 +303,11 @@ static int bcm2708_fb_check_var(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
/* info input, var output */
|
||||
- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n",
|
||||
+ print_debug("%s(%p) %ux%u (%ux%u), %ul, %u\n",
|
||||
__func__, info, info->var.xres, info->var.yres,
|
||||
info->var.xres_virtual, info->var.yres_virtual,
|
||||
- (int)info->screen_size, info->var.bits_per_pixel);
|
||||
- print_debug("%s(%p) %dx%d (%dx%d), %d\n", __func__, var, var->xres,
|
||||
+ info->screen_size, info->var.bits_per_pixel);
|
||||
+ print_debug("%s(%p) %ux%u (%ux%u), %u\n", __func__, var, var->xres,
|
||||
var->yres, var->xres_virtual, var->yres_virtual,
|
||||
var->bits_per_pixel);
|
||||
|
||||
@@ -281,17 +370,24 @@ static int bcm2708_fb_set_par(struct fb_info *info)
|
||||
};
|
||||
int ret, image_size;
|
||||
|
||||
-
|
||||
- print_debug("%s(%p) %dx%d (%dx%d), %d, %d\n", __func__, info,
|
||||
+ print_debug("%s(%p) %dx%d (%dx%d), %d, %d (display %d)\n", __func__,
|
||||
+ info,
|
||||
info->var.xres, info->var.yres, info->var.xres_virtual,
|
||||
info->var.yres_virtual, (int)info->screen_size,
|
||||
- info->var.bits_per_pixel);
|
||||
+ info->var.bits_per_pixel, value);
|
||||
+
|
||||
+ /* Need to set the display number to act on first
|
||||
+ * Cannot do it in the tag list because on older firmware the call
|
||||
+ * will fail and stop the rest of the list being executed.
|
||||
+ * We can ignore this call failing as the default at other end is 0
|
||||
+ */
|
||||
+ set_display_num(fb);
|
||||
|
||||
/* Try allocating our own buffer. We can specify all the parameters */
|
||||
image_size = ((info->var.xres * info->var.yres) *
|
||||
info->var.bits_per_pixel) >> 3;
|
||||
|
||||
- if (!fb->disable_arm_alloc &&
|
||||
+ if (!fb->fbdev->disable_arm_alloc &&
|
||||
(image_size != fb->image_size || !fb->dma_addr)) {
|
||||
if (fb->dma_addr) {
|
||||
dma_free_coherent(info->device, fb->image_size,
|
||||
@@ -306,7 +402,7 @@ static int bcm2708_fb_set_par(struct fb_info *info)
|
||||
|
||||
if (!fb->cpuaddr) {
|
||||
fb->dma_addr = 0;
|
||||
- fb->disable_arm_alloc = true;
|
||||
+ fb->fbdev->disable_arm_alloc = true;
|
||||
} else {
|
||||
fb->image_size = image_size;
|
||||
}
|
||||
@@ -317,7 +413,7 @@ static int bcm2708_fb_set_par(struct fb_info *info)
|
||||
fbinfo.screen_size = image_size;
|
||||
fbinfo.pitch = (info->var.xres * info->var.bits_per_pixel) >> 3;
|
||||
|
||||
- ret = rpi_firmware_property_list(fb->fw, &fbinfo,
|
||||
+ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
|
||||
sizeof(fbinfo));
|
||||
if (ret || fbinfo.base != fb->dma_addr) {
|
||||
/* Firmware either failed, or assigned a different base
|
||||
@@ -330,7 +426,7 @@ static int bcm2708_fb_set_par(struct fb_info *info)
|
||||
fb->image_size = 0;
|
||||
fb->cpuaddr = NULL;
|
||||
fb->dma_addr = 0;
|
||||
- fb->disable_arm_alloc = true;
|
||||
+ fb->fbdev->disable_arm_alloc = true;
|
||||
}
|
||||
} else {
|
||||
/* Our allocation failed - drop into the old scheme of
|
||||
@@ -349,7 +445,7 @@ static int bcm2708_fb_set_par(struct fb_info *info)
|
||||
fbinfo.tag6.tag = RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH;
|
||||
fbinfo.pitch = 0;
|
||||
|
||||
- ret = rpi_firmware_property_list(fb->fw, &fbinfo,
|
||||
+ ret = rpi_firmware_property_list(fb->fbdev->fw, &fbinfo,
|
||||
sizeof(fbinfo));
|
||||
if (ret) {
|
||||
dev_err(info->device,
|
||||
@@ -439,7 +535,10 @@ static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red,
|
||||
packet->length = regno + 1;
|
||||
memcpy(packet->cmap, fb->gpu_cmap,
|
||||
sizeof(packet->cmap));
|
||||
- ret = rpi_firmware_property(fb->fw,
|
||||
+
|
||||
+ set_display_num(fb);
|
||||
+
|
||||
+ ret = rpi_firmware_property(fb->fbdev->fw,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE,
|
||||
packet,
|
||||
(2 + packet->length) * sizeof(u32));
|
||||
@@ -478,8 +577,11 @@ static int bcm2708_fb_blank(int blank_mode, struct fb_info *info)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- ret = rpi_firmware_property(fb->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
|
||||
+ set_display_num(fb);
|
||||
+
|
||||
+ ret = rpi_firmware_property(fb->fbdev->fw, RPI_FIRMWARE_FRAMEBUFFER_BLANK,
|
||||
&value, sizeof(value));
|
||||
+
|
||||
if (ret)
|
||||
dev_err(info->device, "%s(%d) failed: %d\n", __func__,
|
||||
blank_mode, ret);
|
||||
@@ -496,12 +598,14 @@ static int bcm2708_fb_pan_display(struct fb_var_screeninfo *var,
|
||||
info->var.yoffset = var->yoffset;
|
||||
result = bcm2708_fb_set_par(info);
|
||||
if (result != 0)
|
||||
- pr_err("%s(%d,%d) returns=%d\n", __func__, var->xoffset,
|
||||
+ pr_err("%s(%u,%u) returns=%d\n", __func__, var->xoffset,
|
||||
var->yoffset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
|
||||
+static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
+ unsigned long arg)
|
||||
{
|
||||
struct bcm2708_fb *fb = to_bcm2708(info);
|
||||
u32 dummy = 0;
|
||||
@@ -509,7 +613,9 @@ static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long a
|
||||
|
||||
switch (cmd) {
|
||||
case FBIO_WAITFORVSYNC:
|
||||
- ret = rpi_firmware_property(fb->fw,
|
||||
+ set_display_num(fb);
|
||||
+
|
||||
+ ret = rpi_firmware_property(fb->fbdev->fw,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC,
|
||||
&dummy, sizeof(dummy));
|
||||
break;
|
||||
@@ -526,23 +632,22 @@ static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long a
|
||||
static void bcm2708_fb_fillrect(struct fb_info *info,
|
||||
const struct fb_fillrect *rect)
|
||||
{
|
||||
- /* (is called) print_debug("bcm2708_fb_fillrect\n"); */
|
||||
cfb_fillrect(info, rect);
|
||||
}
|
||||
|
||||
/* A helper function for configuring dma control block */
|
||||
static void set_dma_cb(struct bcm2708_dma_cb *cb,
|
||||
- int burst_size,
|
||||
- dma_addr_t dst,
|
||||
- int dst_stride,
|
||||
- dma_addr_t src,
|
||||
- int src_stride,
|
||||
- int w,
|
||||
- int h)
|
||||
+ int burst_size,
|
||||
+ dma_addr_t dst,
|
||||
+ int dst_stride,
|
||||
+ dma_addr_t src,
|
||||
+ int src_stride,
|
||||
+ int w,
|
||||
+ int h)
|
||||
{
|
||||
cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
|
||||
- BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
|
||||
- BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
|
||||
+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
|
||||
+ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
|
||||
cb->dst = dst;
|
||||
cb->src = src;
|
||||
/*
|
||||
@@ -560,15 +665,19 @@ static void bcm2708_fb_copyarea(struct fb_info *info,
|
||||
const struct fb_copyarea *region)
|
||||
{
|
||||
struct bcm2708_fb *fb = to_bcm2708(info);
|
||||
- struct bcm2708_dma_cb *cb = fb->cb_base;
|
||||
+ struct bcm2708_fb_dev *fbdev = fb->fbdev;
|
||||
+ struct bcm2708_dma_cb *cb = fbdev->cb_base;
|
||||
int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3;
|
||||
|
||||
/* Channel 0 supports larger bursts and is a bit faster */
|
||||
- int burst_size = (fb->dma_chan == 0) ? 8 : 2;
|
||||
+ int burst_size = (fbdev->dma_chan == 0) ? 8 : 2;
|
||||
int pixels = region->width * region->height;
|
||||
|
||||
- /* Fallback to cfb_copyarea() if we don't like something */
|
||||
- if (bytes_per_pixel > 4 ||
|
||||
+ /* If DMA is currently in use (ie being used on another FB), then
|
||||
+ * rather than wait for it to finish, just use the cfb_copyarea
|
||||
+ */
|
||||
+ if (!mutex_trylock(&fbdev->dma_mutex) ||
|
||||
+ bytes_per_pixel > 4 ||
|
||||
info->var.xres * info->var.yres > 1920 * 1200 ||
|
||||
region->width <= 0 || region->width > info->var.xres ||
|
||||
region->height <= 0 || region->height > info->var.yres ||
|
||||
@@ -595,8 +704,8 @@ static void bcm2708_fb_copyarea(struct fb_info *info,
|
||||
* 1920x1200 resolution at 32bpp pixel depth.
|
||||
*/
|
||||
int y;
|
||||
- dma_addr_t control_block_pa = fb->cb_handle;
|
||||
- dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024;
|
||||
+ dma_addr_t control_block_pa = fbdev->cb_handle;
|
||||
+ dma_addr_t scratchbuf = fbdev->cb_handle + 16 * 1024;
|
||||
int scanline_size = bytes_per_pixel * region->width;
|
||||
int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size;
|
||||
|
||||
@@ -646,10 +755,10 @@ static void bcm2708_fb_copyarea(struct fb_info *info,
|
||||
}
|
||||
set_dma_cb(cb, burst_size,
|
||||
fb->fb_bus_address + dy * fb->fb.fix.line_length +
|
||||
- bytes_per_pixel * region->dx,
|
||||
+ bytes_per_pixel * region->dx,
|
||||
stride,
|
||||
fb->fb_bus_address + sy * fb->fb.fix.line_length +
|
||||
- bytes_per_pixel * region->sx,
|
||||
+ bytes_per_pixel * region->sx,
|
||||
stride,
|
||||
region->width * bytes_per_pixel,
|
||||
region->height);
|
||||
@@ -659,32 +768,33 @@ static void bcm2708_fb_copyarea(struct fb_info *info,
|
||||
cb->next = 0;
|
||||
|
||||
if (pixels < dma_busy_wait_threshold) {
|
||||
- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
|
||||
- bcm_dma_wait_idle(fb->dma_chan_base);
|
||||
+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
|
||||
+ bcm_dma_wait_idle(fbdev->dma_chan_base);
|
||||
} else {
|
||||
- void __iomem *dma_chan = fb->dma_chan_base;
|
||||
+ void __iomem *local_dma_chan = fbdev->dma_chan_base;
|
||||
|
||||
cb->info |= BCM2708_DMA_INT_EN;
|
||||
- bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
|
||||
- while (bcm_dma_is_busy(dma_chan)) {
|
||||
- wait_event_interruptible(fb->dma_waitq,
|
||||
- !bcm_dma_is_busy(dma_chan));
|
||||
+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
|
||||
+ while (bcm_dma_is_busy(local_dma_chan)) {
|
||||
+ wait_event_interruptible(fbdev->dma_waitq,
|
||||
+ !bcm_dma_is_busy(local_dma_chan));
|
||||
}
|
||||
- fb->stats.dma_irqs++;
|
||||
+ fbdev->dma_stats.dma_irqs++;
|
||||
}
|
||||
- fb->stats.dma_copies++;
|
||||
+ fbdev->dma_stats.dma_copies++;
|
||||
+
|
||||
+ mutex_unlock(&fbdev->dma_mutex);
|
||||
}
|
||||
|
||||
static void bcm2708_fb_imageblit(struct fb_info *info,
|
||||
const struct fb_image *image)
|
||||
{
|
||||
- /* (is called) print_debug("bcm2708_fb_imageblit\n"); */
|
||||
cfb_imageblit(info, image);
|
||||
}
|
||||
|
||||
static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt)
|
||||
{
|
||||
- struct bcm2708_fb *fb = cxt;
|
||||
+ struct bcm2708_fb_dev *fbdev = cxt;
|
||||
|
||||
/* FIXME: should read status register to check if this is
|
||||
* actually interrupting us or not, in case this interrupt
|
||||
@@ -694,9 +804,9 @@ static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt)
|
||||
*/
|
||||
|
||||
/* acknowledge the interrupt */
|
||||
- writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS);
|
||||
+ writel(BCM2708_DMA_INT, fbdev->dma_chan_base + BCM2708_DMA_CS);
|
||||
|
||||
- wake_up(&fb->dma_waitq);
|
||||
+ wake_up(&fbdev->dma_waitq);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -729,11 +839,23 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb)
|
||||
fb->fb.fix.ywrapstep = 0;
|
||||
fb->fb.fix.accel = FB_ACCEL_NONE;
|
||||
|
||||
- fb->fb.var.xres = fbwidth;
|
||||
- fb->fb.var.yres = fbheight;
|
||||
- fb->fb.var.xres_virtual = fbwidth;
|
||||
- fb->fb.var.yres_virtual = fbheight;
|
||||
- fb->fb.var.bits_per_pixel = fbdepth;
|
||||
+ /* If we have data from the VC4 on FB's, use that, otherwise use the
|
||||
+ * module parameters
|
||||
+ */
|
||||
+ if (fb->display_settings.width) {
|
||||
+ fb->fb.var.xres = fb->display_settings.width;
|
||||
+ fb->fb.var.yres = fb->display_settings.height;
|
||||
+ fb->fb.var.xres_virtual = fb->fb.var.xres;
|
||||
+ fb->fb.var.yres_virtual = fb->fb.var.yres;
|
||||
+ fb->fb.var.bits_per_pixel = fb->display_settings.depth;
|
||||
+ } else {
|
||||
+ fb->fb.var.xres = fbwidth;
|
||||
+ fb->fb.var.yres = fbheight;
|
||||
+ fb->fb.var.xres_virtual = fbwidth;
|
||||
+ fb->fb.var.yres_virtual = fbheight;
|
||||
+ fb->fb.var.bits_per_pixel = fbdepth;
|
||||
+ }
|
||||
+
|
||||
fb->fb.var.vmode = FB_VMODE_NONINTERLACED;
|
||||
fb->fb.var.activate = FB_ACTIVATE_NOW;
|
||||
fb->fb.var.nonstd = 0;
|
||||
@@ -749,26 +871,23 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb)
|
||||
fb->fb.monspecs.dclkmax = 100000000;
|
||||
|
||||
bcm2708_fb_set_bitfields(&fb->fb.var);
|
||||
- init_waitqueue_head(&fb->dma_waitq);
|
||||
|
||||
/*
|
||||
* Allocate colourmap.
|
||||
*/
|
||||
-
|
||||
fb_set_var(&fb->fb, &fb->fb.var);
|
||||
+
|
||||
ret = bcm2708_fb_set_par(&fb->fb);
|
||||
+
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n",
|
||||
- fbwidth, fbheight, fbdepth, fbswap);
|
||||
-
|
||||
ret = register_framebuffer(&fb->fb);
|
||||
- print_debug("BCM2708FB: register framebuffer (%d)\n", ret);
|
||||
+
|
||||
if (ret == 0)
|
||||
goto out;
|
||||
|
||||
- print_debug("BCM2708FB: cannot register framebuffer (%d)\n", ret);
|
||||
+ dev_warn(fb->fb.dev, "Unable to register framebuffer (%d)\n", ret);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -777,10 +896,18 @@ static int bcm2708_fb_probe(struct platform_device *dev)
|
||||
{
|
||||
struct device_node *fw_np;
|
||||
struct rpi_firmware *fw;
|
||||
- struct bcm2708_fb *fb;
|
||||
- int ret;
|
||||
+ int ret, i;
|
||||
+ u32 num_displays;
|
||||
+ struct bcm2708_fb_dev *fbdev;
|
||||
+ struct { u32 base, length; } gpu_mem;
|
||||
+
|
||||
+ fbdev = devm_kzalloc(&dev->dev, sizeof(*fbdev), GFP_KERNEL);
|
||||
+
|
||||
+ if (!fbdev)
|
||||
+ return -ENOMEM;
|
||||
|
||||
fw_np = of_parse_phandle(dev->dev.of_node, "firmware", 0);
|
||||
+
|
||||
/* Remove comment when booting without Device Tree is no longer supported
|
||||
* if (!fw_np) {
|
||||
* dev_err(&dev->dev, "Missing firmware node\n");
|
||||
@@ -788,90 +915,154 @@ static int bcm2708_fb_probe(struct platform_device *dev)
|
||||
* }
|
||||
*/
|
||||
fw = rpi_firmware_get(fw_np);
|
||||
+ fbdev->fw = fw;
|
||||
+
|
||||
if (!fw)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
- fb = kzalloc(sizeof(*fb), GFP_KERNEL);
|
||||
- if (!fb) {
|
||||
- ret = -ENOMEM;
|
||||
- goto free_region;
|
||||
+ ret = rpi_firmware_property(fw,
|
||||
+ 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;
|
||||
+ dev_err(&dev->dev,
|
||||
+ "Unable to determine number of FB's. Assuming 1\n");
|
||||
+ ret = 0;
|
||||
+ } else {
|
||||
+ fbdev->firmware_supports_multifb = 1;
|
||||
}
|
||||
|
||||
- fb->fw = fw;
|
||||
- bcm2708_fb_debugfs_init(fb);
|
||||
+ if (num_displays > MAX_FRAMEBUFFERS) {
|
||||
+ dev_warn(&dev->dev,
|
||||
+ "More displays reported from firmware than supported in driver (%u vs %u)",
|
||||
+ num_displays, MAX_FRAMEBUFFERS);
|
||||
+ num_displays = MAX_FRAMEBUFFERS;
|
||||
+ }
|
||||
|
||||
- fb->cb_base = dma_alloc_wc(&dev->dev, SZ_64K,
|
||||
- &fb->cb_handle, GFP_KERNEL);
|
||||
- if (!fb->cb_base) {
|
||||
+ dev_info(&dev->dev, "FB found %d display(s)\n", num_displays);
|
||||
+
|
||||
+ /* Set up the DMA information. Note we have just one set of DMA
|
||||
+ * parameters to work with all the FB's so requires synchronising when
|
||||
+ * being used
|
||||
+ */
|
||||
+
|
||||
+ mutex_init(&fbdev->dma_mutex);
|
||||
+
|
||||
+ fbdev->cb_base = dma_alloc_wc(&dev->dev, SZ_64K,
|
||||
+ &fbdev->cb_handle,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!fbdev->cb_base) {
|
||||
dev_err(&dev->dev, "cannot allocate DMA CBs\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_fb;
|
||||
}
|
||||
|
||||
- pr_info("BCM2708FB: allocated DMA memory %pad\n", &fb->cb_handle);
|
||||
-
|
||||
ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
|
||||
- &fb->dma_chan_base, &fb->dma_irq);
|
||||
+ &fbdev->dma_chan_base,
|
||||
+ &fbdev->dma_irq);
|
||||
if (ret < 0) {
|
||||
- dev_err(&dev->dev, "couldn't allocate a DMA channel\n");
|
||||
+ dev_err(&dev->dev, "Couldn't allocate a DMA channel\n");
|
||||
goto free_cb;
|
||||
}
|
||||
- fb->dma_chan = ret;
|
||||
+ fbdev->dma_chan = ret;
|
||||
|
||||
- ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq,
|
||||
- 0, "bcm2708_fb dma", fb);
|
||||
+ ret = request_irq(fbdev->dma_irq, bcm2708_fb_dma_irq,
|
||||
+ 0, "bcm2708_fb DMA", fbdev);
|
||||
if (ret) {
|
||||
- pr_err("%s: failed to request DMA irq\n", __func__);
|
||||
+ dev_err(&dev->dev,
|
||||
+ "Failed to request DMA irq\n");
|
||||
goto free_dma_chan;
|
||||
}
|
||||
|
||||
- pr_info("BCM2708FB: allocated DMA channel %d\n", fb->dma_chan);
|
||||
+ rpi_firmware_property(fbdev->fw,
|
||||
+ RPI_FIRMWARE_GET_VC_MEMORY,
|
||||
+ &gpu_mem, sizeof(gpu_mem));
|
||||
|
||||
- fb->dev = dev;
|
||||
- fb->fb.device = &dev->dev;
|
||||
+ for (i = 0; i < num_displays; i++) {
|
||||
+ struct bcm2708_fb *fb = &fbdev->displays[i];
|
||||
|
||||
- /* failure here isn't fatal, but we'll fail in vc_mem_copy if
|
||||
- * fb->gpu is not valid
|
||||
- */
|
||||
- rpi_firmware_property(fb->fw, RPI_FIRMWARE_GET_VC_MEMORY, &fb->gpu,
|
||||
- sizeof(fb->gpu));
|
||||
+ fb->display_settings.display_num = i;
|
||||
+ fb->dev = dev;
|
||||
+ fb->fb.device = &dev->dev;
|
||||
+ fb->fbdev = fbdev;
|
||||
|
||||
- ret = bcm2708_fb_register(fb);
|
||||
- if (ret == 0) {
|
||||
- platform_set_drvdata(dev, fb);
|
||||
- goto out;
|
||||
+ fb->gpu.base = gpu_mem.base;
|
||||
+ fb->gpu.length = gpu_mem.length;
|
||||
+
|
||||
+ if (fbdev->firmware_supports_multifb) {
|
||||
+ ret = rpi_firmware_property(fw,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS,
|
||||
+ &fb->display_settings,
|
||||
+ GET_DISPLAY_SETTINGS_PAYLOAD_SIZE);
|
||||
+ } else {
|
||||
+ memset(&fb->display_settings, 0,
|
||||
+ sizeof(fb->display_settings));
|
||||
+ }
|
||||
+
|
||||
+ ret = bcm2708_fb_register(fb);
|
||||
+
|
||||
+ if (ret == 0) {
|
||||
+ bcm2708_fb_debugfs_init(fb);
|
||||
+
|
||||
+ fbdev->num_displays++;
|
||||
+
|
||||
+ dev_info(&dev->dev,
|
||||
+ "Registered framebuffer for display %u, size %ux%u\n",
|
||||
+ fb->display_settings.display_num,
|
||||
+ fb->fb.var.xres,
|
||||
+ fb->fb.var.yres);
|
||||
+ } else {
|
||||
+ // Use this to flag if this FB entry is in use.
|
||||
+ fb->fbdev = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Did we actually successfully create any FB's?
|
||||
+ if (fbdev->num_displays) {
|
||||
+ init_waitqueue_head(&fbdev->dma_waitq);
|
||||
+ platform_set_drvdata(dev, fbdev);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
free_dma_chan:
|
||||
- bcm_dma_chan_free(fb->dma_chan);
|
||||
+ bcm_dma_chan_free(fbdev->dma_chan);
|
||||
free_cb:
|
||||
- dma_free_wc(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
|
||||
+ dma_free_wc(&dev->dev, SZ_64K, fbdev->cb_base,
|
||||
+ fbdev->cb_handle);
|
||||
free_fb:
|
||||
- kfree(fb);
|
||||
-free_region:
|
||||
dev_err(&dev->dev, "probe failed, err %d\n", ret);
|
||||
-out:
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bcm2708_fb_remove(struct platform_device *dev)
|
||||
{
|
||||
- struct bcm2708_fb *fb = platform_get_drvdata(dev);
|
||||
+ struct bcm2708_fb_dev *fbdev = platform_get_drvdata(dev);
|
||||
+ int i;
|
||||
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
||||
- if (fb->fb.screen_base)
|
||||
- iounmap(fb->fb.screen_base);
|
||||
- unregister_framebuffer(&fb->fb);
|
||||
+ for (i = 0; i < fbdev->num_displays; i++) {
|
||||
+ if (fbdev->displays[i].fb.screen_base)
|
||||
+ iounmap(fbdev->displays[i].fb.screen_base);
|
||||
|
||||
- dma_free_wc(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
|
||||
- bcm_dma_chan_free(fb->dma_chan);
|
||||
-
|
||||
- bcm2708_fb_debugfs_deinit(fb);
|
||||
+ if (fbdev->displays[i].fbdev) {
|
||||
+ unregister_framebuffer(&fbdev->displays[i].fb);
|
||||
+ bcm2708_fb_debugfs_deinit(&fbdev->displays[i]);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- free_irq(fb->dma_irq, fb);
|
||||
+ dma_free_wc(&dev->dev, SZ_64K, fbdev->cb_base,
|
||||
+ fbdev->cb_handle);
|
||||
+ bcm_dma_chan_free(fbdev->dma_chan);
|
||||
+ free_irq(fbdev->dma_irq, fbdev);
|
||||
|
||||
- kfree(fb);
|
||||
+ mutex_destroy(&fbdev->dma_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -886,10 +1077,10 @@ static struct platform_driver bcm2708_fb_driver = {
|
||||
.probe = bcm2708_fb_probe,
|
||||
.remove = bcm2708_fb_remove,
|
||||
.driver = {
|
||||
- .name = DRIVER_NAME,
|
||||
- .owner = THIS_MODULE,
|
||||
- .of_match_table = bcm2708_fb_of_match_table,
|
||||
- },
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = bcm2708_fb_of_match_table,
|
||||
+ },
|
||||
};
|
||||
|
||||
static int __init bcm2708_fb_init(void)
|
||||
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
index 40b8a32fced0..a8cff19aea83 100644
|
||||
--- a/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
@@ -104,9 +104,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,
|
||||
@@ -115,6 +121,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,
|
||||
@@ -125,9 +133,12 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
|
||||
+
|
||||
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,
|
||||
@@ -136,6 +147,8 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
|
||||
};
|
||||
|
||||
+#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64
|
||||
+
|
||||
#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
|
||||
int rpi_firmware_property(struct rpi_firmware *fw,
|
||||
u32 tag, void *data, size_t len);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
From 52d69b5f72a13c68f51e2d4baf80d8fa436cc4b1 Mon Sep 17 00:00:00 2001
|
||||
From: Siarhei Siamashka <siarhei.siamashka@gmail.com>
|
||||
Date: Mon, 17 Jun 2013 13:32:11 +0300
|
||||
Subject: [PATCH 075/634] fbdev: add FBIOCOPYAREA ioctl
|
||||
|
||||
Based on the patch authored by Ali Gholami Rudi at
|
||||
https://lkml.org/lkml/2009/7/13/153
|
||||
|
||||
Provide an ioctl for userspace applications, but only if this operation
|
||||
is hardware accelerated (otherwide it does not make any sense).
|
||||
|
||||
Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
|
||||
|
||||
bcm2708_fb: Add ioctl for reading gpu memory through dma
|
||||
|
||||
video: bcm2708_fb: Add compat_ioctl support.
|
||||
|
||||
When using a 64 bit kernel with 32 bit userspace we need
|
||||
compat ioctl handling for FBIODMACOPY as one of the
|
||||
parameters is a pointer.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/video/fbdev/bcm2708_fb.c | 170 ++++++++++++++++++++++++++++++-
|
||||
drivers/video/fbdev/core/fbmem.c | 35 +++++++
|
||||
include/uapi/linux/fb.h | 12 +++
|
||||
3 files changed, 213 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/video/fbdev/bcm2708_fb.c b/drivers/video/fbdev/bcm2708_fb.c
|
||||
index f66957d48dc3..0e9ec3f593b8 100644
|
||||
--- a/drivers/video/fbdev/bcm2708_fb.c
|
||||
+++ b/drivers/video/fbdev/bcm2708_fb.c
|
||||
@@ -32,8 +32,10 @@
|
||||
#include <linux/printk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/debugfs.h>
|
||||
+#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
+#include <linux/cred.h>
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
@@ -184,9 +186,6 @@ static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb)
|
||||
|
||||
fb->debugfs_subdir = debugfs_create_dir(buf, fb->debugfs_dir);
|
||||
|
||||
- debugfs_create_regset32("stats", 0444, fb->debugfs_dir,
|
||||
- &fb->stats.regset);
|
||||
-
|
||||
if (!fb->debugfs_subdir) {
|
||||
dev_warn(fb->fb.dev, "%s: could not create debugfs entry %u\n",
|
||||
__func__, fb->display_settings.display_num);
|
||||
@@ -603,7 +602,110 @@ static int bcm2708_fb_pan_display(struct fb_var_screeninfo *var,
|
||||
return result;
|
||||
}
|
||||
|
||||
-static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
|
||||
+static void dma_memcpy(struct bcm2708_fb *fb, dma_addr_t dst, dma_addr_t src,
|
||||
+ int size)
|
||||
+{
|
||||
+ struct bcm2708_fb_dev *fbdev = fb->fbdev;
|
||||
+ struct bcm2708_dma_cb *cb = fbdev->cb_base;
|
||||
+ int burst_size = (fbdev->dma_chan == 0) ? 8 : 2;
|
||||
+
|
||||
+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
|
||||
+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
|
||||
+ BCM2708_DMA_D_INC;
|
||||
+ cb->dst = dst;
|
||||
+ cb->src = src;
|
||||
+ cb->length = size;
|
||||
+ cb->stride = 0;
|
||||
+ cb->pad[0] = 0;
|
||||
+ cb->pad[1] = 0;
|
||||
+ cb->next = 0;
|
||||
+
|
||||
+ // Not sure what to do if this gets a signal whilst waiting
|
||||
+ if (mutex_lock_interruptible(&fbdev->dma_mutex))
|
||||
+ return;
|
||||
+
|
||||
+ if (size < dma_busy_wait_threshold) {
|
||||
+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
|
||||
+ bcm_dma_wait_idle(fbdev->dma_chan_base);
|
||||
+ } else {
|
||||
+ void __iomem *local_dma_chan = fbdev->dma_chan_base;
|
||||
+
|
||||
+ cb->info |= BCM2708_DMA_INT_EN;
|
||||
+ bcm_dma_start(fbdev->dma_chan_base, fbdev->cb_handle);
|
||||
+ while (bcm_dma_is_busy(local_dma_chan)) {
|
||||
+ wait_event_interruptible(fbdev->dma_waitq,
|
||||
+ !bcm_dma_is_busy(local_dma_chan));
|
||||
+ }
|
||||
+ fbdev->dma_stats.dma_irqs++;
|
||||
+ }
|
||||
+ fbdev->dma_stats.dma_copies++;
|
||||
+
|
||||
+ mutex_unlock(&fbdev->dma_mutex);
|
||||
+}
|
||||
+
|
||||
+/* address with no aliases */
|
||||
+#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000)
|
||||
+/* cache coherent but non-allocating in L1 and L2 */
|
||||
+#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000)
|
||||
+
|
||||
+static long vc_mem_copy(struct bcm2708_fb *fb, struct fb_dmacopy *ioparam)
|
||||
+{
|
||||
+ size_t size = PAGE_SIZE;
|
||||
+ u32 *buf = NULL;
|
||||
+ dma_addr_t bus_addr;
|
||||
+ long rc = 0;
|
||||
+ size_t offset;
|
||||
+
|
||||
+ /* restrict this to root user */
|
||||
+ if (!uid_eq(current_euid(), GLOBAL_ROOT_UID)) {
|
||||
+ rc = -EFAULT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (!fb->gpu.base || !fb->gpu.length) {
|
||||
+ pr_err("[%s]: Unable to determine gpu memory (%x,%x)\n",
|
||||
+ __func__, fb->gpu.base, fb->gpu.length);
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ if (INTALIAS_NORMAL(ioparam->src) < fb->gpu.base ||
|
||||
+ INTALIAS_NORMAL(ioparam->src) >= fb->gpu.base + fb->gpu.length) {
|
||||
+ pr_err("[%s]: Invalid memory access %x (%x-%x)", __func__,
|
||||
+ INTALIAS_NORMAL(ioparam->src), fb->gpu.base,
|
||||
+ fb->gpu.base + fb->gpu.length);
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ buf = dma_alloc_coherent(fb->fb.device, PAGE_ALIGN(size), &bus_addr,
|
||||
+ GFP_ATOMIC);
|
||||
+ if (!buf) {
|
||||
+ pr_err("[%s]: failed to dma_alloc_coherent(%zd)\n", __func__,
|
||||
+ size);
|
||||
+ rc = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ for (offset = 0; offset < ioparam->length; offset += size) {
|
||||
+ size_t remaining = ioparam->length - offset;
|
||||
+ size_t s = min(size, remaining);
|
||||
+ u8 *p = (u8 *)((uintptr_t)ioparam->src + offset);
|
||||
+ u8 *q = (u8 *)ioparam->dst + offset;
|
||||
+
|
||||
+ dma_memcpy(fb, bus_addr,
|
||||
+ INTALIAS_L1L2_NONALLOCATING((dma_addr_t)p), size);
|
||||
+ if (copy_to_user(q, buf, s) != 0) {
|
||||
+ pr_err("[%s]: failed to copy-to-user\n", __func__);
|
||||
+ rc = -EFAULT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+out:
|
||||
+ if (buf)
|
||||
+ dma_free_coherent(fb->fb.device, PAGE_ALIGN(size), buf,
|
||||
+ bus_addr);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
@@ -619,6 +721,21 @@ static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC,
|
||||
&dummy, sizeof(dummy));
|
||||
break;
|
||||
+
|
||||
+ case FBIODMACOPY:
|
||||
+ {
|
||||
+ struct fb_dmacopy ioparam;
|
||||
+ /* Get the parameter data.
|
||||
+ */
|
||||
+ if (copy_from_user
|
||||
+ (&ioparam, (void *)arg, sizeof(ioparam))) {
|
||||
+ pr_err("[%s]: failed to copy-from-user\n", __func__);
|
||||
+ ret = -EFAULT;
|
||||
+ break;
|
||||
+ }
|
||||
+ ret = vc_mem_copy(fb, &ioparam);
|
||||
+ break;
|
||||
+ }
|
||||
default:
|
||||
dev_dbg(info->device, "Unknown ioctl 0x%x\n", cmd);
|
||||
return -ENOTTY;
|
||||
@@ -629,6 +746,48 @@ static int bcm2708_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
|
||||
return ret;
|
||||
}
|
||||
+
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+struct fb_dmacopy32 {
|
||||
+ compat_uptr_t dst;
|
||||
+ __u32 src;
|
||||
+ __u32 length;
|
||||
+};
|
||||
+
|
||||
+#define FBIODMACOPY32 _IOW('z', 0x22, struct fb_dmacopy32)
|
||||
+
|
||||
+static int bcm2708_compat_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
+ unsigned long arg)
|
||||
+{
|
||||
+ struct bcm2708_fb *fb = to_bcm2708(info);
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case FBIODMACOPY32:
|
||||
+ {
|
||||
+ struct fb_dmacopy32 param32;
|
||||
+ struct fb_dmacopy param;
|
||||
+ /* Get the parameter data.
|
||||
+ */
|
||||
+ if (copy_from_user(¶m32, (void *)arg, sizeof(param32))) {
|
||||
+ pr_err("[%s]: failed to copy-from-user\n", __func__);
|
||||
+ ret = -EFAULT;
|
||||
+ break;
|
||||
+ }
|
||||
+ param.dst = compat_ptr(param32.dst);
|
||||
+ param.src = param32.src;
|
||||
+ param.length = param32.length;
|
||||
+ ret = vc_mem_copy(fb, ¶m);
|
||||
+ break;
|
||||
+ }
|
||||
+ default:
|
||||
+ ret = bcm2708_ioctl(info, cmd, arg);
|
||||
+ break;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static void bcm2708_fb_fillrect(struct fb_info *info,
|
||||
const struct fb_fillrect *rect)
|
||||
{
|
||||
@@ -821,6 +980,9 @@ static struct fb_ops bcm2708_fb_ops = {
|
||||
.fb_imageblit = bcm2708_fb_imageblit,
|
||||
.fb_pan_display = bcm2708_fb_pan_display,
|
||||
.fb_ioctl = bcm2708_ioctl,
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+ .fb_compat_ioctl = bcm2708_compat_ioctl,
|
||||
+#endif
|
||||
};
|
||||
|
||||
static int bcm2708_fb_register(struct bcm2708_fb *fb)
|
||||
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
|
||||
index 7420d2c16e47..f9b620f6a074 100644
|
||||
--- a/drivers/video/fbdev/core/fbmem.c
|
||||
+++ b/drivers/video/fbdev/core/fbmem.c
|
||||
@@ -1085,6 +1085,30 @@ fb_blank(struct fb_info *info, int blank)
|
||||
}
|
||||
EXPORT_SYMBOL(fb_blank);
|
||||
|
||||
+static int fb_copyarea_user(struct fb_info *info,
|
||||
+ struct fb_copyarea *copy)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ lock_fb_info(info);
|
||||
+ if (copy->dx >= info->var.xres ||
|
||||
+ copy->sx >= info->var.xres ||
|
||||
+ copy->width > info->var.xres ||
|
||||
+ copy->dy >= info->var.yres ||
|
||||
+ copy->sy >= info->var.yres ||
|
||||
+ copy->height > info->var.yres ||
|
||||
+ copy->dx + copy->width > info->var.xres ||
|
||||
+ copy->sx + copy->width > info->var.xres ||
|
||||
+ copy->dy + copy->height > info->var.yres ||
|
||||
+ copy->sy + copy->height > info->var.yres) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ info->fbops->fb_copyarea(info, copy);
|
||||
+out:
|
||||
+ unlock_fb_info(info);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
@@ -1093,6 +1117,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
struct fb_fix_screeninfo fix;
|
||||
struct fb_cmap cmap_from;
|
||||
struct fb_cmap_user cmap;
|
||||
+ struct fb_copyarea copy;
|
||||
void __user *argp = (void __user *)arg;
|
||||
long ret = 0;
|
||||
|
||||
@@ -1168,6 +1193,15 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
unlock_fb_info(info);
|
||||
console_unlock();
|
||||
break;
|
||||
+ case FBIOCOPYAREA:
|
||||
+ if (info->flags & FBINFO_HWACCEL_COPYAREA) {
|
||||
+ /* only provide this ioctl if it is accelerated */
|
||||
+ if (copy_from_user(©, argp, sizeof(copy)))
|
||||
+ return -EFAULT;
|
||||
+ ret = fb_copyarea_user(info, ©);
|
||||
+ break;
|
||||
+ }
|
||||
+ /* fall through */
|
||||
default:
|
||||
lock_fb_info(info);
|
||||
fb = info->fbops;
|
||||
@@ -1307,6 +1341,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
|
||||
case FBIOPAN_DISPLAY:
|
||||
case FBIOGET_CON2FBMAP:
|
||||
case FBIOPUT_CON2FBMAP:
|
||||
+ case FBIOCOPYAREA:
|
||||
arg = (unsigned long) compat_ptr(arg);
|
||||
fallthrough;
|
||||
case FBIOBLANK:
|
||||
diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h
|
||||
index 4c14e8be7267..3c6f12b76214 100644
|
||||
--- a/include/uapi/linux/fb.h
|
||||
+++ b/include/uapi/linux/fb.h
|
||||
@@ -35,6 +35,12 @@
|
||||
#define FBIOPUT_MODEINFO 0x4617
|
||||
#define FBIOGET_DISPINFO 0x4618
|
||||
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
|
||||
+/*
|
||||
+ * HACK: use 'z' in order not to clash with any other ioctl numbers which might
|
||||
+ * be concurrently added to the mainline kernel
|
||||
+ */
|
||||
+#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea)
|
||||
+#define FBIODMACOPY _IOW('z', 0x22, struct fb_dmacopy)
|
||||
|
||||
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
|
||||
#define FB_TYPE_PLANES 1 /* Non interleaved planes */
|
||||
@@ -348,6 +354,12 @@ struct fb_copyarea {
|
||||
__u32 sy;
|
||||
};
|
||||
|
||||
+struct fb_dmacopy {
|
||||
+ void *dst;
|
||||
+ __u32 src;
|
||||
+ __u32 length;
|
||||
+};
|
||||
+
|
||||
struct fb_fillrect {
|
||||
__u32 dx; /* screen-relative */
|
||||
__u32 dy;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
From 17159d3029ede4324a930ab62cb38d9844e2071e Mon Sep 17 00:00:00 2001
|
||||
From: Harm Hanemaaijer <fgenfb@yahoo.com>
|
||||
Date: Thu, 20 Jun 2013 20:21:39 +0200
|
||||
Subject: [PATCH 076/634] Speed up console framebuffer imageblit function
|
||||
|
||||
Especially on platforms with a slower CPU but a relatively high
|
||||
framebuffer fill bandwidth, like current ARM devices, the existing
|
||||
console monochrome imageblit function used to draw console text is
|
||||
suboptimal for common pixel depths such as 16bpp and 32bpp. The existing
|
||||
code is quite general and can deal with several pixel depths. By creating
|
||||
special case functions for 16bpp and 32bpp, by far the most common pixel
|
||||
formats used on modern systems, a significant speed-up is attained
|
||||
which can be readily felt on ARM-based devices like the Raspberry Pi
|
||||
and the Allwinner platform, but should help any platform using the
|
||||
fb layer.
|
||||
|
||||
The special case functions allow constant folding, eliminating a number
|
||||
of instructions including divide operations, and allow the use of an
|
||||
unrolled loop, eliminating instructions with a variable shift size,
|
||||
reducing source memory access instructions, and eliminating excessive
|
||||
branching. These unrolled loops also allow much better code optimization
|
||||
by the C compiler. The code that selects which optimized variant is used
|
||||
is also simplified, eliminating integer divide instructions.
|
||||
|
||||
The speed-up, measured by timing 'cat file.txt' in the console, varies
|
||||
between 40% and 70%, when testing on the Raspberry Pi and Allwinner
|
||||
ARM-based platforms, depending on font size and the pixel depth, with
|
||||
the greater benefit for 32bpp.
|
||||
|
||||
Signed-off-by: Harm Hanemaaijer <fgenfb@yahoo.com>
|
||||
---
|
||||
drivers/video/fbdev/core/cfbimgblt.c | 152 ++++++++++++++++++++++++++-
|
||||
1 file changed, 147 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c
|
||||
index a2bb276a8b24..436494fba15a 100644
|
||||
--- a/drivers/video/fbdev/core/cfbimgblt.c
|
||||
+++ b/drivers/video/fbdev/core/cfbimgblt.c
|
||||
@@ -28,6 +28,11 @@
|
||||
*
|
||||
* Also need to add code to deal with cards endians that are different than
|
||||
* the native cpu endians. I also need to deal with MSB position in the word.
|
||||
+ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013:
|
||||
+ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are
|
||||
+ * significantly faster than the previous implementation.
|
||||
+ * - Simplify the fast/slow_imageblit selection code, avoiding integer
|
||||
+ * divides.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
@@ -262,6 +267,133 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
|
||||
}
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded
|
||||
+ * into the code, main loop unrolled.
|
||||
+ */
|
||||
+
|
||||
+static inline void fast_imageblit16(const struct fb_image *image,
|
||||
+ struct fb_info *p, u8 __iomem * dst1,
|
||||
+ u32 fgcolor, u32 bgcolor)
|
||||
+{
|
||||
+ u32 fgx = fgcolor, bgx = bgcolor;
|
||||
+ u32 spitch = (image->width + 7) / 8;
|
||||
+ u32 end_mask, eorx;
|
||||
+ const char *s = image->data, *src;
|
||||
+ u32 __iomem *dst;
|
||||
+ const u32 *tab = NULL;
|
||||
+ int i, j, k;
|
||||
+
|
||||
+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
|
||||
+
|
||||
+ fgx <<= 16;
|
||||
+ bgx <<= 16;
|
||||
+ fgx |= fgcolor;
|
||||
+ bgx |= bgcolor;
|
||||
+
|
||||
+ eorx = fgx ^ bgx;
|
||||
+ k = image->width / 2;
|
||||
+
|
||||
+ for (i = image->height; i--;) {
|
||||
+ dst = (u32 __iomem *) dst1;
|
||||
+ src = s;
|
||||
+
|
||||
+ j = k;
|
||||
+ while (j >= 4) {
|
||||
+ u8 bits = *src;
|
||||
+ end_mask = tab[(bits >> 6) & 3];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 4) & 3];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 2) & 3];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[bits & 3];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ src++;
|
||||
+ j -= 4;
|
||||
+ }
|
||||
+ if (j != 0) {
|
||||
+ u8 bits = *src;
|
||||
+ end_mask = tab[(bits >> 6) & 3];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ if (j >= 2) {
|
||||
+ end_mask = tab[(bits >> 4) & 3];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ if (j == 3) {
|
||||
+ end_mask = tab[(bits >> 2) & 3];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ dst1 += p->fix.line_length;
|
||||
+ s += spitch;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded
|
||||
+ * into the code, main loop unrolled.
|
||||
+ */
|
||||
+
|
||||
+static inline void fast_imageblit32(const struct fb_image *image,
|
||||
+ struct fb_info *p, u8 __iomem * dst1,
|
||||
+ u32 fgcolor, u32 bgcolor)
|
||||
+{
|
||||
+ u32 fgx = fgcolor, bgx = bgcolor;
|
||||
+ u32 spitch = (image->width + 7) / 8;
|
||||
+ u32 end_mask, eorx;
|
||||
+ const char *s = image->data, *src;
|
||||
+ u32 __iomem *dst;
|
||||
+ const u32 *tab = NULL;
|
||||
+ int i, j, k;
|
||||
+
|
||||
+ tab = cfb_tab32;
|
||||
+
|
||||
+ eorx = fgx ^ bgx;
|
||||
+ k = image->width;
|
||||
+
|
||||
+ for (i = image->height; i--;) {
|
||||
+ dst = (u32 __iomem *) dst1;
|
||||
+ src = s;
|
||||
+
|
||||
+ j = k;
|
||||
+ while (j >= 8) {
|
||||
+ u8 bits = *src;
|
||||
+ end_mask = tab[(bits >> 7) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 6) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 5) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 4) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 3) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 2) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[(bits >> 1) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ end_mask = tab[bits & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ src++;
|
||||
+ j -= 8;
|
||||
+ }
|
||||
+ if (j != 0) {
|
||||
+ u32 bits = (u32) * src;
|
||||
+ while (j > 1) {
|
||||
+ end_mask = tab[(bits >> 7) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
|
||||
+ bits <<= 1;
|
||||
+ j--;
|
||||
+ }
|
||||
+ end_mask = tab[(bits >> 7) & 1];
|
||||
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
|
||||
+ }
|
||||
+ dst1 += p->fix.line_length;
|
||||
+ s += spitch;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
|
||||
{
|
||||
u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
|
||||
@@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
|
||||
bgcolor = image->bg_color;
|
||||
}
|
||||
|
||||
- if (32 % bpp == 0 && !start_index && !pitch_index &&
|
||||
- ((width & (32/bpp-1)) == 0) &&
|
||||
- bpp >= 8 && bpp <= 32)
|
||||
- fast_imageblit(image, p, dst1, fgcolor, bgcolor);
|
||||
- else
|
||||
+ if (!start_index && !pitch_index) {
|
||||
+ if (bpp == 32)
|
||||
+ fast_imageblit32(image, p, dst1, fgcolor,
|
||||
+ bgcolor);
|
||||
+ else if (bpp == 16 && (width & 1) == 0)
|
||||
+ fast_imageblit16(image, p, dst1, fgcolor,
|
||||
+ bgcolor);
|
||||
+ else if (bpp == 8 && (width & 3) == 0)
|
||||
+ fast_imageblit(image, p, dst1, fgcolor,
|
||||
+ bgcolor);
|
||||
+ else
|
||||
+ slow_imageblit(image, p, dst1, fgcolor,
|
||||
+ bgcolor,
|
||||
+ start_index, pitch_index);
|
||||
+ } else
|
||||
slow_imageblit(image, p, dst1, fgcolor, bgcolor,
|
||||
start_index, pitch_index);
|
||||
} else
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,653 @@
|
|||
From b6c946afd75d362d948800546f05aceb24866f55 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Meier <florian.meier@koalo.de>
|
||||
Date: Fri, 22 Nov 2013 14:22:53 +0100
|
||||
Subject: [PATCH 077/634] dmaengine: Add support for BCM2708
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add support for DMA controller of BCM2708 as used in the Raspberry Pi.
|
||||
Currently it only supports cyclic DMA.
|
||||
|
||||
Signed-off-by: Florian Meier <florian.meier@koalo.de>
|
||||
|
||||
dmaengine: expand functionality by supporting scatter/gather transfers sdhci-bcm2708 and dma.c: fix for LITE channels
|
||||
|
||||
DMA: fix cyclic LITE length overflow bug
|
||||
|
||||
dmaengine: bcm2708: Remove chancnt affectations
|
||||
|
||||
Mirror bcm2835-dma.c commit 9eba5536a7434c69d8c185d4bd1c70734d92287d:
|
||||
chancnt is already filled by dma_async_device_register, which uses the channel
|
||||
list to know how much channels there is.
|
||||
|
||||
Since it's already filled, we can safely remove it from the drivers' probe
|
||||
function.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: overwrite dreq only if it is not set
|
||||
|
||||
dreq is set when the DMA channel is fetched from Device Tree.
|
||||
slave_id is set using dmaengine_slave_config().
|
||||
Only overwrite dreq with slave_id if it is not set.
|
||||
|
||||
dreq/slave_id in the cyclic DMA case is not touched, because I don't
|
||||
have hardware to test with.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: do device registration in the board file
|
||||
|
||||
Don't register the device in the driver. Do it in the board file.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: don't restrict DT support to ARCH_BCM2835
|
||||
|
||||
Both ARCH_BCM2835 and ARCH_BCM270x are built with OF now.
|
||||
Add Device Tree support to the non ARCH_BCM2835 case.
|
||||
Use the same driver name regardless of architecture.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
BCM270x_DT: add bcm2835-dma entry
|
||||
|
||||
Add Device Tree entry for bcm2835-dma.
|
||||
The entry doesn't contain any resources since they are handled
|
||||
by the arch/arm/mach-bcm270x/dma.c driver.
|
||||
In non-DT mode, don't add the device in the board file.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
bcm2708-dmaengine: Add debug options
|
||||
|
||||
BCM270x: Add memory and irq resources to dmaengine device and DT
|
||||
|
||||
Prepare for merging of the legacy DMA API arch driver dma.c
|
||||
with bcm2708-dmaengine by adding memory and irq resources both
|
||||
to platform file device and Device Tree node.
|
||||
Don't use BCM_DMAMAN_DRIVER_NAME so we don't have to include mach/dma.h
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: Merge with arch dma.c driver and disable dma.c
|
||||
|
||||
Merge the legacy DMA API driver with bcm2708-dmaengine.
|
||||
This is done so we can use bcm2708_fb on ARCH_BCM2835 (mailbox
|
||||
driver is also needed).
|
||||
|
||||
Changes to the dma.c code:
|
||||
- Use BIT() macro.
|
||||
- Cutdown some comments to one line.
|
||||
- Add mutex to vc_dmaman and use this, since the dev lock is locked
|
||||
during probing of the engine part.
|
||||
- Add global g_dmaman variable since drvdata is used by the engine part.
|
||||
- Restructure for readability:
|
||||
vc_dmaman_chan_alloc()
|
||||
vc_dmaman_chan_free()
|
||||
bcm_dma_chan_free()
|
||||
- Restructure bcm_dma_chan_alloc() to simplify error handling.
|
||||
- Use device irq resources instead of hardcoded bcm_dma_irqs table.
|
||||
- Remove dev_dmaman_register() and code it directly.
|
||||
- Remove dev_dmaman_deregister() and code it directly.
|
||||
- Simplify bcm_dmaman_probe() using devm_* functions.
|
||||
- Get dmachans from DT if available.
|
||||
- Keep 'dma.dmachans' module argument name for backwards compatibility.
|
||||
|
||||
Make it available on ARCH_BCM2835 as well.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: set residue_granularity field
|
||||
|
||||
bcm2708-dmaengine supports residue reporting at burst level
|
||||
but didn't report this via the residue_granularity field.
|
||||
|
||||
Without this field set properly we get playback issues with I2S cards.
|
||||
|
||||
dmaengine: bcm2708-dmaengine: Fix memory leak when stopping a running transfer
|
||||
|
||||
bcm2708-dmaengine: Use more DMA channels (but not 12)
|
||||
|
||||
1) Only the bcm2708_fb drivers uses the legacy DMA API, and
|
||||
it requires a BULK-capable channel, so all other types
|
||||
(FAST, NORMAL and LITE) can be made available to the regular
|
||||
DMA API.
|
||||
|
||||
2) DMA channels 11-14 share an interrupt. The driver can't
|
||||
handle this, so don't use channels 12-14 (12 was used, probably
|
||||
because it appears to have an interrupt, but in reality that
|
||||
interrupt is for activity on ANY channel). This may explain
|
||||
a lockup encountered when running out of DMA channels.
|
||||
|
||||
The combined effect of this patch is to leave 7 DMA channels
|
||||
available + channel 0 for bcm2708_fb via the legacy API.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1110
|
||||
https://github.com/raspberrypi/linux/issues/1108
|
||||
|
||||
dmaengine: bcm2708: Make legacy API available for bcm2835-dma
|
||||
|
||||
bcm2708_fb uses the legacy DMA API, so in order to start using
|
||||
bcm2835-dma, bcm2835-dma has to support the legacy API. Make this
|
||||
possible by exporting bcm_dmaman_probe() and bcm_dmaman_remove().
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: Change DT compatible string
|
||||
|
||||
Both bcm2835-dma and bcm2708-dmaengine have the same compatible string.
|
||||
So change compatible to "brcm,bcm2708-dma".
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: Remove driver but keep legacy API
|
||||
|
||||
Dropping non-DT support means we don't need this driver,
|
||||
but we still need the legacy DMA API.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
bcm2708-dmaengine - Fix arm64 portability/build issues
|
||||
|
||||
dma-bcm2708: Fix module compilation of CONFIG_DMA_BCM2708
|
||||
|
||||
bcm2708-dmaengine.c defines functions like bcm_dma_start which are
|
||||
defined as well in dma-bcm2708.h as inline versions when
|
||||
CONFIG_DMA_BCM2708 is not defined. This works fine when
|
||||
CONFIG_DMA_BCM2708 is built in, but when it is selected as module build
|
||||
fails with redefinition errors because in the build system when
|
||||
CONFIG_DMA_BCM2708 is selected as module, the macro becomes
|
||||
CONFIG_DMA_BCM2708_MODULE.
|
||||
|
||||
This patch makes the header use CONFIG_DMA_BCM2708_MODULE too when
|
||||
available.
|
||||
|
||||
Fixes https://github.com/raspberrypi/linux/issues/2056
|
||||
|
||||
Signed-off-by: Andrei Gherzan <andrei@gherzan.com>
|
||||
---
|
||||
drivers/dma/Kconfig | 6 +-
|
||||
drivers/dma/Makefile | 1 +
|
||||
drivers/dma/bcm2708-dmaengine.c | 281 ++++++++++++++++++++++
|
||||
include/linux/platform_data/dma-bcm2708.h | 143 +++++++++++
|
||||
4 files changed, 430 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/dma/bcm2708-dmaengine.c
|
||||
create mode 100644 include/linux/platform_data/dma-bcm2708.h
|
||||
|
||||
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
|
||||
index f5afe0ec4f96..bb1e9fb7ecda 100644
|
||||
--- a/drivers/dma/Kconfig
|
||||
+++ b/drivers/dma/Kconfig
|
||||
@@ -127,7 +127,7 @@ config BCM_SBA_RAID
|
||||
|
||||
config DMA_BCM2835
|
||||
tristate "BCM2835 DMA engine support"
|
||||
- depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
|
||||
+ depends on ARCH_BCM2835
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
|
||||
@@ -683,6 +683,10 @@ config UNIPHIER_XDMAC
|
||||
UniPhier platform. This DMA controller can transfer data from
|
||||
memory to memory, memory to peripheral and peripheral to memory.
|
||||
|
||||
+config DMA_BCM2708
|
||||
+ tristate "BCM2708 DMA legacy API support"
|
||||
+ depends on DMA_BCM2835
|
||||
+
|
||||
config XGENE_DMA
|
||||
tristate "APM X-Gene DMA support"
|
||||
depends on ARCH_XGENE || COMPILE_TEST
|
||||
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
|
||||
index 616d926cf2a5..2f9fa1a12f51 100644
|
||||
--- a/drivers/dma/Makefile
|
||||
+++ b/drivers/dma/Makefile
|
||||
@@ -21,6 +21,7 @@ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
|
||||
obj-$(CONFIG_AT_XDMAC) += at_xdmac.o
|
||||
obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o
|
||||
obj-$(CONFIG_BCM_SBA_RAID) += bcm-sba-raid.o
|
||||
+obj-$(CONFIG_DMA_BCM2708) += bcm2708-dmaengine.o
|
||||
obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
|
||||
obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o
|
||||
obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
|
||||
diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c
|
||||
new file mode 100644
|
||||
index 000000000000..075da9aadf6d
|
||||
--- /dev/null
|
||||
+++ b/drivers/dma/bcm2708-dmaengine.c
|
||||
@@ -0,0 +1,281 @@
|
||||
+/*
|
||||
+ * BCM2708 legacy DMA API
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_data/dma-bcm2708.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+
|
||||
+#include "virt-dma.h"
|
||||
+
|
||||
+#define CACHE_LINE_MASK 31
|
||||
+#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */
|
||||
+
|
||||
+/* valid only for channels 0 - 14, 15 has its own base address */
|
||||
+#define BCM2708_DMA_CHAN(n) ((n) << 8) /* base address */
|
||||
+#define BCM2708_DMA_CHANIO(dma_base, n) \
|
||||
+ ((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n)))
|
||||
+
|
||||
+struct vc_dmaman {
|
||||
+ void __iomem *dma_base;
|
||||
+ u32 chan_available; /* bitmap of available channels */
|
||||
+ u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */
|
||||
+ struct mutex lock;
|
||||
+};
|
||||
+
|
||||
+static struct device *dmaman_dev; /* we assume there's only one! */
|
||||
+static struct vc_dmaman *g_dmaman; /* DMA manager */
|
||||
+
|
||||
+/* DMA Auxiliary Functions */
|
||||
+
|
||||
+/* A DMA buffer on an arbitrary boundary may separate a cache line into a
|
||||
+ section inside the DMA buffer and another section outside it.
|
||||
+ Even if we flush DMA buffers from the cache there is always the chance that
|
||||
+ during a DMA someone will access the part of a cache line that is outside
|
||||
+ the DMA buffer - which will then bring in unwelcome data.
|
||||
+ Without being able to dictate our own buffer pools we must insist that
|
||||
+ DMA buffers consist of a whole number of cache lines.
|
||||
+*/
|
||||
+extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < sg_len; i++) {
|
||||
+ if (sg_ptr[i].offset & CACHE_LINE_MASK ||
|
||||
+ sg_ptr[i].length & CACHE_LINE_MASK)
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma);
|
||||
+
|
||||
+extern void bcm_dma_start(void __iomem *dma_chan_base,
|
||||
+ dma_addr_t control_block)
|
||||
+{
|
||||
+ dsb(sy); /* ARM data synchronization (push) operation */
|
||||
+
|
||||
+ writel(control_block, dma_chan_base + BCM2708_DMA_ADDR);
|
||||
+ writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_start);
|
||||
+
|
||||
+extern void bcm_dma_wait_idle(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ dsb(sy);
|
||||
+
|
||||
+ /* ugly busy wait only option for now */
|
||||
+ while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE)
|
||||
+ cpu_relax();
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_wait_idle);
|
||||
+
|
||||
+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ dsb(sy);
|
||||
+
|
||||
+ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_is_busy);
|
||||
+
|
||||
+/* Complete an ongoing DMA (assuming its results are to be ignored)
|
||||
+ Does nothing if there is no DMA in progress.
|
||||
+ This routine waits for the current AXI transfer to complete before
|
||||
+ terminating the current DMA. If the current transfer is hung on a DREQ used
|
||||
+ by an uncooperative peripheral the AXI transfer may never complete. In this
|
||||
+ case the routine times out and return a non-zero error code.
|
||||
+ Use of this routine doesn't guarantee that the ongoing or aborted DMA
|
||||
+ does not produce an interrupt.
|
||||
+*/
|
||||
+extern int bcm_dma_abort(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ unsigned long int cs;
|
||||
+ int rc = 0;
|
||||
+
|
||||
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
|
||||
+
|
||||
+ if (BCM2708_DMA_ACTIVE & cs) {
|
||||
+ long int timeout = 10000;
|
||||
+
|
||||
+ /* write 0 to the active bit - pause the DMA */
|
||||
+ writel(0, dma_chan_base + BCM2708_DMA_CS);
|
||||
+
|
||||
+ /* wait for any current AXI transfer to complete */
|
||||
+ while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0)
|
||||
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
|
||||
+
|
||||
+ if (0 != (cs & BCM2708_DMA_ISPAUSED)) {
|
||||
+ /* we'll un-pause when we set of our next DMA */
|
||||
+ rc = -ETIMEDOUT;
|
||||
+
|
||||
+ } else if (BCM2708_DMA_ACTIVE & cs) {
|
||||
+ /* terminate the control block chain */
|
||||
+ writel(0, dma_chan_base + BCM2708_DMA_NEXTCB);
|
||||
+
|
||||
+ /* abort the whole DMA */
|
||||
+ writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE,
|
||||
+ dma_chan_base + BCM2708_DMA_CS);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_abort);
|
||||
+
|
||||
+ /* DMA Manager Device Methods */
|
||||
+
|
||||
+static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base,
|
||||
+ u32 chans_available)
|
||||
+{
|
||||
+ dmaman->dma_base = dma_base;
|
||||
+ dmaman->chan_available = chans_available;
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* 2 & 3 */
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* 0 */
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* 1 to 7 */
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* 8 to 14 */
|
||||
+}
|
||||
+
|
||||
+static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman,
|
||||
+ unsigned required_feature_set)
|
||||
+{
|
||||
+ u32 chans;
|
||||
+ int chan = 0;
|
||||
+ int feature;
|
||||
+
|
||||
+ chans = dmaman->chan_available;
|
||||
+ for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++)
|
||||
+ /* select the subset of available channels with the desired
|
||||
+ features */
|
||||
+ if (required_feature_set & (1 << feature))
|
||||
+ chans &= dmaman->has_feature[feature];
|
||||
+
|
||||
+ if (!chans)
|
||||
+ return -ENOENT;
|
||||
+
|
||||
+ /* return the ordinal of the first channel in the bitmap */
|
||||
+ while (chans != 0 && (chans & 1) == 0) {
|
||||
+ chans >>= 1;
|
||||
+ chan++;
|
||||
+ }
|
||||
+ /* claim the channel */
|
||||
+ dmaman->chan_available &= ~(1 << chan);
|
||||
+
|
||||
+ return chan;
|
||||
+}
|
||||
+
|
||||
+static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan)
|
||||
+{
|
||||
+ if (chan < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((1 << chan) & dmaman->chan_available)
|
||||
+ return -EIDRM;
|
||||
+
|
||||
+ dmaman->chan_available |= (1 << chan);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* DMA Manager Monitor */
|
||||
+
|
||||
+extern int bcm_dma_chan_alloc(unsigned required_feature_set,
|
||||
+ void __iomem **out_dma_base, int *out_dma_irq)
|
||||
+{
|
||||
+ struct vc_dmaman *dmaman = g_dmaman;
|
||||
+ struct platform_device *pdev = to_platform_device(dmaman_dev);
|
||||
+ struct resource *r;
|
||||
+ int chan;
|
||||
+
|
||||
+ if (!dmaman_dev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ mutex_lock(&dmaman->lock);
|
||||
+ chan = vc_dmaman_chan_alloc(dmaman, required_feature_set);
|
||||
+ if (chan < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan);
|
||||
+ if (!r) {
|
||||
+ dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n",
|
||||
+ chan);
|
||||
+ vc_dmaman_chan_free(dmaman, chan);
|
||||
+ chan = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan);
|
||||
+ *out_dma_irq = r->start;
|
||||
+ dev_dbg(dmaman_dev,
|
||||
+ "Legacy API allocated channel=%d, base=%p, irq=%i\n",
|
||||
+ chan, *out_dma_base, *out_dma_irq);
|
||||
+
|
||||
+out:
|
||||
+ mutex_unlock(&dmaman->lock);
|
||||
+
|
||||
+ return chan;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc);
|
||||
+
|
||||
+extern int bcm_dma_chan_free(int channel)
|
||||
+{
|
||||
+ struct vc_dmaman *dmaman = g_dmaman;
|
||||
+ int rc;
|
||||
+
|
||||
+ if (!dmaman_dev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ mutex_lock(&dmaman->lock);
|
||||
+ rc = vc_dmaman_chan_free(dmaman, channel);
|
||||
+ mutex_unlock(&dmaman->lock);
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_chan_free);
|
||||
+
|
||||
+int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base,
|
||||
+ u32 chans_available)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct vc_dmaman *dmaman;
|
||||
+
|
||||
+ dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL);
|
||||
+ if (!dmaman)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mutex_init(&dmaman->lock);
|
||||
+ vc_dmaman_init(dmaman, base, chans_available);
|
||||
+ g_dmaman = dmaman;
|
||||
+ dmaman_dev = dev;
|
||||
+
|
||||
+ dev_info(dev, "DMA legacy API manager, dmachans=0x%x\n",
|
||||
+ chans_available);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(bcm_dmaman_probe);
|
||||
+
|
||||
+int bcm_dmaman_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ dmaman_dev = NULL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(bcm_dmaman_remove);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/include/linux/platform_data/dma-bcm2708.h b/include/linux/platform_data/dma-bcm2708.h
|
||||
new file mode 100644
|
||||
index 000000000000..6ca874d332a8
|
||||
--- /dev/null
|
||||
+++ b/include/linux/platform_data/dma-bcm2708.h
|
||||
@@ -0,0 +1,143 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2010 Broadcom
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _PLAT_BCM2708_DMA_H
|
||||
+#define _PLAT_BCM2708_DMA_H
|
||||
+
|
||||
+/* DMA CS Control and Status bits */
|
||||
+#define BCM2708_DMA_ACTIVE BIT(0)
|
||||
+#define BCM2708_DMA_INT BIT(2)
|
||||
+#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */
|
||||
+#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */
|
||||
+#define BCM2708_DMA_ERR BIT(8)
|
||||
+#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */
|
||||
+#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */
|
||||
+
|
||||
+/* DMA control block "info" field bits */
|
||||
+#define BCM2708_DMA_INT_EN BIT(0)
|
||||
+#define BCM2708_DMA_TDMODE BIT(1)
|
||||
+#define BCM2708_DMA_WAIT_RESP BIT(3)
|
||||
+#define BCM2708_DMA_D_INC BIT(4)
|
||||
+#define BCM2708_DMA_D_WIDTH BIT(5)
|
||||
+#define BCM2708_DMA_D_DREQ BIT(6)
|
||||
+#define BCM2708_DMA_S_INC BIT(8)
|
||||
+#define BCM2708_DMA_S_WIDTH BIT(9)
|
||||
+#define BCM2708_DMA_S_DREQ BIT(10)
|
||||
+
|
||||
+#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12)
|
||||
+#define BCM2708_DMA_PER_MAP(x) ((x) << 16)
|
||||
+#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21)
|
||||
+
|
||||
+#define BCM2708_DMA_DREQ_EMMC 11
|
||||
+#define BCM2708_DMA_DREQ_SDHOST 13
|
||||
+
|
||||
+#define BCM2708_DMA_CS 0x00 /* Control and Status */
|
||||
+#define BCM2708_DMA_ADDR 0x04
|
||||
+/* the current control block appears in the following registers - read only */
|
||||
+#define BCM2708_DMA_INFO 0x08
|
||||
+#define BCM2708_DMA_SOURCE_AD 0x0c
|
||||
+#define BCM2708_DMA_DEST_AD 0x10
|
||||
+#define BCM2708_DMA_NEXTCB 0x1C
|
||||
+#define BCM2708_DMA_DEBUG 0x20
|
||||
+
|
||||
+#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS)
|
||||
+#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR)
|
||||
+
|
||||
+#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
|
||||
+
|
||||
+/* When listing features we can ask for when allocating DMA channels give
|
||||
+ those with higher priority smaller ordinal numbers */
|
||||
+#define BCM_DMA_FEATURE_FAST_ORD 0
|
||||
+#define BCM_DMA_FEATURE_BULK_ORD 1
|
||||
+#define BCM_DMA_FEATURE_NORMAL_ORD 2
|
||||
+#define BCM_DMA_FEATURE_LITE_ORD 3
|
||||
+#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD)
|
||||
+#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD)
|
||||
+#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD)
|
||||
+#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD)
|
||||
+#define BCM_DMA_FEATURE_COUNT 4
|
||||
+
|
||||
+struct bcm2708_dma_cb {
|
||||
+ u32 info;
|
||||
+ u32 src;
|
||||
+ u32 dst;
|
||||
+ u32 length;
|
||||
+ u32 stride;
|
||||
+ u32 next;
|
||||
+ u32 pad[2];
|
||||
+};
|
||||
+
|
||||
+struct scatterlist;
|
||||
+struct platform_device;
|
||||
+
|
||||
+#if defined(CONFIG_DMA_BCM2708) || defined(CONFIG_DMA_BCM2708_MODULE)
|
||||
+
|
||||
+int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
|
||||
+void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block);
|
||||
+void bcm_dma_wait_idle(void __iomem *dma_chan_base);
|
||||
+bool bcm_dma_is_busy(void __iomem *dma_chan_base);
|
||||
+int bcm_dma_abort(void __iomem *dma_chan_base);
|
||||
+
|
||||
+/* return channel no or -ve error */
|
||||
+int bcm_dma_chan_alloc(unsigned preferred_feature_set,
|
||||
+ void __iomem **out_dma_base, int *out_dma_irq);
|
||||
+int bcm_dma_chan_free(int channel);
|
||||
+
|
||||
+int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base,
|
||||
+ u32 chans_available);
|
||||
+int bcm_dmaman_remove(struct platform_device *pdev);
|
||||
+
|
||||
+#else /* CONFIG_DMA_BCM2708 */
|
||||
+
|
||||
+static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr,
|
||||
+ int sg_len)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline void bcm_dma_start(void __iomem *dma_chan_base,
|
||||
+ dma_addr_t control_block) { }
|
||||
+
|
||||
+static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { }
|
||||
+
|
||||
+static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dma_abort(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set,
|
||||
+ void __iomem **out_dma_base,
|
||||
+ int *out_dma_irq)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dma_chan_free(int channel)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dmaman_probe(struct platform_device *pdev,
|
||||
+ void __iomem *base, u32 chans_available)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dmaman_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif /* CONFIG_DMA_BCM2708 || CONFIG_DMA_BCM2708_MODULE */
|
||||
+
|
||||
+#endif /* _PLAT_BCM2708_DMA_H */
|
||||
--
|
||||
2.33.1
|
||||
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,508 @@
|
|||
From dab7565d73c2f052c9cfe2d8c793682dc51f9dc6 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Fri, 28 Oct 2016 15:36:43 +0100
|
||||
Subject: [PATCH 080/634] vc_mem: Add vc_mem driver for querying firmware
|
||||
memory addresses
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
|
||||
BCM270x: Move vc_mem
|
||||
|
||||
Make the vc_mem module available for ARCH_BCM2835 by moving it.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
char: vc_mem: Fix up compat ioctls for 64bit kernel
|
||||
|
||||
compat_ioctl wasn't defined, so 32bit user/64bit kernel
|
||||
always failed.
|
||||
VC_MEM_IOC_MEM_PHYS_ADDR was defined with parameter size
|
||||
unsigned long, so the ioctl cmd changes between sizes.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
|
||||
char: vc_mem: Fix all coding style issues.
|
||||
|
||||
Cleans up all checkpatch errors in vc_mem.c and vc_mem.h
|
||||
No functional change to the code.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
|
||||
char: vc_mem: Delete dead code
|
||||
|
||||
There are no error exists once device_create has succeeded, and
|
||||
therefore no need to call device_destroy from vc_mem_init.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/char/broadcom/Kconfig | 18 ++
|
||||
drivers/char/broadcom/Makefile | 1 +
|
||||
drivers/char/broadcom/vc_mem.c | 373 ++++++++++++++++++++++++++++++++
|
||||
include/linux/broadcom/vc_mem.h | 39 ++++
|
||||
4 files changed, 431 insertions(+)
|
||||
create mode 100644 drivers/char/broadcom/Kconfig
|
||||
create mode 100644 drivers/char/broadcom/Makefile
|
||||
create mode 100644 drivers/char/broadcom/vc_mem.c
|
||||
create mode 100644 include/linux/broadcom/vc_mem.h
|
||||
|
||||
diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig
|
||||
new file mode 100644
|
||||
index 000000000000..fc1315209dab
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/Kconfig
|
||||
@@ -0,0 +1,18 @@
|
||||
+#
|
||||
+# Broadcom char driver config
|
||||
+#
|
||||
+
|
||||
+menuconfig BRCM_CHAR_DRIVERS
|
||||
+ bool "Broadcom Char Drivers"
|
||||
+ help
|
||||
+ Broadcom's char drivers
|
||||
+
|
||||
+if BRCM_CHAR_DRIVERS
|
||||
+
|
||||
+config BCM2708_VCMEM
|
||||
+ bool "Videocore Memory"
|
||||
+ default y
|
||||
+ help
|
||||
+ Helper for videocore memory access and total size allocation.
|
||||
+
|
||||
+endif
|
||||
diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile
|
||||
new file mode 100644
|
||||
index 000000000000..06c5c8ad00e7
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/Makefile
|
||||
@@ -0,0 +1 @@
|
||||
+obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
|
||||
diff --git a/drivers/char/broadcom/vc_mem.c b/drivers/char/broadcom/vc_mem.c
|
||||
new file mode 100644
|
||||
index 000000000000..195b61a4387c
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/vc_mem.c
|
||||
@@ -0,0 +1,373 @@
|
||||
+/*
|
||||
+ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
|
||||
+ *
|
||||
+ * Unless you and Broadcom execute a separate written software license
|
||||
+ * agreement governing use of this software, this software is licensed to you
|
||||
+ * under the terms of the GNU General Public License version 2, available at
|
||||
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
|
||||
+ *
|
||||
+ * Notwithstanding the above, under no circumstances may you combine this
|
||||
+ * software in any way with any other Broadcom software provided under a
|
||||
+ * license other than the GPL, without Broadcom's express prior written
|
||||
+ * consent.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/cdev.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/debugfs.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
+#include <linux/broadcom/vc_mem.h>
|
||||
+
|
||||
+#define DRIVER_NAME "vc-mem"
|
||||
+
|
||||
+/* Device (/dev) related variables */
|
||||
+static dev_t vc_mem_devnum;
|
||||
+static struct class *vc_mem_class;
|
||||
+static struct cdev vc_mem_cdev;
|
||||
+static int vc_mem_inited;
|
||||
+
|
||||
+#ifdef CONFIG_DEBUG_FS
|
||||
+static struct dentry *vc_mem_debugfs_entry;
|
||||
+#endif
|
||||
+
|
||||
+/*
|
||||
+ * Videocore memory addresses and size
|
||||
+ *
|
||||
+ * Drivers that wish to know the videocore memory addresses and sizes should
|
||||
+ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
|
||||
+ * headers. This allows the other drivers to not be tied down to a a certain
|
||||
+ * address/size at compile time.
|
||||
+ *
|
||||
+ * In the future, the goal is to have the videocore memory virtual address and
|
||||
+ * size be calculated at boot time rather than at compile time. The decision of
|
||||
+ * where the videocore memory resides and its size would be in the hands of the
|
||||
+ * bootloader (and/or kernel). When that happens, the values of these variables
|
||||
+ * would be calculated and assigned in the init function.
|
||||
+ */
|
||||
+/* In the 2835 VC in mapped above ARM, but ARM has full access to VC space */
|
||||
+unsigned long mm_vc_mem_phys_addr;
|
||||
+EXPORT_SYMBOL(mm_vc_mem_phys_addr);
|
||||
+unsigned int mm_vc_mem_size;
|
||||
+EXPORT_SYMBOL(mm_vc_mem_size);
|
||||
+unsigned int mm_vc_mem_base;
|
||||
+EXPORT_SYMBOL(mm_vc_mem_base);
|
||||
+
|
||||
+static uint phys_addr;
|
||||
+static uint mem_size;
|
||||
+static uint mem_base;
|
||||
+
|
||||
+static int
|
||||
+vc_mem_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ (void)inode;
|
||||
+
|
||||
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+vc_mem_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ (void)inode;
|
||||
+
|
||||
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+vc_mem_get_size(void)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+vc_mem_get_base(void)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+vc_mem_get_current_size(void)
|
||||
+{
|
||||
+ return mm_vc_mem_size;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
|
||||
+
|
||||
+static long
|
||||
+vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
+{
|
||||
+ int rc = 0;
|
||||
+
|
||||
+ (void) cmd;
|
||||
+ (void) arg;
|
||||
+
|
||||
+ pr_debug("%s: called file = 0x%p, cmd %08x\n", __func__, file, cmd);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case VC_MEM_IOC_MEM_PHYS_ADDR:
|
||||
+ {
|
||||
+ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
|
||||
+ __func__, (void *)mm_vc_mem_phys_addr);
|
||||
+
|
||||
+ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
|
||||
+ sizeof(mm_vc_mem_phys_addr))) {
|
||||
+ rc = -EFAULT;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ case VC_MEM_IOC_MEM_SIZE:
|
||||
+ {
|
||||
+ /* Get the videocore memory size first */
|
||||
+ vc_mem_get_size();
|
||||
+
|
||||
+ pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%x\n", __func__,
|
||||
+ mm_vc_mem_size);
|
||||
+
|
||||
+ if (copy_to_user((void *)arg, &mm_vc_mem_size,
|
||||
+ sizeof(mm_vc_mem_size))) {
|
||||
+ rc = -EFAULT;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ case VC_MEM_IOC_MEM_BASE:
|
||||
+ {
|
||||
+ /* Get the videocore memory base */
|
||||
+ vc_mem_get_base();
|
||||
+
|
||||
+ pr_debug("%s: VC_MEM_IOC_MEM_BASE=%x\n", __func__,
|
||||
+ mm_vc_mem_base);
|
||||
+
|
||||
+ if (copy_to_user((void *)arg, &mm_vc_mem_base,
|
||||
+ sizeof(mm_vc_mem_base))) {
|
||||
+ rc = -EFAULT;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ case VC_MEM_IOC_MEM_LOAD:
|
||||
+ {
|
||||
+ /* Get the videocore memory base */
|
||||
+ vc_mem_get_base();
|
||||
+
|
||||
+ pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%x\n", __func__,
|
||||
+ mm_vc_mem_base);
|
||||
+
|
||||
+ if (copy_to_user((void *)arg, &mm_vc_mem_base,
|
||||
+ sizeof(mm_vc_mem_base))) {
|
||||
+ rc = -EFAULT;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ default:
|
||||
+ {
|
||||
+ return -ENOTTY;
|
||||
+ }
|
||||
+ }
|
||||
+ pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+static long
|
||||
+vc_mem_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
+{
|
||||
+ int rc = 0;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case VC_MEM_IOC_MEM_PHYS_ADDR32:
|
||||
+ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR32=0x%p\n",
|
||||
+ __func__, (void *)mm_vc_mem_phys_addr);
|
||||
+
|
||||
+ /* This isn't correct, but will cover us for now as
|
||||
+ * VideoCore is 32bit only.
|
||||
+ */
|
||||
+ if (copy_to_user((void *)arg, &mm_vc_mem_phys_addr,
|
||||
+ sizeof(compat_ulong_t)))
|
||||
+ rc = -EFAULT;
|
||||
+
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ rc = vc_mem_ioctl(file, cmd, arg);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static int
|
||||
+vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
+{
|
||||
+ int rc = 0;
|
||||
+ unsigned long length = vma->vm_end - vma->vm_start;
|
||||
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
|
||||
+
|
||||
+ pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
|
||||
+ __func__, (long)vma->vm_start, (long)vma->vm_end,
|
||||
+ (long)vma->vm_pgoff);
|
||||
+
|
||||
+ if (offset + length > mm_vc_mem_size) {
|
||||
+ pr_err("%s: length %ld is too big\n", __func__, length);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ /* Do not cache the memory map */
|
||||
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
+
|
||||
+ rc = remap_pfn_range(vma, vma->vm_start,
|
||||
+ (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
|
||||
+ vma->vm_pgoff, length, vma->vm_page_prot);
|
||||
+ if (rc)
|
||||
+ pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/* File Operations for the driver. */
|
||||
+static const struct file_operations vc_mem_fops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .open = vc_mem_open,
|
||||
+ .release = vc_mem_release,
|
||||
+ .unlocked_ioctl = vc_mem_ioctl,
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+ .compat_ioctl = vc_mem_compat_ioctl,
|
||||
+#endif
|
||||
+ .mmap = vc_mem_mmap,
|
||||
+};
|
||||
+
|
||||
+#ifdef CONFIG_DEBUG_FS
|
||||
+static void vc_mem_debugfs_deinit(void)
|
||||
+{
|
||||
+ debugfs_remove_recursive(vc_mem_debugfs_entry);
|
||||
+ vc_mem_debugfs_entry = NULL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int vc_mem_debugfs_init(
|
||||
+ struct device *dev)
|
||||
+{
|
||||
+ vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
|
||||
+ if (!vc_mem_debugfs_entry) {
|
||||
+ dev_warn(dev, "could not create debugfs entry\n");
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ debugfs_create_x32("vc_mem_phys_addr",
|
||||
+ 0444,
|
||||
+ vc_mem_debugfs_entry,
|
||||
+ (u32 *)&mm_vc_mem_phys_addr);
|
||||
+ debugfs_create_x32("vc_mem_size",
|
||||
+ 0444,
|
||||
+ vc_mem_debugfs_entry,
|
||||
+ (u32 *)&mm_vc_mem_size);
|
||||
+ debugfs_create_x32("vc_mem_base",
|
||||
+ 0444,
|
||||
+ vc_mem_debugfs_entry,
|
||||
+ (u32 *)&mm_vc_mem_base);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif /* CONFIG_DEBUG_FS */
|
||||
+
|
||||
+/* Module load/unload functions */
|
||||
+
|
||||
+static int __init
|
||||
+vc_mem_init(void)
|
||||
+{
|
||||
+ int rc = -EFAULT;
|
||||
+ struct device *dev;
|
||||
+
|
||||
+ pr_debug("%s: called\n", __func__);
|
||||
+
|
||||
+ mm_vc_mem_phys_addr = phys_addr;
|
||||
+ mm_vc_mem_size = mem_size;
|
||||
+ mm_vc_mem_base = mem_base;
|
||||
+
|
||||
+ vc_mem_get_size();
|
||||
+
|
||||
+ pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
|
||||
+ mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size,
|
||||
+ mm_vc_mem_size / (1024 * 1024));
|
||||
+
|
||||
+ rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME);
|
||||
+ if (rc < 0) {
|
||||
+ pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
|
||||
+ __func__, rc);
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+
|
||||
+ cdev_init(&vc_mem_cdev, &vc_mem_fops);
|
||||
+ rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1);
|
||||
+ if (rc) {
|
||||
+ pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
|
||||
+ goto out_unregister;
|
||||
+ }
|
||||
+
|
||||
+ vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
|
||||
+ if (IS_ERR(vc_mem_class)) {
|
||||
+ rc = PTR_ERR(vc_mem_class);
|
||||
+ pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
|
||||
+ goto out_cdev_del;
|
||||
+ }
|
||||
+
|
||||
+ dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
|
||||
+ DRIVER_NAME);
|
||||
+ if (IS_ERR(dev)) {
|
||||
+ rc = PTR_ERR(dev);
|
||||
+ pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
|
||||
+ goto out_class_destroy;
|
||||
+ }
|
||||
+
|
||||
+#ifdef CONFIG_DEBUG_FS
|
||||
+ /* don't fail if the debug entries cannot be created */
|
||||
+ vc_mem_debugfs_init(dev);
|
||||
+#endif
|
||||
+
|
||||
+ vc_mem_inited = 1;
|
||||
+ return 0;
|
||||
+
|
||||
+out_class_destroy:
|
||||
+ class_destroy(vc_mem_class);
|
||||
+ vc_mem_class = NULL;
|
||||
+
|
||||
+out_cdev_del:
|
||||
+ cdev_del(&vc_mem_cdev);
|
||||
+
|
||||
+out_unregister:
|
||||
+ unregister_chrdev_region(vc_mem_devnum, 1);
|
||||
+
|
||||
+out_err:
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+static void __exit
|
||||
+vc_mem_exit(void)
|
||||
+{
|
||||
+ pr_debug("%s: called\n", __func__);
|
||||
+
|
||||
+ if (vc_mem_inited) {
|
||||
+#if CONFIG_DEBUG_FS
|
||||
+ vc_mem_debugfs_deinit();
|
||||
+#endif
|
||||
+ device_destroy(vc_mem_class, vc_mem_devnum);
|
||||
+ class_destroy(vc_mem_class);
|
||||
+ cdev_del(&vc_mem_cdev);
|
||||
+ unregister_chrdev_region(vc_mem_devnum, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+module_init(vc_mem_init);
|
||||
+module_exit(vc_mem_exit);
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Broadcom Corporation");
|
||||
+
|
||||
+module_param(phys_addr, uint, 0644);
|
||||
+module_param(mem_size, uint, 0644);
|
||||
+module_param(mem_base, uint, 0644);
|
||||
diff --git a/include/linux/broadcom/vc_mem.h b/include/linux/broadcom/vc_mem.h
|
||||
new file mode 100644
|
||||
index 000000000000..3c7079237496
|
||||
--- /dev/null
|
||||
+++ b/include/linux/broadcom/vc_mem.h
|
||||
@@ -0,0 +1,39 @@
|
||||
+/*
|
||||
+ * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
|
||||
+ *
|
||||
+ * Unless you and Broadcom execute a separate written software license
|
||||
+ * agreement governing use of this software, this software is licensed to you
|
||||
+ * under the terms of the GNU General Public License version 2, available at
|
||||
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
|
||||
+ *
|
||||
+ * Notwithstanding the above, under no circumstances may you combine this
|
||||
+ * software in any way with any other Broadcom software provided under a
|
||||
+ * license other than the GPL, without Broadcom's express prior written
|
||||
+ * consent.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _VC_MEM_H
|
||||
+#define _VC_MEM_H
|
||||
+
|
||||
+#include <linux/ioctl.h>
|
||||
+
|
||||
+#define VC_MEM_IOC_MAGIC 'v'
|
||||
+
|
||||
+#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR(VC_MEM_IOC_MAGIC, 0, unsigned long)
|
||||
+#define VC_MEM_IOC_MEM_SIZE _IOR(VC_MEM_IOC_MAGIC, 1, unsigned int)
|
||||
+#define VC_MEM_IOC_MEM_BASE _IOR(VC_MEM_IOC_MAGIC, 2, unsigned int)
|
||||
+#define VC_MEM_IOC_MEM_LOAD _IOR(VC_MEM_IOC_MAGIC, 3, unsigned int)
|
||||
+
|
||||
+#ifdef __KERNEL__
|
||||
+#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
|
||||
+
|
||||
+extern unsigned long mm_vc_mem_phys_addr;
|
||||
+extern unsigned int mm_vc_mem_size;
|
||||
+extern int vc_mem_get_current_size(void);
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+#define VC_MEM_IOC_MEM_PHYS_ADDR32 _IOR(VC_MEM_IOC_MAGIC, 0, compat_ulong_t)
|
||||
+#endif
|
||||
+
|
||||
+#endif /* _VC_MEM_H */
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
From 8062954ce5d943c81d3a130cafac4d27853f8f86 Mon Sep 17 00:00:00 2001
|
||||
From: Luke Wren <luke@raspberrypi.org>
|
||||
Date: Fri, 21 Aug 2015 23:14:48 +0100
|
||||
Subject: [PATCH 081/634] Add /dev/gpiomem device for rootless user GPIO access
|
||||
|
||||
Signed-off-by: Luke Wren <luke@raspberrypi.org>
|
||||
|
||||
bcm2835-gpiomem: Fix for ARCH_BCM2835 builds
|
||||
|
||||
Build on ARCH_BCM2835, and fail to probe if no IO resource.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1154
|
||||
---
|
||||
drivers/char/broadcom/Kconfig | 8 +
|
||||
drivers/char/broadcom/Makefile | 1 +
|
||||
drivers/char/broadcom/bcm2835-gpiomem.c | 258 ++++++++++++++++++++++++
|
||||
3 files changed, 267 insertions(+)
|
||||
create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c
|
||||
|
||||
diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig
|
||||
index fc1315209dab..13d4fce859ac 100644
|
||||
--- a/drivers/char/broadcom/Kconfig
|
||||
+++ b/drivers/char/broadcom/Kconfig
|
||||
@@ -16,3 +16,11 @@ config BCM2708_VCMEM
|
||||
Helper for videocore memory access and total size allocation.
|
||||
|
||||
endif
|
||||
+
|
||||
+config BCM2835_DEVGPIOMEM
|
||||
+ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835"
|
||||
+ default m
|
||||
+ help
|
||||
+ Provides users with root-free access to the GPIO registers
|
||||
+ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO
|
||||
+ register page to the user's pointer.
|
||||
diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile
|
||||
index 06c5c8ad00e7..c8747a4a11e7 100644
|
||||
--- a/drivers/char/broadcom/Makefile
|
||||
+++ b/drivers/char/broadcom/Makefile
|
||||
@@ -1 +1,2 @@
|
||||
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
|
||||
+obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
|
||||
diff --git a/drivers/char/broadcom/bcm2835-gpiomem.c b/drivers/char/broadcom/bcm2835-gpiomem.c
|
||||
new file mode 100644
|
||||
index 000000000000..f5e7f1ba8fb6
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/bcm2835-gpiomem.c
|
||||
@@ -0,0 +1,258 @@
|
||||
+/**
|
||||
+ * GPIO memory device driver
|
||||
+ *
|
||||
+ * Creates a chardev /dev/gpiomem which will provide user access to
|
||||
+ * the BCM2835's GPIO registers when it is mmap()'d.
|
||||
+ * No longer need root for user GPIO access, but without relaxing permissions
|
||||
+ * on /dev/mem.
|
||||
+ *
|
||||
+ * Written by Luke Wren <luke@raspberrypi.org>
|
||||
+ * Copyright (c) 2015, 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/platform_device.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/cdev.h>
|
||||
+#include <linux/pagemap.h>
|
||||
+#include <linux/io.h>
|
||||
+
|
||||
+#define DEVICE_NAME "bcm2835-gpiomem"
|
||||
+#define DRIVER_NAME "gpiomem-bcm2835"
|
||||
+#define DEVICE_MINOR 0
|
||||
+
|
||||
+struct bcm2835_gpiomem_instance {
|
||||
+ unsigned long gpio_regs_phys;
|
||||
+ struct device *dev;
|
||||
+};
|
||||
+
|
||||
+static struct cdev bcm2835_gpiomem_cdev;
|
||||
+static dev_t bcm2835_gpiomem_devid;
|
||||
+static struct class *bcm2835_gpiomem_class;
|
||||
+static struct device *bcm2835_gpiomem_dev;
|
||||
+static struct bcm2835_gpiomem_instance *inst;
|
||||
+
|
||||
+
|
||||
+/****************************************************************************
|
||||
+*
|
||||
+* GPIO mem chardev file ops
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+static int bcm2835_gpiomem_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ int dev = iminor(inode);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (dev != DEVICE_MINOR) {
|
||||
+ dev_err(inst->dev, "Unknown minor device: %d", dev);
|
||||
+ ret = -ENXIO;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_gpiomem_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ int dev = iminor(inode);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (dev != DEVICE_MINOR) {
|
||||
+ dev_err(inst->dev, "Unknown minor device %d", dev);
|
||||
+ ret = -ENXIO;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = {
|
||||
+#ifdef CONFIG_HAVE_IOREMAP_PROT
|
||||
+ .access = generic_access_phys
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
+{
|
||||
+ /* Ignore what the user says - they're getting the GPIO regs
|
||||
+ whether they like it or not! */
|
||||
+ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT;
|
||||
+
|
||||
+ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page,
|
||||
+ PAGE_SIZE,
|
||||
+ vma->vm_page_prot);
|
||||
+ vma->vm_ops = &bcm2835_gpiomem_vm_ops;
|
||||
+ if (remap_pfn_range(vma, vma->vm_start,
|
||||
+ gpio_page,
|
||||
+ PAGE_SIZE,
|
||||
+ vma->vm_page_prot)) {
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct file_operations
|
||||
+bcm2835_gpiomem_fops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .open = bcm2835_gpiomem_open,
|
||||
+ .release = bcm2835_gpiomem_release,
|
||||
+ .mmap = bcm2835_gpiomem_mmap,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+ /****************************************************************************
|
||||
+*
|
||||
+* Probe and remove functions
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+
|
||||
+static int bcm2835_gpiomem_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int err;
|
||||
+ void *ptr_err;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct resource *ioresource;
|
||||
+
|
||||
+ /* Allocate buffers and instance data */
|
||||
+
|
||||
+ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL);
|
||||
+
|
||||
+ if (!inst) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto failed_inst_alloc;
|
||||
+ }
|
||||
+
|
||||
+ inst->dev = dev;
|
||||
+
|
||||
+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (ioresource) {
|
||||
+ inst->gpio_regs_phys = ioresource->start;
|
||||
+ } else {
|
||||
+ dev_err(inst->dev, "failed to get IO resource");
|
||||
+ err = -ENOENT;
|
||||
+ goto failed_get_resource;
|
||||
+ }
|
||||
+
|
||||
+ /* Create character device entries */
|
||||
+
|
||||
+ err = alloc_chrdev_region(&bcm2835_gpiomem_devid,
|
||||
+ DEVICE_MINOR, 1, DEVICE_NAME);
|
||||
+ if (err != 0) {
|
||||
+ dev_err(inst->dev, "unable to allocate device number");
|
||||
+ goto failed_alloc_chrdev;
|
||||
+ }
|
||||
+ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops);
|
||||
+ bcm2835_gpiomem_cdev.owner = THIS_MODULE;
|
||||
+ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1);
|
||||
+ if (err != 0) {
|
||||
+ dev_err(inst->dev, "unable to register device");
|
||||
+ goto failed_cdev_add;
|
||||
+ }
|
||||
+
|
||||
+ /* Create sysfs entries */
|
||||
+
|
||||
+ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME);
|
||||
+ ptr_err = bcm2835_gpiomem_class;
|
||||
+ if (IS_ERR(ptr_err))
|
||||
+ goto failed_class_create;
|
||||
+
|
||||
+ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL,
|
||||
+ bcm2835_gpiomem_devid, NULL,
|
||||
+ "gpiomem");
|
||||
+ ptr_err = bcm2835_gpiomem_dev;
|
||||
+ if (IS_ERR(ptr_err))
|
||||
+ goto failed_device_create;
|
||||
+
|
||||
+ dev_info(inst->dev, "Initialised: Registers at 0x%08lx",
|
||||
+ inst->gpio_regs_phys);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+failed_device_create:
|
||||
+ class_destroy(bcm2835_gpiomem_class);
|
||||
+failed_class_create:
|
||||
+ cdev_del(&bcm2835_gpiomem_cdev);
|
||||
+ err = PTR_ERR(ptr_err);
|
||||
+failed_cdev_add:
|
||||
+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
|
||||
+failed_alloc_chrdev:
|
||||
+failed_get_resource:
|
||||
+ kfree(inst);
|
||||
+failed_inst_alloc:
|
||||
+ dev_err(inst->dev, "could not load bcm2835_gpiomem");
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_gpiomem_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = inst->dev;
|
||||
+
|
||||
+ kfree(inst);
|
||||
+ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid);
|
||||
+ class_destroy(bcm2835_gpiomem_class);
|
||||
+ cdev_del(&bcm2835_gpiomem_cdev);
|
||||
+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
|
||||
+
|
||||
+ dev_info(dev, "GPIO mem driver removed - OK");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+ /****************************************************************************
|
||||
+*
|
||||
+* Register the driver with device tree
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+static const struct of_device_id bcm2835_gpiomem_of_match[] = {
|
||||
+ {.compatible = "brcm,bcm2835-gpiomem",},
|
||||
+ { /* sentinel */ },
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match);
|
||||
+
|
||||
+static struct platform_driver bcm2835_gpiomem_driver = {
|
||||
+ .probe = bcm2835_gpiomem_probe,
|
||||
+ .remove = bcm2835_gpiomem_remove,
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = bcm2835_gpiomem_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(bcm2835_gpiomem_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:gpiomem-bcm2835");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace");
|
||||
+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
|
||||
--
|
||||
2.33.1
|
||||
|
1936
root/target/linux/bcm27xx/patches-5.15/0082-Add-SMI-driver.patch
Normal file
1936
root/target/linux/bcm27xx/patches-5.15/0082-Add-SMI-driver.patch
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,670 @@
|
|||
From b464c0603d02e89ac233b65fd71f600c4caa34e5 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 17 Jun 2015 15:44:08 +0100
|
||||
Subject: [PATCH 083/634] Add Chris Boot's i2c driver
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
i2c-bcm2708: fixed baudrate
|
||||
|
||||
Fixed issue where the wrong CDIV value was set for baudrates below 3815 Hz (for 250MHz bus clock).
|
||||
In that case the computed CDIV value was more than 0xffff. However the CDIV register width is only 16 bits.
|
||||
This resulted in incorrect setting of CDIV and higher baudrate than intended.
|
||||
Example: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0x1704 -> 42430Hz
|
||||
After correction: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0xffff -> 3815Hz
|
||||
The correct baudrate is shown in the log after the cdiv > 0xffff correction.
|
||||
|
||||
Perform I2C combined transactions when possible
|
||||
|
||||
Perform I2C combined transactions whenever possible, within the
|
||||
restrictions of the Broadcomm Serial Controller.
|
||||
|
||||
Disable DONE interrupt during TA poll
|
||||
|
||||
Prevent interrupt from being triggered if poll is missed and transfer
|
||||
starts and finishes.
|
||||
|
||||
i2c: Make combined transactions optional and disabled by default
|
||||
|
||||
i2c: bcm2708: add device tree support
|
||||
|
||||
Add DT support to driver and add to .dtsi file.
|
||||
Setup pins in .dts file.
|
||||
i2c is disabled by default.
|
||||
|
||||
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
|
||||
|
||||
bcm2708: don't register i2c controllers when using DT
|
||||
|
||||
The devices for the i2c controllers are in the Device Tree.
|
||||
Only register devices when not using DT.
|
||||
|
||||
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
|
||||
|
||||
I2C: Only register the I2C device for the current board revision
|
||||
|
||||
i2c_bcm2708: Fix clock reference counting
|
||||
|
||||
Fix grabbing lock from atomic context in i2c driver
|
||||
|
||||
2 main changes:
|
||||
- check for timeouts in the bcm2708_bsc_setup function as indicated by this comment:
|
||||
/* poll for transfer start bit (should only take 1-20 polls) */
|
||||
This implies that the setup function can now fail so account for this everywhere it's called
|
||||
- Removed the clk_get_rate call from inside the setup function as it locks a mutex and that's not ok since we call it from under a spin lock.
|
||||
|
||||
i2c-bcm2708: When using DT, leave the GPIO setup to pinctrl
|
||||
|
||||
i2c-bcm2708: Increase timeouts to allow larger transfers
|
||||
|
||||
Use the timeout value provided by the I2C_TIMEOUT ioctl when waiting
|
||||
for completion. The default timeout is 1 second.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/260
|
||||
|
||||
i2c-bcm2708/BCM270X_DT: Add support for I2C2
|
||||
|
||||
The third I2C bus (I2C2) is normally reserved for HDMI use. Careless
|
||||
use of this bus can break an attached display - use with caution.
|
||||
|
||||
It is recommended to disable accesses by VideoCore by setting
|
||||
hdmi_ignore_edid=1 or hdmi_edid_file=1 in config.txt.
|
||||
|
||||
The interface is disabled by default - enable using the
|
||||
i2c2_iknowwhatimdoing DT parameter.
|
||||
|
||||
bcm2708-spi: Don't use static pin configuration with DT
|
||||
|
||||
Also remove superfluous error checking - the SPI framework ensures the
|
||||
validity of the chip_select value.
|
||||
|
||||
i2c-bcm2708: Remove non-DT support
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
Set the BSC_CLKT clock streching timeout to 35ms as per SMBus specs.
|
||||
|
||||
Fixes i2c_bcm2708: Write to FIFO correctly - v2 (#1574)
|
||||
|
||||
* i2c: fix i2c_bcm2708: Clear FIFO before sending data
|
||||
|
||||
Make sure FIFO gets cleared before trying to send
|
||||
data in case of a repeated start (COMBINED=Y).
|
||||
|
||||
* i2c: fix i2c_bcm2708: Only write to FIFO when not full
|
||||
|
||||
Check if FIFO can accept data before writing.
|
||||
To avoid a peripheral read on the last iteration of a loop,
|
||||
both bcm2708_bsc_fifo_fill and ~drain are changed as well.
|
||||
---
|
||||
drivers/i2c/busses/Kconfig | 19 ++
|
||||
drivers/i2c/busses/Makefile | 2 +
|
||||
drivers/i2c/busses/i2c-bcm2708.c | 512 +++++++++++++++++++++++++++++++
|
||||
3 files changed, 533 insertions(+)
|
||||
create mode 100644 drivers/i2c/busses/i2c-bcm2708.c
|
||||
|
||||
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
|
||||
index e17790fe35a7..55597652bbb1 100644
|
||||
--- a/drivers/i2c/busses/Kconfig
|
||||
+++ b/drivers/i2c/busses/Kconfig
|
||||
@@ -9,6 +9,25 @@ menu "I2C Hardware Bus support"
|
||||
comment "PC SMBus host controller drivers"
|
||||
depends on PCI
|
||||
|
||||
+config I2C_BCM2708
|
||||
+ tristate "BCM2708 BSC"
|
||||
+ depends on ARCH_BCM2835
|
||||
+ help
|
||||
+ Enabling this option will add BSC (Broadcom Serial Controller)
|
||||
+ support for the BCM2708. BSC is a Broadcom proprietary bus compatible
|
||||
+ with I2C/TWI/SMBus.
|
||||
+
|
||||
+config I2C_BCM2708_BAUDRATE
|
||||
+ prompt "BCM2708 I2C baudrate"
|
||||
+ depends on I2C_BCM2708
|
||||
+ int
|
||||
+ default 100000
|
||||
+ help
|
||||
+ Set the I2C baudrate. This will alter the default value. A
|
||||
+ different baudrate can be set by using a module parameter as well. If
|
||||
+ no parameter is provided when loading, this is the value that will be
|
||||
+ used.
|
||||
+
|
||||
config I2C_ALI1535
|
||||
tristate "ALI 1535"
|
||||
depends on PCI
|
||||
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
|
||||
index 1336b04f40e2..95fe417d63e3 100644
|
||||
--- a/drivers/i2c/busses/Makefile
|
||||
+++ b/drivers/i2c/busses/Makefile
|
||||
@@ -3,6 +3,8 @@
|
||||
# Makefile for the i2c bus drivers.
|
||||
#
|
||||
|
||||
+obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o
|
||||
+
|
||||
# ACPI drivers
|
||||
obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
|
||||
|
||||
diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c
|
||||
new file mode 100644
|
||||
index 000000000000..962f2e5c7455
|
||||
--- /dev/null
|
||||
+++ b/drivers/i2c/busses/i2c-bcm2708.c
|
||||
@@ -0,0 +1,512 @@
|
||||
+/*
|
||||
+ * Driver for Broadcom BCM2708 BSC Controllers
|
||||
+ *
|
||||
+ * Copyright (C) 2012 Chris Boot & Frank Buss
|
||||
+ *
|
||||
+ * This driver is inspired by:
|
||||
+ * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/sched.h>
|
||||
+#include <linux/wait.h>
|
||||
+
|
||||
+/* BSC register offsets */
|
||||
+#define BSC_C 0x00
|
||||
+#define BSC_S 0x04
|
||||
+#define BSC_DLEN 0x08
|
||||
+#define BSC_A 0x0c
|
||||
+#define BSC_FIFO 0x10
|
||||
+#define BSC_DIV 0x14
|
||||
+#define BSC_DEL 0x18
|
||||
+#define BSC_CLKT 0x1c
|
||||
+
|
||||
+/* Bitfields in BSC_C */
|
||||
+#define BSC_C_I2CEN 0x00008000
|
||||
+#define BSC_C_INTR 0x00000400
|
||||
+#define BSC_C_INTT 0x00000200
|
||||
+#define BSC_C_INTD 0x00000100
|
||||
+#define BSC_C_ST 0x00000080
|
||||
+#define BSC_C_CLEAR_1 0x00000020
|
||||
+#define BSC_C_CLEAR_2 0x00000010
|
||||
+#define BSC_C_READ 0x00000001
|
||||
+
|
||||
+/* Bitfields in BSC_S */
|
||||
+#define BSC_S_CLKT 0x00000200
|
||||
+#define BSC_S_ERR 0x00000100
|
||||
+#define BSC_S_RXF 0x00000080
|
||||
+#define BSC_S_TXE 0x00000040
|
||||
+#define BSC_S_RXD 0x00000020
|
||||
+#define BSC_S_TXD 0x00000010
|
||||
+#define BSC_S_RXR 0x00000008
|
||||
+#define BSC_S_TXW 0x00000004
|
||||
+#define BSC_S_DONE 0x00000002
|
||||
+#define BSC_S_TA 0x00000001
|
||||
+
|
||||
+#define I2C_WAIT_LOOP_COUNT 200
|
||||
+
|
||||
+#define DRV_NAME "bcm2708_i2c"
|
||||
+
|
||||
+static unsigned int baudrate;
|
||||
+module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
+MODULE_PARM_DESC(baudrate, "The I2C baudrate");
|
||||
+
|
||||
+static bool combined = false;
|
||||
+module_param(combined, bool, 0644);
|
||||
+MODULE_PARM_DESC(combined, "Use combined transactions");
|
||||
+
|
||||
+struct bcm2708_i2c {
|
||||
+ struct i2c_adapter adapter;
|
||||
+
|
||||
+ spinlock_t lock;
|
||||
+ void __iomem *base;
|
||||
+ int irq;
|
||||
+ struct clk *clk;
|
||||
+ u32 cdiv;
|
||||
+ u32 clk_tout;
|
||||
+
|
||||
+ struct completion done;
|
||||
+
|
||||
+ struct i2c_msg *msg;
|
||||
+ int pos;
|
||||
+ int nmsgs;
|
||||
+ bool error;
|
||||
+};
|
||||
+
|
||||
+static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
|
||||
+{
|
||||
+ return readl(bi->base + reg);
|
||||
+}
|
||||
+
|
||||
+static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
|
||||
+{
|
||||
+ writel(val, bi->base + reg);
|
||||
+}
|
||||
+
|
||||
+static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
|
||||
+{
|
||||
+ bcm2708_wr(bi, BSC_C, 0);
|
||||
+ bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
|
||||
+}
|
||||
+
|
||||
+static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
|
||||
+{
|
||||
+ while ((bi->pos < bi->msg->len) && (bcm2708_rd(bi, BSC_S) & BSC_S_RXD))
|
||||
+ bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
|
||||
+}
|
||||
+
|
||||
+static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
|
||||
+{
|
||||
+ while ((bi->pos < bi->msg->len) && (bcm2708_rd(bi, BSC_S) & BSC_S_TXD))
|
||||
+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
|
||||
+}
|
||||
+
|
||||
+static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
|
||||
+{
|
||||
+ u32 cdiv, s, clk_tout;
|
||||
+ u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
|
||||
+ int wait_loops = I2C_WAIT_LOOP_COUNT;
|
||||
+
|
||||
+ /* Can't call clk_get_rate as it locks a mutex and here we are spinlocked.
|
||||
+ * Use the value that we cached in the probe.
|
||||
+ */
|
||||
+ cdiv = bi->cdiv;
|
||||
+ clk_tout = bi->clk_tout;
|
||||
+
|
||||
+ if (bi->msg->flags & I2C_M_RD)
|
||||
+ c |= BSC_C_INTR | BSC_C_READ;
|
||||
+ else
|
||||
+ c |= BSC_C_INTT;
|
||||
+
|
||||
+ bcm2708_wr(bi, BSC_CLKT, clk_tout);
|
||||
+ bcm2708_wr(bi, BSC_DIV, cdiv);
|
||||
+ bcm2708_wr(bi, BSC_A, bi->msg->addr);
|
||||
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
|
||||
+ if (combined)
|
||||
+ {
|
||||
+ /* Do the next two messages meet combined transaction criteria?
|
||||
+ - Current message is a write, next message is a read
|
||||
+ - Both messages to same slave address
|
||||
+ - Write message can fit inside FIFO (16 bytes or less) */
|
||||
+ if ( (bi->nmsgs > 1) &&
|
||||
+ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) &&
|
||||
+ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) {
|
||||
+
|
||||
+ /* Clear FIFO */
|
||||
+ bcm2708_wr(bi, BSC_C, BSC_C_CLEAR_1);
|
||||
+
|
||||
+ /* Fill FIFO with entire write message (16 byte FIFO) */
|
||||
+ while (bi->pos < bi->msg->len) {
|
||||
+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
|
||||
+ }
|
||||
+ /* Start write transfer (no interrupts, don't clear FIFO) */
|
||||
+ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);
|
||||
+
|
||||
+ /* poll for transfer start bit (should only take 1-20 polls) */
|
||||
+ do {
|
||||
+ s = bcm2708_rd(bi, BSC_S);
|
||||
+ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE)) && --wait_loops >= 0);
|
||||
+
|
||||
+ /* did we time out or some error occured? */
|
||||
+ if (wait_loops < 0 || (s & (BSC_S_ERR | BSC_S_CLKT))) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ /* Send next read message before the write transfer finishes. */
|
||||
+ bi->nmsgs--;
|
||||
+ bi->msg++;
|
||||
+ bi->pos = 0;
|
||||
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
|
||||
+ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ;
|
||||
+ }
|
||||
+ }
|
||||
+ bcm2708_wr(bi, BSC_C, c);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct bcm2708_i2c *bi = dev_id;
|
||||
+ bool handled = true;
|
||||
+ u32 s;
|
||||
+ int ret;
|
||||
+
|
||||
+ spin_lock(&bi->lock);
|
||||
+
|
||||
+ /* we may see camera interrupts on the "other" I2C channel
|
||||
+ Just return if we've not sent anything */
|
||||
+ if (!bi->nmsgs || !bi->msg) {
|
||||
+ goto early_exit;
|
||||
+ }
|
||||
+
|
||||
+ s = bcm2708_rd(bi, BSC_S);
|
||||
+
|
||||
+ if (s & (BSC_S_CLKT | BSC_S_ERR)) {
|
||||
+ bcm2708_bsc_reset(bi);
|
||||
+ bi->error = true;
|
||||
+
|
||||
+ bi->msg = 0; /* to inform the that all work is done */
|
||||
+ bi->nmsgs = 0;
|
||||
+ /* wake up our bh */
|
||||
+ complete(&bi->done);
|
||||
+ } else if (s & BSC_S_DONE) {
|
||||
+ bi->nmsgs--;
|
||||
+
|
||||
+ if (bi->msg->flags & I2C_M_RD) {
|
||||
+ bcm2708_bsc_fifo_drain(bi);
|
||||
+ }
|
||||
+
|
||||
+ bcm2708_bsc_reset(bi);
|
||||
+
|
||||
+ if (bi->nmsgs) {
|
||||
+ /* advance to next message */
|
||||
+ bi->msg++;
|
||||
+ bi->pos = 0;
|
||||
+ ret = bcm2708_bsc_setup(bi);
|
||||
+ if (ret < 0) {
|
||||
+ bcm2708_bsc_reset(bi);
|
||||
+ bi->error = true;
|
||||
+ bi->msg = 0; /* to inform the that all work is done */
|
||||
+ bi->nmsgs = 0;
|
||||
+ /* wake up our bh */
|
||||
+ complete(&bi->done);
|
||||
+ goto early_exit;
|
||||
+ }
|
||||
+ } else {
|
||||
+ bi->msg = 0; /* to inform the that all work is done */
|
||||
+ bi->nmsgs = 0;
|
||||
+ /* wake up our bh */
|
||||
+ complete(&bi->done);
|
||||
+ }
|
||||
+ } else if (s & BSC_S_TXW) {
|
||||
+ bcm2708_bsc_fifo_fill(bi);
|
||||
+ } else if (s & BSC_S_RXR) {
|
||||
+ bcm2708_bsc_fifo_drain(bi);
|
||||
+ } else {
|
||||
+ handled = false;
|
||||
+ }
|
||||
+
|
||||
+early_exit:
|
||||
+ spin_unlock(&bi->lock);
|
||||
+
|
||||
+ return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
+}
|
||||
+
|
||||
+static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
+ struct i2c_msg *msgs, int num)
|
||||
+{
|
||||
+ struct bcm2708_i2c *bi = adap->algo_data;
|
||||
+ unsigned long flags;
|
||||
+ int ret;
|
||||
+
|
||||
+ spin_lock_irqsave(&bi->lock, flags);
|
||||
+
|
||||
+ reinit_completion(&bi->done);
|
||||
+ bi->msg = msgs;
|
||||
+ bi->pos = 0;
|
||||
+ bi->nmsgs = num;
|
||||
+ bi->error = false;
|
||||
+
|
||||
+ ret = bcm2708_bsc_setup(bi);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&bi->lock, flags);
|
||||
+
|
||||
+ /* check the result of the setup */
|
||||
+ if (ret < 0)
|
||||
+ {
|
||||
+ dev_err(&adap->dev, "transfer setup timed out\n");
|
||||
+ goto error_timeout;
|
||||
+ }
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&bi->done, adap->timeout);
|
||||
+ if (ret == 0) {
|
||||
+ dev_err(&adap->dev, "transfer timed out\n");
|
||||
+ goto error_timeout;
|
||||
+ }
|
||||
+
|
||||
+ ret = bi->error ? -EIO : num;
|
||||
+ return ret;
|
||||
+
|
||||
+error_timeout:
|
||||
+ spin_lock_irqsave(&bi->lock, flags);
|
||||
+ bcm2708_bsc_reset(bi);
|
||||
+ bi->msg = 0; /* to inform the interrupt handler that there's nothing else to be done */
|
||||
+ bi->nmsgs = 0;
|
||||
+ spin_unlock_irqrestore(&bi->lock, flags);
|
||||
+ return -ETIMEDOUT;
|
||||
+}
|
||||
+
|
||||
+static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
|
||||
+{
|
||||
+ return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
|
||||
+}
|
||||
+
|
||||
+static struct i2c_algorithm bcm2708_i2c_algorithm = {
|
||||
+ .master_xfer = bcm2708_i2c_master_xfer,
|
||||
+ .functionality = bcm2708_i2c_functionality,
|
||||
+};
|
||||
+
|
||||
+static int bcm2708_i2c_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct resource *regs;
|
||||
+ int irq, err = -ENOMEM;
|
||||
+ struct clk *clk;
|
||||
+ struct bcm2708_i2c *bi;
|
||||
+ struct i2c_adapter *adap;
|
||||
+ unsigned long bus_hz;
|
||||
+ u32 cdiv, clk_tout;
|
||||
+ u32 baud;
|
||||
+
|
||||
+ baud = CONFIG_I2C_BCM2708_BAUDRATE;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ u32 bus_clk_rate;
|
||||
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
|
||||
+ if (pdev->id < 0) {
|
||||
+ dev_err(&pdev->dev, "alias is missing\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (!of_property_read_u32(pdev->dev.of_node,
|
||||
+ "clock-frequency", &bus_clk_rate))
|
||||
+ baud = bus_clk_rate;
|
||||
+ else
|
||||
+ dev_warn(&pdev->dev,
|
||||
+ "Could not read clock-frequency property\n");
|
||||
+ }
|
||||
+
|
||||
+ if (baudrate)
|
||||
+ baud = baudrate;
|
||||
+
|
||||
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (!regs) {
|
||||
+ dev_err(&pdev->dev, "could not get IO memory\n");
|
||||
+ return -ENXIO;
|
||||
+ }
|
||||
+
|
||||
+ irq = platform_get_irq(pdev, 0);
|
||||
+ if (irq < 0) {
|
||||
+ dev_err(&pdev->dev, "could not get IRQ\n");
|
||||
+ return irq;
|
||||
+ }
|
||||
+
|
||||
+ clk = clk_get(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(clk)) {
|
||||
+ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
|
||||
+ return PTR_ERR(clk);
|
||||
+ }
|
||||
+
|
||||
+ err = clk_prepare_enable(clk);
|
||||
+ if (err) {
|
||||
+ dev_err(&pdev->dev, "could not enable clk: %d\n", err);
|
||||
+ goto out_clk_put;
|
||||
+ }
|
||||
+
|
||||
+ bi = kzalloc(sizeof(*bi), GFP_KERNEL);
|
||||
+ if (!bi)
|
||||
+ goto out_clk_disable;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, bi);
|
||||
+
|
||||
+ adap = &bi->adapter;
|
||||
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC;
|
||||
+ adap->algo = &bcm2708_i2c_algorithm;
|
||||
+ adap->algo_data = bi;
|
||||
+ adap->dev.parent = &pdev->dev;
|
||||
+ adap->nr = pdev->id;
|
||||
+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
|
||||
+ adap->dev.of_node = pdev->dev.of_node;
|
||||
+
|
||||
+ switch (pdev->id) {
|
||||
+ case 0:
|
||||
+ adap->class = I2C_CLASS_HWMON;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ adap->class = I2C_CLASS_DDC;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ adap->class = I2C_CLASS_DDC;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(&pdev->dev, "can only bind to BSC 0, 1 or 2\n");
|
||||
+ err = -ENXIO;
|
||||
+ goto out_free_bi;
|
||||
+ }
|
||||
+
|
||||
+ spin_lock_init(&bi->lock);
|
||||
+ init_completion(&bi->done);
|
||||
+
|
||||
+ bi->base = ioremap(regs->start, resource_size(regs));
|
||||
+ if (!bi->base) {
|
||||
+ dev_err(&pdev->dev, "could not remap memory\n");
|
||||
+ goto out_free_bi;
|
||||
+ }
|
||||
+
|
||||
+ bi->irq = irq;
|
||||
+ bi->clk = clk;
|
||||
+
|
||||
+ err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
|
||||
+ dev_name(&pdev->dev), bi);
|
||||
+ if (err) {
|
||||
+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
|
||||
+ goto out_iounmap;
|
||||
+ }
|
||||
+
|
||||
+ bcm2708_bsc_reset(bi);
|
||||
+
|
||||
+ err = i2c_add_numbered_adapter(adap);
|
||||
+ if (err < 0) {
|
||||
+ dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
|
||||
+ goto out_free_irq;
|
||||
+ }
|
||||
+
|
||||
+ bus_hz = clk_get_rate(bi->clk);
|
||||
+ cdiv = bus_hz / baud;
|
||||
+ if (cdiv > 0xffff) {
|
||||
+ cdiv = 0xffff;
|
||||
+ baud = bus_hz / cdiv;
|
||||
+ }
|
||||
+
|
||||
+ clk_tout = 35/1000*baud; //35ms timeout as per SMBus specs.
|
||||
+ if (clk_tout > 0xffff)
|
||||
+ clk_tout = 0xffff;
|
||||
+
|
||||
+ bi->cdiv = cdiv;
|
||||
+ bi->clk_tout = clk_tout;
|
||||
+
|
||||
+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
|
||||
+ pdev->id, (unsigned long)regs->start, irq, baud);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_free_irq:
|
||||
+ free_irq(bi->irq, bi);
|
||||
+out_iounmap:
|
||||
+ iounmap(bi->base);
|
||||
+out_free_bi:
|
||||
+ kfree(bi);
|
||||
+out_clk_disable:
|
||||
+ clk_disable_unprepare(clk);
|
||||
+out_clk_put:
|
||||
+ clk_put(clk);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int bcm2708_i2c_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+
|
||||
+ i2c_del_adapter(&bi->adapter);
|
||||
+ free_irq(bi->irq, bi);
|
||||
+ iounmap(bi->base);
|
||||
+ clk_disable_unprepare(bi->clk);
|
||||
+ clk_put(bi->clk);
|
||||
+ kfree(bi);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id bcm2708_i2c_of_match[] = {
|
||||
+ { .compatible = "brcm,bcm2708-i2c" },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, bcm2708_i2c_of_match);
|
||||
+
|
||||
+static struct platform_driver bcm2708_i2c_driver = {
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = bcm2708_i2c_of_match,
|
||||
+ },
|
||||
+ .probe = bcm2708_i2c_probe,
|
||||
+ .remove = bcm2708_i2c_remove,
|
||||
+};
|
||||
+
|
||||
+// module_platform_driver(bcm2708_i2c_driver);
|
||||
+
|
||||
+
|
||||
+static int __init bcm2708_i2c_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&bcm2708_i2c_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit bcm2708_i2c_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&bcm2708_i2c_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(bcm2708_i2c_init);
|
||||
+module_exit(bcm2708_i2c_exit);
|
||||
+
|
||||
+
|
||||
+
|
||||
+MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
|
||||
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+MODULE_ALIAS("platform:" DRV_NAME);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
From 14ffde5320a15a12960942b29171637410752006 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 26 Jun 2015 14:27:06 +0200
|
||||
Subject: [PATCH 084/634] char: broadcom: Add vcio module
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add module for accessing the mailbox property channel through
|
||||
/dev/vcio. Was previously in bcm2708-vcio.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
char: vcio: Add compat ioctl handling
|
||||
|
||||
There was no compat ioctl handler, so 32 bit userspace on a
|
||||
64 bit kernel failed as IOCTL_MBOX_PROPERTY used the size
|
||||
of char*.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
|
||||
char: vcio: Fail probe if rpi_firmware is not found.
|
||||
|
||||
Device Tree is now the only supported config mechanism, therefore
|
||||
uncomment the block of code that fails the probe if the
|
||||
firmware node can't be found.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
drivers/char/broadcom/Kconfig | 6 +
|
||||
drivers/char/broadcom/Makefile | 1 +
|
||||
drivers/char/broadcom/vcio.c | 194 +++++++++++++++++++++++++++++++++
|
||||
3 files changed, 201 insertions(+)
|
||||
create mode 100644 drivers/char/broadcom/vcio.c
|
||||
|
||||
diff --git a/drivers/char/broadcom/Kconfig b/drivers/char/broadcom/Kconfig
|
||||
index 48d29e5acb34..c11b834ccdbd 100644
|
||||
--- a/drivers/char/broadcom/Kconfig
|
||||
+++ b/drivers/char/broadcom/Kconfig
|
||||
@@ -15,6 +15,12 @@ config BCM2708_VCMEM
|
||||
help
|
||||
Helper for videocore memory access and total size allocation.
|
||||
|
||||
+config BCM_VCIO
|
||||
+ tristate "Mailbox userspace access"
|
||||
+ depends on BCM2835_MBOX
|
||||
+ help
|
||||
+ Gives access to the mailbox property channel from userspace.
|
||||
+
|
||||
endif
|
||||
|
||||
config BCM2835_DEVGPIOMEM
|
||||
diff --git a/drivers/char/broadcom/Makefile b/drivers/char/broadcom/Makefile
|
||||
index a5d0f33221a3..ea7495b01c28 100644
|
||||
--- a/drivers/char/broadcom/Makefile
|
||||
+++ b/drivers/char/broadcom/Makefile
|
||||
@@ -1,3 +1,4 @@
|
||||
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
|
||||
+obj-$(CONFIG_BCM_VCIO) += vcio.o
|
||||
obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
|
||||
obj-$(CONFIG_BCM2835_SMI_DEV) += bcm2835_smi_dev.o
|
||||
diff --git a/drivers/char/broadcom/vcio.c b/drivers/char/broadcom/vcio.c
|
||||
new file mode 100644
|
||||
index 000000000000..d2598663a2b5
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/vcio.c
|
||||
@@ -0,0 +1,194 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2010 Broadcom
|
||||
+ * Copyright (C) 2015 Noralf Trønnes
|
||||
+ *
|
||||
+ * 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.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
+
|
||||
+#include <linux/cdev.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/ioctl.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+#define MBOX_CHAN_PROPERTY 8
|
||||
+
|
||||
+#define VCIO_IOC_MAGIC 100
|
||||
+#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
|
||||
+#endif
|
||||
+
|
||||
+static struct {
|
||||
+ dev_t devt;
|
||||
+ struct cdev cdev;
|
||||
+ struct class *class;
|
||||
+ struct rpi_firmware *fw;
|
||||
+} vcio;
|
||||
+
|
||||
+static int vcio_user_property_list(void *user)
|
||||
+{
|
||||
+ u32 *buf, size;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* The first 32-bit is the size of the buffer */
|
||||
+ if (copy_from_user(&size, user, sizeof(size)))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ buf = kmalloc(size, GFP_KERNEL);
|
||||
+ if (!buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (copy_from_user(buf, user, size)) {
|
||||
+ kfree(buf);
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ /* Strip off protocol encapsulation */
|
||||
+ ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
|
||||
+ if (ret) {
|
||||
+ kfree(buf);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
|
||||
+ if (copy_to_user(user, buf, size))
|
||||
+ ret = -EFAULT;
|
||||
+
|
||||
+ kfree(buf);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int vcio_device_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ try_module_get(THIS_MODULE);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vcio_device_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ module_put(THIS_MODULE);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
|
||||
+ unsigned long ioctl_param)
|
||||
+{
|
||||
+ switch (ioctl_num) {
|
||||
+ case IOCTL_MBOX_PROPERTY:
|
||||
+ return vcio_user_property_list((void *)ioctl_param);
|
||||
+ default:
|
||||
+ pr_err("unknown ioctl: %x\n", ioctl_num);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
|
||||
+ unsigned long ioctl_param)
|
||||
+{
|
||||
+ switch (ioctl_num) {
|
||||
+ case IOCTL_MBOX_PROPERTY32:
|
||||
+ return vcio_user_property_list(compat_ptr(ioctl_param));
|
||||
+ default:
|
||||
+ pr_err("unknown ioctl: %x\n", ioctl_num);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+const struct file_operations vcio_fops = {
|
||||
+ .unlocked_ioctl = vcio_device_ioctl,
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+ .compat_ioctl = vcio_device_compat_ioctl,
|
||||
+#endif
|
||||
+ .open = vcio_device_open,
|
||||
+ .release = vcio_device_release,
|
||||
+};
|
||||
+
|
||||
+static int __init vcio_init(void)
|
||||
+{
|
||||
+ struct device_node *np;
|
||||
+ static struct device *dev;
|
||||
+ int ret;
|
||||
+
|
||||
+ np = of_find_compatible_node(NULL, NULL,
|
||||
+ "raspberrypi,bcm2835-firmware");
|
||||
+ if (!of_device_is_available(np))
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ vcio.fw = rpi_firmware_get(np);
|
||||
+ if (!vcio.fw)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
|
||||
+ if (ret) {
|
||||
+ pr_err("failed to allocate device number\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ cdev_init(&vcio.cdev, &vcio_fops);
|
||||
+ vcio.cdev.owner = THIS_MODULE;
|
||||
+ ret = cdev_add(&vcio.cdev, vcio.devt, 1);
|
||||
+ if (ret) {
|
||||
+ pr_err("failed to register device\n");
|
||||
+ goto err_unregister_chardev;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Create sysfs entries
|
||||
+ * 'bcm2708_vcio' is used for backwards compatibility so we don't break
|
||||
+ * userspace. Raspian has a udev rule that changes the permissions.
|
||||
+ */
|
||||
+ vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
|
||||
+ if (IS_ERR(vcio.class)) {
|
||||
+ ret = PTR_ERR(vcio.class);
|
||||
+ pr_err("failed to create class\n");
|
||||
+ goto err_cdev_del;
|
||||
+ }
|
||||
+
|
||||
+ dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
|
||||
+ if (IS_ERR(dev)) {
|
||||
+ ret = PTR_ERR(dev);
|
||||
+ pr_err("failed to create device\n");
|
||||
+ goto err_class_destroy;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_class_destroy:
|
||||
+ class_destroy(vcio.class);
|
||||
+err_cdev_del:
|
||||
+ cdev_del(&vcio.cdev);
|
||||
+err_unregister_chardev:
|
||||
+ unregister_chrdev_region(vcio.devt, 1);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+module_init(vcio_init);
|
||||
+
|
||||
+static void __exit vcio_exit(void)
|
||||
+{
|
||||
+ device_destroy(vcio.class, vcio.devt);
|
||||
+ class_destroy(vcio.class);
|
||||
+ cdev_del(&vcio.cdev);
|
||||
+ unregister_chrdev_region(vcio.devt, 1);
|
||||
+}
|
||||
+module_exit(vcio_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Gray Girling");
|
||||
+MODULE_AUTHOR("Noralf Trønnes");
|
||||
+MODULE_DESCRIPTION("Mailbox userspace access");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
From 48748dbf488a3a17297d54fefcddc5a477a1842f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 26 Jun 2015 14:25:01 +0200
|
||||
Subject: [PATCH 085/634] firmware: bcm2835: Support ARCH_BCM270x
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Support booting without Device Tree.
|
||||
Turn on USB power.
|
||||
Load driver early because of lacking support for deferred probing
|
||||
in many drivers.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
firmware: bcm2835: Don't turn on USB power
|
||||
|
||||
The raspberrypi-power driver is now used to turn on USB power.
|
||||
|
||||
This partly reverts commit:
|
||||
firmware: bcm2835: Support ARCH_BCM270x
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/firmware/raspberrypi.c | 17 ++++++++++++++++-
|
||||
1 file changed, 16 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
|
||||
index 4b8978b254f9..54619623fe86 100644
|
||||
--- a/drivers/firmware/raspberrypi.c
|
||||
+++ b/drivers/firmware/raspberrypi.c
|
||||
@@ -32,6 +32,8 @@ struct rpi_firmware {
|
||||
struct kref consumers;
|
||||
};
|
||||
|
||||
+static struct platform_device *g_pdev;
|
||||
+
|
||||
static DEFINE_MUTEX(transaction_lock);
|
||||
|
||||
static void response_callback(struct mbox_client *cl, void *msg)
|
||||
@@ -279,6 +281,7 @@ static int rpi_firmware_probe(struct platform_device *pdev)
|
||||
kref_init(&fw->consumers);
|
||||
|
||||
platform_set_drvdata(pdev, fw);
|
||||
+ g_pdev = pdev;
|
||||
|
||||
rpi_firmware_print_firmware_revision(fw);
|
||||
rpi_register_hwmon_driver(dev, fw);
|
||||
@@ -307,6 +310,7 @@ static int rpi_firmware_remove(struct platform_device *pdev)
|
||||
rpi_clk = NULL;
|
||||
|
||||
rpi_firmware_put(fw);
|
||||
+ g_pdev = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -381,7 +385,18 @@ static struct platform_driver rpi_firmware_driver = {
|
||||
.shutdown = rpi_firmware_shutdown,
|
||||
.remove = rpi_firmware_remove,
|
||||
};
|
||||
-module_platform_driver(rpi_firmware_driver);
|
||||
+
|
||||
+static int __init rpi_firmware_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&rpi_firmware_driver);
|
||||
+}
|
||||
+subsys_initcall(rpi_firmware_init);
|
||||
+
|
||||
+static void __init rpi_firmware_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&rpi_firmware_driver);
|
||||
+}
|
||||
+module_exit(rpi_firmware_exit);
|
||||
|
||||
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
|
||||
MODULE_DESCRIPTION("Raspberry Pi firmware driver");
|
||||
--
|
||||
2.33.1
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,182 @@
|
|||
From baefc74faad90d99d7aa0cb697a468b404f97376 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 6 Feb 2015 13:50:57 +0000
|
||||
Subject: [PATCH 087/634] leds: Add the "input" trigger, for pwr_led
|
||||
|
||||
The "input" trigger makes the associated GPIO an input. This is to support
|
||||
the Raspberry Pi PWR LED, which is driven by external hardware in normal use.
|
||||
|
||||
N.B. pwr_led is not available on Model A or B boards.
|
||||
|
||||
leds-gpio: Implement the brightness_get method
|
||||
|
||||
The power LED uses some clever logic that means it is driven
|
||||
by a voltage measuring circuit when configured as input, otherwise
|
||||
it is driven by the GPIO output value. This patch wires up the
|
||||
brightness_get method for leds-gpio so that user-space can monitor
|
||||
the LED value via /sys/class/gpio/led1/brightness. Using the input
|
||||
trigger this returns an indication of the system power health,
|
||||
otherwise it is just whatever value the trigger has written most
|
||||
recently.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1064
|
||||
---
|
||||
drivers/leds/leds-gpio.c | 17 ++++++++-
|
||||
drivers/leds/trigger/Kconfig | 7 ++++
|
||||
drivers/leds/trigger/Makefile | 1 +
|
||||
drivers/leds/trigger/ledtrig-input.c | 55 ++++++++++++++++++++++++++++
|
||||
include/linux/leds.h | 3 ++
|
||||
5 files changed, 82 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/leds/trigger/ledtrig-input.c
|
||||
|
||||
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
|
||||
index 092eb59a7d32..9e5327056b7a 100644
|
||||
--- a/drivers/leds/leds-gpio.c
|
||||
+++ b/drivers/leds/leds-gpio.c
|
||||
@@ -47,8 +47,15 @@ static void gpio_led_set(struct led_classdev *led_cdev,
|
||||
led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
|
||||
NULL, NULL);
|
||||
led_dat->blinking = 0;
|
||||
+ } else if (led_dat->cdev.flags & SET_GPIO_INPUT) {
|
||||
+ gpiod_direction_input(led_dat->gpiod);
|
||||
+ led_dat->cdev.flags &= ~SET_GPIO_INPUT;
|
||||
+ } else if (led_dat->cdev.flags & SET_GPIO_OUTPUT) {
|
||||
+ gpiod_direction_output(led_dat->gpiod, level);
|
||||
+ led_dat->cdev.flags &= ~SET_GPIO_OUTPUT;
|
||||
} else {
|
||||
- if (led_dat->can_sleep)
|
||||
+ if (led_dat->can_sleep ||
|
||||
+ (led_dat->cdev.flags & (SET_GPIO_INPUT | SET_GPIO_OUTPUT) ))
|
||||
gpiod_set_value_cansleep(led_dat->gpiod, level);
|
||||
else
|
||||
gpiod_set_value(led_dat->gpiod, level);
|
||||
@@ -62,6 +69,13 @@ static int gpio_led_set_blocking(struct led_classdev *led_cdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static enum led_brightness gpio_led_get(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct gpio_led_data *led_dat =
|
||||
+ container_of(led_cdev, struct gpio_led_data, cdev);
|
||||
+ return gpiod_get_value_cansleep(led_dat->gpiod) ? LED_FULL : LED_OFF;
|
||||
+}
|
||||
+
|
||||
static int gpio_blink_set(struct led_classdev *led_cdev,
|
||||
unsigned long *delay_on, unsigned long *delay_off)
|
||||
{
|
||||
@@ -90,6 +104,7 @@ static int create_gpio_led(const struct gpio_led *template,
|
||||
led_dat->platform_gpio_blink_set = blink_set;
|
||||
led_dat->cdev.blink_set = gpio_blink_set;
|
||||
}
|
||||
+ led_dat->cdev.brightness_get = gpio_led_get;
|
||||
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) {
|
||||
state = gpiod_get_value_cansleep(led_dat->gpiod);
|
||||
if (state < 0)
|
||||
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
|
||||
index 1f1d57288085..1d8341f3a6fe 100644
|
||||
--- a/drivers/leds/trigger/Kconfig
|
||||
+++ b/drivers/leds/trigger/Kconfig
|
||||
@@ -114,6 +114,13 @@ config LEDS_TRIGGER_CAMERA
|
||||
This enables direct flash/torch on/off by the driver, kernel space.
|
||||
If unsure, say Y.
|
||||
|
||||
+config LEDS_TRIGGER_INPUT
|
||||
+ tristate "LED Input Trigger"
|
||||
+ depends on LEDS_TRIGGERS
|
||||
+ help
|
||||
+ This allows the GPIOs assigned to be LEDs to be initialised to inputs.
|
||||
+ If unsure, say Y.
|
||||
+
|
||||
config LEDS_TRIGGER_PANIC
|
||||
bool "LED Panic Trigger"
|
||||
help
|
||||
diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
|
||||
index 25c4db97cdd4..5b6bc14865ea 100644
|
||||
--- a/drivers/leds/trigger/Makefile
|
||||
+++ b/drivers/leds/trigger/Makefile
|
||||
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += ledtrig-activity.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
|
||||
+obj-$(CONFIG_LEDS_TRIGGER_INPUT) += ledtrig-input.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o
|
||||
diff --git a/drivers/leds/trigger/ledtrig-input.c b/drivers/leds/trigger/ledtrig-input.c
|
||||
new file mode 100644
|
||||
index 000000000000..8a974a355656
|
||||
--- /dev/null
|
||||
+++ b/drivers/leds/trigger/ledtrig-input.c
|
||||
@@ -0,0 +1,55 @@
|
||||
+/*
|
||||
+ * Set LED GPIO to Input "Trigger"
|
||||
+ *
|
||||
+ * Copyright 2015 Phil Elwell <phil@raspberrypi.org>
|
||||
+ *
|
||||
+ * Based on Nick Forbes's ledtrig-default-on.c.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include "../leds.h"
|
||||
+
|
||||
+static int input_trig_activate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ led_cdev->flags |= SET_GPIO_INPUT;
|
||||
+ led_set_brightness(led_cdev, 0);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void input_trig_deactivate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ led_cdev->flags |= SET_GPIO_OUTPUT;
|
||||
+ led_set_brightness(led_cdev, 0);
|
||||
+}
|
||||
+
|
||||
+static struct led_trigger input_led_trigger = {
|
||||
+ .name = "input",
|
||||
+ .activate = input_trig_activate,
|
||||
+ .deactivate = input_trig_deactivate,
|
||||
+};
|
||||
+
|
||||
+static int __init input_trig_init(void)
|
||||
+{
|
||||
+ return led_trigger_register(&input_led_trigger);
|
||||
+}
|
||||
+
|
||||
+static void __exit input_trig_exit(void)
|
||||
+{
|
||||
+ led_trigger_unregister(&input_led_trigger);
|
||||
+}
|
||||
+
|
||||
+module_init(input_trig_init);
|
||||
+module_exit(input_trig_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
|
||||
+MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\"");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/include/linux/leds.h b/include/linux/leds.h
|
||||
index a0b730be40ad..cb9a65b4b0f4 100644
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -85,6 +85,9 @@ struct led_classdev {
|
||||
#define LED_BRIGHT_HW_CHANGED BIT(21)
|
||||
#define LED_RETAIN_AT_SHUTDOWN BIT(22)
|
||||
#define LED_INIT_DEFAULT_TRIGGER BIT(23)
|
||||
+ /* Additions for Raspberry Pi PWR LED */
|
||||
+#define SET_GPIO_INPUT BIT(30)
|
||||
+#define SET_GPIO_OUTPUT BIT(31)
|
||||
|
||||
/* set_brightness_work / blink_timer flags, atomic, private. */
|
||||
unsigned long work_flags;
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
From 169f2d56546c42705e0dedf2c72bb709c8f1f3df Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 3 Jul 2013 00:54:08 +0100
|
||||
Subject: [PATCH 088/634] Added Device IDs for August DVB-T 205
|
||||
|
||||
---
|
||||
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
|
||||
index 795a012d4020..adb1028d5f25 100644
|
||||
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
|
||||
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
|
||||
@@ -1944,6 +1944,10 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
|
||||
&rtl28xxu_props, "Compro VideoMate U650F", NULL) },
|
||||
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
|
||||
&rtl28xxu_props, "MaxMedia HU394-T", NULL) },
|
||||
+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xb803 /*USB_PID_AUGUST_DVBT205*/,
|
||||
+ &rtl28xxu_props, "August DVB-T 205", NULL) },
|
||||
+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xa803 /*USB_PID_AUGUST_DVBT205*/,
|
||||
+ &rtl28xxu_props, "August DVB-T 205", NULL) },
|
||||
{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
|
||||
&rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
|
||||
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
|
||||
--
|
||||
2.33.1
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,40 @@
|
|||
From 5ea5a578d1596f24191691cd3f10eeaa6e9e72f2 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 25 Jun 2015 12:16:11 +0100
|
||||
Subject: [PATCH 090/634] gpio-poweroff: Allow it to work on Raspberry Pi
|
||||
|
||||
The Raspberry Pi firmware manages the power-down and reboot
|
||||
process. To do this it installs a pm_power_off handler, causing
|
||||
the gpio-poweroff module to abort the probe function.
|
||||
|
||||
This patch introduces a "force" DT property that overrides that
|
||||
behaviour, and also adds a DT overlay to enable and control it.
|
||||
|
||||
Note that running in an active-low configuration (DT parameter
|
||||
"active_low") requires a custom dt-blob.bin and probably won't
|
||||
allow a reboot without switching off, so an external inversion
|
||||
of the trigger signal may be preferable.
|
||||
---
|
||||
drivers/power/reset/gpio-poweroff.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c
|
||||
index 1c5af2fef142..3e670131f2a8 100644
|
||||
--- a/drivers/power/reset/gpio-poweroff.c
|
||||
+++ b/drivers/power/reset/gpio-poweroff.c
|
||||
@@ -50,9 +50,11 @@ static int gpio_poweroff_probe(struct platform_device *pdev)
|
||||
{
|
||||
bool input = false;
|
||||
enum gpiod_flags flags;
|
||||
+ bool force = false;
|
||||
|
||||
/* If a pm_power_off function has already been added, leave it alone */
|
||||
- if (pm_power_off != NULL) {
|
||||
+ force = of_property_read_bool(pdev->dev.of_node, "force");
|
||||
+ if (!force && (pm_power_off != NULL)) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s: pm_power_off function already registered\n",
|
||||
__func__);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,884 @@
|
|||
From 1e57f6601cd08ee1ef0c5125ceff6fd9a9c197c7 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <pelwell@users.noreply.github.com>
|
||||
Date: Tue, 14 Jul 2015 14:32:47 +0100
|
||||
Subject: [PATCH 091/634] mfd: Add Raspberry Pi Sense HAT core driver
|
||||
|
||||
mfd: Add rpi_sense_core of compatible string
|
||||
---
|
||||
drivers/input/joystick/Kconfig | 8 +
|
||||
drivers/input/joystick/Makefile | 1 +
|
||||
drivers/input/joystick/rpisense-js.c | 153 ++++++++++++
|
||||
drivers/mfd/Kconfig | 8 +
|
||||
drivers/mfd/Makefile | 1 +
|
||||
drivers/mfd/rpisense-core.c | 165 +++++++++++++
|
||||
drivers/video/fbdev/Kconfig | 13 +
|
||||
drivers/video/fbdev/Makefile | 1 +
|
||||
drivers/video/fbdev/rpisense-fb.c | 293 +++++++++++++++++++++++
|
||||
include/linux/mfd/rpisense/core.h | 47 ++++
|
||||
include/linux/mfd/rpisense/framebuffer.h | 32 +++
|
||||
include/linux/mfd/rpisense/joystick.h | 35 +++
|
||||
12 files changed, 757 insertions(+)
|
||||
create mode 100644 drivers/input/joystick/rpisense-js.c
|
||||
create mode 100644 drivers/mfd/rpisense-core.c
|
||||
create mode 100644 drivers/video/fbdev/rpisense-fb.c
|
||||
create mode 100644 include/linux/mfd/rpisense/core.h
|
||||
create mode 100644 include/linux/mfd/rpisense/framebuffer.h
|
||||
create mode 100644 include/linux/mfd/rpisense/joystick.h
|
||||
|
||||
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
|
||||
index 3b23078bc7b5..483653110314 100644
|
||||
--- a/drivers/input/joystick/Kconfig
|
||||
+++ b/drivers/input/joystick/Kconfig
|
||||
@@ -399,4 +399,12 @@ config JOYSTICK_N64
|
||||
Say Y here if you want enable support for the four
|
||||
built-in controller ports on the Nintendo 64 console.
|
||||
|
||||
+config JOYSTICK_RPISENSE
|
||||
+ tristate "Raspberry Pi Sense HAT joystick"
|
||||
+ depends on GPIOLIB && INPUT
|
||||
+ select MFD_RPISENSE_CORE
|
||||
+
|
||||
+ help
|
||||
+ This is the joystick driver for the Raspberry Pi Sense HAT
|
||||
+
|
||||
endif
|
||||
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
|
||||
index 5174b8aba2dd..d401dacf7702 100644
|
||||
--- a/drivers/input/joystick/Makefile
|
||||
+++ b/drivers/input/joystick/Makefile
|
||||
@@ -39,3 +39,4 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
|
||||
obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
|
||||
obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
|
||||
obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o
|
||||
+obj-$(CONFIG_JOYSTICK_RPISENSE) += rpisense-js.o
|
||||
diff --git a/drivers/input/joystick/rpisense-js.c b/drivers/input/joystick/rpisense-js.c
|
||||
new file mode 100644
|
||||
index 000000000000..6a416769065d
|
||||
--- /dev/null
|
||||
+++ b/drivers/input/joystick/rpisense-js.c
|
||||
@@ -0,0 +1,153 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT joystick driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+
|
||||
+#include <linux/mfd/rpisense/joystick.h>
|
||||
+#include <linux/mfd/rpisense/core.h>
|
||||
+
|
||||
+static struct rpisense *rpisense;
|
||||
+static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};
|
||||
+
|
||||
+static void keys_work_fn(struct work_struct *work)
|
||||
+{
|
||||
+ int i;
|
||||
+ static s32 prev_keys;
|
||||
+ struct rpisense_js *rpisense_js = &rpisense->joystick;
|
||||
+ s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
|
||||
+ s32 changes = keys ^ prev_keys;
|
||||
+
|
||||
+ prev_keys = keys;
|
||||
+ for (i = 0; i < 5; i++) {
|
||||
+ if (changes & 1) {
|
||||
+ input_report_key(rpisense_js->keys_dev,
|
||||
+ keymap[i], keys & 1);
|
||||
+ }
|
||||
+ changes >>= 1;
|
||||
+ keys >>= 1;
|
||||
+ }
|
||||
+ input_sync(rpisense_js->keys_dev);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t keys_irq_handler(int irq, void *pdev)
|
||||
+{
|
||||
+ struct rpisense_js *rpisense_js = &rpisense->joystick;
|
||||
+
|
||||
+ schedule_work(&rpisense_js->keys_work_s);
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_js_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret;
|
||||
+ int i;
|
||||
+ struct rpisense_js *rpisense_js;
|
||||
+
|
||||
+ rpisense = rpisense_get_dev();
|
||||
+ rpisense_js = &rpisense->joystick;
|
||||
+
|
||||
+ INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);
|
||||
+
|
||||
+ rpisense_js->keys_dev = input_allocate_device();
|
||||
+ if (!rpisense_js->keys_dev) {
|
||||
+ dev_err(&pdev->dev, "Could not allocate input device.\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
+ for (i = 0; i < ARRAY_SIZE(keymap); i++) {
|
||||
+ set_bit(keymap[i],
|
||||
+ rpisense_js->keys_dev->keybit);
|
||||
+ }
|
||||
+
|
||||
+ rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
|
||||
+ rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
|
||||
+ rpisense_js->keys_dev->id.bustype = BUS_I2C;
|
||||
+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
+ rpisense_js->keys_dev->keycode = keymap;
|
||||
+ rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
|
||||
+ rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);
|
||||
+
|
||||
+ ret = input_register_device(rpisense_js->keys_dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Could not register input device.\n");
|
||||
+ goto err_keys_alloc;
|
||||
+ }
|
||||
+
|
||||
+ ret = gpiod_direction_input(rpisense_js->keys_desc);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Could not set keys-int direction.\n");
|
||||
+ goto err_keys_reg;
|
||||
+ }
|
||||
+
|
||||
+ rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
|
||||
+ if (rpisense_js->keys_irq < 0) {
|
||||
+ dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
|
||||
+ ret = rpisense_js->keys_irq;
|
||||
+ goto err_keys_reg;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
|
||||
+ keys_irq_handler, IRQF_TRIGGER_RISING,
|
||||
+ "keys", &pdev->dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "IRQ request failed.\n");
|
||||
+ goto err_keys_reg;
|
||||
+ }
|
||||
+ return 0;
|
||||
+err_keys_reg:
|
||||
+ input_unregister_device(rpisense_js->keys_dev);
|
||||
+err_keys_alloc:
|
||||
+ input_free_device(rpisense_js->keys_dev);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_js_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rpisense_js *rpisense_js = &rpisense->joystick;
|
||||
+
|
||||
+ input_unregister_device(rpisense_js->keys_dev);
|
||||
+ input_free_device(rpisense_js->keys_dev);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_OF
|
||||
+static const struct of_device_id rpisense_js_id[] = {
|
||||
+ { .compatible = "rpi,rpi-sense-js" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rpisense_js_id);
|
||||
+#endif
|
||||
+
|
||||
+static struct platform_device_id rpisense_js_device_id[] = {
|
||||
+ { .name = "rpi-sense-js" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);
|
||||
+
|
||||
+static struct platform_driver rpisense_js_driver = {
|
||||
+ .probe = rpisense_js_probe,
|
||||
+ .remove = rpisense_js_remove,
|
||||
+ .driver = {
|
||||
+ .name = "rpi-sense-js",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(rpisense_js_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
|
||||
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
|
||||
index d2f345245538..c79bb26f48d2 100644
|
||||
--- a/drivers/mfd/Kconfig
|
||||
+++ b/drivers/mfd/Kconfig
|
||||
@@ -11,6 +11,14 @@ config MFD_CORE
|
||||
select IRQ_DOMAIN
|
||||
default n
|
||||
|
||||
+config MFD_RPISENSE_CORE
|
||||
+ tristate "Raspberry Pi Sense HAT core functions"
|
||||
+ depends on I2C
|
||||
+ select MFD_CORE
|
||||
+ help
|
||||
+ This is the core driver for the Raspberry Pi Sense HAT. This provides
|
||||
+ the necessary functions to communicate with the hardware.
|
||||
+
|
||||
config MFD_CS5535
|
||||
tristate "AMD CS5535 and CS5536 southbridge core functions"
|
||||
select MFD_CORE
|
||||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
|
||||
index 2ba6646e874c..0a30247411e8 100644
|
||||
--- a/drivers/mfd/Makefile
|
||||
+++ b/drivers/mfd/Makefile
|
||||
@@ -266,6 +266,7 @@ obj-$(CONFIG_MFD_STMFX) += stmfx.o
|
||||
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o
|
||||
obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
|
||||
obj-$(CONFIG_MFD_QCOM_PM8008) += qcom-pm8008.o
|
||||
+obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.o
|
||||
|
||||
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
|
||||
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
|
||||
diff --git a/drivers/mfd/rpisense-core.c b/drivers/mfd/rpisense-core.c
|
||||
new file mode 100644
|
||||
index 000000000000..6cfd63e5e8b8
|
||||
--- /dev/null
|
||||
+++ b/drivers/mfd/rpisense-core.c
|
||||
@@ -0,0 +1,165 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT core driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ * This driver is based on wm8350 implementation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/moduleparam.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/mfd/rpisense/core.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+static struct rpisense *rpisense;
|
||||
+
|
||||
+static void rpisense_client_dev_register(struct rpisense *rpisense,
|
||||
+ const char *name,
|
||||
+ struct platform_device **pdev)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ *pdev = platform_device_alloc(name, -1);
|
||||
+ if (*pdev == NULL) {
|
||||
+ dev_err(rpisense->dev, "Failed to allocate %s\n", name);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ (*pdev)->dev.parent = rpisense->dev;
|
||||
+ platform_set_drvdata(*pdev, rpisense);
|
||||
+ ret = platform_device_add(*pdev);
|
||||
+ if (ret != 0) {
|
||||
+ dev_err(rpisense->dev, "Failed to register %s: %d\n",
|
||||
+ name, ret);
|
||||
+ platform_device_put(*pdev);
|
||||
+ *pdev = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int rpisense_probe(struct i2c_client *i2c,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct rpisense_js *rpisense_js;
|
||||
+
|
||||
+ rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL);
|
||||
+ if (rpisense == NULL)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ i2c_set_clientdata(i2c, rpisense);
|
||||
+ rpisense->dev = &i2c->dev;
|
||||
+ rpisense->i2c_client = i2c;
|
||||
+
|
||||
+ ret = rpisense_reg_read(rpisense, RPISENSE_WAI);
|
||||
+ if (ret > 0) {
|
||||
+ if (ret != 's')
|
||||
+ return -EINVAL;
|
||||
+ } else {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ ret = rpisense_reg_read(rpisense, RPISENSE_VER);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ dev_info(rpisense->dev,
|
||||
+ "Raspberry Pi Sense HAT firmware version %i\n", ret);
|
||||
+
|
||||
+ rpisense_js = &rpisense->joystick;
|
||||
+ rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev,
|
||||
+ "keys-int", GPIOD_IN);
|
||||
+ if (IS_ERR(rpisense_js->keys_desc)) {
|
||||
+ dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n");
|
||||
+ rpisense_js->keys_desc = gpio_to_desc(23);
|
||||
+ if (rpisense_js->keys_desc == NULL) {
|
||||
+ dev_err(&i2c->dev, "GPIO23 fallback failed.\n");
|
||||
+ return PTR_ERR(rpisense_js->keys_desc);
|
||||
+ }
|
||||
+ }
|
||||
+ rpisense_client_dev_register(rpisense, "rpi-sense-js",
|
||||
+ &(rpisense->joystick.pdev));
|
||||
+ rpisense_client_dev_register(rpisense, "rpi-sense-fb",
|
||||
+ &(rpisense->framebuffer.pdev));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_remove(struct i2c_client *i2c)
|
||||
+{
|
||||
+ struct rpisense *rpisense = i2c_get_clientdata(i2c);
|
||||
+
|
||||
+ platform_device_unregister(rpisense->joystick.pdev);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct rpisense *rpisense_get_dev(void)
|
||||
+{
|
||||
+ return rpisense;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(rpisense_get_dev);
|
||||
+
|
||||
+s32 rpisense_reg_read(struct rpisense *rpisense, int reg)
|
||||
+{
|
||||
+ int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ dev_err(rpisense->dev, "Read from reg %d failed\n", reg);
|
||||
+ /* Due to the BCM270x I2C clock stretching bug, some values
|
||||
+ * may have MSB set. Clear it to avoid incorrect values.
|
||||
+ * */
|
||||
+ return ret & 0x7F;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(rpisense_reg_read);
|
||||
+
|
||||
+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count)
|
||||
+{
|
||||
+ int ret = i2c_master_send(rpisense->i2c_client, buf, count);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ dev_err(rpisense->dev, "Block write failed\n");
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(rpisense_block_write);
|
||||
+
|
||||
+static const struct i2c_device_id rpisense_i2c_id[] = {
|
||||
+ { "rpi-sense", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
|
||||
+
|
||||
+#ifdef CONFIG_OF
|
||||
+static const struct of_device_id rpisense_core_id[] = {
|
||||
+ { .compatible = "rpi,rpi-sense" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rpisense_core_id);
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+static struct i2c_driver rpisense_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rpi-sense",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+ .probe = rpisense_probe,
|
||||
+ .remove = rpisense_remove,
|
||||
+ .id_table = rpisense_i2c_id,
|
||||
+};
|
||||
+
|
||||
+module_i2c_driver(rpisense_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver");
|
||||
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+
|
||||
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
|
||||
index 0b409636ebcd..e7f1a831f947 100644
|
||||
--- a/drivers/video/fbdev/Kconfig
|
||||
+++ b/drivers/video/fbdev/Kconfig
|
||||
@@ -2252,6 +2252,19 @@ config FB_SM712
|
||||
called sm712fb. If you want to compile it as a module, say M
|
||||
here and read <file:Documentation/kbuild/modules.rst>.
|
||||
|
||||
+config FB_RPISENSE
|
||||
+ tristate "Raspberry Pi Sense HAT framebuffer"
|
||||
+ depends on FB
|
||||
+ select MFD_RPISENSE_CORE
|
||||
+ select FB_SYS_FOPS
|
||||
+ select FB_SYS_FILLRECT
|
||||
+ select FB_SYS_COPYAREA
|
||||
+ select FB_SYS_IMAGEBLIT
|
||||
+ select FB_DEFERRED_IO
|
||||
+
|
||||
+ help
|
||||
+ This is the framebuffer driver for the Raspberry Pi Sense HAT
|
||||
+
|
||||
source "drivers/video/fbdev/omap/Kconfig"
|
||||
source "drivers/video/fbdev/omap2/Kconfig"
|
||||
source "drivers/video/fbdev/mmp/Kconfig"
|
||||
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
|
||||
index 36624ffdf2bc..5a478be6bcb4 100644
|
||||
--- a/drivers/video/fbdev/Makefile
|
||||
+++ b/drivers/video/fbdev/Makefile
|
||||
@@ -130,6 +130,7 @@ obj-$(CONFIG_FB_MX3) += mx3fb.o
|
||||
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
|
||||
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
|
||||
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
|
||||
+obj-$(CONFIG_FB_RPISENSE) += rpisense-fb.o
|
||||
|
||||
# the test framebuffer is last
|
||||
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
|
||||
diff --git a/drivers/video/fbdev/rpisense-fb.c b/drivers/video/fbdev/rpisense-fb.c
|
||||
new file mode 100644
|
||||
index 000000000000..26432a5a0b4b
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/rpisense-fb.c
|
||||
@@ -0,0 +1,293 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT framebuffer driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/string.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/init.h>
|
||||
+
|
||||
+#include <linux/mfd/rpisense/framebuffer.h>
|
||||
+#include <linux/mfd/rpisense/core.h>
|
||||
+
|
||||
+static bool lowlight;
|
||||
+module_param(lowlight, bool, 0);
|
||||
+MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third");
|
||||
+
|
||||
+static struct rpisense *rpisense;
|
||||
+
|
||||
+struct rpisense_fb_param {
|
||||
+ char __iomem *vmem;
|
||||
+ u8 *vmem_work;
|
||||
+ u32 vmemsize;
|
||||
+ u8 *gamma;
|
||||
+};
|
||||
+
|
||||
+static u8 gamma_default[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
+ 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
|
||||
+ 0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,};
|
||||
+
|
||||
+static u8 gamma_low[32] = {0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
|
||||
+ 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06,
|
||||
+ 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0A, 0x0A,};
|
||||
+
|
||||
+static u8 gamma_user[32];
|
||||
+
|
||||
+static struct rpisense_fb_param rpisense_fb_param = {
|
||||
+ .vmem = NULL,
|
||||
+ .vmemsize = 128,
|
||||
+ .gamma = gamma_default,
|
||||
+};
|
||||
+
|
||||
+static struct fb_deferred_io rpisense_fb_defio;
|
||||
+
|
||||
+static struct fb_fix_screeninfo rpisense_fb_fix = {
|
||||
+ .id = "RPi-Sense FB",
|
||||
+ .type = FB_TYPE_PACKED_PIXELS,
|
||||
+ .visual = FB_VISUAL_TRUECOLOR,
|
||||
+ .xpanstep = 0,
|
||||
+ .ypanstep = 0,
|
||||
+ .ywrapstep = 0,
|
||||
+ .accel = FB_ACCEL_NONE,
|
||||
+ .line_length = 16,
|
||||
+};
|
||||
+
|
||||
+static struct fb_var_screeninfo rpisense_fb_var = {
|
||||
+ .xres = 8,
|
||||
+ .yres = 8,
|
||||
+ .xres_virtual = 8,
|
||||
+ .yres_virtual = 8,
|
||||
+ .bits_per_pixel = 16,
|
||||
+ .red = {11, 5, 0},
|
||||
+ .green = {5, 6, 0},
|
||||
+ .blue = {0, 5, 0},
|
||||
+};
|
||||
+
|
||||
+static ssize_t rpisense_fb_write(struct fb_info *info,
|
||||
+ const char __user *buf, size_t count,
|
||||
+ loff_t *ppos)
|
||||
+{
|
||||
+ ssize_t res = fb_sys_write(info, buf, count, ppos);
|
||||
+
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_fillrect(struct fb_info *info,
|
||||
+ const struct fb_fillrect *rect)
|
||||
+{
|
||||
+ sys_fillrect(info, rect);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_copyarea(struct fb_info *info,
|
||||
+ const struct fb_copyarea *area)
|
||||
+{
|
||||
+ sys_copyarea(info, area);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_imageblit(struct fb_info *info,
|
||||
+ const struct fb_image *image)
|
||||
+{
|
||||
+ sys_imageblit(info, image);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_deferred_io(struct fb_info *info,
|
||||
+ struct list_head *pagelist)
|
||||
+{
|
||||
+ int i;
|
||||
+ int j;
|
||||
+ u8 *vmem_work = rpisense_fb_param.vmem_work;
|
||||
+ u16 *mem = (u16 *)rpisense_fb_param.vmem;
|
||||
+ u8 *gamma = rpisense_fb_param.gamma;
|
||||
+
|
||||
+ vmem_work[0] = 0;
|
||||
+ for (j = 0; j < 8; j++) {
|
||||
+ for (i = 0; i < 8; i++) {
|
||||
+ vmem_work[(j * 24) + i + 1] =
|
||||
+ gamma[(mem[(j * 8) + i] >> 11) & 0x1F];
|
||||
+ vmem_work[(j * 24) + (i + 8) + 1] =
|
||||
+ gamma[(mem[(j * 8) + i] >> 6) & 0x1F];
|
||||
+ vmem_work[(j * 24) + (i + 16) + 1] =
|
||||
+ gamma[(mem[(j * 8) + i]) & 0x1F];
|
||||
+ }
|
||||
+ }
|
||||
+ rpisense_block_write(rpisense, vmem_work, 193);
|
||||
+}
|
||||
+
|
||||
+static struct fb_deferred_io rpisense_fb_defio = {
|
||||
+ .delay = HZ/100,
|
||||
+ .deferred_io = rpisense_fb_deferred_io,
|
||||
+};
|
||||
+
|
||||
+static int rpisense_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
+ unsigned long arg)
|
||||
+{
|
||||
+ switch (cmd) {
|
||||
+ case SENSEFB_FBIOGET_GAMMA:
|
||||
+ if (copy_to_user((void __user *) arg, rpisense_fb_param.gamma,
|
||||
+ sizeof(u8[32])))
|
||||
+ return -EFAULT;
|
||||
+ return 0;
|
||||
+ case SENSEFB_FBIOSET_GAMMA:
|
||||
+ if (copy_from_user(gamma_user, (void __user *)arg,
|
||||
+ sizeof(u8[32])))
|
||||
+ return -EFAULT;
|
||||
+ rpisense_fb_param.gamma = gamma_user;
|
||||
+ schedule_delayed_work(&info->deferred_work,
|
||||
+ rpisense_fb_defio.delay);
|
||||
+ return 0;
|
||||
+ case SENSEFB_FBIORESET_GAMMA:
|
||||
+ switch (arg) {
|
||||
+ case 0:
|
||||
+ rpisense_fb_param.gamma = gamma_default;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ rpisense_fb_param.gamma = gamma_low;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ rpisense_fb_param.gamma = gamma_user;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ schedule_delayed_work(&info->deferred_work,
|
||||
+ rpisense_fb_defio.delay);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct fb_ops rpisense_fb_ops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .fb_read = fb_sys_read,
|
||||
+ .fb_write = rpisense_fb_write,
|
||||
+ .fb_fillrect = rpisense_fb_fillrect,
|
||||
+ .fb_copyarea = rpisense_fb_copyarea,
|
||||
+ .fb_imageblit = rpisense_fb_imageblit,
|
||||
+ .fb_ioctl = rpisense_fb_ioctl,
|
||||
+};
|
||||
+
|
||||
+static int rpisense_fb_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct fb_info *info;
|
||||
+ int ret = -ENOMEM;
|
||||
+ struct rpisense_fb *rpisense_fb;
|
||||
+
|
||||
+ rpisense = rpisense_get_dev();
|
||||
+ rpisense_fb = &rpisense->framebuffer;
|
||||
+
|
||||
+ rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize);
|
||||
+ if (!rpisense_fb_param.vmem)
|
||||
+ return ret;
|
||||
+
|
||||
+ rpisense_fb_param.vmem_work = devm_kmalloc(&pdev->dev, 193, GFP_KERNEL);
|
||||
+ if (!rpisense_fb_param.vmem_work)
|
||||
+ goto err_malloc;
|
||||
+
|
||||
+ info = framebuffer_alloc(0, &pdev->dev);
|
||||
+ if (!info) {
|
||||
+ dev_err(&pdev->dev, "Could not allocate framebuffer.\n");
|
||||
+ goto err_malloc;
|
||||
+ }
|
||||
+ rpisense_fb->info = info;
|
||||
+
|
||||
+ rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem;
|
||||
+ rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize;
|
||||
+
|
||||
+ info->fbops = &rpisense_fb_ops;
|
||||
+ info->fix = rpisense_fb_fix;
|
||||
+ info->var = rpisense_fb_var;
|
||||
+ info->fbdefio = &rpisense_fb_defio;
|
||||
+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
|
||||
+ info->screen_base = rpisense_fb_param.vmem;
|
||||
+ info->screen_size = rpisense_fb_param.vmemsize;
|
||||
+
|
||||
+ if (lowlight)
|
||||
+ rpisense_fb_param.gamma = gamma_low;
|
||||
+
|
||||
+ fb_deferred_io_init(info);
|
||||
+
|
||||
+ ret = register_framebuffer(info);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&pdev->dev, "Could not register framebuffer.\n");
|
||||
+ goto err_fballoc;
|
||||
+ }
|
||||
+
|
||||
+ fb_info(info, "%s frame buffer device\n", info->fix.id);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+ return 0;
|
||||
+err_fballoc:
|
||||
+ framebuffer_release(info);
|
||||
+err_malloc:
|
||||
+ vfree(rpisense_fb_param.vmem);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_fb_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rpisense_fb *rpisense_fb = &rpisense->framebuffer;
|
||||
+ struct fb_info *info = rpisense_fb->info;
|
||||
+
|
||||
+ if (info) {
|
||||
+ unregister_framebuffer(info);
|
||||
+ fb_deferred_io_cleanup(info);
|
||||
+ framebuffer_release(info);
|
||||
+ vfree(rpisense_fb_param.vmem);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_OF
|
||||
+static const struct of_device_id rpisense_fb_id[] = {
|
||||
+ { .compatible = "rpi,rpi-sense-fb" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rpisense_fb_id);
|
||||
+#endif
|
||||
+
|
||||
+static struct platform_device_id rpisense_fb_device_id[] = {
|
||||
+ { .name = "rpi-sense-fb" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, rpisense_fb_device_id);
|
||||
+
|
||||
+static struct platform_driver rpisense_fb_driver = {
|
||||
+ .probe = rpisense_fb_probe,
|
||||
+ .remove = rpisense_fb_remove,
|
||||
+ .driver = {
|
||||
+ .name = "rpi-sense-fb",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(rpisense_fb_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT framebuffer driver");
|
||||
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+
|
||||
diff --git a/include/linux/mfd/rpisense/core.h b/include/linux/mfd/rpisense/core.h
|
||||
new file mode 100644
|
||||
index 000000000000..4856aa3c8b06
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/rpisense/core.h
|
||||
@@ -0,0 +1,47 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT core driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_MFD_RPISENSE_CORE_H_
|
||||
+#define __LINUX_MFD_RPISENSE_CORE_H_
|
||||
+
|
||||
+#include <linux/mfd/rpisense/joystick.h>
|
||||
+#include <linux/mfd/rpisense/framebuffer.h>
|
||||
+
|
||||
+/*
|
||||
+ * Register values.
|
||||
+ */
|
||||
+#define RPISENSE_FB 0x00
|
||||
+#define RPISENSE_WAI 0xF0
|
||||
+#define RPISENSE_VER 0xF1
|
||||
+#define RPISENSE_KEYS 0xF2
|
||||
+#define RPISENSE_EE_WP 0xF3
|
||||
+
|
||||
+#define RPISENSE_ID 's'
|
||||
+
|
||||
+struct rpisense {
|
||||
+ struct device *dev;
|
||||
+ struct i2c_client *i2c_client;
|
||||
+
|
||||
+ /* Client devices */
|
||||
+ struct rpisense_js joystick;
|
||||
+ struct rpisense_fb framebuffer;
|
||||
+};
|
||||
+
|
||||
+struct rpisense *rpisense_get_dev(void);
|
||||
+s32 rpisense_reg_read(struct rpisense *rpisense, int reg);
|
||||
+int rpisense_reg_write(struct rpisense *rpisense, int reg, u16 val);
|
||||
+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/include/linux/mfd/rpisense/framebuffer.h b/include/linux/mfd/rpisense/framebuffer.h
|
||||
new file mode 100644
|
||||
index 000000000000..2ba95d7eebaf
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/rpisense/framebuffer.h
|
||||
@@ -0,0 +1,32 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT framebuffer driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_RPISENSE_FB_H_
|
||||
+#define __LINUX_RPISENSE_FB_H_
|
||||
+
|
||||
+#define SENSEFB_FBIO_IOC_MAGIC 0xF1
|
||||
+
|
||||
+#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0)
|
||||
+#define SENSEFB_FBIOSET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 1)
|
||||
+#define SENSEFB_FBIORESET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 2)
|
||||
+
|
||||
+struct rpisense;
|
||||
+
|
||||
+struct rpisense_fb {
|
||||
+ struct platform_device *pdev;
|
||||
+ struct fb_info *info;
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
diff --git a/include/linux/mfd/rpisense/joystick.h b/include/linux/mfd/rpisense/joystick.h
|
||||
new file mode 100644
|
||||
index 000000000000..56196dc2af10
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/rpisense/joystick.h
|
||||
@@ -0,0 +1,35 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT joystick driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_RPISENSE_JOYSTICK_H_
|
||||
+#define __LINUX_RPISENSE_JOYSTICK_H_
|
||||
+
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+struct rpisense;
|
||||
+
|
||||
+struct rpisense_js {
|
||||
+ struct platform_device *pdev;
|
||||
+ struct input_dev *keys_dev;
|
||||
+ struct gpio_desc *keys_desc;
|
||||
+ struct work_struct keys_work_s;
|
||||
+ int keys_irq;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
2.33.1
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,182 @@
|
|||
From 1634c4b33f22d71f3a41a4bfb5af3956db60e0a0 Mon Sep 17 00:00:00 2001
|
||||
From: P33M <P33M@github.com>
|
||||
Date: Wed, 21 Oct 2015 14:55:21 +0100
|
||||
Subject: [PATCH 093/634] rpi_display: add backlight driver and overlay
|
||||
|
||||
Add a mailbox-driven backlight controller for the Raspberry Pi DSI
|
||||
touchscreen display. Requires updated GPU firmware to recognise the
|
||||
mailbox request.
|
||||
|
||||
Signed-off-by: Gordon Hollingworth <gordon@raspberrypi.org>
|
||||
|
||||
Add Raspberry Pi firmware driver to the dependencies of backlight driver
|
||||
|
||||
Otherwise the backlight driver fails to build if the firmware
|
||||
loading driver is not in the kernel
|
||||
|
||||
Signed-off-by: Alex Riesen <alexander.riesen@cetitec.com>
|
||||
---
|
||||
drivers/video/backlight/Kconfig | 7 ++
|
||||
drivers/video/backlight/Makefile | 1 +
|
||||
drivers/video/backlight/rpi_backlight.c | 119 ++++++++++++++++++++++++
|
||||
3 files changed, 127 insertions(+)
|
||||
create mode 100644 drivers/video/backlight/rpi_backlight.c
|
||||
|
||||
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
|
||||
index e32694c13da5..853ae0bd961d 100644
|
||||
--- a/drivers/video/backlight/Kconfig
|
||||
+++ b/drivers/video/backlight/Kconfig
|
||||
@@ -248,6 +248,13 @@ config BACKLIGHT_PWM
|
||||
If you have a LCD backlight adjustable by PWM, say Y to enable
|
||||
this driver.
|
||||
|
||||
+config BACKLIGHT_RPI
|
||||
+ tristate "Raspberry Pi display firmware driven backlight"
|
||||
+ depends on RASPBERRYPI_FIRMWARE
|
||||
+ help
|
||||
+ If you have the Raspberry Pi DSI touchscreen display, say Y to
|
||||
+ enable the mailbox-controlled backlight driver.
|
||||
+
|
||||
config BACKLIGHT_DA903X
|
||||
tristate "Backlight Driver for DA9030/DA9034 using WLED"
|
||||
depends on PMIC_DA903X
|
||||
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
|
||||
index cae2c83422ae..30a17f4be040 100644
|
||||
--- a/drivers/video/backlight/Makefile
|
||||
+++ b/drivers/video/backlight/Makefile
|
||||
@@ -49,6 +49,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_QCOM_WLED) += qcom-wled.o
|
||||
+obj-$(CONFIG_BACKLIGHT_RPI) += rpi_backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_RT4831) += rt4831-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
|
||||
diff --git a/drivers/video/backlight/rpi_backlight.c b/drivers/video/backlight/rpi_backlight.c
|
||||
new file mode 100644
|
||||
index 000000000000..14a0d9b03739
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/backlight/rpi_backlight.c
|
||||
@@ -0,0 +1,119 @@
|
||||
+/*
|
||||
+ * rpi_bl.c - Backlight controller through VPU
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/backlight.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+struct rpi_backlight {
|
||||
+ struct device *dev;
|
||||
+ struct device *fbdev;
|
||||
+ struct rpi_firmware *fw;
|
||||
+};
|
||||
+
|
||||
+static int rpi_backlight_update_status(struct backlight_device *bl)
|
||||
+{
|
||||
+ struct rpi_backlight *gbl = bl_get_data(bl);
|
||||
+ int brightness = bl->props.brightness;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (bl->props.power != FB_BLANK_UNBLANK ||
|
||||
+ bl->props.fb_blank != FB_BLANK_UNBLANK ||
|
||||
+ bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
|
||||
+ brightness = 0;
|
||||
+
|
||||
+ ret = rpi_firmware_property(gbl->fw,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT,
|
||||
+ &brightness, sizeof(brightness));
|
||||
+ if (ret) {
|
||||
+ dev_err(gbl->dev, "Failed to set brightness\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (brightness < 0) {
|
||||
+ dev_err(gbl->dev, "Backlight change failed\n");
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct backlight_ops rpi_backlight_ops = {
|
||||
+ .options = BL_CORE_SUSPENDRESUME,
|
||||
+ .update_status = rpi_backlight_update_status,
|
||||
+};
|
||||
+
|
||||
+static int rpi_backlight_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct backlight_properties props;
|
||||
+ struct backlight_device *bl;
|
||||
+ struct rpi_backlight *gbl;
|
||||
+ struct device_node *fw_node;
|
||||
+
|
||||
+ gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
|
||||
+ if (gbl == NULL)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ gbl->dev = &pdev->dev;
|
||||
+
|
||||
+ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
|
||||
+ if (!fw_node) {
|
||||
+ dev_err(&pdev->dev, "Missing firmware node\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ gbl->fw = rpi_firmware_get(fw_node);
|
||||
+ if (!gbl->fw)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ memset(&props, 0, sizeof(props));
|
||||
+ props.type = BACKLIGHT_RAW;
|
||||
+ props.max_brightness = 255;
|
||||
+ bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
|
||||
+ &pdev->dev, gbl, &rpi_backlight_ops,
|
||||
+ &props);
|
||||
+ if (IS_ERR(bl)) {
|
||||
+ dev_err(&pdev->dev, "failed to register backlight\n");
|
||||
+ return PTR_ERR(bl);
|
||||
+ }
|
||||
+
|
||||
+ bl->props.brightness = 255;
|
||||
+ backlight_update_status(bl);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, bl);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id rpi_backlight_of_match[] = {
|
||||
+ { .compatible = "raspberrypi,rpi-backlight" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rpi_backlight_of_match);
|
||||
+
|
||||
+static struct platform_driver rpi_backlight_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rpi-backlight",
|
||||
+ .of_match_table = of_match_ptr(rpi_backlight_of_match),
|
||||
+ },
|
||||
+ .probe = rpi_backlight_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(rpi_backlight_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Gordon Hollingworth <gordon@raspberrypi.org>");
|
||||
+MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
From 70c00ff96cc66354d96b742eea2ac93e36b27e8d Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 23 Feb 2016 19:56:04 +0000
|
||||
Subject: [PATCH 094/634] bcm2835-virtgpio: Virtual GPIO driver
|
||||
|
||||
Add a virtual GPIO driver that uses the firmware mailbox interface to
|
||||
request that the VPU toggles LEDs.
|
||||
---
|
||||
drivers/gpio/Kconfig | 6 +
|
||||
drivers/gpio/Makefile | 1 +
|
||||
drivers/gpio/gpio-bcm-virt.c | 214 +++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 221 insertions(+)
|
||||
create mode 100644 drivers/gpio/gpio-bcm-virt.c
|
||||
|
||||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
|
||||
index fae5141251e5..138ca5c8dab1 100644
|
||||
--- a/drivers/gpio/Kconfig
|
||||
+++ b/drivers/gpio/Kconfig
|
||||
@@ -194,6 +194,12 @@ config GPIO_BCM_XGS_IPROC
|
||||
help
|
||||
Say yes here to enable GPIO support for Broadcom XGS iProc SoCs.
|
||||
|
||||
+config GPIO_BCM_VIRT
|
||||
+ bool "Broadcom Virt GPIO"
|
||||
+ depends on OF_GPIO && RASPBERRYPI_FIRMWARE && (ARCH_BCM2835 || COMPILE_TEST)
|
||||
+ help
|
||||
+ Turn on virtual GPIO support for Broadcom BCM283X chips.
|
||||
+
|
||||
config GPIO_BRCMSTB
|
||||
tristate "BRCMSTB GPIO support"
|
||||
default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
|
||||
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
|
||||
index fbcda637d5e1..4e1ce3c97bca 100644
|
||||
--- a/drivers/gpio/Makefile
|
||||
+++ b/drivers/gpio/Makefile
|
||||
@@ -38,6 +38,7 @@ obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o
|
||||
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o
|
||||
+obj-$(CONFIG_GPIO_BCM_VIRT) += gpio-bcm-virt.o
|
||||
obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
|
||||
obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o
|
||||
obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
|
||||
diff --git a/drivers/gpio/gpio-bcm-virt.c b/drivers/gpio/gpio-bcm-virt.c
|
||||
new file mode 100644
|
||||
index 000000000000..49e28ad9760e
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpio/gpio-bcm-virt.c
|
||||
@@ -0,0 +1,214 @@
|
||||
+/*
|
||||
+ * brcmvirt GPIO driver
|
||||
+ *
|
||||
+ * Copyright (C) 2012,2013 Dom Cobley <popcornmix@gmail.com>
|
||||
+ * Based on gpio-clps711x.c by Alexander Shiyan <shc_work@mail.ru>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+#define MODULE_NAME "brcmvirt-gpio"
|
||||
+#define NUM_GPIO 2
|
||||
+
|
||||
+struct brcmvirt_gpio {
|
||||
+ struct gpio_chip gc;
|
||||
+ u32 __iomem *ts_base;
|
||||
+ /* two packed 16-bit counts of enabled and disables
|
||||
+ Allows host to detect a brief enable that was missed */
|
||||
+ u32 enables_disables[NUM_GPIO];
|
||||
+ dma_addr_t bus_addr;
|
||||
+};
|
||||
+
|
||||
+static int brcmvirt_gpio_dir_in(struct gpio_chip *gc, unsigned off)
|
||||
+{
|
||||
+ struct brcmvirt_gpio *gpio;
|
||||
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int brcmvirt_gpio_dir_out(struct gpio_chip *gc, unsigned off, int val)
|
||||
+{
|
||||
+ struct brcmvirt_gpio *gpio;
|
||||
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int brcmvirt_gpio_get(struct gpio_chip *gc, unsigned off)
|
||||
+{
|
||||
+ struct brcmvirt_gpio *gpio;
|
||||
+ unsigned v;
|
||||
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
|
||||
+ v = readl(gpio->ts_base + off);
|
||||
+ return (v >> off) & 1;
|
||||
+}
|
||||
+
|
||||
+static void brcmvirt_gpio_set(struct gpio_chip *gc, unsigned off, int val)
|
||||
+{
|
||||
+ struct brcmvirt_gpio *gpio;
|
||||
+ u16 enables, disables;
|
||||
+ s16 diff;
|
||||
+ bool lit;
|
||||
+ gpio = container_of(gc, struct brcmvirt_gpio, gc);
|
||||
+ enables = gpio->enables_disables[off] >> 16;
|
||||
+ disables = gpio->enables_disables[off] >> 0;
|
||||
+ diff = (s16)(enables - disables);
|
||||
+ lit = diff > 0;
|
||||
+ if ((val && lit) || (!val && !lit))
|
||||
+ return;
|
||||
+ if (val)
|
||||
+ enables++;
|
||||
+ else
|
||||
+ disables++;
|
||||
+ diff = (s16)(enables - disables);
|
||||
+ BUG_ON(diff != 0 && diff != 1);
|
||||
+ gpio->enables_disables[off] = (enables << 16) | (disables << 0);
|
||||
+ writel(gpio->enables_disables[off], gpio->ts_base + off);
|
||||
+}
|
||||
+
|
||||
+static int brcmvirt_gpio_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int err = 0;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device_node *np = dev->of_node;
|
||||
+ struct device_node *fw_node;
|
||||
+ struct rpi_firmware *fw;
|
||||
+ struct brcmvirt_gpio *ucb;
|
||||
+ u32 gpiovirtbuf;
|
||||
+
|
||||
+ fw_node = of_parse_phandle(np, "firmware", 0);
|
||||
+ if (!fw_node) {
|
||||
+ dev_err(dev, "Missing firmware node\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ fw = rpi_firmware_get(fw_node);
|
||||
+ if (!fw)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ ucb = devm_kzalloc(dev, sizeof *ucb, GFP_KERNEL);
|
||||
+ if (!ucb) {
|
||||
+ err = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ucb->ts_base = dma_alloc_coherent(dev, PAGE_SIZE, &ucb->bus_addr, GFP_KERNEL);
|
||||
+ if (!ucb->ts_base) {
|
||||
+ pr_err("[%s]: failed to dma_alloc_coherent(%ld)\n",
|
||||
+ __func__, PAGE_SIZE);
|
||||
+ err = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ gpiovirtbuf = (u32)ucb->bus_addr;
|
||||
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF,
|
||||
+ &gpiovirtbuf, sizeof(gpiovirtbuf));
|
||||
+
|
||||
+ if (err || gpiovirtbuf != 0) {
|
||||
+ dev_warn(dev, "Failed to set gpiovirtbuf, trying to get err:%x\n", err);
|
||||
+ dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
|
||||
+ ucb->ts_base = 0;
|
||||
+ ucb->bus_addr = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (!ucb->ts_base) {
|
||||
+ err = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF,
|
||||
+ &gpiovirtbuf, sizeof(gpiovirtbuf));
|
||||
+
|
||||
+ if (err) {
|
||||
+ dev_err(dev, "Failed to get gpiovirtbuf\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (!gpiovirtbuf) {
|
||||
+ dev_err(dev, "No virtgpio buffer\n");
|
||||
+ err = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ // mmap the physical memory
|
||||
+ gpiovirtbuf &= ~0xc0000000;
|
||||
+ ucb->ts_base = ioremap(gpiovirtbuf, 4096);
|
||||
+ if (ucb->ts_base == NULL) {
|
||||
+ dev_err(dev, "Failed to map physical address\n");
|
||||
+ err = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ ucb->bus_addr = 0;
|
||||
+ }
|
||||
+ ucb->gc.label = MODULE_NAME;
|
||||
+ ucb->gc.owner = THIS_MODULE;
|
||||
+ //ucb->gc.dev = dev;
|
||||
+ ucb->gc.of_node = np;
|
||||
+ ucb->gc.base = 100;
|
||||
+ ucb->gc.ngpio = NUM_GPIO;
|
||||
+
|
||||
+ ucb->gc.direction_input = brcmvirt_gpio_dir_in;
|
||||
+ ucb->gc.direction_output = brcmvirt_gpio_dir_out;
|
||||
+ ucb->gc.get = brcmvirt_gpio_get;
|
||||
+ ucb->gc.set = brcmvirt_gpio_set;
|
||||
+ ucb->gc.can_sleep = true;
|
||||
+
|
||||
+ err = gpiochip_add(&ucb->gc);
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, ucb);
|
||||
+
|
||||
+ return 0;
|
||||
+out:
|
||||
+ if (ucb->bus_addr) {
|
||||
+ dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
|
||||
+ ucb->bus_addr = 0;
|
||||
+ ucb->ts_base = NULL;
|
||||
+ } else if (ucb->ts_base) {
|
||||
+ iounmap(ucb->ts_base);
|
||||
+ ucb->ts_base = NULL;
|
||||
+ }
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int brcmvirt_gpio_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ int err = 0;
|
||||
+ struct brcmvirt_gpio *ucb = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ gpiochip_remove(&ucb->gc);
|
||||
+ if (ucb->bus_addr)
|
||||
+ dma_free_coherent(dev, PAGE_SIZE, ucb->ts_base, ucb->bus_addr);
|
||||
+ else if (ucb->ts_base)
|
||||
+ iounmap(ucb->ts_base);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id __maybe_unused brcmvirt_gpio_ids[] = {
|
||||
+ { .compatible = "brcm,bcm2835-virtgpio" },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, brcmvirt_gpio_ids);
|
||||
+
|
||||
+static struct platform_driver brcmvirt_gpio_driver = {
|
||||
+ .driver = {
|
||||
+ .name = MODULE_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = of_match_ptr(brcmvirt_gpio_ids),
|
||||
+ },
|
||||
+ .probe = brcmvirt_gpio_probe,
|
||||
+ .remove = brcmvirt_gpio_remove,
|
||||
+};
|
||||
+module_platform_driver(brcmvirt_gpio_driver);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Dom Cobley <popcornmix@gmail.com>");
|
||||
+MODULE_DESCRIPTION("brcmvirt GPIO driver");
|
||||
+MODULE_ALIAS("platform:brcmvirt-gpio");
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,440 @@
|
|||
From 66b07995a6f590646045ca6ad6d67b5e5933324e Mon Sep 17 00:00:00 2001
|
||||
From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
|
||||
Date: Wed, 3 Dec 2014 13:23:28 +0200
|
||||
Subject: [PATCH 095/634] OF: DT-Overlay configfs interface
|
||||
|
||||
This is a port of Pantelis Antoniou's v3 port that makes use of the
|
||||
new upstreamed configfs support for binary attributes.
|
||||
|
||||
Original commit message:
|
||||
|
||||
Add a runtime interface to using configfs for generic device tree overlay
|
||||
usage. With it its possible to use device tree overlays without having
|
||||
to use a per-platform overlay manager.
|
||||
|
||||
Please see Documentation/devicetree/configfs-overlays.txt for more info.
|
||||
|
||||
Changes since v2:
|
||||
- Removed ifdef CONFIG_OF_OVERLAY (since for now it's required)
|
||||
- Created a documentation entry
|
||||
- Slight rewording in Kconfig
|
||||
|
||||
Changes since v1:
|
||||
- of_resolve() -> of_resolve_phandles().
|
||||
|
||||
Originally-signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
DT configfs: Fix build errors on other platforms
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
DT configfs: fix build error
|
||||
|
||||
There is an error when compiling rpi-4.6.y branch:
|
||||
CC drivers/of/configfs.o
|
||||
drivers/of/configfs.c:291:21: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
|
||||
.default_groups = of_cfs_def_groups,
|
||||
^
|
||||
drivers/of/configfs.c:291:21: note: (near initialization for 'of_cfs_subsys.su_group.default_groups.next')
|
||||
|
||||
The .default_groups is linked list since commit
|
||||
1ae1602de028acaa42a0f6ff18d19756f8e825c6.
|
||||
This commit uses configfs_add_default_group to fix this problem.
|
||||
|
||||
Signed-off-by: Slawomir Stepien <sst@poczta.fm>
|
||||
|
||||
configfs: New of_overlay API
|
||||
---
|
||||
.../devicetree/configfs-overlays.txt | 31 ++
|
||||
drivers/of/Kconfig | 7 +
|
||||
drivers/of/Makefile | 1 +
|
||||
drivers/of/configfs.c | 310 ++++++++++++++++++
|
||||
4 files changed, 349 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/configfs-overlays.txt
|
||||
create mode 100644 drivers/of/configfs.c
|
||||
|
||||
diff --git a/Documentation/devicetree/configfs-overlays.txt b/Documentation/devicetree/configfs-overlays.txt
|
||||
new file mode 100644
|
||||
index 000000000000..5fa43e064307
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/configfs-overlays.txt
|
||||
@@ -0,0 +1,31 @@
|
||||
+Howto use the configfs overlay interface.
|
||||
+
|
||||
+A device-tree configfs entry is created in /config/device-tree/overlays
|
||||
+and and it is manipulated using standard file system I/O.
|
||||
+Note that this is a debug level interface, for use by developers and
|
||||
+not necessarily something accessed by normal users due to the
|
||||
+security implications of having direct access to the kernel's device tree.
|
||||
+
|
||||
+* To create an overlay you mkdir the directory:
|
||||
+
|
||||
+ # mkdir /config/device-tree/overlays/foo
|
||||
+
|
||||
+* Either you echo the overlay firmware file to the path property file.
|
||||
+
|
||||
+ # echo foo.dtbo >/config/device-tree/overlays/foo/path
|
||||
+
|
||||
+* Or you cat the contents of the overlay to the dtbo file
|
||||
+
|
||||
+ # cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
|
||||
+
|
||||
+The overlay file will be applied, and devices will be created/destroyed
|
||||
+as required.
|
||||
+
|
||||
+To remove it simply rmdir the directory.
|
||||
+
|
||||
+ # rmdir /config/device-tree/overlays/foo
|
||||
+
|
||||
+The rationalle of the dual interface (firmware & direct copy) is that each is
|
||||
+better suited to different use patterns. The firmware interface is what's
|
||||
+intended to be used by hardware managers in the kernel, while the copy interface
|
||||
+make sense for developers (since it avoids problems with namespaces).
|
||||
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
|
||||
index 3dfeae8912df..654a25f96897 100644
|
||||
--- a/drivers/of/Kconfig
|
||||
+++ b/drivers/of/Kconfig
|
||||
@@ -98,4 +98,11 @@ config OF_DMA_DEFAULT_COHERENT
|
||||
# arches should select this if DMA is coherent by default for OF devices
|
||||
bool
|
||||
|
||||
+config OF_CONFIGFS
|
||||
+ bool "Device Tree Overlay ConfigFS interface"
|
||||
+ select CONFIGFS_FS
|
||||
+ select OF_OVERLAY
|
||||
+ help
|
||||
+ Enable a simple user-space driven DT overlay interface.
|
||||
+
|
||||
endif # OF
|
||||
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
|
||||
index c13b982084a3..957a5b60c167 100644
|
||||
--- a/drivers/of/Makefile
|
||||
+++ b/drivers/of/Makefile
|
||||
@@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-y = base.o device.o platform.o property.o
|
||||
obj-$(CONFIG_OF_KOBJ) += kobj.o
|
||||
+obj-$(CONFIG_OF_CONFIGFS) += configfs.o
|
||||
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
|
||||
obj-$(CONFIG_OF_FLATTREE) += fdt.o
|
||||
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
|
||||
diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c
|
||||
new file mode 100644
|
||||
index 000000000000..178f0629b0f0
|
||||
--- /dev/null
|
||||
+++ b/drivers/of/configfs.c
|
||||
@@ -0,0 +1,310 @@
|
||||
+/*
|
||||
+ * Configfs entries for device-tree
|
||||
+ *
|
||||
+ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * as published by the Free Software Foundation; either version
|
||||
+ * 2 of the License, or (at your option) any later version.
|
||||
+ */
|
||||
+#include <linux/ctype.h>
|
||||
+#include <linux/cpu.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_fdt.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/proc_fs.h>
|
||||
+#include <linux/configfs.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/stat.h>
|
||||
+#include <linux/limits.h>
|
||||
+#include <linux/file.h>
|
||||
+#include <linux/vmalloc.h>
|
||||
+#include <linux/firmware.h>
|
||||
+#include <linux/sizes.h>
|
||||
+
|
||||
+#include "of_private.h"
|
||||
+
|
||||
+struct cfs_overlay_item {
|
||||
+ struct config_item item;
|
||||
+
|
||||
+ char path[PATH_MAX];
|
||||
+
|
||||
+ const struct firmware *fw;
|
||||
+ struct device_node *overlay;
|
||||
+ int ov_id;
|
||||
+
|
||||
+ void *dtbo;
|
||||
+ int dtbo_size;
|
||||
+};
|
||||
+
|
||||
+static int create_overlay(struct cfs_overlay_item *overlay, void *blob)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ /* unflatten the tree */
|
||||
+ of_fdt_unflatten_tree(blob, NULL, &overlay->overlay);
|
||||
+ if (overlay->overlay == NULL) {
|
||||
+ pr_err("%s: failed to unflatten tree\n", __func__);
|
||||
+ err = -EINVAL;
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+ pr_debug("%s: unflattened OK\n", __func__);
|
||||
+
|
||||
+ /* mark it as detached */
|
||||
+ of_node_set_flag(overlay->overlay, OF_DETACHED);
|
||||
+
|
||||
+ /* perform resolution */
|
||||
+ err = of_resolve_phandles(overlay->overlay);
|
||||
+ if (err != 0) {
|
||||
+ pr_err("%s: Failed to resolve tree\n", __func__);
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+ pr_debug("%s: resolved OK\n", __func__);
|
||||
+
|
||||
+ err = of_overlay_apply(overlay->overlay, &overlay->ov_id);
|
||||
+ if (err < 0) {
|
||||
+ pr_err("%s: Failed to create overlay (err=%d)\n",
|
||||
+ __func__, err);
|
||||
+ goto out_err;
|
||||
+ }
|
||||
+
|
||||
+out_err:
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static inline struct cfs_overlay_item *to_cfs_overlay_item(
|
||||
+ struct config_item *item)
|
||||
+{
|
||||
+ return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
|
||||
+}
|
||||
+
|
||||
+static ssize_t cfs_overlay_item_path_show(struct config_item *item,
|
||||
+ char *page)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
||||
+ return sprintf(page, "%s\n", overlay->path);
|
||||
+}
|
||||
+
|
||||
+static ssize_t cfs_overlay_item_path_store(struct config_item *item,
|
||||
+ const char *page, size_t count)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
||||
+ const char *p = page;
|
||||
+ char *s;
|
||||
+ int err;
|
||||
+
|
||||
+ /* if it's set do not allow changes */
|
||||
+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
|
||||
+ return -EPERM;
|
||||
+
|
||||
+ /* copy to path buffer (and make sure it's always zero terminated */
|
||||
+ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
|
||||
+ overlay->path[sizeof(overlay->path) - 1] = '\0';
|
||||
+
|
||||
+ /* strip trailing newlines */
|
||||
+ s = overlay->path + strlen(overlay->path);
|
||||
+ while (s > overlay->path && *--s == '\n')
|
||||
+ *s = '\0';
|
||||
+
|
||||
+ pr_debug("%s: path is '%s'\n", __func__, overlay->path);
|
||||
+
|
||||
+ err = request_firmware(&overlay->fw, overlay->path, NULL);
|
||||
+ if (err != 0)
|
||||
+ goto out_err;
|
||||
+
|
||||
+ err = create_overlay(overlay, (void *)overlay->fw->data);
|
||||
+ if (err != 0)
|
||||
+ goto out_err;
|
||||
+
|
||||
+ return count;
|
||||
+
|
||||
+out_err:
|
||||
+
|
||||
+ release_firmware(overlay->fw);
|
||||
+ overlay->fw = NULL;
|
||||
+
|
||||
+ overlay->path[0] = '\0';
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static ssize_t cfs_overlay_item_status_show(struct config_item *item,
|
||||
+ char *page)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
||||
+
|
||||
+ return sprintf(page, "%s\n",
|
||||
+ overlay->ov_id >= 0 ? "applied" : "unapplied");
|
||||
+}
|
||||
+
|
||||
+CONFIGFS_ATTR(cfs_overlay_item_, path);
|
||||
+CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
|
||||
+
|
||||
+static struct configfs_attribute *cfs_overlay_attrs[] = {
|
||||
+ &cfs_overlay_item_attr_path,
|
||||
+ &cfs_overlay_item_attr_status,
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
+ssize_t cfs_overlay_item_dtbo_read(struct config_item *item,
|
||||
+ void *buf, size_t max_count)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
||||
+
|
||||
+ pr_debug("%s: buf=%p max_count=%zu\n", __func__,
|
||||
+ buf, max_count);
|
||||
+
|
||||
+ if (overlay->dtbo == NULL)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* copy if buffer provided */
|
||||
+ if (buf != NULL) {
|
||||
+ /* the buffer must be large enough */
|
||||
+ if (overlay->dtbo_size > max_count)
|
||||
+ return -ENOSPC;
|
||||
+
|
||||
+ memcpy(buf, overlay->dtbo, overlay->dtbo_size);
|
||||
+ }
|
||||
+
|
||||
+ return overlay->dtbo_size;
|
||||
+}
|
||||
+
|
||||
+ssize_t cfs_overlay_item_dtbo_write(struct config_item *item,
|
||||
+ const void *buf, size_t count)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
||||
+ int err;
|
||||
+
|
||||
+ /* if it's set do not allow changes */
|
||||
+ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
|
||||
+ return -EPERM;
|
||||
+
|
||||
+ /* copy the contents */
|
||||
+ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
|
||||
+ if (overlay->dtbo == NULL)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ overlay->dtbo_size = count;
|
||||
+
|
||||
+ err = create_overlay(overlay, overlay->dtbo);
|
||||
+ if (err != 0)
|
||||
+ goto out_err;
|
||||
+
|
||||
+ return count;
|
||||
+
|
||||
+out_err:
|
||||
+ kfree(overlay->dtbo);
|
||||
+ overlay->dtbo = NULL;
|
||||
+ overlay->dtbo_size = 0;
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
|
||||
+
|
||||
+static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
|
||||
+ &cfs_overlay_item_attr_dtbo,
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
+static void cfs_overlay_release(struct config_item *item)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
||||
+
|
||||
+ if (overlay->ov_id >= 0)
|
||||
+ of_overlay_remove(&overlay->ov_id);
|
||||
+ if (overlay->fw)
|
||||
+ release_firmware(overlay->fw);
|
||||
+ /* kfree with NULL is safe */
|
||||
+ kfree(overlay->dtbo);
|
||||
+ kfree(overlay);
|
||||
+}
|
||||
+
|
||||
+static struct configfs_item_operations cfs_overlay_item_ops = {
|
||||
+ .release = cfs_overlay_release,
|
||||
+};
|
||||
+
|
||||
+static struct config_item_type cfs_overlay_type = {
|
||||
+ .ct_item_ops = &cfs_overlay_item_ops,
|
||||
+ .ct_attrs = cfs_overlay_attrs,
|
||||
+ .ct_bin_attrs = cfs_overlay_bin_attrs,
|
||||
+ .ct_owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static struct config_item *cfs_overlay_group_make_item(
|
||||
+ struct config_group *group, const char *name)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay;
|
||||
+
|
||||
+ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
|
||||
+ if (!overlay)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+ overlay->ov_id = -1;
|
||||
+
|
||||
+ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
|
||||
+ return &overlay->item;
|
||||
+}
|
||||
+
|
||||
+static void cfs_overlay_group_drop_item(struct config_group *group,
|
||||
+ struct config_item *item)
|
||||
+{
|
||||
+ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
|
||||
+
|
||||
+ config_item_put(&overlay->item);
|
||||
+}
|
||||
+
|
||||
+static struct configfs_group_operations overlays_ops = {
|
||||
+ .make_item = cfs_overlay_group_make_item,
|
||||
+ .drop_item = cfs_overlay_group_drop_item,
|
||||
+};
|
||||
+
|
||||
+static struct config_item_type overlays_type = {
|
||||
+ .ct_group_ops = &overlays_ops,
|
||||
+ .ct_owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static struct configfs_group_operations of_cfs_ops = {
|
||||
+ /* empty - we don't allow anything to be created */
|
||||
+};
|
||||
+
|
||||
+static struct config_item_type of_cfs_type = {
|
||||
+ .ct_group_ops = &of_cfs_ops,
|
||||
+ .ct_owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+struct config_group of_cfs_overlay_group;
|
||||
+
|
||||
+static struct configfs_subsystem of_cfs_subsys = {
|
||||
+ .su_group = {
|
||||
+ .cg_item = {
|
||||
+ .ci_namebuf = "device-tree",
|
||||
+ .ci_type = &of_cfs_type,
|
||||
+ },
|
||||
+ },
|
||||
+ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
|
||||
+};
|
||||
+
|
||||
+static int __init of_cfs_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ pr_info("%s\n", __func__);
|
||||
+
|
||||
+ config_group_init(&of_cfs_subsys.su_group);
|
||||
+ config_group_init_type_name(&of_cfs_overlay_group, "overlays",
|
||||
+ &overlays_type);
|
||||
+ configfs_add_default_group(&of_cfs_overlay_group,
|
||||
+ &of_cfs_subsys.su_group);
|
||||
+
|
||||
+ ret = configfs_register_subsystem(&of_cfs_subsys);
|
||||
+ if (ret != 0) {
|
||||
+ pr_err("%s: failed to register subsys\n", __func__);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ pr_info("%s: OK\n", __func__);
|
||||
+out:
|
||||
+ return ret;
|
||||
+}
|
||||
+late_initcall(of_cfs_init);
|
||||
--
|
||||
2.33.1
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
From a9c3bd5396da5807087ceeaa50312fffc069339e Mon Sep 17 00:00:00 2001
|
||||
From: Cheong2K <cheong@redbear.cc>
|
||||
Date: Fri, 26 Feb 2016 18:20:10 +0800
|
||||
Subject: [PATCH 096/634] brcm: adds support for BCM43341 wifi
|
||||
|
||||
brcmfmac: Disable power management
|
||||
|
||||
Disable wireless power saving in the brcmfmac WLAN driver. This is a
|
||||
temporary measure until the connectivity loss resulting from power
|
||||
saving is resolved.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
brcmfmac: Use original country code as a fallback
|
||||
|
||||
Commit 73345fd212980d2e28a5c6d83801c903bd773680:
|
||||
|
||||
brcmfmac: Configure country code using device specific settings
|
||||
|
||||
prevents region codes from working on devices that lack a region code
|
||||
translation table. In the event of an absent table, preserve the old
|
||||
behaviour of using the provided code as-is.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
brcmfmac: Plug memory leak in brcmf_fill_bss_param
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1471
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
brcmfmac: do not use internal roaming engine by default
|
||||
|
||||
Some evidence of curing disconnects with this disabled, so make it a default.
|
||||
Can be overridden with module parameter roamoff=0
|
||||
See: http://projectable.me/optimize-my-pi-wi-fi/
|
||||
|
||||
brcmfmac: Change stop_ap sequence
|
||||
|
||||
Patch from Broadcom/Cypress to resolve a customer error
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
Revert "brcmfmac: Disable power management"
|
||||
|
||||
Shortly after the release of the Pi 3B, a loss of SSH connectivity
|
||||
over WiFi was traced to the power management handling, so power
|
||||
management was disabled. And so it has remained ever since.
|
||||
|
||||
Enabling power management saves 55mA (~270mW) on a Pi 4B, so is very
|
||||
much worth the minimal effort of reverting this patch, which was
|
||||
squashed and rebased many times since then to the commit hash is
|
||||
meaningless.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +-
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | 2 +-
|
||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 3 ++-
|
||||
3 files changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
||||
index 9db12ffd2ff8..c388d56269bc 100644
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
||||
@@ -2953,7 +2953,7 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
|
||||
brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
|
||||
pm = PM_OFF;
|
||||
}
|
||||
- brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
|
||||
+ brcmf_err("power save %s\n", (pm ? "enabled" : "disabled"));
|
||||
|
||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
|
||||
if (err) {
|
||||
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
|
||||
index e3758bd86acf..591dcd04b4b4 100644
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
|
||||
@@ -59,7 +59,7 @@ static int brcmf_fcmode;
|
||||
module_param_named(fcmode, brcmf_fcmode, int, 0);
|
||||
MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
|
||||
|
||||
-static int brcmf_roamoff;
|
||||
+static int brcmf_roamoff = 1;
|
||||
module_param_named(roamoff, brcmf_roamoff, int, 0400);
|
||||
MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
|
||||
|
||||
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
index 8effeb7a7269..14b2cdafe378 100644
|
||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
||||
@@ -611,6 +611,7 @@ BRCMF_FW_DEF(4329, "brcmfmac4329-sdio");
|
||||
BRCMF_FW_DEF(4330, "brcmfmac4330-sdio");
|
||||
BRCMF_FW_DEF(4334, "brcmfmac4334-sdio");
|
||||
BRCMF_FW_DEF(43340, "brcmfmac43340-sdio");
|
||||
+BRCMF_FW_DEF(43341, "brcmfmac43341-sdio");
|
||||
BRCMF_FW_DEF(4335, "brcmfmac4335-sdio");
|
||||
BRCMF_FW_DEF(43362, "brcmfmac43362-sdio");
|
||||
BRCMF_FW_DEF(4339, "brcmfmac4339-sdio");
|
||||
@@ -643,7 +644,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
|
||||
BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340),
|
||||
- BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340),
|
||||
+ BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43341),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362),
|
||||
BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
|
||||
--
|
||||
2.33.1
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue