bcm27xx: add kernel 5.10 support

Rebased RPi foundation patches on linux 5.10.59, removed applied and reverted
patches, wireless patches and defconfig patches.

bcm2708: boot tested on RPi B+ v1.2
bcm2709: boot tested on RPi 4B v1.1 4G
bcm2711: boot tested on RPi 4B v1.1 4G

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
This commit is contained in:
Álvaro Fernández Rojas 2021-08-21 10:54:34 +02:00
parent 33b6885975
commit 8299d1f057
745 changed files with 227568 additions and 2 deletions

View 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

View File

@ -0,0 +1,464 @@
# 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_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_STALL_COMMON=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

View File

@ -0,0 +1,448 @@
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_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_STALL_COMMON=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

View File

@ -0,0 +1,463 @@
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=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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_ETH is not set
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

View File

@ -365,6 +365,26 @@ endef
$(eval $(call KernelPackage,sound-soc-audioinjector-pi-soundcard))
define KernelPackage/sound-soc-chipdip-dac
TITLE:=Support for ChipDip DAC
KCONFIG:= \
CONFIG_SND_BCM2708_SOC_CHIPDIP_DAC
FILES:= \
$(LINUX_DIR)/sound/soc/bcm/snd-soc-chipdip-dac.ko
AUTOLOAD:=$(call AutoLoad,68,snd-soc-chipdip-dac)
DEPENDS:= \
kmod-sound-soc-bcm2835-i2s \
@LINUX_5_10
$(call AddDepends/sound)
endef
define KernelPackage/sound-soc-chipdip-dac/description
This package contains support for ChipDip DAC
endef
$(eval $(call KernelPackage,sound-soc-chipdip-dac))
define KernelPackage/sound-soc-digidac1-soundcard
TITLE:=Support for RRA DigiDAC1
KCONFIG:= \

View File

@ -6,7 +6,9 @@ define KernelPackage/camera-bcm2835
TITLE:=BCM2835 Camera
KCONFIG:= \
CONFIG_VIDEO_BCM2835 \
CONFIG_VIDEO_BCM2835_MMAL
CONFIG_VIDEO_BCM2835_MMAL \
CONFIG_VIDEO_BCM2835_UNICAM=n \
CONFIG_VIDEO_ISP_BCM2835=n
FILES:= \
$(LINUX_DIR)/drivers/staging/vc04_services/bcm2835-camera/bcm2835-v4l2.ko
AUTOLOAD:=$(call AutoLoad,65,bcm2835-v4l2)
@ -31,12 +33,14 @@ define KernelPackage/drm-vc4
KCONFIG:= \
CONFIG_DRM_VC4 \
CONFIG_DRM_VC4_HDMI_CEC=y \
CONFIG_DRM_GUD=n \
CONFIG_DRM_V3D=n \
CONFIG_DRM_TVE200=n
FILES:= \
$(LINUX_DIR)/drivers/gpu/drm/vc4/vc4.ko \
$(LINUX_DIR)/drivers/gpu/drm/drm_kms_helper.ko \
$(LINUX_DIR)/drivers/media/cec/cec.ko
$(LINUX_DIR)/drivers/media/cec/cec.ko@lt5.10 \
$(LINUX_DIR)/drivers/media/cec/core/cec.ko@ge5.10
AUTOLOAD:=$(call AutoProbe,vc4)
endef

View File

@ -0,0 +1,99 @@
From c966ee565b122d840d7aac4c07c53b0d679d2d33 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] 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(+)
--- 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(voi
* 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
--- 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(co
#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
--- 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
--- 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

View File

@ -0,0 +1,56 @@
From f4888774b6bf2f68fa2b389690eee07d7e8efdb9 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 29 Oct 2018 14:45:45 +0000
Subject: [PATCH] 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 | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -205,8 +205,28 @@ static int pcf8523_rtc_read_time(struct
if (err < 0)
return err;
- if (regs[0] & REG_SECONDS_OS)
- return -EINVAL;
+ if (regs[0] & REG_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] &= ~REG_SECONDS_OS;
+
+ err = pcf8523_write(client, REG_SECONDS, regs[0]);
+ if (err < 0)
+ return err;
+
+ err = pcf8523_read(client, REG_SECONDS, &regs[0]);
+ if (err < 0)
+ return err;
+
+ if (regs[0] & REG_SECONDS_OS)
+ return -EAGAIN;
+ }
tm->tm_sec = bcd2bin(regs[0] & 0x7f);
tm->tm_min = bcd2bin(regs[1] & 0x7f);
@@ -242,7 +262,6 @@ static int pcf8523_rtc_set_time(struct d
return err;
regs[0] = REG_SECONDS;
- /* This will purposely overwrite REG_SECONDS_OS */
regs[1] = bin2bcd(tm->tm_sec);
regs[2] = bin2bcd(tm->tm_min);
regs[3] = bin2bcd(tm->tm_hour);

View File

@ -0,0 +1,96 @@
From 2aa4bd3751f6792bf00d59e4d9cd8a5550872cdb Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 15 Mar 2019 21:11:10 +0000
Subject: [PATCH] Revert "staging: bcm2835-audio: Drop DT dependency"
This reverts commit b7491a9fca2dc2535b9dc922550a37c5baae9d3d.
---
.../vc04_services/bcm2835-audio/bcm2835.c | 31 +++++++++++++------
1 file changed, 22 insertions(+), 9 deletions(-)
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
@@ -6,13 +6,13 @@
#include <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, "Ena
module_param(enable_compat_alsa, bool, 0444);
MODULE_PARM_DESC(enable_compat_alsa,
"Enables ALSA compatibility virtual audio device");
-module_param(num_channels, int, 0644);
-MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)");
static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
{
@@ -296,19 +294,28 @@ static int snd_add_child_devices(struct
static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ u32 numchans;
int err;
- if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) {
- num_channels = MAX_SUBSTREAMS;
- dev_warn(dev, "Illegal num_channels value, will use %u\n",
- num_channels);
+ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
+ &numchans);
+ if (err) {
+ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
+ return err;
+ }
+
+ if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
+ numchans = MAX_SUBSTREAMS;
+ dev_warn(dev,
+ "Illegal 'brcm,pwm-channels' value, will use %u\n",
+ numchans);
}
err = bcm2835_devm_add_vchi_ctx(dev);
if (err)
return err;
- err = snd_add_child_devices(dev, num_channels);
+ err = snd_add_child_devices(dev, numchans);
if (err)
return err;
@@ -330,6 +337,12 @@ static int snd_bcm2835_alsa_resume(struc
#endif
+static const struct of_device_id snd_bcm2835_of_match_table[] = {
+ { .compatible = "brcm,bcm2835-audio",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
+
static struct platform_driver bcm2835_alsa_driver = {
.probe = snd_bcm2835_alsa_probe,
#ifdef CONFIG_PM
@@ -338,6 +351,7 @@ static struct platform_driver bcm2835_al
#endif
.driver = {
.name = "bcm2835_audio",
+ .of_match_table = snd_bcm2835_of_match_table,
},
};
module_platform_driver(bcm2835_alsa_driver);
@@ -345,4 +359,3 @@ module_platform_driver(bcm2835_alsa_driv
MODULE_AUTHOR("Dom Cobley");
MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:bcm2835_audio");

View File

@ -0,0 +1,32 @@
From 086a38a1e0eea3b7cbb207384b92d5dc82c62454 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 20 Apr 2020 13:41:10 +0100
Subject: [PATCH] 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(-)
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -402,7 +402,6 @@ spidev_ioctl(struct file *filp, unsigned
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
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);

View File

@ -0,0 +1,58 @@
From a8fb0d43b8acd25d68a0d2c24fd0260393148447 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 3 Nov 2020 11:49:53 +0000
Subject: [PATCH] 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(-)
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -82,12 +82,9 @@ static void msg_submit(struct mbox_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_hrtim
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;
}
}

View File

@ -0,0 +1,47 @@
From dbfae4876cd4c8525a0100f19307f16cf7fb384a 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] 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(-)
--- 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)
{
@@ -1827,7 +1831,8 @@ static int smsc95xx_rx_fixup(struct usbn
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;
}
@@ -1845,7 +1850,8 @@ static int smsc95xx_rx_fixup(struct usbn
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);
}

View File

@ -0,0 +1,43 @@
From 5792c081bb959c57b381439e40d07c919193a993 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] 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(-)
--- 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
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",

View File

@ -0,0 +1,96 @@
From a5e86e4e7cc86e6a24844d758d2258c8b23f18f0 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 26 Mar 2013 17:26:38 +0000
Subject: [PATCH] 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(+)
--- 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_dev
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(st
}
}
+ /* 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");

View File

@ -0,0 +1,28 @@
From f146f2bb597fe00b6c2e5da169a766dc8ab2a4fa Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 13 Mar 2015 12:43:36 +0000
Subject: [PATCH] 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(+)
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -214,6 +214,12 @@ static int __release_resource(struct res
{
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;

View File

@ -0,0 +1,24 @@
From 55a3a6691b480c57613f9db3a0e1aca02b7f68c1 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 9 Feb 2017 14:33:30 +0000
Subject: [PATCH] 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(-)
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -128,7 +128,7 @@ static int bcm2836_map(struct irq_domain
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;
}

View File

@ -0,0 +1,127 @@
From ad12646921360036adf7ecdcf1325b9a880b316a 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] 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(-)
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -161,6 +161,7 @@ config ARCH_BCM2835
select ARM_TIMER_SP804
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
select BCM2835_TIMER
+ select FIQ
select PINCTRL
select PINCTRL_BCM2835
select MFD_CORE
--- 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 bcm283
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
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
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;
}

View File

@ -0,0 +1,99 @@
From 18774f96f2766eb711d462842626ae603110c18e 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] 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(-)
--- 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_
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
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++) {

View File

@ -0,0 +1,24 @@
From 8469be136aebf9fe06746ec47e4495c77d5522f5 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 14 Jul 2015 10:26:09 +0100
Subject: [PATCH] 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(-)
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -733,7 +733,7 @@ static int spidev_probe(struct spi_devic
* 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);

View File

@ -0,0 +1,101 @@
From 1fafff0383c50bbbb2d5bb3205923904f3f55ce8 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] 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(-)
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -134,7 +134,7 @@ config COH901318
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
--- 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 plat
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 plat
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 pla
{
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_dm
},
};
-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");

View File

@ -0,0 +1,27 @@
From b7ad81911a06fd8047ca36c07bd49d8317833502 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 25 Jan 2016 17:25:12 +0000
Subject: [PATCH] firmware: Updated mailbox header
---
include/soc/bcm2835/raspberrypi-firmware.h | 3 +++
1 file changed, 3 insertions(+)
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -9,6 +9,8 @@
#include <linux/types.h>
#include <linux/of_device.h>
+#define RPI_FIRMWARE_CHAN_FB 1
+
struct rpi_firmware;
enum rpi_firmware_property_status {
@@ -159,5 +161,6 @@ static inline struct rpi_firmware *rpi_f
return NULL;
}
#endif
+int rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data);
#endif /* __SOC_RASPBERRY_FIRMWARE_H__ */

View File

@ -0,0 +1,20 @@
From d9fa2c594a6dfd5f538c50eaa6a06449d06c5a8e Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 15 Jun 2016 16:48:41 +0100
Subject: [PATCH] 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(+)
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -465,3 +465,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");

View File

@ -0,0 +1,102 @@
From 351b9cbfc6aed837c7e23462d7109372de22e2bb 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] 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(-)
--- 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_time
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 watchd
{
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_wd
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)

View File

@ -0,0 +1,23 @@
From e722eb6ced1ad7a162782fe10dd5d4225a6b4e0d Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 5 Apr 2016 19:40:12 +0100
Subject: [PATCH] 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(-)
--- a/arch/arm/kernel/reboot.c
+++ b/arch/arm/kernel/reboot.c
@@ -102,9 +102,7 @@ void machine_shutdown(void)
*/
void machine_halt(void)
{
- local_irq_disable();
- smp_send_stop();
- while (1);
+ machine_power_off();
}
/*

View File

@ -0,0 +1,19 @@
From 0bc33dc51825662d4fc7a46c5e622de00e5cbf80 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 9 Nov 2016 13:02:52 +0000
Subject: [PATCH] bcm: Make RASPBERRYPI_POWER depend on PM
---
drivers/soc/bcm/Kconfig | 1 +
1 file changed, 1 insertion(+)
--- 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

View File

@ -0,0 +1,45 @@
From 41e34cd05d40eca6674e25eb9a85e5f7992d4e83 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] 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(-)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -2295,8 +2295,15 @@ static int bcm2835_clk_probe(struct plat
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 = {
@@ -2322,7 +2329,11 @@ static struct platform_driver bcm2835_cl
.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");

View File

@ -0,0 +1,25 @@
From 102d9fbd0a8d762835a9f9a7917e9eace3a9d84e Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 6 Dec 2016 17:05:39 +0000
Subject: [PATCH] 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(-)
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -102,8 +102,10 @@ static int bcm2835_rng_init(struct hwrng
}
/* 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;
}

View File

@ -0,0 +1,28 @@
From 3af9c4ed5775b7675e679a80a381eafe2ce726ae Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 13 Feb 2017 17:20:08 +0000
Subject: [PATCH] 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(+)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1384,6 +1384,11 @@ bcm2835_register_pll_divider(struct bcm2
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;

View File

@ -0,0 +1,120 @@
From 05cae664e29e510111cf24f2beb1c31cba09bcce Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 13 Feb 2017 17:20:08 +0000
Subject: [PATCH] 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(-)
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1312,6 +1312,8 @@ static const struct clk_ops bcm2835_vpu_
.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)
{
@@ -1329,6 +1331,9 @@ static struct clk_hw *bcm2835_register_p
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;
@@ -1384,9 +1389,11 @@ bcm2835_register_pll_divider(struct bcm2
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;
@@ -1443,6 +1450,15 @@ static struct clk_hw *bcm2835_register_c
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.
*/
@@ -2221,6 +2237,8 @@ static const struct bcm2835_clk_desc clk
.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.
*
@@ -2240,6 +2258,19 @@ static int bcm2835_mark_sdc_parent_criti
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;
@@ -2249,6 +2280,7 @@ static int bcm2835_clk_probe(struct plat
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);
@@ -2267,6 +2299,13 @@ static int bcm2835_clk_probe(struct plat
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,

View File

@ -0,0 +1,115 @@
From 6ac8a6c58b51d02780b7a1fc882df33ae2560798 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 6 Mar 2017 09:06:18 +0000
Subject: [PATCH] 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(-)
--- 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_n
struct bcm2835_cprman {
struct device *dev;
void __iomem *regs;
+ struct rpi_firmware *fw;
spinlock_t regs_lock; /* spinlock for all clocks */
unsigned int soc;
@@ -1016,6 +1020,30 @@ static unsigned long bcm2835_clock_get_r
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;
@@ -1304,7 +1332,7 @@ static int bcm2835_vpu_clock_is_on(struc
*/
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,
@@ -2279,6 +2307,7 @@ static int bcm2835_clk_probe(struct plat
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;
@@ -2299,6 +2328,14 @@ static int bcm2835_clk_probe(struct plat
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",

View File

@ -0,0 +1,35 @@
From 2a0e0c15c001bfde3666f159552e414217fe44ac Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 9 Feb 2017 14:36:44 +0000
Subject: [PATCH] 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(-)
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1016,7 +1016,7 @@ int snd_soc_add_pcm_runtime(struct snd_s
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;
}
@@ -1027,7 +1027,7 @@ int snd_soc_add_pcm_runtime(struct snd_s
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;
}

View File

@ -0,0 +1,137 @@
From 55f18cc01fc9c93999ea935f7d869d136f5204ed Mon Sep 17 00:00:00 2001
From: Claggy3 <stephen.maclagan@hotmail.com>
Date: Sat, 11 Feb 2017 14:00:30 +0000
Subject: [PATCH] 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(-)
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -176,8 +176,11 @@ static int vfp_notifier(struct notifier_
* 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
/*
* 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
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
/* 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,

View File

@ -0,0 +1,189 @@
From ee7f5d2470712e25e2bde81ead7c191a3eff41e2 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] 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(-)
--- 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(s
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 t
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_a
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_a
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_a
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;

View File

@ -0,0 +1,25 @@
From a432a3f7142e7e76fd1708debe509ffbea3a3658 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Thu, 18 Dec 2014 16:07:15 -0800
Subject: [PATCH] mm: Remove the PFN busy warning
See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is
expected sometimes when using CMA. However, that commit still spams
my kernel log with these warnings.
Signed-off-by: Eric Anholt <eric@anholt.net>
---
mm/page_alloc.c | 2 --
1 file changed, 2 deletions(-)
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -8594,8 +8594,6 @@ int alloc_contig_range(unsigned long sta
/* Make sure the range is really isolated. */
if (test_pages_isolated(outer_start, end, 0)) {
- pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
- __func__, outer_start, end);
ret = -EBUSY;
goto done;
}

View File

@ -0,0 +1,112 @@
From 9ab633ec6dd4bb60c13486c8474cf30045c0a422 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 23 Jan 2018 16:52:45 +0000
Subject: [PATCH] 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(-)
--- 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 ir
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
}
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 */
--- 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
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,

View File

@ -0,0 +1,48 @@
From 021908b753875198daddfa9e77a0d2fd8004a469 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 17 Oct 2017 15:04:29 +0100
Subject: [PATCH] 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 | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2453,6 +2453,11 @@ static int lan78xx_reset(struct lan78xx_
int ret = 0;
unsigned long timeout;
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);
buf |= HW_CFG_LRST_;
@@ -2506,6 +2511,9 @@ static int lan78xx_reset(struct lan78xx_
ret = lan78xx_read_reg(dev, HW_CFG, &buf);
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);
ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
@@ -2561,6 +2569,9 @@ static int lan78xx_reset(struct lan78xx_
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);
ret = lan78xx_read_reg(dev, MAC_TX, &buf);

View File

@ -0,0 +1,29 @@
From a79b4327445a827be28b9939592da8e812a19b29 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 23 Feb 2016 17:26:48 +0000
Subject: [PATCH] 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(+)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2599,7 +2599,12 @@ static int pl011_setup_port(struct devic
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;

View File

@ -0,0 +1,86 @@
From e3f28ae66fd94f4a7a10099a96d6dd5273904943 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 1 Mar 2017 16:07:39 +0000
Subject: [PATCH] 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(-)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1642,6 +1642,23 @@ static void pl011_put_poll_char(struct u
#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 =
@@ -1658,7 +1675,7 @@ static int pl011_hwinit(struct uart_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 |
@@ -2313,7 +2330,7 @@ static int pl011_console_setup(struct co
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;
@@ -2530,6 +2547,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;
@@ -2561,6 +2579,7 @@ static int pl011_probe_dt_alias(int inde
return ret;
}
+#endif
/* unregisters the driver also if no more ports are left */
static void pl011_unregister_port(struct uart_amba_port *uap)

View File

@ -0,0 +1,27 @@
From f44d321993ccf1707f5774dc443b900adae5d9d5 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 29 Sep 2017 10:32:19 +0100
Subject: [PATCH] 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(+)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1377,6 +1377,7 @@ static bool pl011_tx_char(struct uart_am
return false; /* unable to transmit character */
pl011_write(c, uap, REG_DR);
+ mb();
uap->port.icount.tx++;
return true;

View File

@ -0,0 +1,50 @@
From 8ccf96729972504acf4ca0e1868278ba549e0f5a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 29 Sep 2017 10:32:19 +0100
Subject: [PATCH] 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(+)
--- a/Documentation/devicetree/bindings/serial/pl011.yaml
+++ b/Documentation/devicetree/bindings/serial/pl011.yaml
@@ -98,6 +98,12 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
default: 3000
+ cts-event-workaround:
+ description:
+ Enables the (otherwise vendor-specific) workaround for the
+ CTS-induced TX lockup.
+ type: boolean
+
required:
- compatible
- reg
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2686,6 +2686,11 @@ static int pl011_probe(struct amba_devic
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);

View File

@ -0,0 +1,85 @@
From 28c2408f991d97de5e3d1da9711cf5486f411d02 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 11 Jul 2019 13:13:39 +0100
Subject: [PATCH] tty: amba-pl011: Make TX optimisation conditional
pl011_tx_chars takes a "from_irq" parameter to reduce the number of
register accesses. When from_irq is true the function assumes that the
FIFO is half empty and writes up to half a FIFO's worth of bytes
without polling the FIFO status register, the reasoning being that
the function is being called as a result of the TX interrupt being
raised. This logic would work were it not for the fact that
pl011_rx_chars, called from pl011_int before pl011_tx_chars, releases
the spinlock before calling tty_flip_buffer_push.
A user thread writing to the UART claims the spinlock and ultimately
calls pl011_tx_chars with from_irq set to false. This reverts to the
older logic that polls the FIFO status register before sending every
byte. If this happen on an SMP system during the section of the IRQ
handler where the spinlock has been released, then by the time the TX
interrupt handler is called, the FIFO may already be full, and any
further writes are likely to be lost.
The fix involves adding a per-port flag that is true iff running from
within the interrupt handler and the spinlock has not yet been released.
This flag is then used as the value for the from_irq parameter of
pl011_tx_chars, causing polling to be used in the unsafe case.
Fixes: 1e84d22322ce ("serial/amba-pl011: Refactor and simplify TX FIFO handling")
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/tty/serial/amba-pl011.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -265,6 +265,7 @@ struct uart_amba_port {
unsigned int old_cr; /* state during shutdown */
unsigned int fixed_baud; /* vendor-set fixed baud rate */
char type[12];
+ bool irq_locked; /* in irq, unreleased lock */
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
bool using_tx_dma;
@@ -811,6 +812,7 @@ __acquires(&uap->port.lock)
if (!uap->using_tx_dma)
return;
+ uap->irq_locked = 0;
dmaengine_terminate_async(uap->dmatx.chan);
if (uap->dmatx.queued) {
@@ -937,6 +939,7 @@ static void pl011_dma_rx_chars(struct ua
fifotaken = pl011_fifo_to_tty(uap);
}
+ uap->irq_locked = 0;
spin_unlock(&uap->port.lock);
dev_vdbg(uap->port.dev,
"Took %d chars from DMA buffer and %d chars from the FIFO\n",
@@ -1341,6 +1344,7 @@ __acquires(&uap->port.lock)
{
pl011_fifo_to_tty(uap);
+ uap->irq_locked = 0;
spin_unlock(&uap->port.lock);
tty_flip_buffer_push(&uap->port.state->port);
/*
@@ -1474,6 +1478,7 @@ static irqreturn_t pl011_int(int irq, vo
int handled = 0;
spin_lock_irqsave(&uap->port.lock, flags);
+ uap->irq_locked = 1;
status = pl011_read(uap, REG_RIS) & uap->im;
if (status) {
do {
@@ -1493,7 +1498,7 @@ static irqreturn_t pl011_int(int irq, vo
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
if (status & UART011_TXIS)
- pl011_tx_chars(uap, true);
+ pl011_tx_chars(uap, uap->irq_locked);
if (pass_counter-- == 0)
break;

View File

@ -0,0 +1,61 @@
From 3cec61f1b19a6f589f8b2aef97977e1c38eb7b70 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 24 Jan 2020 11:38:28 +0000
Subject: [PATCH] tty: amba-pl011: Add un/throttle support
The PL011 driver lacks throttle and unthrottle methods. As a result,
sending more data to the Pi than it can immediately sink while CRTSCTS
is enabled causes a NULL pointer to be followed.
Add a throttle handler that disables the RX interrupts, and an
unthrottle handler that reenables them.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1317,6 +1317,32 @@ static void pl011_start_tx(struct uart_p
pl011_start_tx_pio(uap);
}
+static void pl011_throttle(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+ unsigned long flags;
+
+ spin_lock_irqsave(&uap->port.lock, flags);
+ uap->im &= ~(UART011_RTIM | UART011_RXIM);
+ pl011_write(uap->im, uap, REG_IMSC);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static void pl011_unthrottle(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+ unsigned long flags;
+
+ spin_lock_irqsave(&uap->port.lock, flags);
+ uap->im |= UART011_RTIM;
+ if (!pl011_dma_rx_running(uap))
+ uap->im |= UART011_RXIM;
+ pl011_write(uap->im, uap, REG_IMSC);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
static void pl011_stop_rx(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -2156,6 +2182,8 @@ static const struct uart_ops amba_pl011_
.stop_tx = pl011_stop_tx,
.start_tx = pl011_start_tx,
.stop_rx = pl011_stop_rx,
+ .throttle = pl011_throttle,
+ .unthrottle = pl011_unthrottle,
.enable_ms = pl011_enable_ms,
.break_ctl = pl011_break_ctl,
.startup = pl011_startup,

View File

@ -0,0 +1,42 @@
From e9addfee683ceabeae5da9dc5503fef536f7385a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 29 Jan 2020 09:35:19 +0000
Subject: [PATCH] tty: amba-pl011: Avoid rare write-when-full error
Under some circumstances on BCM283x processors data loss can be
observed - a single byte missing from the TX output stream. These bytes
are always the last byte of a batch of 8 written from pl011_tx_chars
when from_irq is true, meaning that the FIFO full flag is not checked
before writing.
The transmit optimisation relies on the FIFO being half-empty when the
TX interrupt is raised. Instrumenting the driver further showed that
the failure case correlated with the TX FIFO full flag being set at the
point where the last byte was written to the data register, which
explains the data loss but not how the FIFO appeared to be prematurely
full. A possible explanation is that a FIFO write was in flight at the
time the interrupt was raised, but as yet there is no hypothesis as to
how this might occur.
In the absence of a clear understanding of the failure mechanism, avoid
the problem by checking the FIFO levels before writing the last byte of
the group, which will have minimal performance impact.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/tty/serial/amba-pl011.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1438,6 +1438,10 @@ static bool pl011_tx_chars(struct uart_a
if (likely(from_irq) && count-- == 0)
break;
+ if (likely(from_irq) && count == 0 &&
+ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
+ break;
+
if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
break;

View File

@ -0,0 +1,22 @@
From 68ef623a719071e05f5d62270c7bee35a2984452 Mon Sep 17 00:00:00 2001
From: notro <notro@tronnes.org>
Date: Thu, 10 Jul 2014 13:59:47 +0200
Subject: [PATCH] pinctrl-bcm2835: Set base to 0 give expected gpio
numbering
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
---
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -362,7 +362,7 @@ static const struct gpio_chip bcm2835_gp
.get = bcm2835_gpio_get,
.set = bcm2835_gpio_set,
.set_config = gpiochip_generic_config,
- .base = -1,
+ .base = 0,
.ngpio = BCM2835_NUM_GPIOS,
.can_sleep = false,
};

View File

@ -0,0 +1,150 @@
From 0ef60858b9927024cd310038c97976e27e4daada Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 12 May 2013 12:24:19 +0100
Subject: [PATCH] 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(-)
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -165,6 +165,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.
--- 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)
--- 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
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;
}
--- 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 pla
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",
@@ -195,7 +198,18 @@ static struct platform_driver bcm2835_mb
},
.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");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,828 @@
From 4ac7128970e15d83ef3c2a65e65ca9ee4096c9d1 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] 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(-)
--- 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)},
};
- fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
+ 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_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 f
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_
};
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_
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_
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_
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_
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
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_mo
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
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
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
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 f
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 f
* 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 f
}
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 f
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(in
*/
/* 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 bc
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 bc
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 platf
{
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 platf
* }
*/
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;
+ }
+
+ 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->fw = fw;
- bcm2708_fb_debugfs_init(fb);
+ 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);
- fb->cb_base = dma_alloc_wc(&dev->dev, SZ_64K,
- &fb->cb_handle, GFP_KERNEL);
- if (!fb->cb_base) {
+ 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));
+
+ for (i = 0; i < num_displays; i++) {
+ struct bcm2708_fb *fb = &fbdev->displays[i];
+
+ fb->display_settings.display_num = i;
+ fb->dev = dev;
+ fb->fb.device = &dev->dev;
+ fb->fbdev = fbdev;
+
+ 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));
+ }
- fb->dev = dev;
- fb->fb.device = &dev->dev;
+ ret = bcm2708_fb_register(fb);
- /* 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));
+ if (ret == 0) {
+ bcm2708_fb_debugfs_init(fb);
- ret = bcm2708_fb_register(fb);
- if (ret == 0) {
- platform_set_drvdata(dev, fb);
- goto out;
+ 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);
-
- 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);
+ for (i = 0; i < fbdev->num_displays; i++) {
+ if (fbdev->displays[i].fb.screen_base)
+ iounmap(fbdev->displays[i].fb.screen_base);
+
+ 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
.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)
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -106,9 +106,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,
@@ -117,6 +123,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,
@@ -127,9 +135,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,
@@ -138,6 +149,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);

View File

@ -0,0 +1,337 @@
From 6005247285065235845f233077bbeedb19a484c7 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] 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(-)
--- 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(struc
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
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
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
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(&param32, (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, &param);
+ 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)
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1079,6 +1079,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)
{
@@ -1087,6 +1111,7 @@ static long do_fb_ioctl(struct fb_info *
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;
@@ -1162,6 +1187,15 @@ static long do_fb_ioctl(struct fb_info *
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(&copy, argp, sizeof(copy)))
+ return -EFAULT;
+ ret = fb_copyarea_user(info, &copy);
+ break;
+ }
+ /* fall through */
default:
lock_fb_info(info);
fb = info->fbops;
@@ -1307,6 +1341,7 @@ static long fb_compat_ioctl(struct file
case FBIOPAN_DISPLAY:
case FBIOGET_CON2FBMAP:
case FBIOPUT_CON2FBMAP:
+ case FBIOCOPYAREA:
arg = (unsigned long) compat_ptr(arg);
fallthrough;
case FBIOBLANK:
--- 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;

View File

@ -0,0 +1,209 @@
From cac14f80f1e41f9a977c3cd84b0b3b73740818f8 Mon Sep 17 00:00:00 2001
From: Harm Hanemaaijer <fgenfb@yahoo.com>
Date: Thu, 20 Jun 2013 20:21:39 +0200
Subject: [PATCH] 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(-)
--- 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
}
}
+/*
+ * 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, co
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

View File

@ -0,0 +1,640 @@
From 9ac0f4ce3beaad7700af1e771776d12ae7813f97 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] 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
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -134,7 +134,7 @@ config COH901318
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
@@ -652,6 +652,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
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -21,6 +21,7 @@ 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_COH901318) += coh901318.o coh901318_lli.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
--- /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");
--- /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 */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,488 @@
From 156d50d2fb05f132d53927cbf9fad3c9c37e8937 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 28 Oct 2016 15:36:43 +0100
Subject: [PATCH] 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>
---
drivers/char/broadcom/Kconfig | 18 ++
drivers/char/broadcom/Makefile | 1 +
drivers/char/broadcom/vc_mem.c | 375 ++++++++++++++++++++++++++++++++
include/linux/broadcom/vc_mem.h | 39 ++++
4 files changed, 433 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
--- /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
--- /dev/null
+++ b/drivers/char/broadcom/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
--- /dev/null
+++ b/drivers/char/broadcom/vc_mem.c
@@ -0,0 +1,375 @@
+/*
+ * 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;
+
+ device_destroy(vc_mem_class, vc_mem_devnum);
+
+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);
--- /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 */

View File

@ -0,0 +1,299 @@
From 09897ac552d99d483131bcf107866ac2dc51694f Mon Sep 17 00:00:00 2001
From: Luke Wren <luke@raspberrypi.org>
Date: Fri, 21 Aug 2015 23:14:48 +0100
Subject: [PATCH] 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
--- 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.
--- 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
--- /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>");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,660 @@
From 8e6989f4270ffc86166cbab697b1f539f4cdeb03 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 17 Jun 2015 15:44:08 +0100
Subject: [PATCH] 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
--- 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
--- 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
--- /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);

View File

@ -0,0 +1,254 @@
From ee17bae9c9f8fbe02644f13c01c6dd06e9c4bbc3 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] 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
--- 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
--- 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
--- /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");

View File

@ -0,0 +1,83 @@
From 410ae9727ad520a140b88c7151e0432d58516bc3 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] 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 | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -29,6 +29,8 @@ struct rpi_firmware {
u32 enabled;
};
+static struct platform_device *g_pdev;
+
static DEFINE_MUTEX(transaction_lock);
static void response_callback(struct mbox_client *cl, void *msg)
@@ -249,6 +251,7 @@ static int rpi_firmware_probe(struct pla
init_completion(&fw->c);
platform_set_drvdata(pdev, fw);
+ g_pdev = pdev;
rpi_firmware_print_firmware_revision(fw);
rpi_register_hwmon_driver(dev, fw);
@@ -276,6 +279,7 @@ static int rpi_firmware_remove(struct pl
platform_device_unregister(rpi_clk);
rpi_clk = NULL;
mbox_free_channel(fw->chan);
+ g_pdev = NULL;
return 0;
}
@@ -288,7 +292,7 @@ static int rpi_firmware_remove(struct pl
*/
struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
{
- struct platform_device *pdev = of_find_device_by_node(firmware_node);
+ struct platform_device *pdev = g_pdev;
if (!pdev)
return NULL;
@@ -312,7 +316,18 @@ static struct platform_driver rpi_firmwa
.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");

View File

@ -0,0 +1,169 @@
From 3bb38201fc6c1aef7709c3c744824db23f06c629 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 6 Feb 2015 13:50:57 +0000
Subject: [PATCH] BCM270x_DT: Add pwr_led, and the required "input"
trigger
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
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -46,8 +46,15 @@ static void gpio_led_set(struct led_clas
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);
@@ -61,6 +68,13 @@ static int gpio_led_set_blocking(struct
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)
{
@@ -89,6 +103,7 @@ static int create_gpio_led(const struct
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)
--- 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
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += l
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
--- /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");
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -79,6 +79,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;

View File

@ -0,0 +1,22 @@
From 6bfe5935985ffc3b5365877db6e8b90ba4924540 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jul 2013 00:54:08 +0100
Subject: [PATCH] Added Device IDs for August DVB-T 205
---
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1953,6 +1953,10 @@ static const struct usb_device_id rtl28x
&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,

View File

@ -0,0 +1,35 @@
From 95a7bcf89e17aa8ec8cabc06d47479e1ecb76976 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 25 Jun 2015 12:16:11 +0100
Subject: [PATCH] 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(-)
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -50,9 +50,11 @@ static int gpio_poweroff_probe(struct pl
{
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__);

View File

@ -0,0 +1,852 @@
From cf000173e9ee4a80ac245e5feb042c18c5643d6c 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] 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 | 2 +-
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(+), 1 deletion(-)
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
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -382,4 +382,12 @@ config JOYSTICK_FSIA6B
To compile this driver as a module, choose M here: the
module will be called fsia6b.
+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
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -37,4 +37,4 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warri
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
--- /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");
--- 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
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -263,6 +263,7 @@ obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-b
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.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
--- /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");
+
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2250,6 +2250,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"
--- 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
--- /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");
+
--- /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
--- /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
--- /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

View File

@ -0,0 +1,46 @@
From 4be98b29d123fc7615ea8404fbda450ec8acb084 Mon Sep 17 00:00:00 2001
From: Joerg Schambacher <joerg@i2audio.com>
Date: Fri, 16 Oct 2020 15:17:07 +0200
Subject: [PATCH] Fixes a problem when module probes before i2c module
is available
The driver crashed while a NULL pointer returned by i2c_get_adapter()
has been used to access the i2c bus functions.
The headphone probing function hb_hp_probe() now returns -EPROBE_DEFER
in case the i2c module has not been loaded yet.
Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
---
sound/soc/bcm/hifiberry_dacplus.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
--- a/sound/soc/bcm/hifiberry_dacplus.c
+++ b/sound/soc/bcm/hifiberry_dacplus.c
@@ -315,12 +315,14 @@ static int hb_hp_detect(void)
{
struct i2c_adapter *adap = i2c_get_adapter(1);
int ret;
-
struct i2c_client tpa_i2c_client = {
.addr = 0x60,
.adapter = adap,
};
+ if (!adap)
+ return -EPROBE_DEFER; /* I2C module not yet available */
+
ret = i2c_smbus_read_byte(&tpa_i2c_client) >= 0;
i2c_put_adapter(adap);
return ret;
@@ -342,7 +344,10 @@ static int snd_rpi_hifiberry_dacplus_pro
struct of_changeset ocs;
/* probe for head phone amp */
- if (hb_hp_detect()) {
+ ret = hb_hp_detect();
+ if (ret < 0)
+ return ret;
+ if (ret) {
card->aux_dev = hifiberry_dacplus_aux_devs;
card->num_aux_devs =
ARRAY_SIZE(hifiberry_dacplus_aux_devs);

View File

@ -0,0 +1,172 @@
From 3bbdfc9493655ea9ff7e3c8eeee85f28b0f84369 Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Wed, 21 Oct 2015 14:55:21 +0100
Subject: [PATCH] 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
--- 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
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pand
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_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
--- /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");

View File

@ -0,0 +1,256 @@
From f82deda879262289568dec22dd43ecc10c265fb6 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 23 Feb 2016 19:56:04 +0000
Subject: [PATCH] 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
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -193,6 +193,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)
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio
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_BD71828) += gpio-bd71828.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
--- /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");

View File

@ -0,0 +1,427 @@
From 3027a12f910d164be1cb7c028dd178409ace7f0a 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] 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
--- /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).
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -100,4 +100,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
--- 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
--- /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);

View File

@ -0,0 +1,23 @@
From 32fe7cc286f4a4d7f5d623ddb9fba10907c2abea Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 17 Dec 2015 13:37:07 +0000
Subject: [PATCH] hci_h5: Don't send conf_req when ACTIVE
Without this patch, a modem and kernel can continuously bombard each
other with conf_req and conf_rsp messages, in a demented game of tag.
---
drivers/bluetooth/hci_h5.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -343,7 +343,8 @@ static void h5_handle_internal_rx(struct
h5_link_control(hu, conf_req, 3);
} else if (memcmp(data, conf_req, 2) == 0) {
h5_link_control(hu, conf_rsp, 2);
- h5_link_control(hu, conf_req, 3);
+ if (h5->state != H5_ACTIVE)
+ h5_link_control(hu, conf_req, 3);
} else if (memcmp(data, conf_rsp, 2) == 0) {
if (H5_HDR_LEN(hdr) > 2)
h5->tx_win = (data[2] & 0x07);

View File

@ -0,0 +1,72 @@
From 443eb00795c4da76e3877ae7448697ba14584596 Mon Sep 17 00:00:00 2001
From: Michael Zoran <mzoran@crowfest.net>
Date: Sat, 14 Jan 2017 21:43:57 -0800
Subject: [PATCH] ARM64: Round-Robin dispatch IRQs between CPUs.
IRQ-CPU mapping is round robined on ARM64 to increase
concurrency and allow multiple interrupts to be serviced
at a time. This reduces the need for FIQ.
Signed-off-by: Michael Zoran <mzoran@crowfest.net>
---
drivers/irqchip/irq-bcm2835.c | 15 ++++++++++++++-
drivers/irqchip/irq-bcm2836.c | 21 +++++++++++++++++++++
2 files changed, 35 insertions(+), 1 deletion(-)
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -154,10 +154,23 @@ static void armctrl_unmask_irq(struct ir
}
}
+#ifdef CONFIG_ARM64
+void bcm2836_arm_irqchip_spin_gpu_irq(void);
+
+static void armctrl_ack_irq(struct irq_data *d)
+{
+ bcm2836_arm_irqchip_spin_gpu_irq();
+}
+
+#endif
+
static struct irq_chip armctrl_chip = {
.name = "ARMCTRL-level",
.irq_mask = armctrl_mask_irq,
- .irq_unmask = armctrl_unmask_irq
+ .irq_unmask = armctrl_unmask_irq,
+#ifdef CONFIG_ARM64
+ .irq_ack = armctrl_ack_irq
+#endif
};
static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -87,6 +87,27 @@ static void bcm2836_arm_irqchip_unmask_g
{
}
+#ifdef CONFIG_ARM64
+
+void bcm2836_arm_irqchip_spin_gpu_irq(void)
+{
+ u32 i;
+ void __iomem *gpurouting = (intc.base + LOCAL_GPU_ROUTING);
+ u32 routing_val = readl(gpurouting);
+
+ for (i = 1; i <= 3; i++) {
+ u32 new_routing_val = (routing_val + i) & 3;
+
+ if (cpu_active(new_routing_val)) {
+ writel(new_routing_val, gpurouting);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL(bcm2836_arm_irqchip_spin_gpu_irq);
+
+#endif
+
static struct irq_chip bcm2836_arm_irqchip_gpu = {
.name = "bcm2836-gpu",
.irq_mask = bcm2836_arm_irqchip_mask_gpu_irq,

View File

@ -0,0 +1,28 @@
From b4e6e3b95c4f41b415d9d7fed7f121a1850af042 Mon Sep 17 00:00:00 2001
From: Michael Zoran <mzoran@crowfest.net>
Date: Sat, 11 Feb 2017 01:18:31 -0800
Subject: [PATCH] ARM64: Force hardware emulation of deprecated
instructions.
---
arch/arm64/kernel/armv8_deprecated.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -182,10 +182,15 @@ static void __init register_insn_emulati
switch (ops->status) {
case INSN_DEPRECATED:
+#if 0
insn->current_mode = INSN_EMULATE;
/* Disable the HW mode if it was turned on at early boot time */
run_all_cpu_set_hw_mode(insn, false);
+#else
+ insn->current_mode = INSN_HW;
+ run_all_cpu_set_hw_mode(insn, true);
insn->max = INSN_HW;
+#endif
break;
case INSN_OBSOLETE:
insn->current_mode = INSN_UNDEF;

View File

@ -0,0 +1,53 @@
From c9cb22efe558ee7fb1f30deb19dfe7b7bfe1f369 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 25 Aug 2017 19:18:13 +0100
Subject: [PATCH] cache: export clean and invalidate
hack: cache: Fix linker error
---
arch/arm/mm/cache-v6.S | 4 ++--
arch/arm/mm/cache-v7.S | 6 ++++--
2 files changed, 6 insertions(+), 4 deletions(-)
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -198,7 +198,7 @@ ENTRY(v6_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v6_dma_inv_range:
+ENTRY(v6_dma_inv_range)
#ifdef CONFIG_DMA_CACHE_RWFO
ldrb r2, [r0] @ read for ownership
strb r2, [r0] @ write for ownership
@@ -243,7 +243,7 @@ v6_dma_inv_range:
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v6_dma_clean_range:
+ENTRY(v6_dma_clean_range)
bic r0, r0, #D_CACHE_LINE_SIZE - 1
1:
#ifdef CONFIG_DMA_CACHE_RWFO
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -363,7 +363,8 @@ ENDPROC(v7_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_inv_range:
+ENTRY(b15_dma_inv_range)
+ENTRY(v7_dma_inv_range)
dcache_line_size r2, r3
sub r3, r2, #1
tst r0, r3
@@ -393,7 +394,8 @@ ENDPROC(v7_dma_inv_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_clean_range:
+ENTRY(b15_dma_clean_range)
+ENTRY(v7_dma_clean_range)
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3

View File

@ -0,0 +1,691 @@
From d9151380fdab4a0f2abcc08d2c344b0eabe48ab9 Mon Sep 17 00:00:00 2001
From: James Hughes <JamesH65@users.noreply.github.com>
Date: Tue, 14 Nov 2017 15:13:15 +0000
Subject: [PATCH] AXI performance monitor driver (#2222)
Uses the debugfs I/F to provide access to the AXI
bus performance monitors.
Requires the new mailbox peripheral access for access
to the VPU performance registers, system bus access
is done using direct register reads.
Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
raspberrypi_axi_monitor: suppress warning
Suppress the following warning by casting the pointer to and uintptr_t
before to u32:
Signed-off-by: Matteo Croce <mcroce@redhat.com>
---
drivers/perf/Kconfig | 8 +
drivers/perf/Makefile | 1 +
drivers/perf/raspberrypi_axi_monitor.c | 637 +++++++++++++++++++++++++
3 files changed, 646 insertions(+)
create mode 100644 drivers/perf/raspberrypi_axi_monitor.c
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -130,6 +130,14 @@ config ARM_SPE_PMU
Extension, which provides periodic sampling of operations in
the CPU pipeline and reports this via the perf AUX interface.
+config RPI_AXIPERF
+ depends on ARCH_BCM2835
+ tristate "RaspberryPi AXI Performance monitors"
+ default n
+ help
+ Say y if you want to use Raspberry Pi AXI performance monitors, m if
+ you want to build it as a module.
+
source "drivers/perf/hisilicon/Kconfig"
endmenu
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu
obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o
obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o
+obj-$(CONFIG_RPI_AXIPERF) += raspberrypi_axi_monitor.o
--- /dev/null
+++ b/drivers/perf/raspberrypi_axi_monitor.c
@@ -0,0 +1,637 @@
+/*
+ * raspberrypi_axi_monitor.c
+ *
+ * Author: james.hughes@raspberrypi.org
+ *
+ * Raspberry Pi AXI performance counters.
+ *
+ * Copyright (C) 2017 Raspberry Pi Trading Ltd.
+ *
+ * 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/debugfs.h>
+#include <linux/devcoredump.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define NUM_MONITORS 2
+#define NUM_BUS_WATCHERS_PER_MONITOR 3
+
+#define SYSTEM_MONITOR 0
+#define VPU_MONITOR 1
+
+#define MAX_BUSES 16
+#define DEFAULT_SAMPLE_TIME 100
+
+#define NUM_BUS_WATCHER_RESULTS 9
+
+struct bus_watcher_data {
+ union {
+ u32 results[NUM_BUS_WATCHER_RESULTS];
+ struct {
+ u32 atrans;
+ u32 atwait;
+ u32 amax;
+ u32 wtrans;
+ u32 wtwait;
+ u32 wmax;
+ u32 rtrans;
+ u32 rtwait;
+ u32 rmax;
+ };
+ };
+};
+
+
+struct rpi_axiperf {
+ struct platform_device *dev;
+ struct dentry *root_folder;
+
+ struct task_struct *monitor_thread;
+ struct mutex lock;
+
+ struct rpi_firmware *firmware;
+
+ /* Sample time spent on for each bus */
+ int sample_time;
+
+ /* Now storage for the per monitor settings and the resulting
+ * performance figures
+ */
+ struct {
+ /* Bit field of buses we want to monitor */
+ int bus_enabled;
+ /* Bit field of buses to filter by */
+ int bus_filter;
+ /* The current buses being monitored on this monitor */
+ int current_bus[NUM_BUS_WATCHERS_PER_MONITOR];
+ /* The last bus monitored on this monitor */
+ int last_monitored;
+
+ /* Set true if this mailbox must use the mailbox interface
+ * rather than access registers directly.
+ */
+ int use_mailbox_interface;
+
+ /* Current result values */
+ struct bus_watcher_data results[MAX_BUSES];
+
+ struct dentry *debugfs_entry;
+ void __iomem *base_address;
+
+ } monitor[NUM_MONITORS];
+
+};
+
+static struct rpi_axiperf *state;
+
+/* Two monitors, System and VPU, each with the following register sets.
+ * Each monitor can only monitor one bus at a time, so we time share them,
+ * giving each bus 100ms (default, settable via debugfs) of time on its
+ * associated monitor
+ * Record results from the three Bus watchers per monitor and push to the sysfs
+ */
+
+/* general registers */
+const int GEN_CTRL;
+
+const int GEN_CTL_ENABLE_BIT = BIT(0);
+const int GEN_CTL_RESET_BIT = BIT(1);
+
+/* Bus watcher registers */
+const int BW_PITCH = 0x40;
+
+const int BW0_CTRL = 0x40;
+const int BW1_CTRL = 0x80;
+const int BW2_CTRL = 0xc0;
+
+const int BW_ATRANS_OFFSET = 0x04;
+const int BW_ATWAIT_OFFSET = 0x08;
+const int BW_AMAX_OFFSET = 0x0c;
+const int BW_WTRANS_OFFSET = 0x10;
+const int BW_WTWAIT_OFFSET = 0x14;
+const int BW_WMAX_OFFSET = 0x18;
+const int BW_RTRANS_OFFSET = 0x1c;
+const int BW_RTWAIT_OFFSET = 0x20;
+const int BW_RMAX_OFFSET = 0x24;
+
+const int BW_CTRL_RESET_BIT = BIT(31);
+const int BW_CTRL_ENABLE_BIT = BIT(30);
+const int BW_CTRL_ENABLE_ID_FILTER_BIT = BIT(29);
+const int BW_CTRL_LIMIT_HALT_BIT = BIT(28);
+
+const int BW_CTRL_SOURCE_SHIFT = 8;
+const int BW_CTRL_SOURCE_MASK = GENMASK(12, 8); // 5 bits
+const int BW_CTRL_BUS_WATCH_SHIFT;
+const int BW_CTRL_BUS_WATCH_MASK = GENMASK(5, 0); // 6 bits
+const int BW_CTRL_BUS_FILTER_SHIFT = 8;
+
+const static char *bus_filter_strings[] = {
+ "",
+ "CORE0_V",
+ "ICACHE0",
+ "DCACHE0",
+ "CORE1_V",
+ "ICACHE1",
+ "DCACHE1",
+ "L2_MAIN",
+ "HOST_PORT",
+ "HOST_PORT2",
+ "HVS",
+ "ISP",
+ "VIDEO_DCT",
+ "VIDEO_SD2AXI",
+ "CAM0",
+ "CAM1",
+ "DMA0",
+ "DMA1",
+ "DMA2_VPU",
+ "JPEG",
+ "VIDEO_CME",
+ "TRANSPOSER",
+ "VIDEO_FME",
+ "CCP2TX",
+ "USB",
+ "V3D0",
+ "V3D1",
+ "V3D2",
+ "AVE",
+ "DEBUG",
+ "CPU",
+ "M30"
+};
+
+const int num_bus_filters = ARRAY_SIZE(bus_filter_strings);
+
+const static char *system_bus_string[] = {
+ "DMA_L2",
+ "TRANS",
+ "JPEG",
+ "SYSTEM_UC",
+ "DMA_UC",
+ "SYSTEM_L2",
+ "CCP2TX",
+ "MPHI_RX",
+ "MPHI_TX",
+ "HVS",
+ "H264",
+ "ISP",
+ "V3D",
+ "PERIPHERAL",
+ "CPU_UC",
+ "CPU_L2"
+};
+
+const int num_system_buses = ARRAY_SIZE(system_bus_string);
+
+const static char *vpu_bus_string[] = {
+ "VPU1_D_L2",
+ "VPU0_D_L2",
+ "VPU1_I_L2",
+ "VPU0_I_L2",
+ "SYSTEM_L2",
+ "L2_FLUSH",
+ "DMA_L2",
+ "VPU1_D_UC",
+ "VPU0_D_UC",
+ "VPU1_I_UC",
+ "VPU0_I_UC",
+ "SYSTEM_UC",
+ "L2_OUT",
+ "DMA_UC",
+ "SDRAM",
+ "L2_IN"
+};
+
+const int num_vpu_buses = ARRAY_SIZE(vpu_bus_string);
+
+const static char *monitor_name[] = {
+ "System",
+ "VPU"
+};
+
+static inline void write_reg(int monitor, int reg, u32 value)
+{
+ writel(value, state->monitor[monitor].base_address + reg);
+}
+
+static inline u32 read_reg(int monitor, u32 reg)
+{
+ return readl(state->monitor[monitor].base_address + reg);
+}
+
+static void read_bus_watcher(int monitor, int watcher, u32 *results)
+{
+ if (state->monitor[monitor].use_mailbox_interface) {
+ /* We have 9 results, plus the overheads of start address and
+ * length So 11 u32 to define
+ */
+ u32 tmp[11];
+ int err;
+
+ tmp[0] = (u32)(uintptr_t)(state->monitor[monitor].base_address + watcher
+ + BW_ATRANS_OFFSET);
+ tmp[1] = NUM_BUS_WATCHER_RESULTS;
+
+ err = rpi_firmware_property(state->firmware,
+ RPI_FIRMWARE_GET_PERIPH_REG,
+ tmp, sizeof(tmp));
+
+ if (err < 0 || tmp[1] != NUM_BUS_WATCHER_RESULTS)
+ dev_err_once(&state->dev->dev,
+ "Failed to read bus watcher");
+ else
+ memcpy(results, &tmp[2],
+ NUM_BUS_WATCHER_RESULTS * sizeof(u32));
+ } else {
+ int i;
+ void __iomem *addr = state->monitor[monitor].base_address
+ + watcher + BW_ATRANS_OFFSET;
+ for (i = 0; i < NUM_BUS_WATCHER_RESULTS; i++, addr += 4)
+ *results++ = readl(addr);
+ }
+}
+
+static void set_monitor_control(int monitor, u32 set)
+{
+ if (state->monitor[monitor].use_mailbox_interface) {
+ u32 tmp[3] = {(u32)(uintptr_t)(state->monitor[monitor].base_address +
+ GEN_CTRL), 1, set};
+ int err = rpi_firmware_property(state->firmware,
+ RPI_FIRMWARE_SET_PERIPH_REG,
+ tmp, sizeof(tmp));
+
+ if (err < 0 || tmp[1] != 1)
+ dev_err_once(&state->dev->dev,
+ "Failed to set monitor control");
+ } else
+ write_reg(monitor, GEN_CTRL, set);
+}
+
+static void set_bus_watcher_control(int monitor, int watcher, u32 set)
+{
+ if (state->monitor[monitor].use_mailbox_interface) {
+ u32 tmp[3] = {(u32)(uintptr_t)(state->monitor[monitor].base_address +
+ watcher), 1, set};
+ int err = rpi_firmware_property(state->firmware,
+ RPI_FIRMWARE_SET_PERIPH_REG,
+ tmp, sizeof(tmp));
+ if (err < 0 || tmp[1] != 1)
+ dev_err_once(&state->dev->dev,
+ "Failed to set bus watcher control");
+ } else
+ write_reg(monitor, watcher, set);
+}
+
+static void monitor(struct rpi_axiperf *state)
+{
+ int monitor, num_buses[NUM_MONITORS];
+
+ mutex_lock(&state->lock);
+
+ for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
+ typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
+
+ /* Anything enabled? */
+ if (mon->bus_enabled == 0) {
+ /* No, disable all monitoring for this monitor */
+ set_monitor_control(monitor, GEN_CTL_RESET_BIT);
+ } else {
+ int i;
+
+ /* Find out how many busses we want to monitor, and
+ * spread our 3 actual monitors over them
+ */
+ num_buses[monitor] = hweight32(mon->bus_enabled);
+ num_buses[monitor] = min(num_buses[monitor],
+ NUM_BUS_WATCHERS_PER_MONITOR);
+
+ for (i = 0; i < num_buses[monitor]; i++) {
+ int bus_control;
+
+ do {
+ mon->last_monitored++;
+ mon->last_monitored &= 0xf;
+ } while ((mon->bus_enabled &
+ (1 << mon->last_monitored)) == 0);
+
+ mon->current_bus[i] = mon->last_monitored;
+
+ /* Reset the counters */
+ set_bus_watcher_control(monitor,
+ BW0_CTRL +
+ i*BW_PITCH,
+ BW_CTRL_RESET_BIT);
+
+ bus_control = BW_CTRL_ENABLE_BIT |
+ mon->current_bus[i];
+
+ if (mon->bus_filter) {
+ bus_control |=
+ BW_CTRL_ENABLE_ID_FILTER_BIT;
+ bus_control |=
+ ((mon->bus_filter & 0x1f)
+ << BW_CTRL_BUS_FILTER_SHIFT);
+ }
+
+ // Start capture
+ set_bus_watcher_control(monitor,
+ BW0_CTRL + i*BW_PITCH,
+ bus_control);
+ }
+ }
+
+ /* start monitoring */
+ set_monitor_control(monitor, GEN_CTL_ENABLE_BIT);
+ }
+
+ mutex_unlock(&state->lock);
+
+ msleep(state->sample_time);
+
+ /* Now read the results */
+
+ mutex_lock(&state->lock);
+ for (monitor = 0; monitor < NUM_MONITORS; monitor++) {
+ typeof(state->monitor[0]) *mon = &(state->monitor[monitor]);
+
+ /* Anything enabled? */
+ if (mon->bus_enabled == 0) {
+ /* No, disable all monitoring for this monitor */
+ set_monitor_control(monitor, 0);
+ } else {
+ int i;
+
+ for (i = 0; i < num_buses[monitor]; i++) {
+ int bus = mon->current_bus[i];
+
+ read_bus_watcher(monitor,
+ BW0_CTRL + i*BW_PITCH,
+ (u32 *)&mon->results[bus].results);
+ }
+ }
+ }
+ mutex_unlock(&state->lock);
+}
+
+static int monitor_thread(void *data)
+{
+ struct rpi_axiperf *state = data;
+
+ while (1) {
+ monitor(state);
+
+ if (kthread_should_stop())
+ return 0;
+ }
+ return 0;
+}
+
+static ssize_t myreader(struct file *fp, char __user *user_buffer,
+ size_t count, loff_t *position)
+{
+#define INIT_BUFF_SIZE 2048
+
+ int i;
+ int idx = (int)(uintptr_t)(fp->private_data);
+ int num_buses, cnt;
+ char *string_buffer;
+ int buff_size = INIT_BUFF_SIZE;
+ char *p;
+ typeof(state->monitor[0]) *mon = &(state->monitor[idx]);
+
+ if (idx < 0 || idx > NUM_MONITORS)
+ idx = 0;
+
+ num_buses = idx == SYSTEM_MONITOR ? num_system_buses : num_vpu_buses;
+
+ string_buffer = kmalloc(buff_size, GFP_KERNEL);
+
+ if (!string_buffer) {
+ dev_err(&state->dev->dev,
+ "Failed temporary string allocation\n");
+ return 0;
+ }
+
+ p = string_buffer;
+
+ mutex_lock(&state->lock);
+
+ if (mon->bus_filter) {
+ int filt = min(mon->bus_filter & 0x1f, num_bus_filters);
+
+ cnt = snprintf(p, buff_size,
+ "\nMonitoring transactions from %s only\n",
+ bus_filter_strings[filt]);
+ p += cnt;
+ buff_size -= cnt;
+ }
+
+ cnt = snprintf(p, buff_size, " Bus | Atrans Atwait AMax Wtrans Wtwait WMax Rtrans Rtwait RMax\n"
+ "======================================================================================================\n");
+
+ if (cnt >= buff_size)
+ goto done;
+
+ p += cnt;
+ buff_size -= cnt;
+
+ for (i = 0; i < num_buses; i++) {
+ if (mon->bus_enabled & (1 << i)) {
+#define DIVIDER (1024)
+ typeof(mon->results[0]) *res = &(mon->results[i]);
+
+ cnt = snprintf(p, buff_size,
+ "%10s | %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK %8uK\n",
+ idx == SYSTEM_MONITOR ?
+ system_bus_string[i] :
+ vpu_bus_string[i],
+ res->atrans/DIVIDER,
+ res->atwait/DIVIDER,
+ res->amax/DIVIDER,
+ res->wtrans/DIVIDER,
+ res->wtwait/DIVIDER,
+ res->wmax/DIVIDER,
+ res->rtrans/DIVIDER,
+ res->rtwait/DIVIDER,
+ res->rmax/DIVIDER
+ );
+ if (cnt >= buff_size)
+ goto done;
+
+ p += cnt;
+ buff_size -= cnt;
+ }
+ }
+
+ mutex_unlock(&state->lock);
+
+done:
+
+ /* did the last string entry exceeed our buffer size? ie out of string
+ * buffer space. Null terminate, use what we have.
+ */
+ if (cnt >= buff_size) {
+ buff_size = 0;
+ string_buffer[INIT_BUFF_SIZE] = 0;
+ }
+
+ cnt = simple_read_from_buffer(user_buffer, count, position,
+ string_buffer,
+ INIT_BUFF_SIZE - buff_size);
+
+ kfree(string_buffer);
+
+ return cnt;
+}
+
+static ssize_t mywriter(struct file *fp, const char __user *user_buffer,
+ size_t count, loff_t *position)
+{
+ int idx = (int)(uintptr_t)(fp->private_data);
+
+ if (idx < 0 || idx > NUM_MONITORS)
+ idx = 0;
+
+ /* At the moment, this does nothing, but in the future it could be
+ * used to reset counters etc
+ */
+ return count;
+}
+
+static const struct file_operations fops_debug = {
+ .read = myreader,
+ .write = mywriter,
+ .open = simple_open
+};
+
+static int rpi_axiperf_probe(struct platform_device *pdev)
+{
+ int ret = 0, i;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *fw_node;
+
+ state = kzalloc(sizeof(struct rpi_axiperf), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ /* Get the firmware handle for future rpi-firmware-xxx calls */
+ fw_node = of_parse_phandle(np, "firmware", 0);
+ if (!fw_node) {
+ dev_err(dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ state->firmware = rpi_firmware_get(fw_node);
+ if (!state->firmware)
+ return -EPROBE_DEFER;
+
+ /* Special case for the VPU monitor, we must use the mailbox interface
+ * as it is not accessible from the ARM address space.
+ */
+ state->monitor[VPU_MONITOR].use_mailbox_interface = 1;
+ state->monitor[SYSTEM_MONITOR].use_mailbox_interface = 0;
+
+ for (i = 0; i < NUM_MONITORS; i++) {
+ if (state->monitor[i].use_mailbox_interface) {
+ of_property_read_u32_index(np, "reg", i*2,
+ (u32 *)(&state->monitor[i].base_address));
+ } else {
+ struct resource *resource =
+ platform_get_resource(pdev, IORESOURCE_MEM, i);
+
+ state->monitor[i].base_address =
+ devm_ioremap_resource(&pdev->dev, resource);
+ }
+
+ if (IS_ERR(state->monitor[i].base_address))
+ return PTR_ERR(state->monitor[i].base_address);
+
+ /* Enable all buses by default */
+ state->monitor[i].bus_enabled = 0xffff;
+ }
+
+ state->dev = pdev;
+ platform_set_drvdata(pdev, state);
+
+ state->sample_time = DEFAULT_SAMPLE_TIME;
+
+ /* Set up all the debugfs stuff */
+ state->root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+ for (i = 0; i < NUM_MONITORS; i++) {
+ state->monitor[i].debugfs_entry =
+ debugfs_create_dir(monitor_name[i], state->root_folder);
+ if (IS_ERR(state->monitor[i].debugfs_entry))
+ state->monitor[i].debugfs_entry = NULL;
+
+ debugfs_create_file("data", 0444,
+ state->monitor[i].debugfs_entry,
+ (void *)(uintptr_t)i, &fops_debug);
+ debugfs_create_u32("enable", 0644,
+ state->monitor[i].debugfs_entry,
+ &state->monitor[i].bus_enabled);
+ debugfs_create_u32("filter", 0644,
+ state->monitor[i].debugfs_entry,
+ &state->monitor[i].bus_filter);
+ debugfs_create_u32("sample_time", 0644,
+ state->monitor[i].debugfs_entry,
+ &state->sample_time);
+ }
+
+ mutex_init(&state->lock);
+
+ state->monitor_thread = kthread_run(monitor_thread, state,
+ "rpi-axiperfmon");
+
+ return ret;
+
+}
+
+static int rpi_axiperf_remove(struct platform_device *dev)
+{
+ int ret = 0;
+
+ kthread_stop(state->monitor_thread);
+
+ debugfs_remove_recursive(state->root_folder);
+ state->root_folder = NULL;
+
+ return ret;
+}
+
+static const struct of_device_id rpi_axiperf_match[] = {
+ {
+ .compatible = "brcm,bcm2835-axiperf",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rpi_axiperf_match);
+
+static struct platform_driver rpi_axiperf_driver = {
+ .probe = rpi_axiperf_probe,
+ .remove = rpi_axiperf_remove,
+ .driver = {
+ .name = "rpi-bcm2835-axiperf",
+ .of_match_table = of_match_ptr(rpi_axiperf_match),
+ },
+};
+
+module_platform_driver(rpi_axiperf_driver);
+
+/* Module information */
+MODULE_AUTHOR("James Hughes <james.hughes@raspberrypi.org>");
+MODULE_DESCRIPTION("RPI AXI Performance monitor driver");
+MODULE_LICENSE("GPL");
+

View File

@ -0,0 +1,63 @@
From 65565784e5faad0af487d54f3f92d9d4c9c38e4a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Wed, 3 Jun 2015 12:26:13 +0200
Subject: [PATCH] ARM: bcm2835: Set Serial number and Revision
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The VideoCore bootloader passes in Serial number and
Revision number through Device Tree. Make these available to
userspace through /proc/cpuinfo.
Mainline status:
There is a commit in linux-next that standardize passing the serial
number through Device Tree (string: /serial-number):
ARM: 8355/1: arch: Show the serial number from devicetree in cpuinfo
There was an attempt to do the same with the revision number, but it
didn't get in:
[PATCH v2 1/2] arm: devtree: Set system_rev from DT revision
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
arch/arm/mach-bcm/board_bcm2835.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
--- a/arch/arm/mach-bcm/board_bcm2835.c
+++ b/arch/arm/mach-bcm/board_bcm2835.c
@@ -6,12 +6,25 @@
#include <linux/init.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
+#include <asm/system_info.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "platsmp.h"
+static void __init bcm2835_init(void)
+{
+ struct device_node *np = of_find_node_by_path("/system");
+ u32 val;
+ u64 val64;
+
+ if (!of_property_read_u32(np, "linux,revision", &val))
+ system_rev = val;
+ if (!of_property_read_u64(np, "linux,serial", &val64))
+ system_serial_low = val64;
+}
+
static const char * const bcm2835_compat[] = {
#ifdef CONFIG_ARCH_MULTI_V6
"brcm,bcm2835",
@@ -24,6 +37,7 @@ static const char * const bcm2835_compat
};
DT_MACHINE_START(BCM2835, "BCM2835")
+ .init_machine = bcm2835_init,
.dt_compat = bcm2835_compat,
.smp = smp_ops(bcm2836_smp_ops),
MACHINE_END

View File

@ -0,0 +1,116 @@
From 347167bd9ac2a68870064edd921f2525bd569c6d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 16 Jul 2018 14:40:13 +0100
Subject: [PATCH] dwc-otg: FIQ: Fix "bad mode in data abort handler"
Create a semi-static mapping for the USB registers early in the boot
process, before additional kernel threads are started, so all threads
will have the mappings from the start. This avoids the need for
data aborts to lazily update them.
See: https://github.com/raspberrypi/linux/issues/2450
Signed-off-by: Floris Bos <bos@je-eigen-domein.nl>
---
arch/arm/mach-bcm/board_bcm2835.c | 69 +++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
--- a/arch/arm/mach-bcm/board_bcm2835.c
+++ b/arch/arm/mach-bcm/board_bcm2835.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
+#include <linux/of_fdt.h>
#include <asm/system_info.h>
#include <asm/mach/arch.h>
@@ -13,6 +14,9 @@
#include "platsmp.h"
+#define BCM2835_USB_VIRT_BASE 0xf0980000
+#define BCM2835_USB_VIRT_MPHI 0xf0006000
+
static void __init bcm2835_init(void)
{
struct device_node *np = of_find_node_by_path("/system");
@@ -25,6 +29,70 @@ static void __init bcm2835_init(void)
system_serial_low = val64;
}
+/*
+ * We need to map registers that are going to be accessed by the FIQ
+ * very early, before any kernel threads are spawned. Because if done
+ * later, the mapping tables are not updated instantly but lazily upon
+ * first access through a data abort handler. While that is fine
+ * when executing regular kernel code, if the first access in a specific
+ * thread happens while running FIQ code this will result in a panic.
+ *
+ * For more background see the following old mailing list thread:
+ * https://www.spinics.net/lists/arm-kernel/msg325250.html
+ */
+static int __init bcm2835_map_usb(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ struct map_desc map[2];
+ const __be32 *reg;
+ int len;
+ unsigned long p2b_offset = *((unsigned long *) data);
+
+ if (!of_flat_dt_is_compatible(node, "brcm,bcm2708-usb"))
+ return 0;
+ reg = of_get_flat_dt_prop(node, "reg", &len);
+ if (!reg || len != (sizeof(unsigned long) * 4))
+ return 0;
+
+ /* Use information about the physical addresses of the
+ * registers from the device tree, but use legacy
+ * iotable_init() static mapping function to map them,
+ * as ioremap() is not functional at this stage in boot.
+ */
+ map[0].virtual = (unsigned long) BCM2835_USB_VIRT_BASE;
+ map[0].pfn = __phys_to_pfn(be32_to_cpu(reg[0]) - p2b_offset);
+ map[0].length = be32_to_cpu(reg[1]);
+ map[0].type = MT_DEVICE;
+ map[1].virtual = (unsigned long) BCM2835_USB_VIRT_MPHI;
+ map[1].pfn = __phys_to_pfn(be32_to_cpu(reg[2]) - p2b_offset);
+ map[1].length = be32_to_cpu(reg[3]);
+ map[1].type = MT_DEVICE;
+ iotable_init(map, 2);
+
+ return 1;
+}
+
+static void __init bcm2835_map_io(void)
+{
+ const __be32 *ranges;
+ int soc, len;
+ unsigned long p2b_offset;
+
+ debug_ll_io_init();
+
+ /* Find out how to map bus to physical address first from soc/ranges */
+ soc = of_get_flat_dt_subnode_by_name(of_get_flat_dt_root(), "soc");
+ if (soc < 0)
+ return;
+ ranges = of_get_flat_dt_prop(soc, "ranges", &len);
+ if (!ranges || len < (sizeof(unsigned long) * 3))
+ return;
+ p2b_offset = be32_to_cpu(ranges[0]) - be32_to_cpu(ranges[1]);
+
+ /* Now search for bcm2708-usb node in device tree */
+ of_scan_flat_dt(bcm2835_map_usb, &p2b_offset);
+}
+
static const char * const bcm2835_compat[] = {
#ifdef CONFIG_ARCH_MULTI_V6
"brcm,bcm2835",
@@ -37,6 +105,7 @@ static const char * const bcm2835_compat
};
DT_MACHINE_START(BCM2835, "BCM2835")
+ .map_io = bcm2835_map_io,
.init_machine = bcm2835_init,
.dt_compat = bcm2835_compat,
.smp = smp_ops(bcm2836_smp_ops),

View File

@ -0,0 +1,36 @@
From 594abebdffdcff606bc445f2661d9a504f180136 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 11 Dec 2017 09:18:32 +0000
Subject: [PATCH] ARM: Activate FIQs to avoid __irq_startup warnings
There is a new test in __irq_startup that the IRQ is activated, which
hasn't been the case for FIQs since they bypass some of the usual setup.
Augment enable_fiq to include a call to irq_activate to avoid the
warning.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
arch/arm/kernel/fiq.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -56,6 +56,8 @@
static unsigned long dfl_fiq_insn;
static struct pt_regs dfl_fiq_regs;
+extern int irq_activate(struct irq_desc *desc);
+
/* Default reacquire function
* - we always relinquish FIQ control
* - we always reacquire FIQ control
@@ -140,6 +142,8 @@ static int fiq_start;
void enable_fiq(int fiq)
{
+ struct irq_desc *desc = irq_to_desc(fiq + fiq_start);
+ irq_activate(desc);
enable_irq(fiq + fiq_start);
}

View File

@ -0,0 +1,32 @@
From 9cf689eda644ccba0c80982cbd821c9163f5de39 Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Wed, 14 Sep 2016 09:16:19 +0100
Subject: [PATCH] raspberrypi-firmware: Export the general transaction
function.
The vc4-firmware-kms module is going to be doing the MBOX FB call.
Signed-off-by: Eric Anholt <eric@anholt.net>
---
drivers/firmware/raspberrypi.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -43,7 +43,7 @@ static void response_callback(struct mbo
* Sends a request to the firmware through the BCM2835 mailbox driver,
* and synchronously waits for the reply.
*/
-static int
+int
rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
{
u32 message = MBOX_MSG(chan, data);
@@ -68,6 +68,7 @@ rpi_firmware_transaction(struct rpi_firm
return ret;
}
+EXPORT_SYMBOL_GPL(rpi_firmware_transaction);
/**
* rpi_firmware_property_list - Submit firmware property list

View File

@ -0,0 +1,35 @@
From 798407c217fee8f4869bf76d9cd2cda16f93e24f Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 20 Feb 2018 10:07:27 +0000
Subject: [PATCH] i2c-gpio: Also set bus numbers from reg property
I2C busses can be assigned specific bus numbers using aliases in
Device Tree - string properties where the name is the alias and the
value is the path to the node. The current DT parameter mechanism
does not allow property names to be derived from a parameter value
in any way, so it isn't possible to generate unique or matching
aliases for nodes from an overlay that can generate multiple
instances, e.g. i2c-gpio.
Work around this limitation (at least temporarily) by allowing
the i2c adapter number to be initialised from the "reg" property
if present.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/i2c/busses/i2c-gpio.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -445,7 +445,9 @@ static int i2c_gpio_probe(struct platfor
adap->dev.parent = dev;
adap->dev.of_node = np;
- adap->nr = pdev->id;
+ if (pdev->id != PLATFORM_DEVID_NONE || !pdev->dev.of_node ||
+ of_property_read_u32(pdev->dev.of_node, "reg", &adap->nr))
+ adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
if (ret)
return ret;

View File

@ -0,0 +1,21 @@
From 781bfd769e192aa39ef93fa37c812af444a9cf93 Mon Sep 17 00:00:00 2001
From: hdoverobinson <hdoverobinson@gmail.com>
Date: Tue, 13 Mar 2018 06:58:39 -0400
Subject: [PATCH] added capture_clear option to pps-gpio via dtoverlay
(#2433)
---
drivers/pps/clients/pps-gpio.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/pps/clients/pps-gpio.c
+++ b/drivers/pps/clients/pps-gpio.c
@@ -145,6 +145,8 @@ static int pps_gpio_setup(struct platfor
if (of_property_read_bool(np, "assert-falling-edge"))
data->assert_falling_edge = true;
+ if (of_property_read_bool(np, "capture-clear"))
+ data->capture_clear = true;
return 0;
}

View File

@ -0,0 +1,40 @@
From 1fbf5f72be35918230b0bbdff3bcf44318f1374a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 9 Mar 2018 12:01:00 +0000
Subject: [PATCH] lan78xx: Read initial EEE status from DT
Add two new DT properties:
* microchip,eee-enabled - a boolean to enable EEE
* microchip,tx-lpi-timer - time in microseconds to wait before entering
low power state
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/net/usb/lan78xx.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2635,6 +2635,22 @@ static int lan78xx_open(struct net_devic
netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
+ if (of_property_read_bool(dev->udev->dev.of_node,
+ "microchip,eee-enabled")) {
+ struct ethtool_eee edata;
+ memset(&edata, 0, sizeof(edata));
+ edata.cmd = ETHTOOL_SEEE;
+ edata.advertised = ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full;
+ edata.eee_enabled = true;
+ edata.tx_lpi_enabled = true;
+ if (of_property_read_u32(dev->udev->dev.of_node,
+ "microchip,tx-lpi-timer",
+ &edata.tx_lpi_timer))
+ edata.tx_lpi_timer = 600; /* non-aggressive */
+ (void)lan78xx_set_eee(net, &edata);
+ }
+
/* for Link Check */
if (dev->urb_intr) {
ret = usb_submit_urb(dev->urb_intr, GFP_KERNEL);

View File

@ -0,0 +1,32 @@
From 32648d9e5440756f571bff70e8c49069dbba5137 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 14 Jul 2014 22:02:09 +0100
Subject: [PATCH] hid: Reduce default mouse polling interval to 60Hz
Reduces overhead when using X
---
drivers/hid/usbhid/hid-core.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -45,7 +45,7 @@
* Module parameters.
*/
-static unsigned int hid_mousepoll_interval;
+static unsigned int hid_mousepoll_interval = ~0;
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
@@ -1114,7 +1114,9 @@ static int usbhid_start(struct hid_devic
*/
switch (hid->collection->usage) {
case HID_GD_MOUSE:
- if (hid_mousepoll_interval > 0)
+ if (hid_mousepoll_interval == ~0 && interval < 16)
+ interval = 16;
+ else if (hid_mousepoll_interval != ~0 && hid_mousepoll_interval != 0)
interval = hid_mousepoll_interval;
break;
case HID_GD_JOYSTICK:

View File

@ -0,0 +1,57 @@
From a8d5d1b7fbc78132f5def4b8af4f221df83df04e Mon Sep 17 00:00:00 2001
From: Nick Bulleid <nedbulleid@fastmail.com>
Date: Thu, 10 May 2018 21:57:02 +0100
Subject: [PATCH] Add ability to export gpio used by gpio-poweroff
Signed-off-by: Nick Bulleid <nedbulleid@fastmail.com>
Added export feature to gpio-poweroff documentation
Signed-off-by: Nick Bulleid <nedbulleid@fastmail.com>
---
.../devicetree/bindings/power/reset/gpio-poweroff.txt | 1 +
drivers/power/reset/gpio-poweroff.c | 9 +++++++++
2 files changed, 10 insertions(+)
--- a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt
+++ b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt
@@ -31,6 +31,7 @@ Optional properties:
- inactive-delay-ms: Delay (default 100) to wait after driving gpio inactive
- timeout-ms: Time to wait before asserting a WARN_ON(1). If nothing is
specified, 3000 ms is used.
+- export : Export the GPIO line to the sysfs system
Examples:
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -51,6 +51,7 @@ static int gpio_poweroff_probe(struct pl
bool input = false;
enum gpiod_flags flags;
bool force = false;
+ bool export = false;
/* If a pm_power_off function has already been added, leave it alone */
force = of_property_read_bool(pdev->dev.of_node, "force");
@@ -76,6 +77,12 @@ static int gpio_poweroff_probe(struct pl
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
+ export = of_property_read_bool(pdev->dev.of_node, "export");
+ if (export) {
+ gpiod_export(reset_gpio, false);
+ gpiod_export_link(&pdev->dev, "poweroff-gpio", reset_gpio);
+ }
+
pm_power_off = &gpio_poweroff_do_poweroff;
return 0;
}
@@ -85,6 +92,8 @@ static int gpio_poweroff_remove(struct p
if (pm_power_off == &gpio_poweroff_do_poweroff)
pm_power_off = NULL;
+ gpiod_unexport(reset_gpio);
+
return 0;
}

View File

@ -0,0 +1,84 @@
From bf6b5dbb7c8423b9d6bdfec21a9122691f2587d9 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Sat, 12 May 2018 21:35:43 +0100
Subject: [PATCH] firmware/raspberrypi: Notify firmware of a reboot
Register for reboot notifications, sending RPI_FIRMWARE_NOTIFY_REBOOT
over the mailbox interface on reception.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/firmware/raspberrypi.c | 40 +++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/slab.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
@@ -177,6 +178,26 @@ int rpi_firmware_property(struct rpi_fir
}
EXPORT_SYMBOL_GPL(rpi_firmware_property);
+static int rpi_firmware_notify_reboot(struct notifier_block *nb,
+ unsigned long action,
+ void *data)
+{
+ struct rpi_firmware *fw;
+ struct platform_device *pdev = g_pdev;
+
+ if (!pdev)
+ return 0;
+
+ fw = platform_get_drvdata(pdev);
+ if (!fw)
+ return 0;
+
+ (void)rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT,
+ 0, 0);
+
+ return 0;
+}
+
static void
rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
{
@@ -318,15 +339,32 @@ static struct platform_driver rpi_firmwa
.remove = rpi_firmware_remove,
};
+static struct notifier_block rpi_firmware_reboot_notifier = {
+ .notifier_call = rpi_firmware_notify_reboot,
+};
+
static int __init rpi_firmware_init(void)
{
- return platform_driver_register(&rpi_firmware_driver);
+ int ret = register_reboot_notifier(&rpi_firmware_reboot_notifier);
+ if (ret)
+ goto out1;
+ ret = platform_driver_register(&rpi_firmware_driver);
+ if (ret)
+ goto out2;
+
+ return 0;
+
+out2:
+ unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
+out1:
+ return ret;
}
subsys_initcall(rpi_firmware_init);
static void __init rpi_firmware_exit(void)
{
platform_driver_unregister(&rpi_firmware_driver);
+ unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
}
module_exit(rpi_firmware_exit);

View File

@ -0,0 +1,66 @@
From 35a38d723d9cd61be4c39defad4e44b1a6acc4b8 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 14 Jun 2018 11:21:04 +0100
Subject: [PATCH] irqchip: irq-bcm2835: Calc. FIQ_START at boot-time
ad83c7cb2f37 ("irqchip/irq-bcm2836: Add support for DT interrupt polarity")
changed the way that the BCM2836/7 local interrupts are mapped; instead
of being pre-mapped they are now mapped on-demand. A side effect of this
change is that the call to irq_of_parse_and_map from armctrl_of_init
creates a new mapping, forming a gap between the IRQs and the FIQs. This
gap breaks the FIQ<->IRQ mapping which up to now has been done by assuming:
1) that the value of FIQ_START is the same as the number of normal IRQs
that will be mapped (still true), and
2) that this value is also the offset between an IRQ and its equivalent
FIQ (which is no longer the case).
Remove both assumptions by measuring the interval between the last IRQ
and the last FIQ, passing it as the parameter to init_FIQ().
Fixes: https://github.com/raspberrypi/linux/issues/2432
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/irqchip/irq-bcm2835.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -74,8 +74,6 @@
#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 };
static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
@@ -203,7 +201,7 @@ static int __init armctrl_of_init(struct
bool is_2836)
{
void __iomem *base;
- int irq, b, i;
+ int irq = 0, last_irq, b, i;
u32 reg;
base = of_iomap(node, 0);
@@ -243,6 +241,8 @@ static int __init armctrl_of_init(struct
pr_err(FW_BUG "Bootloader left fiq enabled\n");
}
+ last_irq = irq;
+
if (is_2836) {
int parent_irq = irq_of_parse_and_map(node, 0);
@@ -273,7 +273,7 @@ static int __init armctrl_of_init(struct
}
}
#ifndef CONFIG_ARM64
- init_FIQ(FIQ_START);
+ init_FIQ(irq - last_irq);
#endif
return 0;

View File

@ -0,0 +1,114 @@
From 342afb4c37627f9d8e9d5bb07b3182a5c412c75e Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 14 Jun 2018 15:07:26 +0100
Subject: [PATCH] of: configfs: Use of_overlay_fdt_apply API call
The published API to the dynamic overlay application mechanism now
takes a Flattened Device Tree blob as input so that it can manage the
lifetime of the unflattened tree. Conveniently, the new API call -
of_overlay_fdt_apply - is virtually a drop-in replacement for
create_overlay, which can now be deleted.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/of/configfs.c | 47 +++++++------------------------------------
1 file changed, 7 insertions(+), 40 deletions(-)
--- a/drivers/of/configfs.c
+++ b/drivers/of/configfs.c
@@ -40,41 +40,6 @@ struct cfs_overlay_item {
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)
{
@@ -115,7 +80,8 @@ static ssize_t cfs_overlay_item_path_sto
if (err != 0)
goto out_err;
- err = create_overlay(overlay, (void *)overlay->fw->data);
+ err = of_overlay_fdt_apply((void *)overlay->fw->data,
+ (u32)overlay->fw->size, &overlay->ov_id);
if (err != 0)
goto out_err;
@@ -136,7 +102,7 @@ static ssize_t cfs_overlay_item_status_s
struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
return sprintf(page, "%s\n",
- overlay->ov_id >= 0 ? "applied" : "unapplied");
+ overlay->ov_id > 0 ? "applied" : "unapplied");
}
CONFIGFS_ATTR(cfs_overlay_item_, path);
@@ -188,7 +154,8 @@ ssize_t cfs_overlay_item_dtbo_write(stru
overlay->dtbo_size = count;
- err = create_overlay(overlay, overlay->dtbo);
+ err = of_overlay_fdt_apply(overlay->dtbo, overlay->dtbo_size,
+ &overlay->ov_id);
if (err != 0)
goto out_err;
@@ -198,6 +165,7 @@ out_err:
kfree(overlay->dtbo);
overlay->dtbo = NULL;
overlay->dtbo_size = 0;
+ overlay->ov_id = 0;
return err;
}
@@ -213,7 +181,7 @@ static void cfs_overlay_release(struct c
{
struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
- if (overlay->ov_id >= 0)
+ if (overlay->ov_id > 0)
of_overlay_remove(&overlay->ov_id);
if (overlay->fw)
release_firmware(overlay->fw);
@@ -241,7 +209,6 @@ static struct config_item *cfs_overlay_g
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;

View File

@ -0,0 +1,56 @@
From 42606db546588b0e0b8084466b9b31ec111640a4 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Wed, 13 Jun 2018 15:21:10 +0100
Subject: [PATCH] net: lan78xx: Disable TCP Segmentation Offload (TSO)
TSO seems to be having issues when packets are dropped and the
remote end uses Selective Acknowledge (SACK) to denote that
data is missing. The missing data is never resent, so the
connection eventually stalls.
There is a module parameter of enable_tso added to allow
further debugging without forcing a rebuild of the kernel.
https://github.com/raspberrypi/linux/issues/2449
https://github.com/raspberrypi/linux/issues/2482
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/net/usb/lan78xx.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -425,6 +425,15 @@ static int msg_level = -1;
module_param(msg_level, int, 0);
MODULE_PARM_DESC(msg_level, "Override default message level");
+/* TSO seems to be having some issue with Selective Acknowledge (SACK) that
+ * results in lost data never being retransmitted.
+ * Disable it by default now, but adds a module parameter to enable it for
+ * debug purposes (the full cause is not currently understood).
+ */
+static bool enable_tso;
+module_param(enable_tso, bool, 0644);
+MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload");
+
static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
{
u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
@@ -2917,8 +2926,14 @@ static int lan78xx_bind(struct lan78xx_n
if (DEFAULT_RX_CSUM_ENABLE)
dev->net->features |= NETIF_F_RXCSUM;
- if (DEFAULT_TSO_CSUM_ENABLE)
- dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG;
+ if (DEFAULT_TSO_CSUM_ENABLE) {
+ dev->net->features |= NETIF_F_SG;
+ /* Use module parameter to control TCP segmentation offload as
+ * it appears to cause issues.
+ */
+ if (enable_tso)
+ dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6;
+ }
if (DEFAULT_VLAN_RX_OFFLOAD)
dev->net->features |= NETIF_F_HW_VLAN_CTAG_RX;

View File

@ -0,0 +1,64 @@
From c6edee4700821a65c9d94ac8e16b488fc652efd8 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 5 Apr 2018 14:46:11 +0100
Subject: [PATCH] lan78xx: Move enabling of EEE into PHY init code
Enable EEE mode as soon as possible after connecting to the PHY, and
before phy_start. This avoids a second link negotiation, which speeds
up booting and stops the interface failing to become ready.
See: https://github.com/raspberrypi/linux/issues/2437
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/net/usb/lan78xx.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2167,6 +2167,22 @@ static int lan78xx_phy_init(struct lan78
mii_adv_to_linkmode_adv_t(fc, mii_adv);
linkmode_or(phydev->advertising, fc, phydev->advertising);
+ if (of_property_read_bool(dev->udev->dev.of_node,
+ "microchip,eee-enabled")) {
+ struct ethtool_eee edata;
+ memset(&edata, 0, sizeof(edata));
+ edata.cmd = ETHTOOL_SEEE;
+ edata.advertised = ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full;
+ edata.eee_enabled = true;
+ edata.tx_lpi_enabled = true;
+ if (of_property_read_u32(dev->udev->dev.of_node,
+ "microchip,tx-lpi-timer",
+ &edata.tx_lpi_timer))
+ edata.tx_lpi_timer = 600; /* non-aggressive */
+ (void)lan78xx_set_eee(dev->net, &edata);
+ }
+
if (phydev->mdio.dev.of_node) {
u32 reg;
int len;
@@ -2644,22 +2660,6 @@ static int lan78xx_open(struct net_devic
netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
- if (of_property_read_bool(dev->udev->dev.of_node,
- "microchip,eee-enabled")) {
- struct ethtool_eee edata;
- memset(&edata, 0, sizeof(edata));
- edata.cmd = ETHTOOL_SEEE;
- edata.advertised = ADVERTISED_1000baseT_Full |
- ADVERTISED_100baseT_Full;
- edata.eee_enabled = true;
- edata.tx_lpi_enabled = true;
- if (of_property_read_u32(dev->udev->dev.of_node,
- "microchip,tx-lpi-timer",
- &edata.tx_lpi_timer))
- edata.tx_lpi_timer = 600; /* non-aggressive */
- (void)lan78xx_set_eee(net, &edata);
- }
-
/* for Link Check */
if (dev->urb_intr) {
ret = usb_submit_urb(dev->urb_intr, GFP_KERNEL);

View File

@ -0,0 +1,581 @@
From 079bce6210d997fda44d6143b4b394173360bef1 Mon Sep 17 00:00:00 2001
From: Serge Schneider <serge@raspberrypi.org>
Date: Mon, 9 Jul 2018 12:54:25 +0100
Subject: [PATCH] Add rpi-poe-fan driver
Signed-off-by: Serge Schneider <serge@raspberrypi.org>
PoE HAT driver cleanup
* Fix undeclared variable in rpi_poe_fan_suspend
* Add SPDX-License-Identifier
* Expand PoE acronym in Kconfig help
* Give clearer error message on of_property_count_u32_elems fail
* Add documentation
* Add vendor to of_device_id compatible string.
* Rename m_data_s struct to fw_data_s
* Fix typos
Fixes: #2665
Signed-off-by: Serge Schneider <serge@raspberrypi.org>
rpi-poe-fan: fix def_pwm1 writes
Signed-off-by: Serge Schneider <serge@raspberrypi.org>
---
.../devicetree/bindings/hwmon/rpi-poe-fan.txt | 55 +++
Documentation/hwmon/rpi-poe-fan | 15 +
drivers/hwmon/Kconfig | 11 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/rpi-poe-fan.c | 436 ++++++++++++++++++
5 files changed, 518 insertions(+)
create mode 100644 Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt
create mode 100644 Documentation/hwmon/rpi-poe-fan
create mode 100644 drivers/hwmon/rpi-poe-fan.c
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/rpi-poe-fan.txt
@@ -0,0 +1,55 @@
+Bindings for the Raspberry Pi PoE HAT fan
+
+Required properties:
+- compatible : "raspberrypi,rpi-poe-fan"
+- firmware : Reference to the RPi firmware device node
+- pwms : the PWM that is used to control the PWM fan
+- cooling-levels : PWM duty cycle values in a range from 0 to 255
+ which correspond to thermal cooling states
+
+Example:
+ fan0: rpi-poe-fan@0 {
+ compatible = "raspberrypi,rpi-poe-fan";
+ firmware = <&firmware>;
+ cooling-min-state = <0>;
+ cooling-max-state = <3>;
+ #cooling-cells = <2>;
+ cooling-levels = <0 50 150 255>;
+ status = "okay";
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ trips {
+ threshold: trip-point@0 {
+ temperature = <45000>;
+ hysteresis = <5000>;
+ type = "active";
+ };
+ target: trip-point@1 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_hot: cpu_hot@0 {
+ temperature = <55000>;
+ hysteresis = <2000>;
+ type = "active";
+ };
+ };
+ cooling-maps {
+ map0 {
+ trip = <&threshold>;
+ cooling-device = <&fan0 0 1>;
+ };
+ map1 {
+ trip = <&target>;
+ cooling-device = <&fan0 1 2>;
+ };
+ map2 {
+ trip = <&cpu_hot>;
+ cooling-device = <&fan0 2 3>;
+ };
+ };
+ };
+ };
--- /dev/null
+++ b/Documentation/hwmon/rpi-poe-fan
@@ -0,0 +1,15 @@
+Kernel driver rpi-poe-fan
+=====================
+
+This driver enables the use of the Raspberry Pi PoE HAT fan.
+
+Author: Serge Schneider <serge@raspberrypi.org>
+
+Description
+-----------
+
+The driver implements a simple interface for driving the Raspberry Pi PoE
+(Power over Ethernet) HAT fan. The driver passes commands to the Raspberry Pi
+firmware through the mailbox property interface. The firmware then forwards
+the commands to the board over I2C on the ID_EEPROM pins. The driver exposes
+the fan to the user space through the hwmon sysfs interface.
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1489,6 +1489,17 @@ config SENSORS_RASPBERRYPI_HWMON
This driver can also be built as a module. If so, the module
will be called raspberrypi-hwmon.
+config SENSORS_RPI_POE_FAN
+ tristate "Raspberry Pi PoE HAT fan"
+ depends on RASPBERRYPI_FIRMWARE
+ depends on THERMAL || THERMAL=n
+ help
+ If you say yes here you get support for Raspberry Pi PoE (Power over
+ Ethernet) HAT fan.
+
+ This driver can also be built as a module. If so, the module
+ will be called rpi-poe-fan.
+
config SENSORS_SL28CPLD
tristate "Kontron sl28cpld hardware monitoring driver"
depends on MFD_SL28CPLD || COMPILE_TEST
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -157,6 +157,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
+obj-$(CONFIG_SENSORS_RPI_POE_FAN) += rpi-poe-fan.o
obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
--- /dev/null
+++ b/drivers/hwmon/rpi-poe-fan.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * rpi-poe-fan.c - Hwmon driver for Raspberry Pi PoE HAT fan.
+ *
+ * Copyright (C) 2018 Raspberry Pi (Trading) Ltd.
+ * Based on pwm-fan.c by Kamil Debski <k.debski@samsung.com>
+ *
+ * Author: Serge Schneider <serge@raspberrypi.org>
+ */
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/sysfs.h>
+#include <linux/thermal.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MAX_PWM 255
+
+#define POE_CUR_PWM 0x0
+#define POE_DEF_PWM 0x1
+
+struct rpi_poe_fan_ctx {
+ struct mutex lock;
+ struct rpi_firmware *fw;
+ unsigned int pwm_value;
+ unsigned int def_pwm_value;
+ unsigned int rpi_poe_fan_state;
+ unsigned int rpi_poe_fan_max_state;
+ unsigned int *rpi_poe_fan_cooling_levels;
+ struct thermal_cooling_device *cdev;
+ struct notifier_block nb;
+};
+
+struct fw_tag_data_s{
+ u32 reg;
+ u32 val;
+ u32 ret;
+};
+
+static int write_reg(struct rpi_firmware *fw, u32 reg, u32 *val){
+ struct fw_tag_data_s fw_tag_data = {
+ .reg = reg,
+ .val = *val
+ };
+ int ret;
+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POE_HAT_VAL,
+ &fw_tag_data, sizeof(fw_tag_data));
+ if (ret) {
+ return ret;
+ } else if (fw_tag_data.ret) {
+ return -EIO;
+ }
+ return 0;
+}
+
+static int read_reg(struct rpi_firmware *fw, u32 reg, u32 *val){
+ struct fw_tag_data_s fw_tag_data = {
+ .reg = reg,
+ };
+ int ret;
+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POE_HAT_VAL,
+ &fw_tag_data, sizeof(fw_tag_data));
+ if (ret) {
+ return ret;
+ } else if (fw_tag_data.ret) {
+ return -EIO;
+ }
+ *val = fw_tag_data.val;
+ return 0;
+}
+
+static int rpi_poe_reboot(struct notifier_block *nb, unsigned long code,
+ void *unused)
+{
+ struct rpi_poe_fan_ctx *ctx = container_of(nb, struct rpi_poe_fan_ctx,
+ nb);
+
+ if (ctx->pwm_value != ctx->def_pwm_value)
+ write_reg(ctx->fw, POE_CUR_PWM, &ctx->def_pwm_value);
+
+ return NOTIFY_DONE;
+}
+
+static int __set_pwm(struct rpi_poe_fan_ctx *ctx, u32 pwm)
+{
+ int ret = 0;
+
+ mutex_lock(&ctx->lock);
+ if (ctx->pwm_value == pwm)
+ goto exit_set_pwm_err;
+
+ ret = write_reg(ctx->fw, POE_CUR_PWM, &pwm);
+ if (!ret)
+ ctx->pwm_value = pwm;
+exit_set_pwm_err:
+ mutex_unlock(&ctx->lock);
+ return ret;
+}
+
+static int __set_def_pwm(struct rpi_poe_fan_ctx *ctx, u32 def_pwm)
+{
+ int ret = 0;
+ mutex_lock(&ctx->lock);
+ if (ctx->def_pwm_value == def_pwm)
+ goto exit_set_def_pwm_err;
+
+ ret = write_reg(ctx->fw, POE_DEF_PWM, &def_pwm);
+ if (!ret)
+ ctx->def_pwm_value = def_pwm;
+exit_set_def_pwm_err:
+ mutex_unlock(&ctx->lock);
+ return ret;
+}
+
+static void rpi_poe_fan_update_state(struct rpi_poe_fan_ctx *ctx,
+ unsigned long pwm)
+{
+ int i;
+
+ for (i = 0; i < ctx->rpi_poe_fan_max_state; ++i)
+ if (pwm < ctx->rpi_poe_fan_cooling_levels[i + 1])
+ break;
+
+ ctx->rpi_poe_fan_state = i;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+ unsigned long pwm;
+ int ret;
+
+ if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM)
+ return -EINVAL;
+
+ ret = __set_pwm(ctx, pwm);
+ if (ret)
+ return ret;
+
+ rpi_poe_fan_update_state(ctx, pwm);
+ return count;
+}
+
+static ssize_t set_def_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+ unsigned long def_pwm;
+ int ret;
+
+ if (kstrtoul(buf, 10, &def_pwm) || def_pwm > MAX_PWM)
+ return -EINVAL;
+
+ ret = __set_def_pwm(ctx, def_pwm);
+ if (ret)
+ return ret;
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ctx->pwm_value);
+}
+
+static ssize_t show_def_pwm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ctx->def_pwm_value);
+}
+
+
+static SENSOR_DEVICE_ATTR(pwm1, 0644, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(def_pwm1, 0644, show_def_pwm, set_def_pwm, 1);
+
+static struct attribute *rpi_poe_fan_attrs[] = {
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_def_pwm1.dev_attr.attr,
+ NULL,
+};
+
+ATTRIBUTE_GROUPS(rpi_poe_fan);
+
+/* thermal cooling device callbacks */
+static int rpi_poe_fan_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct rpi_poe_fan_ctx *ctx = cdev->devdata;
+
+ if (!ctx)
+ return -EINVAL;
+
+ *state = ctx->rpi_poe_fan_max_state;
+
+ return 0;
+}
+
+static int rpi_poe_fan_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct rpi_poe_fan_ctx *ctx = cdev->devdata;
+
+ if (!ctx)
+ return -EINVAL;
+
+ *state = ctx->rpi_poe_fan_state;
+
+ return 0;
+}
+
+static int rpi_poe_fan_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct rpi_poe_fan_ctx *ctx = cdev->devdata;
+ int ret;
+
+ if (!ctx || (state > ctx->rpi_poe_fan_max_state))
+ return -EINVAL;
+
+ if (state == ctx->rpi_poe_fan_state)
+ return 0;
+
+ ret = __set_pwm(ctx, ctx->rpi_poe_fan_cooling_levels[state]);
+ if (ret) {
+ dev_err(&cdev->device, "Cannot set pwm!\n");
+ return ret;
+ }
+
+ ctx->rpi_poe_fan_state = state;
+
+ return ret;
+}
+
+static const struct thermal_cooling_device_ops rpi_poe_fan_cooling_ops = {
+ .get_max_state = rpi_poe_fan_get_max_state,
+ .get_cur_state = rpi_poe_fan_get_cur_state,
+ .set_cur_state = rpi_poe_fan_set_cur_state,
+};
+
+static int rpi_poe_fan_of_get_cooling_data(struct device *dev,
+ struct rpi_poe_fan_ctx *ctx)
+{
+ struct device_node *np = dev->of_node;
+ int num, i, ret;
+
+ if (!of_find_property(np, "cooling-levels", NULL))
+ return 0;
+
+ ret = of_property_count_u32_elems(np, "cooling-levels");
+ if (ret <= 0) {
+ dev_err(dev, "cooling-levels property missing or invalid: %d\n",
+ ret);
+ return ret ? : -EINVAL;
+ }
+
+ num = ret;
+ ctx->rpi_poe_fan_cooling_levels = devm_kzalloc(dev, num * sizeof(u32),
+ GFP_KERNEL);
+ if (!ctx->rpi_poe_fan_cooling_levels)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "cooling-levels",
+ ctx->rpi_poe_fan_cooling_levels, num);
+ if (ret) {
+ dev_err(dev, "Property 'cooling-levels' cannot be read!\n");
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (ctx->rpi_poe_fan_cooling_levels[i] > MAX_PWM) {
+ dev_err(dev, "PWM fan state[%d]:%d > %d\n", i,
+ ctx->rpi_poe_fan_cooling_levels[i], MAX_PWM);
+ return -EINVAL;
+ }
+ }
+
+ ctx->rpi_poe_fan_max_state = num - 1;
+
+ return 0;
+}
+
+static int rpi_poe_fan_probe(struct platform_device *pdev)
+{
+ struct thermal_cooling_device *cdev;
+ struct rpi_poe_fan_ctx *ctx;
+ struct device *hwmon;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *fw_node;
+ int ret;
+
+ fw_node = of_parse_phandle(np, "firmware", 0);
+ if (!fw_node) {
+ dev_err(&pdev->dev, "Missing firmware node\n");
+ return -ENOENT;
+ }
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ mutex_init(&ctx->lock);
+
+ ctx->fw = rpi_firmware_get(fw_node);
+ if (!ctx->fw)
+ return -EPROBE_DEFER;
+
+ platform_set_drvdata(pdev, ctx);
+
+ ctx->nb.notifier_call = rpi_poe_reboot;
+ ret = register_reboot_notifier(&ctx->nb);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register reboot notifier: %i\n",
+ ret);
+ return ret;
+ }
+ ret = read_reg(ctx->fw, POE_DEF_PWM, &ctx->def_pwm_value);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get default PWM value: %i\n",
+ ret);
+ goto err;
+ }
+ ret = read_reg(ctx->fw, POE_CUR_PWM, &ctx->pwm_value);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get current PWM value: %i\n",
+ ret);
+ goto err;
+ }
+
+ hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "rpipoefan",
+ ctx, rpi_poe_fan_groups);
+ if (IS_ERR(hwmon)) {
+ dev_err(&pdev->dev, "Failed to register hwmon device\n");
+ ret = PTR_ERR(hwmon);
+ goto err;
+ }
+
+ ret = rpi_poe_fan_of_get_cooling_data(&pdev->dev, ctx);
+ if (ret)
+ return ret;
+
+ rpi_poe_fan_update_state(ctx, ctx->pwm_value);
+ if (!IS_ENABLED(CONFIG_THERMAL))
+ return 0;
+
+ cdev = thermal_of_cooling_device_register(np,
+ "rpi-poe-fan", ctx,
+ &rpi_poe_fan_cooling_ops);
+ if (IS_ERR(cdev)) {
+ dev_err(&pdev->dev,
+ "Failed to register rpi-poe-fan as cooling device");
+ ret = PTR_ERR(cdev);
+ goto err;
+ }
+ ctx->cdev = cdev;
+ thermal_cdev_update(cdev);
+
+ return 0;
+err:
+ unregister_reboot_notifier(&ctx->nb);
+ return ret;
+}
+
+static int rpi_poe_fan_remove(struct platform_device *pdev)
+{
+ struct rpi_poe_fan_ctx *ctx = platform_get_drvdata(pdev);
+ u32 value = ctx->def_pwm_value;
+
+ unregister_reboot_notifier(&ctx->nb);
+ thermal_cooling_device_unregister(ctx->cdev);
+ if (ctx->pwm_value != value) {
+ write_reg(ctx->fw, POE_CUR_PWM, &value);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int rpi_poe_fan_suspend(struct device *dev)
+{
+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+ u32 value = 0;
+ int ret = 0;
+
+ if (ctx->pwm_value != value)
+ ret = write_reg(ctx->fw, POE_CUR_PWM, &value);
+ return ret;
+}
+
+static int rpi_poe_fan_resume(struct device *dev)
+{
+ struct rpi_poe_fan_ctx *ctx = dev_get_drvdata(dev);
+ u32 value = ctx->pwm_value;
+ int ret = 0;
+
+ if (value != 0)
+ ret = write_reg(ctx->fw, POE_CUR_PWM, &value);
+
+ return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rpi_poe_fan_pm, rpi_poe_fan_suspend,
+ rpi_poe_fan_resume);
+
+static const struct of_device_id of_rpi_poe_fan_match[] = {
+ { .compatible = "raspberrypi,rpi-poe-fan", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_rpi_poe_fan_match);
+
+static struct platform_driver rpi_poe_fan_driver = {
+ .probe = rpi_poe_fan_probe,
+ .remove = rpi_poe_fan_remove,
+ .driver = {
+ .name = "rpi-poe-fan",
+ .pm = &rpi_poe_fan_pm,
+ .of_match_table = of_rpi_poe_fan_match,
+ },
+};
+
+module_platform_driver(rpi_poe_fan_driver);
+
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
+MODULE_ALIAS("platform:rpi-poe-fan");
+MODULE_DESCRIPTION("Raspberry Pi PoE HAT fan driver");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,20 @@
From 5156d25449f1a76a72be090a595ee7e25cb74bc6 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 17 Sep 2018 17:31:18 +0100
Subject: [PATCH] cxd2880: CXD2880_SPI_DRV should select DVB_CXD2880
with MEDIA_SUBDRV_AUTOSELECT
---
drivers/media/spi/Kconfig | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/media/spi/Kconfig
+++ b/drivers/media/spi/Kconfig
@@ -25,6 +25,7 @@ menu "Media SPI Adapters"
config CXD2880_SPI_DRV
tristate "Sony CXD2880 SPI support"
depends on DVB_CORE && SPI
+ select DVB_CXD2880 if MEDIA_SUBDRV_AUTOSELECT
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Choose if you would like to have SPI interface support for Sony CXD2880.

View File

@ -0,0 +1,75 @@
From f6e40957774cd71b4a8ce2190d94ef8e9b289938 Mon Sep 17 00:00:00 2001
From: Stefan Wahren <stefan.wahren@i2se.com>
Date: Sat, 6 Oct 2018 16:46:18 +0200
Subject: [PATCH] hwmon: raspberrypi: Prevent voltage low warnings from
filling log
Although the correct fix for low voltage warnings is to
improve the power supply, the current implementation
of the detection can fill the log if the warning
happens freqently. This replaces the logging with
slightly custom ratelimited logging.
Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/hwmon/raspberrypi-hwmon.c | 41 ++++++++++++++++++++++++++++---
1 file changed, 37 insertions(+), 4 deletions(-)
--- a/drivers/hwmon/raspberrypi-hwmon.c
+++ b/drivers/hwmon/raspberrypi-hwmon.c
@@ -15,6 +15,36 @@
#include <linux/workqueue.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
+/*
+ * This section defines some rate limited logging that prevent
+ * repeated messages at much lower Hz than the default kernel settings.
+ * It's usually 5s, this is 5 minutes.
+ * Burst 3 means you may get three messages 'quickly', before
+ * the ratelimiting kicks in.
+ */
+#define LOCAL_RATELIMIT_INTERVAL (5 * 60 * HZ)
+#define LOCAL_RATELIMIT_BURST 3
+
+#ifdef CONFIG_PRINTK
+#define printk_ratelimited_local(fmt, ...) \
+({ \
+ static DEFINE_RATELIMIT_STATE(_rs, \
+ LOCAL_RATELIMIT_INTERVAL, \
+ LOCAL_RATELIMIT_BURST); \
+ \
+ if (__ratelimit(&_rs)) \
+ printk(fmt, ##__VA_ARGS__); \
+})
+#else
+#define printk_ratelimited_local(fmt, ...) \
+ no_printk(fmt, ##__VA_ARGS__)
+#endif
+
+#define pr_crit_ratelimited_local(fmt, ...) \
+ printk_ratelimited_local(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info_ratelimited_local(fmt, ...) \
+printk_ratelimited_local(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+
#define UNDERVOLTAGE_STICKY_BIT BIT(16)
struct rpi_hwmon_data {
@@ -47,10 +77,13 @@ static void rpi_firmware_get_throttled(s
if (new_uv == old_uv)
return;
- if (new_uv)
- dev_crit(data->hwmon_dev, "Undervoltage detected!\n");
- else
- dev_info(data->hwmon_dev, "Voltage normalised\n");
+ if (new_uv) {
+ pr_crit_ratelimited_local("Under-voltage detected! (0x%08x)\n",
+ value);
+ } else {
+ pr_info_ratelimited_local("Voltage normalised (0x%08x)\n",
+ value);
+ }
sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm");
}

View File

@ -0,0 +1,79 @@
From 1910584831fe065c50efc3c07b8ea08ff90e6f31 Mon Sep 17 00:00:00 2001
From: Stefan Wahren <stefan.wahren@i2se.com>
Date: Sat, 13 Oct 2018 13:31:21 +0200
Subject: [PATCH] firmware: raspberrypi: Add backward compatible
get_throttled
Avoid a hard userspace ABI change by adding a compatible get_throttled
sysfs entry. Its value is now feed by the GET_THROTTLED requests of the
new hwmon driver. The first access to get_throttled will generate
a warning.
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/firmware/raspberrypi.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -28,6 +28,7 @@ struct rpi_firmware {
struct mbox_chan *chan; /* The property channel. */
struct completion c;
u32 enabled;
+ u32 get_throttled;
};
static struct platform_device *g_pdev;
@@ -174,6 +175,12 @@ int rpi_firmware_property(struct rpi_fir
kfree(data);
+ if ((tag == RPI_FIRMWARE_GET_THROTTLED) &&
+ memcmp(&fw->get_throttled, tag_data, sizeof(fw->get_throttled))) {
+ memcpy(&fw->get_throttled, tag_data, sizeof(fw->get_throttled));
+ sysfs_notify(&fw->cl.dev->kobj, NULL, "get_throttled");
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(rpi_firmware_property);
@@ -198,6 +205,27 @@ static int rpi_firmware_notify_reboot(st
return 0;
}
+static ssize_t get_throttled_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rpi_firmware *fw = dev_get_drvdata(dev);
+
+ WARN_ONCE(1, "deprecated, use hwmon sysfs instead\n");
+
+ return sprintf(buf, "%x\n", fw->get_throttled);
+}
+
+static DEVICE_ATTR_RO(get_throttled);
+
+static struct attribute *rpi_firmware_dev_attrs[] = {
+ &dev_attr_get_throttled.attr,
+ NULL,
+};
+
+static const struct attribute_group rpi_firmware_dev_group = {
+ .attrs = rpi_firmware_dev_attrs,
+};
+
static void
rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
{
@@ -227,6 +255,11 @@ rpi_register_hwmon_driver(struct device
rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon",
-1, NULL, 0);
+
+ if (!IS_ERR_OR_NULL(rpi_hwmon)) {
+ if (devm_device_add_group(dev, &rpi_firmware_dev_group))
+ dev_err(dev, "Failed to create get_trottled attr\n");
+ }
}
static void rpi_register_clk_driver(struct device *dev)

View File

@ -0,0 +1,23 @@
From 0041d17ed3cd7e4ffc6168164c6020e5dcf7aeb4 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 6 Nov 2018 12:57:48 +0000
Subject: [PATCH] sc16is7xx: Don't spin if no data received
See: https://github.com/raspberrypi/linux/issues/2676
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/tty/serial/sc16is7xx.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -696,6 +696,8 @@ static bool sc16is7xx_port_irq(struct sc
rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG);
if (rxlen)
sc16is7xx_handle_rx(port, rxlen, iir);
+ else
+ return false;
break;
case SC16IS7XX_IIR_THRI_SRC:
sc16is7xx_handle_tx(port);

View File

@ -0,0 +1,94 @@
From 61e2e6bc4c30ceca12a917de93ffa9645e4944f7 Mon Sep 17 00:00:00 2001
From: Ram Chandrasekar <rkumbako@codeaurora.org>
Date: Mon, 7 May 2018 11:54:08 -0600
Subject: [PATCH] drivers: thermal: step_wise: add support for
hysteresis
Step wise governor increases the mitigation level when the temperature
goes above a threshold and will decrease the mitigation when the
temperature falls below the threshold. If it were a case, where the
temperature hovers around a threshold, the mitigation will be applied
and removed at every iteration. This reaction to the temperature is
inefficient for performance.
The use of hysteresis temperature could avoid this ping-pong of
mitigation by relaxing the mitigation to happen only when the
temperature goes below this lower hysteresis value.
Signed-off-by: Ram Chandrasekar <rkumbako@codeaurora.org>
Signed-off-by: Lina Iyer <ilina@codeaurora.org>
---
drivers/thermal/gov_step_wise.c | 33 +++++++++++++++++++++++----------
1 file changed, 23 insertions(+), 10 deletions(-)
--- a/drivers/thermal/gov_step_wise.c
+++ b/drivers/thermal/gov_step_wise.c
@@ -24,7 +24,7 @@
* for this trip point
* d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit
* for this trip point
- * If the temperature is lower than a trip point,
+ * If the temperature is lower than a hysteresis temperature,
* a. if the trend is THERMAL_TREND_RAISING, do nothing
* b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
* state for this trip point, if the cooling state already
@@ -115,7 +115,7 @@ static void update_passive_instance(stru
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
{
- int trip_temp;
+ int trip_temp, hyst_temp;
enum thermal_trip_type trip_type;
enum thermal_trend trend;
struct thermal_instance *instance;
@@ -123,22 +123,23 @@ static void thermal_zone_trip_update(str
int old_target;
if (trip == THERMAL_TRIPS_NONE) {
- trip_temp = tz->forced_passive;
+ hyst_temp = trip_temp = tz->forced_passive;
trip_type = THERMAL_TRIPS_NONE;
} else {
tz->ops->get_trip_temp(tz, trip, &trip_temp);
+ hyst_temp = trip_temp;
+ if (tz->ops->get_trip_hyst) {
+ tz->ops->get_trip_hyst(tz, trip, &hyst_temp);
+ hyst_temp = trip_temp - hyst_temp;
+ }
tz->ops->get_trip_type(tz, trip, &trip_type);
}
trend = get_tz_trend(tz, trip);
- if (tz->temperature >= trip_temp) {
- throttle = true;
- trace_thermal_zone_trip(tz, trip, trip_type);
- }
-
- dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
- trip, trip_type, trip_temp, trend, throttle);
+ dev_dbg(&tz->device,
+ "Trip%d[type=%d,temp=%d,hyst=%d]:trend=%d,throttle=%d\n",
+ trip, trip_type, trip_temp, hyst_temp, trend, throttle);
mutex_lock(&tz->lock);
@@ -147,6 +148,18 @@ static void thermal_zone_trip_update(str
continue;
old_target = instance->target;
+ throttle = false;
+ /*
+ * Lower the mitigation only if the temperature
+ * goes below the hysteresis temperature.
+ */
+ if (tz->temperature >= trip_temp ||
+ (tz->temperature >= hyst_temp &&
+ old_target != THERMAL_NO_TARGET)) {
+ throttle = true;
+ trace_thermal_zone_trip(tz, trip, trip_type);
+ }
+
instance->target = get_target_state(instance, trend, throttle);
dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
old_target, (int)instance->target);

View File

@ -0,0 +1,22 @@
From f220efa380854e2423a47f26acde9355ae016ea3 Mon Sep 17 00:00:00 2001
From: Serge Schneider <serge@raspberrypi.org>
Date: Tue, 2 Oct 2018 11:14:15 +0100
Subject: [PATCH] drivers: thermal: step_wise: avoid throttling at
hysteresis temperature after dropping below it
Signed-off-by: Serge Schneider <serge@raspberrypi.org>
---
drivers/thermal/gov_step_wise.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/thermal/gov_step_wise.c
+++ b/drivers/thermal/gov_step_wise.c
@@ -155,7 +155,7 @@ static void thermal_zone_trip_update(str
*/
if (tz->temperature >= trip_temp ||
(tz->temperature >= hyst_temp &&
- old_target != THERMAL_NO_TARGET)) {
+ old_target == instance->upper)) {
throttle = true;
trace_thermal_zone_trip(tz, trip, trip_type);
}

View File

@ -0,0 +1,47 @@
From 87b9a65d3f7102400bff69dcc692d238fe1d6203 Mon Sep 17 00:00:00 2001
From: James Hughes <JamesH65@users.noreply.github.com>
Date: Fri, 2 Nov 2018 11:55:49 +0000
Subject: [PATCH] Update issue templates (#2736)
---
.github/ISSUE_TEMPLATE/bug_report.md | 34 ++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,34 @@
+---
+name: Bug report
+about: Create a report to help us fix your issue
+
+---
+
+**Is this the right place for my bug report?**
+This repository contains the Linux kernel used on the Raspberry Pi. If you believe that the issue you are seeing is kernel-related, this is the right place. If not, we have other repositories for the GPU firmware at [github.com/raspberrypi/firmware](https://github.com/raspberrypi/firmware) and Raspberry Pi userland applications at [github.com/raspberrypi/userland](https://github.com/raspberrypi/userland). If you have problems with the Raspbian distribution packages, report them in the [github.com/RPi-Distro/repo](https://github.com/RPi-Distro/repo). If you simply have a question, then [the Raspberry Pi forums](https://www.raspberrypi.org/forums) are the best place to ask it.
+
+**Describe the bug**
+Add a clear and concise description of what you think the bug is.
+
+**To reproduce**
+List the steps required to reproduce the issue.
+
+**Expected behaviour**
+Add a clear and concise description of what you expected to happen.
+
+**Actual behaviour**
+Add a clear and concise description of what actually happened.
+
+**System**
+ Copy and paste the results of the raspinfo command in to this section. Alternatively, copy and paste a pastebin link, or add answers to the following questions:
+
+* Which model of Raspberry Pi? e.g. Pi3B+, PiZeroW
+* Which OS and version (`cat /etc/rpi-issue`)?
+* Which firmware version (`vcgencmd version`)?
+* Which kernel version (`uname -a`)?
+
+**Logs**
+If applicable, add the relevant output from `dmesg` or similar.
+
+**Additional context**
+Add any other relevant context for the problem.

View File

@ -0,0 +1,91 @@
From cbc38ebf8ff6d01cd11270d99762d4216ff4237d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 26 Nov 2018 19:46:58 +0000
Subject: [PATCH] net: lan78xx: Support auto-downshift to 100Mb/s
Ethernet cables with faulty or missing pairs (specifically pairs C and
D) allow auto-negotiation to 1000Mbs, but do not support the successful
establishment of a link. Add a DT property, "microchip,downshift-after",
to configure the number of auto-negotiation failures after which it
falls back to 100Mbs. Valid values are 2, 3, 4, 5 and 0, where 0 means
never downshift.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
.../bindings/net/microchip,lan78xx.txt | 3 +++
drivers/net/phy/microchip.c | 27 +++++++++++++++++++
include/linux/microchipphy.h | 8 ++++++
3 files changed, 38 insertions(+)
--- a/Documentation/devicetree/bindings/net/microchip,lan78xx.txt
+++ b/Documentation/devicetree/bindings/net/microchip,lan78xx.txt
@@ -14,6 +14,9 @@ Optional properties of the embedded PHY:
- microchip,led-modes: a 0..4 element vector, with each element configuring
the operating mode of an LED. Omitted LEDs are turned off. Allowed values
are defined in "include/dt-bindings/net/microchip-lan78xx.h".
+- microchip,downshift-after: sets the number of failed auto-negotiation
+ attempts after which the link is downgraded from 1000BASE-T. Should be one of
+ 2, 3, 4, 5 or 0, where 0 means never downshift.
Example:
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -217,6 +217,7 @@ static int lan88xx_probe(struct phy_devi
struct device *dev = &phydev->mdio.dev;
struct lan88xx_priv *priv;
u32 led_modes[4];
+ u32 downshift_after = 0;
int len;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -246,6 +247,32 @@ static int lan88xx_probe(struct phy_devi
return -EINVAL;
}
+ if (!of_property_read_u32(dev->of_node,
+ "microchip,downshift-after",
+ &downshift_after)) {
+ u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK;
+ u32 val= LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+
+ switch (downshift_after) {
+ case 2: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
+ break;
+ case 3: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
+ break;
+ case 4: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
+ break;
+ case 5: val |= LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
+ break;
+ case 0: // Disable completely
+ mask = LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ (void)phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+ mask, val);
+ }
+
/* these values can be used to identify internal PHY */
priv->chip_id = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_ID);
priv->chip_rev = phy_read_mmd(phydev, 3, LAN88XX_MMD3_CHIP_REV);
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -61,6 +61,14 @@
/* Registers specific to the LAN7800/LAN7850 embedded phy */
#define LAN78XX_PHY_LED_MODE_SELECT (0x1D)
+#define LAN78XX_PHY_CTRL3 (0x14)
+#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT (0x0010)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK (0x000c)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2 (0x0000)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3 (0x0004)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4 (0x0008)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5 (0x000c)
+
/* DSP registers */
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A)
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000)

View File

@ -0,0 +1,101 @@
From ab759f3138e5ea798e93003e6ce0ffe66ac2970f Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
Date: Thu, 10 Jan 2019 17:58:06 +0000
Subject: [PATCH] firmware: raspberrypi: Report the fw variant during
probe
The driver already reported the firmware build date during probe.
The mailbox calls have been extended to also report the variant
1 = standard start.elf
2 = start_x.elf (includes camera stack)
3 = start_db.elf (includes assert logging)
4 = start_cd.elf (cutdown version for smallest memory footprint).
Log the variant during probe.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
firmware: raspberrypi: Report the fw git hash during probe
The firmware can now report the git hash from which it was built
via the mailbox, so report it during probe.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
---
drivers/firmware/raspberrypi.c | 40 +++++++++++++++++++++-
include/soc/bcm2835/raspberrypi-firmware.h | 2 ++
2 files changed, 41 insertions(+), 1 deletion(-)
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -231,6 +231,15 @@ rpi_firmware_print_firmware_revision(str
{
time64_t date_and_time;
u32 packet;
+ static const char * const variant_strs[] = {
+ "unknown",
+ "start",
+ "start_x",
+ "start_db",
+ "start_cd",
+ };
+ const char *variant_str = "cmd unsupported";
+ u32 variant;
int ret = rpi_firmware_property(fw,
RPI_FIRMWARE_GET_FIRMWARE_REVISION,
&packet, sizeof(packet));
@@ -240,7 +249,35 @@ rpi_firmware_print_firmware_revision(str
/* This is not compatible with y2038 */
date_and_time = packet;
- dev_info(fw->cl.dev, "Attached to firmware from %ptT\n", &date_and_time);
+
+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_FIRMWARE_VARIANT,
+ &variant, sizeof(variant));
+
+ if (!ret) {
+ if (variant >= ARRAY_SIZE(variant_strs))
+ variant = 0;
+ variant_str = variant_strs[variant];
+ }
+
+ dev_info(fw->cl.dev,
+ "Attached to firmware from %ptT, variant %s\n",
+ &date_and_time, variant_str);
+}
+
+static void
+rpi_firmware_print_firmware_hash(struct rpi_firmware *fw)
+{
+ u32 hash[5];
+ int ret = rpi_firmware_property(fw,
+ RPI_FIRMWARE_GET_FIRMWARE_HASH,
+ hash, sizeof(hash));
+
+ if (ret)
+ return;
+
+ dev_info(fw->cl.dev,
+ "Firmware hash is %08x%08x%08x%08x%08x\n",
+ hash[0], hash[1], hash[2], hash[3], hash[4]);
}
static void
@@ -309,6 +346,7 @@ static int rpi_firmware_probe(struct pla
g_pdev = pdev;
rpi_firmware_print_firmware_revision(fw);
+ rpi_firmware_print_firmware_hash(fw);
rpi_register_hwmon_driver(dev, fw);
rpi_register_clk_driver(dev);
--- a/include/soc/bcm2835/raspberrypi-firmware.h
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -38,6 +38,8 @@ struct rpi_firmware_property_tag_header
enum rpi_firmware_property_tag {
RPI_FIRMWARE_PROPERTY_END = 0,
RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
+ RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002,
+ RPI_FIRMWARE_GET_FIRMWARE_HASH = 0x00000003,
RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,

View File

@ -0,0 +1,45 @@
From a242ba451fd64f0b9f07605ff0d8f6981aa6e955 Mon Sep 17 00:00:00 2001
From: Joshua Emele <jemele@acm.org>
Date: Wed, 7 Nov 2018 16:07:40 -0800
Subject: [PATCH] lan78xx: Debounce link events to minimize poll storm
The bInterval is set to 4 (i.e. 8 microframes => 1ms) and the only bit
that the driver pays attention to is "link was reset". If there's a
flapping status bit in that endpoint data, (such as if PHY negotiation
needs a few tries to get a stable link) then polling at a slower rate
would act as a de-bounce.
See: https://github.com/raspberrypi/linux/issues/2447
---
drivers/net/usb/lan78xx.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -434,6 +434,11 @@ static bool enable_tso;
module_param(enable_tso, bool, 0644);
MODULE_PARM_DESC(enable_tso, "Enables TCP segmentation offload");
+#define INT_URB_MICROFRAMES_PER_MS 8
+static int int_urb_interval_ms = 8;
+module_param(int_urb_interval_ms, int, 0);
+MODULE_PARM_DESC(int_urb_interval_ms, "Override usb interrupt urb interval");
+
static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
{
u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
@@ -3760,7 +3765,13 @@ static int lan78xx_probe(struct usb_inte
netdev->max_mtu = MAX_SINGLE_PACKET_SIZE;
netif_set_gso_max_size(netdev, MAX_SINGLE_PACKET_SIZE - MAX_HEADER);
- period = ep_intr->desc.bInterval;
+ if (int_urb_interval_ms <= 0)
+ period = ep_intr->desc.bInterval;
+ else
+ period = int_urb_interval_ms * INT_URB_MICROFRAMES_PER_MS;
+
+ netif_notice(dev, probe, netdev, "int urb period %d\n", period);
+
maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0);
buf = kmalloc(maxp, GFP_KERNEL);
if (buf) {

Some files were not shown because too many files have changed in this diff Show More