mirror of https://github.com/hak5/openwrt.git
bcm27xx: add linux 5.4 support
Tested on bcm2710 (Raspberry Pi 3B). Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>master
parent
a8aa974a9d
commit
a1383655cf
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (C) 2012-2019 OpenWrt.org
|
||||
# Copyright (C) 2012-2020 OpenWrt.org
|
||||
# Copyright (C) 2017 LEDE project
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
|
@ -15,6 +15,7 @@ MAINTAINER:=Álvaro Fernández Rojas <noltari@gmail.com>
|
|||
SUBTARGETS:=bcm2708 bcm2709 bcm2710 bcm2711
|
||||
|
||||
KERNEL_PATCHVER:=4.19
|
||||
KERNEL_TESTING_PATCHVER=5.4
|
||||
|
||||
define Target/Description
|
||||
Build firmware image for Broadcom BCM27xx SoC devices.
|
||||
|
|
|
@ -0,0 +1,411 @@
|
|||
# CONFIG_AIO is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_BCM=y
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
CONFIG_ARCH_CLOCKSOURCE_DATA=y
|
||||
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
|
||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
||||
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
|
||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
CONFIG_ARCH_HAS_KCOV=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
CONFIG_ARCH_HAS_PHYS_TO_DMA=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_SG_CHAIN=y
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
||||
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=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_SUPPORTS_ATOMIC_RMW=y
|
||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
|
||||
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
|
||||
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
||||
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_BCM2835_CPUFREQ=y
|
||||
CONFIG_ARM_CPU_SUSPEND=y
|
||||
CONFIG_ARM_ERRATA_411920=y
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_HAS_SG_CHAIN=y
|
||||
CONFIG_ARM_L1_CACHE_SHIFT=5
|
||||
CONFIG_ARM_PATCH_PHYS_VIRT=y
|
||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SP805_WATCHDOG is not set
|
||||
CONFIG_ARM_THUMB=y
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_ARM_UNWIND=y
|
||||
CONFIG_AUTO_ZRELADDR=y
|
||||
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
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=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_SCSI_REQUEST=y
|
||||
# CONFIG_BRCMSTB_THERMAL is not set
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
CONFIG_BUILD_BIN2C=y
|
||||
# CONFIG_CACHE_L2X0 is not set
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
# CONFIG_CLK_RASPBERRYPI is not set
|
||||
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_CONFIGFS_FS=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
# CONFIG_CPUFREQ_DT is not set
|
||||
CONFIG_CPU_32v6=y
|
||||
CONFIG_CPU_32v6K=y
|
||||
CONFIG_CPU_ABRT_EV6=y
|
||||
# CONFIG_CPU_BPREDICT_DISABLE is not set
|
||||
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_ICACHE_DISABLE is not set
|
||||
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_THERMAL is not set
|
||||
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_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_WORKQUEUE=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
|
||||
# CONFIG_DEBUG_USER is not set
|
||||
CONFIG_DEFAULT_CFQ=y
|
||||
# CONFIG_DEFAULT_DEADLINE is not set
|
||||
CONFIG_DEFAULT_IOSCHED="cfq"
|
||||
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_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_CHECK_FS is not set
|
||||
CONFIG_F2FS_FS=y
|
||||
# CONFIG_F2FS_FS_SECURITY is not set
|
||||
CONFIG_F2FS_FS_XATTR=y
|
||||
CONFIG_F2FS_STAT_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_FIX_EARLYCON_MEM=y
|
||||
# CONFIG_FONTS is not set
|
||||
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_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_EFFECTIVE_AFF_MASK=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_RASPBERRYPI_EXP=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_HANDLE_DOMAIN_IRQ=y
|
||||
CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT_MAP=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_ARCH_PFN_VALID=y
|
||||
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_HAVE_CONTEXT_TRACKING=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
||||
CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y
|
||||
CONFIG_HAVE_MEMBLOCK=y
|
||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
CONFIG_HAVE_OPROFILE=y
|
||||
CONFIG_HAVE_OPTPROBES=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HAVE_PERF_REGS=y
|
||||
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
|
||||
CONFIG_HAVE_PROC_CPU=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
CONFIG_HAVE_RSEQ=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_UID16=y
|
||||
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_HZ_FIXED=0
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
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_IOSCHED_CFQ=y
|
||||
CONFIG_IRQCHIP=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JBD2=y
|
||||
CONFIG_KERNEL_GZIP=y
|
||||
# CONFIG_KERNEL_XZ is not set
|
||||
# CONFIG_LCD_CLASS_DEVICE is not set
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_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_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_MIGHT_HAVE_PCI=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_BOOTMEM=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NVMEM=y
|
||||
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_NET=y
|
||||
CONFIG_OF_OVERLAY=y
|
||||
CONFIG_OF_RESERVED_MEM=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_PINCTRL=y
|
||||
CONFIG_PINCTRL_BCM2835=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_CLK=y
|
||||
# CONFIG_PM_DEBUG is not set
|
||||
CONFIG_PM_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_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_REFCOUNT_FULL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=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_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=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_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_DWCOTG=y
|
||||
# CONFIG_USB_EHCI_HCD is not set
|
||||
CONFIG_USB_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
|
|
@ -0,0 +1,556 @@
|
|||
CONFIG_64BIT_TIME=y
|
||||
# CONFIG_AIO is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
# CONFIG_ARCH_AXXIA is not set
|
||||
CONFIG_ARCH_BCM=y
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
# CONFIG_ARCH_BCM_HR2 is not set
|
||||
CONFIG_ARCH_CLOCKSOURCE_DATA=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_HAS_BINFMT_FLAT=y
|
||||
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
|
||||
CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y
|
||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
||||
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
|
||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
CONFIG_ARCH_HAS_KCOV=y
|
||||
CONFIG_ARCH_HAS_KEEPINITRD=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
CONFIG_ARCH_HAS_PHYS_TO_DMA=y
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_ARCH_HAS_SETUP_DMA_OPS=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y
|
||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y
|
||||
CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y
|
||||
CONFIG_ARCH_HAS_TICK_BROADCAST=y
|
||||
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
|
||||
# CONFIG_ARCH_MILBEAUT is not set
|
||||
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_RDA is not set
|
||||
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
|
||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
|
||||
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
|
||||
CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
|
||||
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
||||
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
# CONFIG_ARM_BCM2835_CPUFREQ is not set
|
||||
CONFIG_ARM_CPU_SUSPEND=y
|
||||
# CONFIG_ARM_ERRATA_814220 is not set
|
||||
# CONFIG_ARM_ERRATA_857271 is not set
|
||||
# CONFIG_ARM_ERRATA_857272 is not set
|
||||
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_SCMI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SP805_WATCHDOG is not set
|
||||
CONFIG_ARM_THUMB=y
|
||||
# CONFIG_ARM_THUMBEE is not set
|
||||
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_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=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_THERMAL=y
|
||||
CONFIG_BRCM_CHAR_DRIVERS=y
|
||||
CONFIG_BROADCOM_PHY=y
|
||||
# CONFIG_CACHE_L2X0 is not set
|
||||
CONFIG_CC_HAS_KASAN_GENERIC=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLK_BCM2835=y
|
||||
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_BPREDICT_DISABLE is not set
|
||||
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_HOTPLUG_STATE_CONTROL is not set
|
||||
# CONFIG_CPU_ICACHE_DISABLE is not set
|
||||
# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
# CONFIG_CPU_IDLE_GOV_TEO is not set
|
||||
CONFIG_CPU_PABRT_V7=y
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
CONFIG_CPU_SPECTRE=y
|
||||
# CONFIG_CPU_THERMAL is not set
|
||||
CONFIG_CPU_THUMB_CAPABLE=y
|
||||
CONFIG_CPU_TLB_V7=y
|
||||
CONFIG_CPU_V7=y
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_AEAD=y
|
||||
CONFIG_CRYPTO_AEAD2=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_CTR=y
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
CONFIG_CRYPTO_DRBG_MENU=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_JITTERENTROPY=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
CONFIG_CRYPTO_SEQIV=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
|
||||
# CONFIG_DEBUG_USER is not set
|
||||
CONFIG_DIMLIB=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_DECLARE_COHERENT=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_ATOMIC_SCRUB=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
# CONFIG_ENERGY_MODEL is not set
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
# CONFIG_F2FS_CHECK_FS is not set
|
||||
CONFIG_F2FS_FS=y
|
||||
# CONFIG_F2FS_FS_SECURITY is not set
|
||||
CONFIG_F2FS_FS_XATTR=y
|
||||
CONFIG_F2FS_STAT_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_FONTS is not set
|
||||
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_FSL_QDMA is not set
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=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_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
|
||||
CONFIG_GENERIC_IRQ_MIGRATION=y
|
||||
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_GENERIC_PCI_IOMAP=y
|
||||
CONFIG_GENERIC_PHY=y
|
||||
CONFIG_GENERIC_PINCONF=y
|
||||
CONFIG_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
|
||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||
CONFIG_GENERIC_STRNLEN_USER=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
CONFIG_GPIO_BCM_VIRT=y
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
# CONFIG_GVE is not set
|
||||
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_ARCH_BITREVERSE=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_ARCH_PFN_VALID=y
|
||||
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
|
||||
CONFIG_HAVE_ARM_ARCH_TIMER=y
|
||||
CONFIG_HAVE_ARM_SMCCC=y
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_HAVE_CONTEXT_TRACKING=y
|
||||
CONFIG_HAVE_COPY_THREAD_TLS=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
|
||||
CONFIG_HAVE_FAST_GUP=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_IDE=y
|
||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
||||
CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y
|
||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
CONFIG_HAVE_OPROFILE=y
|
||||
CONFIG_HAVE_OPTPROBES=y
|
||||
CONFIG_HAVE_PCI=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HAVE_PERF_REGS=y
|
||||
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
|
||||
CONFIG_HAVE_PROC_CPU=y
|
||||
CONFIG_HAVE_RCU_TABLE_FREE=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
CONFIG_HAVE_RSEQ=y
|
||||
CONFIG_HAVE_SMP=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_UID16=y
|
||||
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
|
||||
CONFIG_HIGHMEM=y
|
||||
CONFIG_HIGHPTE=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
# CONFIG_HUGETLBFS is not set
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_HZ_FIXED=0
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
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_KASAN_STACK=1
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_LOCK_SPIN_ON_OWNER=y
|
||||
CONFIG_LOGO=y
|
||||
CONFIG_LOGO_LINUX_CLUT224=y
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_MAILBOX=y
|
||||
# CONFIG_MAILBOX_TEST is not set
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
CONFIG_MDIO_BCM_UNIMAC=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_LOCHNAGAR is not set
|
||||
# CONFIG_MFD_ROHM_BD70528 is not set
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
# CONFIG_MFD_STPMIC1 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_MMC_TIFM_SD is not set
|
||||
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_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
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_RESERVED_MEM=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_BW is not set
|
||||
CONFIG_PCIE_PME=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
# CONFIG_PCI_MESON is not set
|
||||
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_DEBUG is not set
|
||||
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_REFCOUNT_FULL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_REGULATOR_GPIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS is not set
|
||||
CONFIG_SERIAL_8250_BCM2835AUX=y
|
||||
# CONFIG_SERIAL_8250_DMA is not set
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_FSL=y
|
||||
CONFIG_SERIAL_8250_NR_UARTS=1
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=0
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
CONFIG_SERIAL_DEV_BUS=y
|
||||
# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SMP_ON_UP=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_THUMB2_KERNEL is not set
|
||||
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_TRUSTED_FOUNDATIONS is not set
|
||||
CONFIG_UBSAN_ALIGNMENT=y
|
||||
CONFIG_UEVENT_HELPER_PATH=""
|
||||
# CONFIG_UID16 is not set
|
||||
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
|
||||
CONFIG_UNIX_SCM=y
|
||||
CONFIG_UNWINDER_ARM=y
|
||||
# CONFIG_UNWINDER_FRAME_POINTER is not set
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_DWCOTG=y
|
||||
# CONFIG_USB_EHCI_HCD is not set
|
||||
CONFIG_USB_LAN78XX=y
|
||||
CONFIG_USB_NET_DRIVERS=y
|
||||
CONFIG_USB_NET_SMSC95XX=y
|
||||
CONFIG_USB_PCI=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
|
|
@ -0,0 +1,622 @@
|
|||
CONFIG_64BIT=y
|
||||
CONFIG_64BIT_TIME=y
|
||||
# CONFIG_AIO is not set
|
||||
# CONFIG_ARCH_AGILEX is not set
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
# CONFIG_ARCH_BITMAIN is not set
|
||||
CONFIG_ARCH_CLOCKSOURCE_DATA=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
|
||||
CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y
|
||||
CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y
|
||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
||||
CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
|
||||
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
|
||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
|
||||
CONFIG_ARCH_HAS_KCOV=y
|
||||
CONFIG_ARCH_HAS_KEEPINITRD=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
CONFIG_ARCH_HAS_PTE_DEVMAP=y
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_ARCH_HAS_SETUP_DMA_OPS=y
|
||||
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y
|
||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y
|
||||
CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
|
||||
CONFIG_ARCH_HAS_TICK_BROADCAST=y
|
||||
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y
|
||||
CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y
|
||||
CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
CONFIG_ARCH_MMAP_RND_BITS=18
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MAX=24
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MIN=18
|
||||
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
|
||||
CONFIG_ARCH_PROC_KCORE_TEXT=y
|
||||
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
|
||||
CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
||||
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
|
||||
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
||||
CONFIG_ARCH_SUPPORTS_INT128=y
|
||||
CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
|
||||
CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
|
||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
|
||||
CONFIG_ARCH_USE_MEMREMAP_PROT=y
|
||||
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
|
||||
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
|
||||
CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
|
||||
CONFIG_ARCH_WANT_FRAME_POINTERS=y
|
||||
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
|
||||
CONFIG_ARM64=y
|
||||
# CONFIG_ARM64_16K_PAGES is not set
|
||||
CONFIG_ARM64_4K_PAGES=y
|
||||
# CONFIG_ARM64_64K_PAGES is not set
|
||||
CONFIG_ARM64_CNP=y
|
||||
CONFIG_ARM64_CONT_SHIFT=4
|
||||
# CONFIG_ARM64_CRYPTO is not set
|
||||
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_PMEM is not set
|
||||
# CONFIG_ARM64_PSEUDO_NMI is not set
|
||||
# CONFIG_ARM64_PTDUMP_DEBUGFS is not set
|
||||
CONFIG_ARM64_PTR_AUTH=y
|
||||
# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
|
||||
CONFIG_ARM64_SSBD=y
|
||||
CONFIG_ARM64_SVE=y
|
||||
CONFIG_ARM64_TAGGED_ADDR_ABI=y
|
||||
CONFIG_ARM64_UAO=y
|
||||
CONFIG_ARM64_VA_BITS=39
|
||||
CONFIG_ARM64_VA_BITS_39=y
|
||||
# CONFIG_ARM64_VA_BITS_48 is not set
|
||||
CONFIG_ARM64_VHE=y
|
||||
CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
|
||||
CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
|
||||
# CONFIG_ARM_BCM2835_CPUFREQ is not set
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_GIC_V2M=y
|
||||
CONFIG_ARM_GIC_V3=y
|
||||
CONFIG_ARM_GIC_V3_ITS=y
|
||||
CONFIG_ARM_GIC_V3_ITS_PCI=y
|
||||
# CONFIG_ARM_PSCI_CPUIDLE is not set
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
|
||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SP805_WATCHDOG is not set
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BCM2708_VCMEM=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_VCHIQ=y
|
||||
# CONFIG_BCM2835_VCHIQ_MMAL is not set
|
||||
CONFIG_BCM2835_WDT=y
|
||||
CONFIG_BCM_VCIO=y
|
||||
# CONFIG_BCM_VC_SM is not set
|
||||
# CONFIG_BCM_VC_SM_CMA is not set
|
||||
CONFIG_BCM_VIDEOCORE=y
|
||||
# CONFIG_BLK_DEV_INITRD is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_COUNT=16
|
||||
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BLK_MQ_PCI=y
|
||||
CONFIG_BLK_PM=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BRCMSTB_THERMAL=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_HAS_KASAN_GENERIC=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLK_BCM2835=y
|
||||
CONFIG_CLK_RASPBERRYPI=y
|
||||
CONFIG_CLONE_BACKWARDS=y
|
||||
CONFIG_CMA=y
|
||||
CONFIG_CMA_ALIGNMENT=8
|
||||
CONFIG_CMA_AREAS=7
|
||||
# CONFIG_CMA_DEBUG is not set
|
||||
# CONFIG_CMA_DEBUGFS is not set
|
||||
CONFIG_CMA_SIZE_MBYTES=5
|
||||
# CONFIG_CMA_SIZE_SEL_MAX is not set
|
||||
CONFIG_CMA_SIZE_SEL_MBYTES=y
|
||||
# CONFIG_CMA_SIZE_SEL_MIN is not set
|
||||
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_COMMON_CLK_XGENE=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||
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_HOTPLUG_STATE_CONTROL is not set
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
# CONFIG_CPU_IDLE_GOV_TEO is not set
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
# CONFIG_CPU_THERMAL is not set
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_AEAD=y
|
||||
CONFIG_CRYPTO_AEAD2=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_CTR=y
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
CONFIG_CRYPTO_DRBG_MENU=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_JITTERENTROPY=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
CONFIG_CRYPTO_SEQIV=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_DECLARE_COHERENT=y
|
||||
CONFIG_DMA_DIRECT_REMAP=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_REMAP=y
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_DRM_RCAR_WRITEBACK=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_EFI_EARLYCON=y
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
# CONFIG_ENERGY_MODEL is not set
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
# CONFIG_F2FS_CHECK_FS is not set
|
||||
CONFIG_F2FS_FS=y
|
||||
# CONFIG_F2FS_FS_SECURITY is not set
|
||||
CONFIG_F2FS_FS_XATTR=y
|
||||
CONFIG_F2FS_STAT_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_FONTS is not set
|
||||
CONFIG_FONT_8x16=y
|
||||
CONFIG_FONT_8x8=y
|
||||
CONFIG_FONT_SUPPORT=y
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_FREEZER=y
|
||||
CONFIG_FSL_ERRATUM_A008585=y
|
||||
# CONFIG_FSL_QDMA is not set
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_FUJITSU_ERRATUM_010001=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_GENERIC_ALLOCATOR=y
|
||||
CONFIG_GENERIC_ARCH_TOPOLOGY=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_CPU_VULNERABILITIES=y
|
||||
CONFIG_GENERIC_CSUM=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
|
||||
CONFIG_GENERIC_IRQ_MIGRATION=y
|
||||
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_GENERIC_PCI_IOMAP=y
|
||||
CONFIG_GENERIC_PINCONF=y
|
||||
CONFIG_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
|
||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||
CONFIG_GENERIC_STRNLEN_USER=y
|
||||
CONFIG_GENERIC_TIME_VSYSCALL=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
CONFIG_GPIO_BCM_VIRT=y
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
# CONFIG_GVE is not set
|
||||
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_ALIGNED_STRUCT_PAGE=y
|
||||
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
|
||||
CONFIG_HAVE_ARCH_BITREVERSE=y
|
||||
CONFIG_HAVE_ARCH_HUGE_VMAP=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
|
||||
CONFIG_HAVE_ARCH_KASAN=y
|
||||
CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_ARCH_PFN_VALID=y
|
||||
CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
|
||||
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
|
||||
CONFIG_HAVE_ARCH_STACKLEAK=y
|
||||
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
|
||||
CONFIG_HAVE_ARCH_VMAP_STACK=y
|
||||
CONFIG_HAVE_ARM_SMCCC=y
|
||||
CONFIG_HAVE_ASM_MODVERSIONS=y
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_HAVE_CMPXCHG_DOUBLE=y
|
||||
CONFIG_HAVE_CMPXCHG_LOCAL=y
|
||||
CONFIG_HAVE_CONTEXT_TRACKING=y
|
||||
CONFIG_HAVE_COPY_THREAD_TLS=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
|
||||
CONFIG_HAVE_FAST_GUP=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
|
||||
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_GENERIC_VDSO=y
|
||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
||||
CONFIG_HAVE_MEMORY_PRESENT=y
|
||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
CONFIG_HAVE_PATA_PLATFORM=y
|
||||
CONFIG_HAVE_PCI=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HAVE_PERF_REGS=y
|
||||
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
|
||||
CONFIG_HAVE_RCU_TABLE_FREE=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
CONFIG_HAVE_RSEQ=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
|
||||
CONFIG_HOLES_IN_ZONE=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
# CONFIG_HUGETLBFS is not set
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
CONFIG_INLINE_READ_LOCK=y
|
||||
CONFIG_INLINE_READ_LOCK_BH=y
|
||||
CONFIG_INLINE_READ_LOCK_IRQ=y
|
||||
CONFIG_INLINE_READ_LOCK_IRQSAVE=y
|
||||
CONFIG_INLINE_READ_UNLOCK_BH=y
|
||||
CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_INLINE_SPIN_LOCK=y
|
||||
CONFIG_INLINE_SPIN_LOCK_BH=y
|
||||
CONFIG_INLINE_SPIN_LOCK_IRQ=y
|
||||
CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y
|
||||
CONFIG_INLINE_SPIN_TRYLOCK=y
|
||||
CONFIG_INLINE_SPIN_TRYLOCK_BH=y
|
||||
CONFIG_INLINE_SPIN_UNLOCK_BH=y
|
||||
CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_INLINE_WRITE_LOCK=y
|
||||
CONFIG_INLINE_WRITE_LOCK_BH=y
|
||||
CONFIG_INLINE_WRITE_LOCK_IRQ=y
|
||||
CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y
|
||||
CONFIG_INLINE_WRITE_UNLOCK_BH=y
|
||||
CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_INPUT=y
|
||||
CONFIG_INPUT_MOUSEDEV=y
|
||||
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
|
||||
# CONFIG_IONIC is not set
|
||||
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_KASAN_STACK=1
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_LOCK_SPIN_ON_OWNER=y
|
||||
CONFIG_LOGO=y
|
||||
CONFIG_LOGO_LINUX_CLUT224=y
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_MAILBOX=y
|
||||
# CONFIG_MAILBOX_TEST is not set
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
# CONFIG_MEMORY_HOTPLUG is not set
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_LOCHNAGAR is not set
|
||||
# CONFIG_MFD_ROHM_BD70528 is not set
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
# CONFIG_MFD_STPMIC1 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_MMC_TIFM_SD is not set
|
||||
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_NUMA is not set
|
||||
CONFIG_NVMEM=y
|
||||
# CONFIG_NVMEM_REBOOT_MODE is not set
|
||||
# CONFIG_OCTEONTX2_AF 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_RESERVED_MEM=y
|
||||
CONFIG_OF_RESOLVE=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PARTITION_PERCPU=y
|
||||
CONFIG_PCI=y
|
||||
# CONFIG_PCIE_AL is not set
|
||||
# CONFIG_PCIE_BRCMSTB is not set
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
# CONFIG_PCI_MESON is not set
|
||||
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_DEBUG is not set
|
||||
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_RANDOMIZE_BASE is not set
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_RCU_NEED_SEGCBLIST=y
|
||||
CONFIG_RCU_STALL_COMMON=y
|
||||
CONFIG_REFCOUNT_FULL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_REGULATOR_GPIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS is not set
|
||||
CONFIG_SERIAL_8250_BCM2835AUX=y
|
||||
# CONFIG_SERIAL_8250_DMA is not set
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_FSL=y
|
||||
CONFIG_SERIAL_8250_NR_UARTS=1
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=0
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
CONFIG_SERIAL_DEV_BUS=y
|
||||
# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SPARSEMEM=y
|
||||
CONFIG_SPARSEMEM_EXTREME=y
|
||||
CONFIG_SPARSEMEM_MANUAL=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=y
|
||||
CONFIG_SWIOTLB=y
|
||||
CONFIG_SWPHY=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
CONFIG_SYS_SUPPORTS_HUGETLBFS=y
|
||||
# CONFIG_TEXTSEARCH is not set
|
||||
CONFIG_THERMAL=y
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_OF=y
|
||||
CONFIG_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_UBSAN_ALIGNMENT=y
|
||||
CONFIG_UEVENT_HELPER_PATH=""
|
||||
CONFIG_UNIX_SCM=y
|
||||
CONFIG_UNMAP_KERNEL_AT_EL0=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_DWCOTG=y
|
||||
# CONFIG_USB_EHCI_HCD is not set
|
||||
CONFIG_USB_LAN78XX=y
|
||||
CONFIG_USB_NET_DRIVERS=y
|
||||
CONFIG_USB_NET_SMSC95XX=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_USB_UAS=y
|
||||
CONFIG_USB_USBNET=y
|
||||
CONFIG_VMAP_STACK=y
|
||||
CONFIG_VT=y
|
||||
CONFIG_VT_CONSOLE=y
|
||||
CONFIG_VT_CONSOLE_SLEEP=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_XPS=y
|
||||
CONFIG_XZ_DEC_ARM=y
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
CONFIG_ZONE_DMA32=y
|
|
@ -0,0 +1,634 @@
|
|||
CONFIG_64BIT=y
|
||||
CONFIG_64BIT_TIME=y
|
||||
# CONFIG_AIO is not set
|
||||
# CONFIG_ARCH_AGILEX is not set
|
||||
CONFIG_ARCH_BCM2835=y
|
||||
# CONFIG_ARCH_BITMAIN is not set
|
||||
CONFIG_ARCH_CLOCKSOURCE_DATA=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
|
||||
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
|
||||
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
|
||||
CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y
|
||||
CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y
|
||||
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
||||
CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
|
||||
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
|
||||
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
|
||||
CONFIG_ARCH_HAS_KCOV=y
|
||||
CONFIG_ARCH_HAS_KEEPINITRD=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
CONFIG_ARCH_HAS_PTE_DEVMAP=y
|
||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||
CONFIG_ARCH_HAS_SETUP_DMA_OPS=y
|
||||
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
|
||||
CONFIG_ARCH_HAS_SET_MEMORY=y
|
||||
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
||||
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y
|
||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y
|
||||
CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
|
||||
CONFIG_ARCH_HAS_TICK_BROADCAST=y
|
||||
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y
|
||||
CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y
|
||||
CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y
|
||||
CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
CONFIG_ARCH_MMAP_RND_BITS=18
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MAX=24
|
||||
CONFIG_ARCH_MMAP_RND_BITS_MIN=18
|
||||
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
|
||||
CONFIG_ARCH_PROC_KCORE_TEXT=y
|
||||
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
|
||||
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
|
||||
CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
||||
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
|
||||
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
||||
CONFIG_ARCH_SUPPORTS_INT128=y
|
||||
CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
|
||||
CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
|
||||
CONFIG_ARCH_SUPPORTS_UPROBES=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
|
||||
CONFIG_ARCH_USE_MEMREMAP_PROT=y
|
||||
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
|
||||
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
|
||||
CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
|
||||
CONFIG_ARCH_WANT_FRAME_POINTERS=y
|
||||
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
|
||||
CONFIG_ARM64=y
|
||||
# CONFIG_ARM64_16K_PAGES is not set
|
||||
CONFIG_ARM64_4K_PAGES=y
|
||||
# CONFIG_ARM64_64K_PAGES is not set
|
||||
CONFIG_ARM64_CNP=y
|
||||
CONFIG_ARM64_CONT_SHIFT=4
|
||||
# CONFIG_ARM64_CRYPTO is not set
|
||||
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_PMEM is not set
|
||||
# CONFIG_ARM64_PSEUDO_NMI is not set
|
||||
# CONFIG_ARM64_PTDUMP_DEBUGFS is not set
|
||||
CONFIG_ARM64_PTR_AUTH=y
|
||||
# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
|
||||
CONFIG_ARM64_SSBD=y
|
||||
CONFIG_ARM64_SVE=y
|
||||
CONFIG_ARM64_TAGGED_ADDR_ABI=y
|
||||
CONFIG_ARM64_UAO=y
|
||||
CONFIG_ARM64_VA_BITS=39
|
||||
CONFIG_ARM64_VA_BITS_39=y
|
||||
# CONFIG_ARM64_VA_BITS_48 is not set
|
||||
CONFIG_ARM64_VHE=y
|
||||
CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y
|
||||
CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
|
||||
CONFIG_ARM_AMBA=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y
|
||||
# CONFIG_ARM_BCM2835_CPUFREQ is not set
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_GIC_V2M=y
|
||||
CONFIG_ARM_GIC_V3=y
|
||||
CONFIG_ARM_GIC_V3_ITS=y
|
||||
CONFIG_ARM_GIC_V3_ITS_PCI=y
|
||||
# CONFIG_ARM_PSCI_CPUIDLE is not set
|
||||
CONFIG_ARM_PSCI_FW=y
|
||||
CONFIG_ARM_RASPBERRYPI_CPUFREQ=y
|
||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||
# CONFIG_ARM_SP805_WATCHDOG is not set
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
# CONFIG_BCM2835_THERMAL is not set
|
||||
CONFIG_BCM2835_VCHIQ=y
|
||||
# CONFIG_BCM2835_VCHIQ_MMAL is not set
|
||||
CONFIG_BCM2835_WDT=y
|
||||
CONFIG_BCM7XXX_PHY=y
|
||||
CONFIG_BCMGENET=y
|
||||
CONFIG_BCM_NET_PHYLIB=y
|
||||
CONFIG_BCM_VCIO=y
|
||||
# CONFIG_BCM_VC_SM is not set
|
||||
# CONFIG_BCM_VC_SM_CMA is not set
|
||||
CONFIG_BCM_VIDEOCORE=y
|
||||
# CONFIG_BLK_DEV_INITRD is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_COUNT=16
|
||||
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BLK_MQ_PCI=y
|
||||
CONFIG_BLK_PM=y
|
||||
CONFIG_BLK_SCSI_REQUEST=y
|
||||
CONFIG_BRCMSTB_THERMAL=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_HAS_KASAN_GENERIC=y
|
||||
CONFIG_CLKDEV_LOOKUP=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_CLK_BCM2835=y
|
||||
CONFIG_CLK_RASPBERRYPI=y
|
||||
CONFIG_CLONE_BACKWARDS=y
|
||||
CONFIG_CMA=y
|
||||
CONFIG_CMA_ALIGNMENT=8
|
||||
CONFIG_CMA_AREAS=7
|
||||
# CONFIG_CMA_DEBUG is not set
|
||||
# CONFIG_CMA_DEBUGFS is not set
|
||||
CONFIG_CMA_SIZE_MBYTES=5
|
||||
# CONFIG_CMA_SIZE_SEL_MAX is not set
|
||||
CONFIG_CMA_SIZE_SEL_MBYTES=y
|
||||
# CONFIG_CMA_SIZE_SEL_MIN is not set
|
||||
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_COMMON_CLK_XGENE=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
CONFIG_CONTIG_ALLOC=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||
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_HOTPLUG_STATE_CONTROL is not set
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_CPU_IDLE_GOV_LADDER=y
|
||||
CONFIG_CPU_IDLE_GOV_MENU=y
|
||||
# CONFIG_CPU_IDLE_GOV_TEO is not set
|
||||
CONFIG_CPU_PM=y
|
||||
CONFIG_CPU_RMAP=y
|
||||
# CONFIG_CPU_THERMAL is not set
|
||||
CONFIG_CRC16=y
|
||||
CONFIG_CRYPTO_AEAD=y
|
||||
CONFIG_CRYPTO_AEAD2=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CRC32=y
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_CTR=y
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_DRBG=y
|
||||
CONFIG_CRYPTO_DRBG_HMAC=y
|
||||
CONFIG_CRYPTO_DRBG_MENU=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_HASH=y
|
||||
CONFIG_CRYPTO_HASH2=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_JITTERENTROPY=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
CONFIG_CRYPTO_SEQIV=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DIMLIB=y
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
CONFIG_DMA_BCM2835=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DMA_DECLARE_COHERENT=y
|
||||
CONFIG_DMA_DIRECT_REMAP=y
|
||||
CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_OF=y
|
||||
CONFIG_DMA_REMAP=y
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_DRM_RCAR_WRITEBACK=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
CONFIG_EDAC_SUPPORT=y
|
||||
CONFIG_EFI_EARLYCON=y
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
# CONFIG_ENERGY_MODEL is not set
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
# CONFIG_F2FS_CHECK_FS is not set
|
||||
CONFIG_F2FS_FS=y
|
||||
# CONFIG_F2FS_FS_SECURITY is not set
|
||||
CONFIG_F2FS_FS_XATTR=y
|
||||
CONFIG_F2FS_STAT_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_FONTS is not set
|
||||
CONFIG_FONT_8x16=y
|
||||
CONFIG_FONT_8x8=y
|
||||
CONFIG_FONT_SUPPORT=y
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
|
||||
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_FREEZER=y
|
||||
CONFIG_FSL_ERRATUM_A008585=y
|
||||
# CONFIG_FSL_QDMA is not set
|
||||
CONFIG_FS_ENCRYPTION=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_MBCACHE=y
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_FUJITSU_ERRATUM_010001=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_GENERIC_ALLOCATOR=y
|
||||
CONFIG_GENERIC_ARCH_TOPOLOGY=y
|
||||
CONFIG_GENERIC_BUG=y
|
||||
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_CPU_VULNERABILITIES=y
|
||||
CONFIG_GENERIC_CSUM=y
|
||||
CONFIG_GENERIC_EARLY_IOREMAP=y
|
||||
CONFIG_GENERIC_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
|
||||
CONFIG_GENERIC_IRQ_MIGRATION=y
|
||||
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_GENERIC_PCI_IOMAP=y
|
||||
CONFIG_GENERIC_PHY=y
|
||||
CONFIG_GENERIC_PINCONF=y
|
||||
CONFIG_GENERIC_PINCTRL_GROUPS=y
|
||||
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
|
||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||
CONFIG_GENERIC_STRNLEN_USER=y
|
||||
CONFIG_GENERIC_TIME_VSYSCALL=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIOLIB_IRQCHIP=y
|
||||
CONFIG_GPIO_BCM_VIRT=y
|
||||
CONFIG_GPIO_RASPBERRYPI_EXP=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
# CONFIG_GVE is not set
|
||||
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_ALIGNED_STRUCT_PAGE=y
|
||||
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
|
||||
CONFIG_HAVE_ARCH_BITREVERSE=y
|
||||
CONFIG_HAVE_ARCH_HUGE_VMAP=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
|
||||
CONFIG_HAVE_ARCH_KASAN=y
|
||||
CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_ARCH_PFN_VALID=y
|
||||
CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
|
||||
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
|
||||
CONFIG_HAVE_ARCH_STACKLEAK=y
|
||||
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
|
||||
CONFIG_HAVE_ARCH_VMAP_STACK=y
|
||||
CONFIG_HAVE_ARM_SMCCC=y
|
||||
CONFIG_HAVE_ASM_MODVERSIONS=y
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_HAVE_CLK_PREPARE=y
|
||||
CONFIG_HAVE_CMPXCHG_DOUBLE=y
|
||||
CONFIG_HAVE_CMPXCHG_LOCAL=y
|
||||
CONFIG_HAVE_CONTEXT_TRACKING=y
|
||||
CONFIG_HAVE_COPY_THREAD_TLS=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_EBPF_JIT=y
|
||||
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
|
||||
CONFIG_HAVE_FAST_GUP=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
|
||||
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_GENERIC_VDSO=y
|
||||
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
||||
CONFIG_HAVE_MEMORY_PRESENT=y
|
||||
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
||||
CONFIG_HAVE_NET_DSA=y
|
||||
CONFIG_HAVE_PATA_PLATFORM=y
|
||||
CONFIG_HAVE_PCI=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HAVE_PERF_REGS=y
|
||||
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
|
||||
CONFIG_HAVE_RCU_TABLE_FREE=y
|
||||
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||
CONFIG_HAVE_RSEQ=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
|
||||
CONFIG_HOLES_IN_ZONE=y
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
# CONFIG_HUGETLBFS is not set
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_I2C_BCM2708 is not set
|
||||
CONFIG_I2C_BOARDINFO=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||
CONFIG_INLINE_READ_LOCK=y
|
||||
CONFIG_INLINE_READ_LOCK_BH=y
|
||||
CONFIG_INLINE_READ_LOCK_IRQ=y
|
||||
CONFIG_INLINE_READ_LOCK_IRQSAVE=y
|
||||
CONFIG_INLINE_READ_UNLOCK_BH=y
|
||||
CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_INLINE_SPIN_LOCK=y
|
||||
CONFIG_INLINE_SPIN_LOCK_BH=y
|
||||
CONFIG_INLINE_SPIN_LOCK_IRQ=y
|
||||
CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y
|
||||
CONFIG_INLINE_SPIN_TRYLOCK=y
|
||||
CONFIG_INLINE_SPIN_TRYLOCK_BH=y
|
||||
CONFIG_INLINE_SPIN_UNLOCK_BH=y
|
||||
CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_INLINE_WRITE_LOCK=y
|
||||
CONFIG_INLINE_WRITE_LOCK_BH=y
|
||||
CONFIG_INLINE_WRITE_LOCK_IRQ=y
|
||||
CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y
|
||||
CONFIG_INLINE_WRITE_UNLOCK_BH=y
|
||||
CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y
|
||||
CONFIG_INPUT=y
|
||||
CONFIG_INPUT_MOUSEDEV=y
|
||||
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
|
||||
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
|
||||
# CONFIG_IONIC is not set
|
||||
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_KASAN_STACK=1
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_LEDS_TRIGGER_INPUT=y
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_LOCK_SPIN_ON_OWNER=y
|
||||
CONFIG_LOGO=y
|
||||
CONFIG_LOGO_LINUX_CLUT224=y
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_MAILBOX=y
|
||||
# CONFIG_MAILBOX_TEST is not set
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
CONFIG_MDIO_BCM_UNIMAC=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
# CONFIG_MEMORY_HOTPLUG is not set
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_LOCHNAGAR is not set
|
||||
# CONFIG_MFD_ROHM_BD70528 is not set
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
# CONFIG_MFD_STPMIC1 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_MMC_TIFM_SD is not set
|
||||
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_NUMA is not set
|
||||
CONFIG_NVMEM=y
|
||||
# CONFIG_NVMEM_REBOOT_MODE is not set
|
||||
# CONFIG_OCTEONTX2_AF 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_RESERVED_MEM=y
|
||||
CONFIG_OF_RESOLVE=y
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PARTITION_PERCPU=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCIEAER=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
# CONFIG_PCIE_AL is not set
|
||||
CONFIG_PCIE_BRCMSTB=y
|
||||
# CONFIG_PCIE_BW is not set
|
||||
CONFIG_PCIE_PME=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PCI_DOMAINS_GENERIC=y
|
||||
# CONFIG_PCI_MESON is not set
|
||||
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_DEBUG is not set
|
||||
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_RANDOMIZE_BASE is not set
|
||||
CONFIG_RAS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_RCU_NEED_SEGCBLIST=y
|
||||
CONFIG_RCU_STALL_COMMON=y
|
||||
CONFIG_REFCOUNT_FULL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
CONFIG_REGULATOR_GPIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
|
||||
# CONFIG_RPIVID_MEM is not set
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_PROC_FS is not set
|
||||
CONFIG_SERIAL_8250_BCM2835AUX=y
|
||||
# CONFIG_SERIAL_8250_DMA is not set
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_FSL=y
|
||||
CONFIG_SERIAL_8250_NR_UARTS=1
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=0
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
CONFIG_SERIAL_DEV_BUS=y
|
||||
# CONFIG_SERIAL_DEV_CTRL_TTYPORT is not set
|
||||
CONFIG_SERIAL_MCTRL_GPIO=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SPARSEMEM=y
|
||||
CONFIG_SPARSEMEM_EXTREME=y
|
||||
CONFIG_SPARSEMEM_MANUAL=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP=y
|
||||
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_SUSPEND_FREEZER=y
|
||||
CONFIG_SWIOTLB=y
|
||||
CONFIG_SWPHY=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
CONFIG_SYS_SUPPORTS_HUGETLBFS=y
|
||||
# CONFIG_TEXTSEARCH is not set
|
||||
CONFIG_THERMAL=y
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_OF=y
|
||||
CONFIG_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_UBSAN_ALIGNMENT=y
|
||||
CONFIG_UEVENT_HELPER_PATH=""
|
||||
CONFIG_UNIX_SCM=y
|
||||
CONFIG_UNMAP_KERNEL_AT_EL0=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_COMMON=y
|
||||
CONFIG_USB_DWCOTG=y
|
||||
# CONFIG_USB_EHCI_HCD is not set
|
||||
CONFIG_USB_PCI=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_USB_UAS=y
|
||||
# CONFIG_USB_UHCI_HCD is not set
|
||||
CONFIG_USB_XHCI_HCD=y
|
||||
CONFIG_USB_XHCI_PCI=y
|
||||
CONFIG_USB_XHCI_PLATFORM=y
|
||||
CONFIG_VMAP_STACK=y
|
||||
CONFIG_VT=y
|
||||
CONFIG_VT_CONSOLE=y
|
||||
CONFIG_VT_CONSOLE_SLEEP=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_WATCHDOG_CORE=y
|
||||
CONFIG_XPS=y
|
||||
CONFIG_XZ_DEC_ARM=y
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
CONFIG_ZONE_DMA32=y
|
|
@ -0,0 +1,99 @@
|
|||
From 74ff908650ed96eac907178fb5888f967cefb282 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
|
||||
@@ -335,6 +335,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
|
|
@ -0,0 +1,56 @@
|
|||
From c5bb7a9c84494071bbed123af04556f6bc76c56f 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
|
||||
@@ -209,8 +209,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, ®s[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);
|
||||
@@ -246,7 +266,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);
|
|
@ -0,0 +1,47 @@
|
|||
From bb137167247980c89005d607e5e89417f8f59634 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
|
||||
@@ -70,6 +70,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)
|
||||
{
|
||||
@@ -1957,7 +1961,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;
|
||||
}
|
||||
@@ -1975,7 +1980,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);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
From e8d276834dcea140cc65b31ec2ac48783c09f0d2 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
|
||||
@@ -74,6 +74,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)
|
||||
{
|
||||
@@ -1095,13 +1099,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",
|
|
@ -0,0 +1,96 @@
|
|||
From 72c3c77ff3338b2302025dd5e851b4ba737c8979 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
|
||||
@@ -48,6 +48,7 @@
|
||||
#define SUSPEND_SUSPEND3 (0x08)
|
||||
#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
|
||||
SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
|
||||
+#define MAC_ADDR_LEN (6)
|
||||
|
||||
#define CARRIER_CHECK_DELAY (2 * HZ)
|
||||
|
||||
@@ -78,6 +79,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)
|
||||
{
|
||||
@@ -907,6 +912,53 @@ static int smsc95xx_ioctl(struct net_dev
|
||||
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
|
||||
}
|
||||
|
||||
+/* 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)
|
||||
{
|
||||
const u8 *mac_addr;
|
||||
@@ -928,6 +980,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");
|
|
@ -0,0 +1,28 @@
|
|||
From f60fc28e618bb4830dc626435d45169b9c659311 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;
|
|
@ -0,0 +1,27 @@
|
|||
From 7e33284486a91fe400505003f49f50f496b906a7 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 4 Dec 2015 17:41:50 +0000
|
||||
Subject: [PATCH] irq-bcm2836: Prevent spurious interrupts, and trap
|
||||
them early
|
||||
|
||||
The old arch-specific IRQ macros included a dsb to ensure the
|
||||
write to clear the mailbox interrupt completed before returning
|
||||
from the interrupt. The BCM2836 irqchip driver needs the same
|
||||
precaution to avoid spurious interrupts.
|
||||
|
||||
Spurious interrupts are still possible for other reasons,
|
||||
though, so trap them early.
|
||||
---
|
||||
drivers/irqchip/irq-bcm2836.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/irqchip/irq-bcm2836.c
|
||||
+++ b/drivers/irqchip/irq-bcm2836.c
|
||||
@@ -135,6 +135,7 @@ __exception_irq_entry bcm2836_arm_irqchi
|
||||
u32 ipi = ffs(mbox_val) - 1;
|
||||
|
||||
writel(1 << ipi, mailbox0);
|
||||
+ dsb(sy);
|
||||
handle_IPI(ipi, regs);
|
||||
#endif
|
||||
} else if (stat) {
|
|
@ -0,0 +1,24 @@
|
|||
From 3588e218af8258a6ea86c37c6c65e6761461302a 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
|
||||
@@ -115,7 +115,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;
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
From 6265a10a86d09fb1b1240655dd56e9bfa0df3e07 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
|
||||
@@ -165,6 +165,7 @@ config ARCH_BCM2835
|
||||
select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
|
||||
select TIMER_OF
|
||||
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)
|
||||
|
||||
@@ -61,9 +61,13 @@
|
||||
| SHORTCUT1_MASK | SHORTCUT2_MASK)
|
||||
|
||||
#define REG_FIQ_CONTROL 0x0c
|
||||
+#define REG_FIQ_ENABLE 0x80
|
||||
+#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 };
|
||||
@@ -88,14 +92,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 = {
|
||||
@@ -140,8 +168,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);
|
||||
|
||||
@@ -171,6 +200,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;
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
From 42c41d1381e50a2b4378401c1e4e1a4d1f506d8a 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 REG_FIQ_ENABLE 0x80
|
||||
#define REG_FIQ_DISABLE 0
|
||||
@@ -85,6 +91,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;
|
||||
@@ -118,12 +125,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 = {
|
||||
@@ -200,6 +230,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++) {
|
|
@ -0,0 +1,24 @@
|
|||
From f828923b460216a0b6bb0b12879731f4b336c3db 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
|
||||
@@ -724,7 +724,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);
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
From 9a111b4b03340341604941cb7611a2b1d16e8edd 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
|
||||
@@ -133,7 +133,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
|
||||
@@ -912,6 +914,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;
|
||||
|
||||
@@ -957,6 +962,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 */
|
||||
@@ -1031,6 +1039,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);
|
||||
|
||||
@@ -1046,7 +1055,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");
|
|
@ -0,0 +1,27 @@
|
|||
From 451f9c888e9728142832b3acb2df16bda63366ce 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__ */
|
|
@ -0,0 +1,20 @@
|
|||
From 9f03ab46c12226255c6c1fb7c715a60cb52c3b23 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");
|
|
@ -0,0 +1,102 @@
|
|||
From 46c30599f994d0d1db25b9f71bd6b24ae80c1a7c 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)
|
|
@ -0,0 +1,23 @@
|
|||
From f2a746939f1e1257d8c85c25a745627cfa7c97d9 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();
|
||||
}
|
||||
|
||||
/*
|
|
@ -0,0 +1,19 @@
|
|||
From 7a51bd86a5883312dd8f3f6c6cca8d95e414b22e 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
|
|
@ -0,0 +1,45 @@
|
|||
From fe4c14f1d934801361e9c9e2456f8250af2fffbd 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
|
||||
@@ -2248,8 +2248,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 = {
|
||||
@@ -2275,7 +2282,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");
|
|
@ -0,0 +1,25 @@
|
|||
From 5cf8059baa23779d979bcd8febe5ed4670e58fe3 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;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
From a50ed3cb374d57704b9a4706608b98d8c0ba3eb9 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
|
||||
@@ -1363,6 +1363,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 = data;
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
From b7c3fda0df5da90e87b037348c6d27f669c38388 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 | 34 ++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 32 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -1295,6 +1295,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 struct bcm2835_pll_data *data)
|
||||
{
|
||||
@@ -1311,6 +1313,9 @@ static struct clk_hw *bcm2835_register_p
|
||||
init.ops = &bcm2835_pll_clk_ops;
|
||||
init.flags = CLK_IGNORE_UNUSED;
|
||||
|
||||
+ if (!bcm2835_clk_is_claimed(data->name))
|
||||
+ init.flags |= CLK_IS_CRITICAL;
|
||||
+
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return NULL;
|
||||
@@ -1364,8 +1369,10 @@ bcm2835_register_pll_divider(struct bcm2
|
||||
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 (!bcm2835_clk_is_claimed(data->source_pll))
|
||||
+ init.flags |= CLK_IS_CRITICAL;
|
||||
+ if (!bcm2835_clk_is_claimed(data->name))
|
||||
+ divider->div.flags |= CLK_IS_CRITICAL;
|
||||
}
|
||||
|
||||
divider->cprman = cprman;
|
||||
@@ -2173,6 +2180,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.
|
||||
*
|
||||
@@ -2192,6 +2201,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;
|
||||
@@ -2202,6 +2224,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);
|
||||
@@ -2221,6 +2244,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,
|
|
@ -0,0 +1,115 @@
|
|||
From 9667f053b5015bfb486e16d3c88a79b961395876 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 */
|
||||
|
||||
/*
|
||||
@@ -999,6 +1003,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;
|
||||
@@ -1287,7 +1315,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,
|
||||
@@ -2223,6 +2251,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;
|
||||
@@ -2244,6 +2273,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",
|
|
@ -0,0 +1,38 @@
|
|||
From 9eeebf9e7bb7a25a81f72c0e21793614fab49ec4 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 9 May 2016 17:28:18 -0700
|
||||
Subject: [PATCH] clk: bcm2835: Mark GPIO clocks enabled at boot as
|
||||
critical.
|
||||
|
||||
These divide off of PLLD_PER and are used for the ethernet and wifi
|
||||
PHYs source PLLs. Neither of them is currently represented by a phy
|
||||
device that would grab the clock for us.
|
||||
|
||||
This keeps other drivers from killing the networking PHYs when they
|
||||
disable their own clocks and trigger PLLD_PER's refcount going to 0.
|
||||
|
||||
v2: Skip marking as critical if they aren't on at boot.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/clk/bcm/clk-bcm2835.c | 9 +++++++++
|
||||
1 file changed, 9 insertions(+)
|
||||
|
||||
--- a/drivers/clk/bcm/clk-bcm2835.c
|
||||
+++ b/drivers/clk/bcm/clk-bcm2835.c
|
||||
@@ -1455,6 +1455,15 @@ static struct clk_hw *bcm2835_register_c
|
||||
init.flags = 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, 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.
|
||||
*/
|
|
@ -0,0 +1,35 @@
|
|||
From afabe0abad549625f731baa088c21965a970ffa7 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
|
||||
@@ -898,7 +898,7 @@ static int soc_bind_dai_link(struct snd_
|
||||
/* FIXME: we need multi CPU support in the future */
|
||||
rtd->cpu_dai = snd_soc_find_dai(dai_link->cpus);
|
||||
if (!rtd->cpu_dai) {
|
||||
- dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
|
||||
+ dev_info(card->dev, "ASoC: CPU DAI %s not registered - will retry\n",
|
||||
dai_link->cpus->dai_name);
|
||||
goto _err_defer;
|
||||
}
|
||||
@@ -909,7 +909,7 @@ static int soc_bind_dai_link(struct snd_
|
||||
for_each_link_codecs(dai_link, i, codec) {
|
||||
rtd->codec_dais[i] = snd_soc_find_dai(codec);
|
||||
if (!rtd->codec_dais[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;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
From d90a8aca4e7b01edad7f40240c1409047b55f8a3 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;
|
||||
@@ -682,7 +694,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,
|
|
@ -0,0 +1,189 @@
|
|||
From d4739fb63aa2b47132b66225cef55eb66784df13 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;
|
|
@ -0,0 +1,25 @@
|
|||
From 61db00ea52454a76345a4ee189a01bc24d97895e 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
|
||||
@@ -8477,8 +8477,6 @@ int alloc_contig_range(unsigned long sta
|
||||
|
||||
/* Make sure the range is really isolated. */
|
||||
if (test_pages_isolated(outer_start, end, false)) {
|
||||
- pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
|
||||
- __func__, outer_start, end);
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
From a9d4adcadc82cfbeea0fc32dbadd2e7792c7b7b5 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 23 Mar 2017 10:06:56 +0000
|
||||
Subject: [PATCH] ASoC: Add prompt for ICS43432 codec
|
||||
|
||||
Without a prompt string, a config setting can't be included in a
|
||||
defconfig. Give CONFIG_SND_SOC_ICS43432 a prompt so that Pi soundcards
|
||||
can use the driver.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
sound/soc/codecs/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/sound/soc/codecs/Kconfig
|
||||
+++ b/sound/soc/codecs/Kconfig
|
||||
@@ -710,7 +710,7 @@ config SND_SOC_HDAC_HDA
|
||||
select SND_HDA
|
||||
|
||||
config SND_SOC_ICS43432
|
||||
- tristate
|
||||
+ tristate "InvenSense ICS43432 I2S microphone codec"
|
||||
|
||||
config SND_SOC_INNO_RK3036
|
||||
tristate "Inno codec driver for RK3036 SoC"
|
|
@ -0,0 +1,112 @@
|
|||
From fef7d3ecae689f5f6eeb75da93f431d1a8a3200b 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>
|
||||
@@ -91,7 +89,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;
|
||||
@@ -128,24 +126,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),
|
||||
@@ -231,12 +225,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
|
||||
@@ -21,6 +21,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)
|
||||
@@ -225,6 +228,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,
|
|
@ -0,0 +1,48 @@
|
|||
From e91aa9302b0d3f9730983d0f1b168a081aab6236 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
|
||||
@@ -2465,6 +2465,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_;
|
||||
@@ -2518,6 +2523,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);
|
||||
@@ -2573,6 +2581,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);
|
|
@ -0,0 +1,29 @@
|
|||
From 803eba9a3e9a343903ebe0f6bf2ad80475736200 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
|
||||
@@ -2576,7 +2576,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;
|
|
@ -0,0 +1,86 @@
|
|||
From 409f4b56de7611d703790c54a70fad9a6e2bb161 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
|
||||
@@ -1650,6 +1650,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 =
|
||||
@@ -1666,7 +1683,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 |
|
||||
@@ -2322,7 +2339,7 @@ static int __init pl011_console_setup(st
|
||||
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;
|
||||
@@ -2507,6 +2524,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;
|
||||
@@ -2538,6 +2556,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)
|
|
@ -0,0 +1,27 @@
|
|||
From 37e06c9ed7219cf6cf08a0463f7e2b5b2c51f3e6 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
|
||||
@@ -1383,6 +1383,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;
|
|
@ -0,0 +1,50 @@
|
|||
From 2cb280484c8dde281972690cd67299005a796485 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
|
||||
@@ -100,6 +100,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
|
||||
@@ -2659,6 +2659,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);
|
|
@ -0,0 +1,22 @@
|
|||
From d91be214849b0efa6a75ce4a2d1fb469c26b416b 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
|
||||
@@ -350,7 +350,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,
|
||||
};
|
|
@ -0,0 +1,150 @@
|
|||
From 3dc766a6dbab6aeb99ed8b555fe6f59276e47f53 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
|
||||
@@ -169,6 +169,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 BCM2835 and BCM2836 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))
|
||||
@@ -71,6 +73,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 };
|
||||
@@ -238,10 +241,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
|
@ -0,0 +1,843 @@
|
|||
From 4dcb742bde0e0d11386035d9069ca23e6abc28af 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 | 467 +++++++++++++++------
|
||||
include/soc/bcm2835/raspberrypi-firmware.h | 13 +
|
||||
2 files changed, 343 insertions(+), 137 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,65 +82,139 @@ struct bcm2708_fb_stats {
|
||||
u32 dma_irqs;
|
||||
};
|
||||
|
||||
+struct vc4_display_settings_t {
|
||||
+ u32 display_num;
|
||||
+ u32 width;
|
||||
+ u32 height;
|
||||
+ u32 depth;
|
||||
+ u32 pitch;
|
||||
+ u32 virtual_width;
|
||||
+ u32 virtual_height;
|
||||
+ u32 virtual_width_offset;
|
||||
+ u32 virtual_height_offset;
|
||||
+ unsigned long fb_bus_address;
|
||||
+};
|
||||
+
|
||||
+struct bcm2708_fb_dev;
|
||||
+
|
||||
struct bcm2708_fb {
|
||||
struct fb_info fb;
|
||||
struct platform_device *dev;
|
||||
- struct rpi_firmware *fw;
|
||||
u32 cmap[16];
|
||||
u32 gpu_cmap[256];
|
||||
- int dma_chan;
|
||||
- int dma_irq;
|
||||
- void __iomem *dma_chan_base;
|
||||
- void *cb_base; /* DMA control blocks */
|
||||
- dma_addr_t cb_handle;
|
||||
struct dentry *debugfs_dir;
|
||||
- wait_queue_head_t dma_waitq;
|
||||
- struct bcm2708_fb_stats stats;
|
||||
+ struct dentry *debugfs_subdir;
|
||||
unsigned long fb_bus_address;
|
||||
- bool disable_arm_alloc;
|
||||
+ struct { u32 base, length; } gpu;
|
||||
+ struct vc4_display_settings_t display_settings;
|
||||
+ struct debugfs_regset32 screeninfo_regset;
|
||||
+ struct bcm2708_fb_dev *fbdev;
|
||||
unsigned int image_size;
|
||||
dma_addr_t dma_addr;
|
||||
void *cpuaddr;
|
||||
};
|
||||
|
||||
+#define MAX_FRAMEBUFFERS 3
|
||||
+
|
||||
+struct bcm2708_fb_dev {
|
||||
+ int firmware_supports_multifb;
|
||||
+ /* Protects the DMA system from multiple FB access */
|
||||
+ struct mutex dma_mutex;
|
||||
+ int dma_chan;
|
||||
+ int dma_irq;
|
||||
+ void __iomem *dma_chan_base;
|
||||
+ wait_queue_head_t dma_waitq;
|
||||
+ bool disable_arm_alloc;
|
||||
+ struct bcm2708_fb_stats dma_stats;
|
||||
+ void *cb_base; /* DMA control blocks */
|
||||
+ dma_addr_t cb_handle;
|
||||
+ int instance_count;
|
||||
+ int num_displays;
|
||||
+ struct rpi_firmware *fw;
|
||||
+ struct bcm2708_fb displays[MAX_FRAMEBUFFERS];
|
||||
+};
|
||||
+
|
||||
#define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
|
||||
|
||||
static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb)
|
||||
{
|
||||
- debugfs_remove_recursive(fb->debugfs_dir);
|
||||
- fb->debugfs_dir = NULL;
|
||||
+ debugfs_remove_recursive(fb->debugfs_subdir);
|
||||
+ fb->debugfs_subdir = NULL;
|
||||
+
|
||||
+ fb->fbdev->instance_count--;
|
||||
+
|
||||
+ if (!fb->fbdev->instance_count) {
|
||||
+ debugfs_remove_recursive(fb->debugfs_dir);
|
||||
+ fb->debugfs_dir = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb)
|
||||
{
|
||||
+ char buf[3];
|
||||
+ struct bcm2708_fb_dev *fbdev = fb->fbdev;
|
||||
+
|
||||
static struct debugfs_reg32 stats_registers[] = {
|
||||
- {
|
||||
- "dma_copies",
|
||||
- offsetof(struct bcm2708_fb_stats, dma_copies)
|
||||
- },
|
||||
- {
|
||||
- "dma_irqs",
|
||||
- offsetof(struct bcm2708_fb_stats, dma_irqs)
|
||||
- },
|
||||
+ {"dma_copies", offsetof(struct bcm2708_fb_stats, dma_copies)},
|
||||
+ {"dma_irqs", offsetof(struct bcm2708_fb_stats, dma_irqs)},
|
||||
+ };
|
||||
+
|
||||
+ static struct debugfs_reg32 screeninfo[] = {
|
||||
+ {"width", offsetof(struct fb_var_screeninfo, xres)},
|
||||
+ {"height", offsetof(struct fb_var_screeninfo, yres)},
|
||||
+ {"bpp", offsetof(struct fb_var_screeninfo, bits_per_pixel)},
|
||||
+ {"xres_virtual", offsetof(struct fb_var_screeninfo, xres_virtual)},
|
||||
+ {"yres_virtual", offsetof(struct fb_var_screeninfo, yres_virtual)},
|
||||
+ {"xoffset", offsetof(struct fb_var_screeninfo, xoffset)},
|
||||
+ {"yoffset", offsetof(struct fb_var_screeninfo, yoffset)},
|
||||
};
|
||||
|
||||
- fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
|
||||
+ fb->debugfs_dir = debugfs_lookup(DRIVER_NAME, NULL);
|
||||
+
|
||||
+ if (!fb->debugfs_dir)
|
||||
+ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
|
||||
+
|
||||
if (!fb->debugfs_dir) {
|
||||
- pr_warn("%s: could not create debugfs entry\n",
|
||||
- __func__);
|
||||
+ dev_warn(fb->fb.dev, "%s: could not create debugfs folder\n",
|
||||
+ __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
- fb->stats.regset.regs = stats_registers;
|
||||
- fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
|
||||
- fb->stats.regset.base = &fb->stats;
|
||||
-
|
||||
- if (!debugfs_create_regset32("stats", 0444, fb->debugfs_dir,
|
||||
- &fb->stats.regset)) {
|
||||
- pr_warn("%s: could not create statistics registers\n",
|
||||
- __func__);
|
||||
+ snprintf(buf, sizeof(buf), "%u", fb->display_settings.display_num);
|
||||
+
|
||||
+ fb->debugfs_subdir = debugfs_create_dir(buf, fb->debugfs_dir);
|
||||
+
|
||||
+ 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;
|
||||
+
|
||||
+ if (!debugfs_create_regset32("dma_stats", 0444, fb->debugfs_subdir,
|
||||
+ &fbdev->dma_stats.regset)) {
|
||||
+ dev_warn(fb->fb.dev, "%s: could not create statistics registers\n",
|
||||
+ __func__);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ fb->screeninfo_regset.regs = screeninfo;
|
||||
+ fb->screeninfo_regset.nregs = ARRAY_SIZE(screeninfo);
|
||||
+ fb->screeninfo_regset.base = &fb->fb.var;
|
||||
+
|
||||
+ if (!debugfs_create_regset32("screeninfo", 0444, fb->debugfs_subdir,
|
||||
+ &fb->screeninfo_regset)) {
|
||||
+ dev_warn(fb->fb.dev,
|
||||
+ "%s: could not create dimensions registers\n",
|
||||
+ __func__);
|
||||
goto fail;
|
||||
}
|
||||
+
|
||||
+ fbdev->instance_count++;
|
||||
+
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -145,6 +222,20 @@ fail:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
+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;
|
||||
@@ -222,11 +313,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);
|
||||
|
||||
@@ -289,17 +380,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,
|
||||
@@ -314,7 +412,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;
|
||||
}
|
||||
@@ -325,7 +423,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
|
||||
@@ -338,7 +436,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
|
||||
@@ -357,7 +455,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,
|
||||
@@ -447,7 +545,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));
|
||||
@@ -486,8 +587,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);
|
||||
@@ -504,12 +608,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;
|
||||
@@ -517,7 +623,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;
|
||||
@@ -534,23 +642,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;
|
||||
/*
|
||||
@@ -568,15 +675,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 ||
|
||||
@@ -603,8 +714,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;
|
||||
|
||||
@@ -654,10 +765,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);
|
||||
@@ -667,32 +778,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
|
||||
@@ -702,9 +814,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;
|
||||
}
|
||||
|
||||
@@ -737,11 +849,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;
|
||||
@@ -757,26 +881,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;
|
||||
}
|
||||
@@ -785,10 +906,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");
|
||||
@@ -796,90 +925,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));
|
||||
+ }
|
||||
+
|
||||
+ ret = bcm2708_fb_register(fb);
|
||||
|
||||
- fb->dev = dev;
|
||||
- fb->fb.device = &dev->dev;
|
||||
+ if (ret == 0) {
|
||||
+ bcm2708_fb_debugfs_init(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));
|
||||
+ fbdev->num_displays++;
|
||||
|
||||
- ret = bcm2708_fb_register(fb);
|
||||
- if (ret == 0) {
|
||||
- platform_set_drvdata(dev, fb);
|
||||
- goto out;
|
||||
+ 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;
|
||||
}
|
||||
@@ -894,10 +1087,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);
|
|
@ -0,0 +1,327 @@
|
|||
From 764b96cc27c293fb37a8b9031ddb25290974e3a2 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 | 167 ++++++++++++++++++++++++++++++-
|
||||
drivers/video/fbdev/core/fbmem.c | 35 +++++++
|
||||
include/uapi/linux/fb.h | 12 +++
|
||||
3 files changed, 213 insertions(+), 1 deletion(-)
|
||||
|
||||
--- 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>
|
||||
|
||||
@@ -613,7 +615,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)
|
||||
{
|
||||
@@ -629,6 +734,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;
|
||||
@@ -639,6 +759,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(¶m32, (void *)arg, sizeof(param32))) {
|
||||
+ pr_err("[%s]: failed to copy-from-user\n", __func__);
|
||||
+ ret = -EFAULT;
|
||||
+ break;
|
||||
+ }
|
||||
+ param.dst = compat_ptr(param32.dst);
|
||||
+ param.src = param32.src;
|
||||
+ param.length = param32.length;
|
||||
+ ret = vc_mem_copy(fb, ¶m);
|
||||
+ break;
|
||||
+ }
|
||||
+ default:
|
||||
+ ret = bcm2708_ioctl(info, cmd, arg);
|
||||
+ break;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static void bcm2708_fb_fillrect(struct fb_info *info,
|
||||
const struct fb_fillrect *rect)
|
||||
{
|
||||
@@ -831,6 +993,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
|
||||
@@ -1076,6 +1076,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)
|
||||
{
|
||||
@@ -1084,6 +1108,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;
|
||||
|
||||
@@ -1159,6 +1184,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(©, argp, sizeof(copy)))
|
||||
+ return -EFAULT;
|
||||
+ ret = fb_copyarea_user(info, ©);
|
||||
+ break;
|
||||
+ }
|
||||
+ /* fall through */
|
||||
default:
|
||||
lock_fb_info(info);
|
||||
fb = info->fbops;
|
||||
@@ -1304,6 +1338,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);
|
||||
/* fall through */
|
||||
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 */
|
||||
@@ -347,6 +353,12 @@ struct fb_copyarea {
|
||||
__u32 sy;
|
||||
};
|
||||
|
||||
+struct fb_dmacopy {
|
||||
+ void *dst;
|
||||
+ __u32 src;
|
||||
+ __u32 length;
|
||||
+};
|
||||
+
|
||||
struct fb_fillrect {
|
||||
__u32 dx; /* screen-relative */
|
||||
__u32 dy;
|
|
@ -0,0 +1,209 @@
|
|||
From 36be92675cdb5eb76ec03997b6ee0b8a1863b08a 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
|
|
@ -0,0 +1,640 @@
|
|||
From d3751959a74b762e35bb1024e1d33b62b9a97b9b 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
|
||||
@@ -133,7 +133,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
|
||||
|
||||
@@ -608,6 +608,10 @@ config UNIPHIER_MDMAC
|
||||
UniPhier platform. This DMA controller is used as the external
|
||||
DMA engine of the SD/eMMC controllers of the LD4, Pro4, sLD8 SoCs.
|
||||
|
||||
+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
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,506 @@
|
|||
From e6c9324a2112d016d2a89f0e3b98d564938971c8 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 | 393 ++++++++++++++++++++++++++++++++
|
||||
include/linux/broadcom/vc_mem.h | 39 ++++
|
||||
4 files changed, 451 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,393 @@
|
||||
+/*
|
||||
+ * 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;
|
||||
+ }
|
||||
+
|
||||
+ if (!debugfs_create_x32("vc_mem_phys_addr",
|
||||
+ 0444,
|
||||
+ vc_mem_debugfs_entry,
|
||||
+ (u32 *)&mm_vc_mem_phys_addr)) {
|
||||
+ dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
|
||||
+ __func__);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ if (!debugfs_create_x32("vc_mem_size",
|
||||
+ 0444,
|
||||
+ vc_mem_debugfs_entry,
|
||||
+ (u32 *)&mm_vc_mem_size)) {
|
||||
+ dev_warn(dev, "%s:could not create vc_mem_size entry\n",
|
||||
+ __func__);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ if (!debugfs_create_x32("vc_mem_base",
|
||||
+ 0444,
|
||||
+ vc_mem_debugfs_entry,
|
||||
+ (u32 *)&mm_vc_mem_base)) {
|
||||
+ dev_warn(dev, "%s:could not create vc_mem_base entry\n",
|
||||
+ __func__);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+fail:
|
||||
+ vc_mem_debugfs_deinit();
|
||||
+ return -EFAULT;
|
||||
+}
|
||||
+
|
||||
+#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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,303 @@
|
|||
From 8f01b6c283ab74efa8bc94fb45aca340c50d73df 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 | 9 +
|
||||
drivers/char/broadcom/Makefile | 3 +
|
||||
drivers/char/broadcom/bcm2835-gpiomem.c | 258 ++++++++++++++++++++++++
|
||||
3 files changed, 270 insertions(+)
|
||||
create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c
|
||||
|
||||
--- a/drivers/char/broadcom/Kconfig
|
||||
+++ b/drivers/char/broadcom/Kconfig
|
||||
@@ -26,3 +26,12 @@ config BCM_VC_SM
|
||||
help
|
||||
Support for the VC shared memory on the Broadcom reference
|
||||
design. Uses the VCHIQ stack.
|
||||
+
|
||||
+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,2 +1,5 @@
|
||||
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
|
||||
obj-$(CONFIG_BCM_VC_SM) += vc_sm/
|
||||
+
|
||||
+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
|
@ -0,0 +1,260 @@
|
|||
From 0ab080ba0ac496efa285450a555d0a06a1e166d8 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 3 Jul 2013 00:49:20 +0100
|
||||
Subject: [PATCH] Add cpufreq driver
|
||||
|
||||
Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
|
||||
bcm2835-cpufreq: Change licence to GPLv2
|
||||
|
||||
Signed-off-by: Eben Upton <eben.upton@broadcom.com>
|
||||
Signed-off-by: Dom Cobley <dom@raspberrypi.com>
|
||||
---
|
||||
drivers/cpufreq/Kconfig.arm | 9 ++
|
||||
drivers/cpufreq/Makefile | 1 +
|
||||
drivers/cpufreq/bcm2835-cpufreq.c | 211 ++++++++++++++++++++++++++++++
|
||||
3 files changed, 221 insertions(+)
|
||||
create mode 100644 drivers/cpufreq/bcm2835-cpufreq.c
|
||||
|
||||
--- a/drivers/cpufreq/Kconfig.arm
|
||||
+++ b/drivers/cpufreq/Kconfig.arm
|
||||
@@ -300,6 +300,15 @@ config ARM_TANGO_CPUFREQ
|
||||
depends on CPUFREQ_DT && ARCH_TANGO
|
||||
default y
|
||||
|
||||
+config ARM_BCM2835_CPUFREQ
|
||||
+ depends on RASPBERRYPI_FIRMWARE
|
||||
+ bool "BCM2835 Driver"
|
||||
+ default y
|
||||
+ help
|
||||
+ This adds the CPUFreq driver for BCM2835
|
||||
+
|
||||
+ If in doubt, say N.
|
||||
+
|
||||
config ARM_TEGRA20_CPUFREQ
|
||||
tristate "Tegra20 CPUFreq support"
|
||||
depends on ARCH_TEGRA
|
||||
--- a/drivers/cpufreq/Makefile
|
||||
+++ b/drivers/cpufreq/Makefile
|
||||
@@ -82,6 +82,7 @@ obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spea
|
||||
obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o
|
||||
obj-$(CONFIG_ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM) += sun50i-cpufreq-nvmem.o
|
||||
obj-$(CONFIG_ARM_TANGO_CPUFREQ) += tango-cpufreq.o
|
||||
+obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
|
||||
obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
|
||||
obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
|
||||
obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/cpufreq/bcm2835-cpufreq.c
|
||||
@@ -0,0 +1,211 @@
|
||||
+/*
|
||||
+ * Copyright 2011 Broadcom Corporation.
|
||||
+ *
|
||||
+ * 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; version 2
|
||||
+ * of the License.
|
||||
+ *
|
||||
+ * This driver dynamically manages the CPU Frequency of the ARM
|
||||
+ * processor. Messages are sent to Videocore either setting or requesting the
|
||||
+ * frequency of the ARM in order to match an appropiate frequency to the current
|
||||
+ * usage of the processor. The policy which selects the frequency to use is
|
||||
+ * defined in the kernel .config file, but can be changed during runtime.
|
||||
+ */
|
||||
+
|
||||
+/* ---------- INCLUDES ---------- */
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/cpufreq.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+/* ---------- DEFINES ---------- */
|
||||
+/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
|
||||
+#define MODULE_NAME "bcm2835-cpufreq"
|
||||
+
|
||||
+#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
|
||||
+
|
||||
+/* debug printk macros */
|
||||
+#ifdef CPUFREQ_DEBUG_ENABLE
|
||||
+#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
|
||||
+#else
|
||||
+#define print_debug(fmt,...)
|
||||
+#endif
|
||||
+#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
|
||||
+#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)
|
||||
+
|
||||
+/* ---------- GLOBALS ---------- */
|
||||
+static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */
|
||||
+static unsigned int min_frequency, max_frequency;
|
||||
+static struct cpufreq_frequency_table bcm2835_freq_table[3];
|
||||
+
|
||||
+/*
|
||||
+ ===============================================
|
||||
+ clk_rate either gets or sets the clock rates.
|
||||
+ ===============================================
|
||||
+*/
|
||||
+
|
||||
+static int bcm2835_cpufreq_clock_property(u32 tag, u32 id, u32 *val)
|
||||
+{
|
||||
+ struct rpi_firmware *fw = rpi_firmware_get(NULL);
|
||||
+ struct {
|
||||
+ u32 id;
|
||||
+ u32 val;
|
||||
+ } packet;
|
||||
+ int ret;
|
||||
+
|
||||
+ packet.id = id;
|
||||
+ packet.val = *val;
|
||||
+ ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ *val = packet.val;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
|
||||
+{
|
||||
+ u32 rate = arm_rate * 1000;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = bcm2835_cpufreq_clock_property(RPI_FIRMWARE_SET_CLOCK_RATE, VCMSG_ID_ARM_CLOCK, &rate);
|
||||
+ if (ret) {
|
||||
+ print_err("Failed to set clock: %d (%d)\n", arm_rate, ret);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ rate /= 1000;
|
||||
+ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, rate);
|
||||
+
|
||||
+ return rate;
|
||||
+}
|
||||
+
|
||||
+static uint32_t bcm2835_cpufreq_get_clock(int tag)
|
||||
+{
|
||||
+ u32 rate;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = bcm2835_cpufreq_clock_property(tag, VCMSG_ID_ARM_CLOCK, &rate);
|
||||
+ if (ret) {
|
||||
+ print_err("Failed to get clock (%d)\n", ret);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ rate /= 1000;
|
||||
+ print_debug("%s frequency = %u\n",
|
||||
+ tag == RPI_FIRMWARE_GET_CLOCK_RATE ? "Current":
|
||||
+ tag == RPI_FIRMWARE_GET_MIN_CLOCK_RATE ? "Min":
|
||||
+ tag == RPI_FIRMWARE_GET_MAX_CLOCK_RATE ? "Max":
|
||||
+ "Unexpected", rate);
|
||||
+
|
||||
+ return rate;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ ====================================================
|
||||
+ Module Initialisation registers the cpufreq driver
|
||||
+ ====================================================
|
||||
+*/
|
||||
+static int __init bcm2835_cpufreq_module_init(void)
|
||||
+{
|
||||
+ print_debug("IN\n");
|
||||
+ return cpufreq_register_driver(&bcm2835_cpufreq_driver);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ =============
|
||||
+ Module exit
|
||||
+ =============
|
||||
+*/
|
||||
+static void __exit bcm2835_cpufreq_module_exit(void)
|
||||
+{
|
||||
+ print_debug("IN\n");
|
||||
+ cpufreq_unregister_driver(&bcm2835_cpufreq_driver);
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ ==============================================================
|
||||
+ Initialisation function sets up the CPU policy for first use
|
||||
+ ==============================================================
|
||||
+*/
|
||||
+static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||
+{
|
||||
+ /* measured value of how long it takes to change frequency */
|
||||
+ const unsigned int transition_latency = 355000; /* ns */
|
||||
+
|
||||
+ if (!rpi_firmware_get(NULL)) {
|
||||
+ print_err("Firmware is not available\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* now find out what the maximum and minimum frequencies are */
|
||||
+ min_frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
|
||||
+ max_frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
|
||||
+
|
||||
+ if (min_frequency == max_frequency) {
|
||||
+ bcm2835_freq_table[0].frequency = min_frequency;
|
||||
+ bcm2835_freq_table[1].frequency = CPUFREQ_TABLE_END;
|
||||
+ } else {
|
||||
+ bcm2835_freq_table[0].frequency = min_frequency;
|
||||
+ bcm2835_freq_table[1].frequency = max_frequency;
|
||||
+ bcm2835_freq_table[2].frequency = CPUFREQ_TABLE_END;
|
||||
+ }
|
||||
+
|
||||
+ print_info("min=%d max=%d\n", min_frequency, max_frequency);
|
||||
+ cpufreq_generic_init(policy, bcm2835_freq_table, transition_latency);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ =====================================================================
|
||||
+ Target index function chooses the requested frequency from the table
|
||||
+ =====================================================================
|
||||
+*/
|
||||
+
|
||||
+static int bcm2835_cpufreq_driver_target_index(struct cpufreq_policy *policy, unsigned int state)
|
||||
+{
|
||||
+ unsigned int target_freq = state == 0 ? min_frequency : max_frequency;
|
||||
+ unsigned int cur = bcm2835_cpufreq_set_clock(policy->cur, target_freq);
|
||||
+
|
||||
+ if (!cur)
|
||||
+ {
|
||||
+ print_err("Error occurred setting a new frequency (%d)\n", target_freq);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ print_debug("%s: %i: freq %d->%d\n", policy->governor->name, state, policy->cur, cur);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ ======================================================
|
||||
+ Get function returns the current frequency from table
|
||||
+ ======================================================
|
||||
+*/
|
||||
+
|
||||
+static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
|
||||
+{
|
||||
+ unsigned int actual_rate = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_CLOCK_RATE);
|
||||
+ print_debug("cpu%d: freq=%d\n", cpu, actual_rate);
|
||||
+ return actual_rate <= min_frequency ? min_frequency : max_frequency;
|
||||
+}
|
||||
+
|
||||
+/* the CPUFreq driver */
|
||||
+static struct cpufreq_driver bcm2835_cpufreq_driver = {
|
||||
+ .name = "BCM2835 CPUFreq",
|
||||
+ .init = bcm2835_cpufreq_driver_init,
|
||||
+ .verify = cpufreq_generic_frequency_table_verify,
|
||||
+ .target_index = bcm2835_cpufreq_driver_target_index,
|
||||
+ .get = bcm2835_cpufreq_driver_get,
|
||||
+ .attr = cpufreq_generic_attr,
|
||||
+};
|
||||
+
|
||||
+MODULE_AUTHOR("Dorian Peake and Dom Cobley");
|
||||
+MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+
|
||||
+module_init(bcm2835_cpufreq_module_init);
|
||||
+module_exit(bcm2835_cpufreq_module_exit);
|
|
@ -0,0 +1,660 @@
|
|||
From 2f53b727b2ba07ec39bc552f1b24f8bb33d2bb17 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);
|
|
@ -0,0 +1,255 @@
|
|||
From 665ddd6b1e4bad3473ef5f4834c04db3e8968867 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 BCM_VC_SM
|
||||
--- a/drivers/char/broadcom/Makefile
|
||||
+++ b/drivers/char/broadcom/Makefile
|
||||
@@ -1,4 +1,5 @@
|
||||
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
|
||||
+obj-$(CONFIG_BCM_VCIO) += vcio.o
|
||||
obj-$(CONFIG_BCM_VC_SM) += vc_sm/
|
||||
|
||||
obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.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");
|
|
@ -0,0 +1,83 @@
|
|||
From 3e01b7e87a6164aaf4e89eacb4f4462a6c19a1fb 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)
|
||||
@@ -238,6 +240,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);
|
||||
@@ -265,6 +268,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;
|
||||
}
|
||||
@@ -277,7 +281,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;
|
||||
@@ -301,7 +305,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");
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,169 @@
|
|||
From 1cd811a043be06cbe4b7fcb78b669b45e0e7a7b7 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
|
||||
@@ -73,6 +73,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;
|
|
@ -0,0 +1,22 @@
|
|||
From c973f0c0feeee0d79d05953304bc001416a777ba 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
|
||||
@@ -1938,6 +1938,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,
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
From a4755f727de773ecd1218300b5234e2b49eddf06 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",
|
||||
__func__);
|
|
@ -0,0 +1,850 @@
|
|||
From 34a1607afd3225d589ee0451c6c16b790e898cbc 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
|
||||
@@ -372,4 +372,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
|
||||
@@ -36,4 +36,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
|
||||
@@ -255,4 +255,5 @@ obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
|
||||
obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
|
||||
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
|
||||
obj-$(CONFIG_MFD_STMFX) += stmfx.o
|
||||
+obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.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
|
||||
@@ -2277,6 +2277,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
|
||||
@@ -132,6 +132,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
|
|
@ -0,0 +1,123 @@
|
|||
From 2f7b03ee22ad1597dc2f21797466ac477997b06f Mon Sep 17 00:00:00 2001
|
||||
From: Florian Meier <florian.meier@koalo.de>
|
||||
Date: Mon, 25 Jan 2016 15:48:59 +0000
|
||||
Subject: [PATCH] ASoC: Add support for Rpi-DAC
|
||||
|
||||
---
|
||||
sound/soc/codecs/Kconfig | 5 +++
|
||||
sound/soc/codecs/Makefile | 2 ++
|
||||
sound/soc/codecs/pcm1794a.c | 69 +++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 76 insertions(+)
|
||||
create mode 100644 sound/soc/codecs/pcm1794a.c
|
||||
|
||||
--- a/sound/soc/codecs/Kconfig
|
||||
+++ b/sound/soc/codecs/Kconfig
|
||||
@@ -134,6 +134,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_PCM179X_SPI if SPI_MASTER
|
||||
select SND_SOC_PCM186X_I2C if I2C
|
||||
select SND_SOC_PCM186X_SPI if SPI_MASTER
|
||||
+ select SND_SOC_PCM1794A if I2C
|
||||
select SND_SOC_PCM3008
|
||||
select SND_SOC_PCM3060_I2C if I2C
|
||||
select SND_SOC_PCM3060_SPI if SPI_MASTER
|
||||
@@ -980,6 +981,10 @@ config SND_SOC_RT5616
|
||||
tristate "Realtek RT5616 CODEC"
|
||||
depends on I2C
|
||||
|
||||
+config SND_SOC_PCM1794A
|
||||
+ tristate
|
||||
+ depends on I2C
|
||||
+
|
||||
config SND_SOC_RT5631
|
||||
tristate "Realtek ALC5631/RT5631 CODEC"
|
||||
depends on I2C
|
||||
--- a/sound/soc/codecs/Makefile
|
||||
+++ b/sound/soc/codecs/Makefile
|
||||
@@ -134,6 +134,7 @@ snd-soc-pcm179x-spi-objs := pcm179x-spi.
|
||||
snd-soc-pcm186x-objs := pcm186x.o
|
||||
snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
|
||||
snd-soc-pcm186x-spi-objs := pcm186x-spi.o
|
||||
+snd-soc-pcm1794a-objs := pcm1794a.o
|
||||
snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-pcm3060-objs := pcm3060.o
|
||||
snd-soc-pcm3060-i2c-objs := pcm3060-i2c.o
|
||||
@@ -430,6 +431,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
|
||||
+obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o
|
||||
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
|
||||
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
|
||||
obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/codecs/pcm1794a.c
|
||||
@@ -0,0 +1,69 @@
|
||||
+/*
|
||||
+ * Driver for the PCM1794A codec
|
||||
+ *
|
||||
+ * Author: Florian Meier <florian.meier@koalo.de>
|
||||
+ * Copyright 2013
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+static struct snd_soc_dai_driver pcm1794a_dai = {
|
||||
+ .name = "pcm1794a-hifi",
|
||||
+ .playback = {
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_192000,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_component_driver soc_component_dev_pcm1794a;
|
||||
+
|
||||
+static int pcm1794a_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ return snd_soc_register_component(&pdev->dev, &soc_component_dev_pcm1794a,
|
||||
+ &pcm1794a_dai, 1);
|
||||
+}
|
||||
+
|
||||
+static int pcm1794a_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ snd_soc_unregister_component(&pdev->dev);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id pcm1794a_of_match[] = {
|
||||
+ { .compatible = "ti,pcm1794a", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, pcm1794a_of_match);
|
||||
+
|
||||
+static struct platform_driver pcm1794a_component_driver = {
|
||||
+ .probe = pcm1794a_probe,
|
||||
+ .remove = pcm1794a_remove,
|
||||
+ .driver = {
|
||||
+ .name = "pcm1794a-codec",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = of_match_ptr(pcm1794a_of_match),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(pcm1794a_component_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("ASoC PCM1794A codec driver");
|
||||
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,298 @@
|
|||
From 1372d5148783da0f382be29705de8b742dcc9d2a Mon Sep 17 00:00:00 2001
|
||||
From: Gordon Garrity <gordon@iqaudio.com>
|
||||
Date: Sat, 8 Mar 2014 16:56:57 +0000
|
||||
Subject: [PATCH] Add IQaudIO Sound Card support for Raspberry Pi
|
||||
|
||||
Set a limit of 0dB on Digital Volume Control
|
||||
|
||||
The main volume control in the PCM512x DAC has a range up to
|
||||
+24dB. This is dangerously loud and can potentially cause massive
|
||||
clipping in the output stages. Therefore this sets a sensible
|
||||
limit of 0dB for this control.
|
||||
|
||||
Allow up to 24dB digital gain to be applied when using IQAudIO DAC+
|
||||
|
||||
24db_digital_gain DT param can be used to specify that PCM512x
|
||||
codec "Digital" volume control should not be limited to 0dB gain,
|
||||
and if specified will allow the full 24dB gain.
|
||||
|
||||
Modify IQAudIO DAC+ ASoC driver to set card/dai config from dt
|
||||
|
||||
Add the ability to set the card name, dai name and dai stream name, from
|
||||
dt config.
|
||||
|
||||
Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
|
||||
|
||||
IQaudIO: auto-mute for AMP+ and DigiAMP+
|
||||
|
||||
IQAudIO amplifier mute via GPIO22. Add dt params for "one-shot" unmute
|
||||
and auto mute.
|
||||
|
||||
Revision 2, auto mute implementing HiassofT suggestion to mute/unmute
|
||||
using set_bias_level, rather than startup/shutdown....
|
||||
"By default DAPM waits 5 seconds (pmdown_time) before shutting down
|
||||
playback streams so a close/stop immediately followed by open/start
|
||||
doesn't trigger an amp mute+unmute."
|
||||
|
||||
Tested on both AMP+ (via DAC+) and DigiAMP+, with both options...
|
||||
|
||||
dtoverlay=iqaudio-dacplus,unmute_amp
|
||||
"one-shot" unmute when kernel module loads.
|
||||
|
||||
dtoverlay=iqaudio-dacplus,auto_mute_amp
|
||||
Unmute amp when ALSA device opened by a client. Mute, with 5 second delay
|
||||
when ALSA device closed. (Re-opening the device within the 5 second close
|
||||
window, will cancel mute.)
|
||||
|
||||
Revision 4, using gpiod.
|
||||
|
||||
Revision 5, clean-up formatting before adding mute code.
|
||||
- Convert tab plus 4 space formatting to 2x tab
|
||||
- Remove '// NOT USED' commented code
|
||||
|
||||
Revision 6, don't attempt to "one-shot" unmute amp, unless card is
|
||||
successfully registered.
|
||||
|
||||
Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
|
||||
|
||||
ASoC: iqaudio-dac: fix S24_LE format
|
||||
|
||||
Remove set_bclk_ratio call so 24-bit data is transmitted in
|
||||
24 bclk cycles.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: iqaudio-dac: use modern dai_link style
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/iqaudio-dac.c | 223 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 223 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/iqaudio-dac.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/iqaudio-dac.c
|
||||
@@ -0,0 +1,223 @@
|
||||
+/*
|
||||
+ * ASoC Driver for IQaudIO DAC
|
||||
+ *
|
||||
+ * Author: Florian Meier <florian.meier@koalo.de>
|
||||
+ * Copyright 2013
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+
|
||||
+static bool digital_gain_0db_limit = true;
|
||||
+
|
||||
+static struct gpio_desc *mute_gpio;
|
||||
+
|
||||
+static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ if (digital_gain_0db_limit)
|
||||
+ {
|
||||
+ int ret;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void snd_rpi_iqaudio_gpio_mute(struct snd_soc_card *card)
|
||||
+{
|
||||
+ if (mute_gpio) {
|
||||
+ dev_info(card->dev, "%s: muting amp using GPIO22\n",
|
||||
+ __func__);
|
||||
+ gpiod_set_value_cansleep(mute_gpio, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void snd_rpi_iqaudio_gpio_unmute(struct snd_soc_card *card)
|
||||
+{
|
||||
+ if (mute_gpio) {
|
||||
+ dev_info(card->dev, "%s: un-muting amp using GPIO22\n",
|
||||
+ __func__);
|
||||
+ gpiod_set_value_cansleep(mute_gpio, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_iqaudio_set_bias_level(struct snd_soc_card *card,
|
||||
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd;
|
||||
+ struct snd_soc_dai *codec_dai;
|
||||
+
|
||||
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
|
||||
+ codec_dai = rtd->codec_dai;
|
||||
+
|
||||
+ if (dapm->dev != codec_dai->dev)
|
||||
+ return 0;
|
||||
+
|
||||
+ switch (level) {
|
||||
+ case SND_SOC_BIAS_PREPARE:
|
||||
+ if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
|
||||
+ break;
|
||||
+
|
||||
+ /* UNMUTE AMP */
|
||||
+ snd_rpi_iqaudio_gpio_unmute(card);
|
||||
+
|
||||
+ break;
|
||||
+ case SND_SOC_BIAS_STANDBY:
|
||||
+ if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
|
||||
+ break;
|
||||
+
|
||||
+ /* MUTE AMP */
|
||||
+ snd_rpi_iqaudio_gpio_mute(card);
|
||||
+
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(hifi,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004c", "pcm512x-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = {
|
||||
+{
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ .init = snd_rpi_iqaudio_dac_init,
|
||||
+ SND_SOC_DAILINK_REG(hifi),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_rpi_iqaudio_dac = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = snd_rpi_iqaudio_dac_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ bool gpio_unmute = false;
|
||||
+
|
||||
+ snd_rpi_iqaudio_dac.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_card *card = &snd_rpi_iqaudio_dac;
|
||||
+ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
|
||||
+ bool auto_gpio_mute = false;
|
||||
+
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+
|
||||
+ digital_gain_0db_limit = !of_property_read_bool(
|
||||
+ pdev->dev.of_node, "iqaudio,24db_digital_gain");
|
||||
+
|
||||
+ if (of_property_read_string(pdev->dev.of_node, "card_name",
|
||||
+ &card->name))
|
||||
+ card->name = "IQaudIODAC";
|
||||
+
|
||||
+ if (of_property_read_string(pdev->dev.of_node, "dai_name",
|
||||
+ &dai->name))
|
||||
+ dai->name = "IQaudIO DAC";
|
||||
+
|
||||
+ if (of_property_read_string(pdev->dev.of_node,
|
||||
+ "dai_stream_name", &dai->stream_name))
|
||||
+ dai->stream_name = "IQaudIO DAC HiFi";
|
||||
+
|
||||
+ /* gpio_unmute - one time unmute amp using GPIO */
|
||||
+ gpio_unmute = of_property_read_bool(pdev->dev.of_node,
|
||||
+ "iqaudio-dac,unmute-amp");
|
||||
+
|
||||
+ /* auto_gpio_mute - mute/unmute amp using GPIO */
|
||||
+ auto_gpio_mute = of_property_read_bool(pdev->dev.of_node,
|
||||
+ "iqaudio-dac,auto-mute-amp");
|
||||
+
|
||||
+ if (auto_gpio_mute || gpio_unmute) {
|
||||
+ mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute",
|
||||
+ GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(mute_gpio)) {
|
||||
+ ret = PTR_ERR(mute_gpio);
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "Failed to get mute gpio: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (auto_gpio_mute && mute_gpio)
|
||||
+ snd_rpi_iqaudio_dac.set_bias_level =
|
||||
+ snd_rpi_iqaudio_set_bias_level;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
|
||||
+ if (ret) {
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "snd_soc_register_card() failed: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (gpio_unmute && mute_gpio)
|
||||
+ snd_rpi_iqaudio_gpio_unmute(&snd_rpi_iqaudio_dac);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ snd_rpi_iqaudio_gpio_mute(&snd_rpi_iqaudio_dac);
|
||||
+
|
||||
+ return snd_soc_unregister_card(&snd_rpi_iqaudio_dac);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id iqaudio_of_match[] = {
|
||||
+ { .compatible = "iqaudio,iqaudio-dac", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, iqaudio_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_rpi_iqaudio_dac_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-iqaudio-dac",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = iqaudio_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_iqaudio_dac_probe,
|
||||
+ .remove = snd_rpi_iqaudio_dac_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_rpi_iqaudio_dac_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,616 @@
|
|||
From cd09df67ff15ee1a7c6aa33df6d76d1427ad23f8 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Matuschek <info@crazy-audio.com>
|
||||
Date: Mon, 4 Aug 2014 10:06:56 +0200
|
||||
Subject: [PATCH] Added support for HiFiBerry DAC+
|
||||
|
||||
The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses
|
||||
a different codec chip (PCM5122), therefore a new driver is necessary.
|
||||
|
||||
Add support for the HiFiBerry DAC+ Pro.
|
||||
|
||||
The HiFiBerry DAC+ and DAC+ Pro products both use the existing bcm sound driver with the DAC+ Pro having a special clock device driver representing the two high precision oscillators.
|
||||
|
||||
An addition bug fix is included for the PCM512x codec where by the physical size of the sample frame is used in the calculation of the LRCK divisor as it was found to be wrong when using 24-bit depth sample contained in a little endian 4-byte sample frame.
|
||||
|
||||
Limit PCM512x "Digital" gain to 0dB by default with HiFiBerry DAC+
|
||||
|
||||
24db_digital_gain DT param can be used to specify that PCM512x
|
||||
codec "Digital" volume control should not be limited to 0dB gain,
|
||||
and if specified will allow the full 24dB gain.
|
||||
|
||||
Add dt param to force HiFiBerry DAC+ Pro into slave mode
|
||||
|
||||
"dtoverlay=hifiberry-dacplus,slave"
|
||||
|
||||
Add 'slave' param to use HiFiBerry DAC+ Pro in slave mode,
|
||||
with Pi as master for bit and frame clock.
|
||||
|
||||
Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
|
||||
|
||||
Fixed a bug when using 352.8kHz sample rate
|
||||
|
||||
Signed-off-by: Daniel Matuschek <daniel@hifiberry.com>
|
||||
|
||||
ASoC: pcm512x: revert downstream changes
|
||||
|
||||
This partially reverts commit 185ea05465aac8bf02a0d2b2f4289d42c72870b7
|
||||
which was added by https://github.com/raspberrypi/linux/pull/1152
|
||||
|
||||
The downstream pcm512x changes caused a regression, it broke normal
|
||||
use of the 24bit format with the codec, eg when using simple-audio-card.
|
||||
|
||||
The actual bug with 24bit playback is the incorrect usage
|
||||
of physical_width in various drivers in the downstream tree
|
||||
which causes 24bit data to be transmitted with 32 clock
|
||||
cycles. So it's not the pcm512x that needs fixing, it's the
|
||||
soundcard drivers.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: hifiberry_dacplus: fix S24_LE format
|
||||
|
||||
Remove set_bclk_ratio call so 24-bit data is transmitted in
|
||||
24 bclk cycles.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: hifiberry_dacplus: transmit S24_LE with 64 BCLK cycles
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
hifiberry_dacplus: switch to snd_soc_dai_set_bclk_ratio
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: hifiberry_dacplus: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
drivers/clk/Kconfig | 3 +
|
||||
drivers/clk/Makefile | 1 +
|
||||
drivers/clk/clk-hifiberry-dacpro.c | 160 +++++++++++++
|
||||
sound/soc/bcm/hifiberry_dacplus.c | 352 +++++++++++++++++++++++++++++
|
||||
4 files changed, 516 insertions(+)
|
||||
create mode 100644 drivers/clk/clk-hifiberry-dacpro.c
|
||||
create mode 100644 sound/soc/bcm/hifiberry_dacplus.c
|
||||
|
||||
--- a/drivers/clk/Kconfig
|
||||
+++ b/drivers/clk/Kconfig
|
||||
@@ -70,6 +70,9 @@ config COMMON_CLK_HI655X
|
||||
multi-function device has one fixed-rate oscillator, clocked
|
||||
at 32KHz.
|
||||
|
||||
+config COMMON_CLK_HIFIBERRY_DACPRO
|
||||
+ tristate
|
||||
+
|
||||
config COMMON_CLK_SCMI
|
||||
tristate "Clock driver controlled via SCMI interface"
|
||||
depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
|
||||
--- a/drivers/clk/Makefile
|
||||
+++ b/drivers/clk/Makefile
|
||||
@@ -34,6 +34,7 @@ obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast
|
||||
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
|
||||
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
|
||||
obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
|
||||
+obj-$(CONFIG_COMMON_CLK_HIFIBERRY_DACPRO) += clk-hifiberry-dacpro.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
|
||||
obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/clk-hifiberry-dacpro.c
|
||||
@@ -0,0 +1,160 @@
|
||||
+/*
|
||||
+ * Clock Driver for HiFiBerry DAC Pro
|
||||
+ *
|
||||
+ * Author: Stuart MacLean
|
||||
+ * Copyright 2015
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk-provider.h>
|
||||
+#include <linux/clkdev.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+/* Clock rate of CLK44EN attached to GPIO6 pin */
|
||||
+#define CLK_44EN_RATE 22579200UL
|
||||
+/* Clock rate of CLK48EN attached to GPIO3 pin */
|
||||
+#define CLK_48EN_RATE 24576000UL
|
||||
+
|
||||
+/**
|
||||
+ * struct hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro
|
||||
+ * @hw: clk_hw for the common clk framework
|
||||
+ * @mode: 0 => CLK44EN, 1 => CLK48EN
|
||||
+ */
|
||||
+struct clk_hifiberry_hw {
|
||||
+ struct clk_hw hw;
|
||||
+ uint8_t mode;
|
||||
+};
|
||||
+
|
||||
+#define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw)
|
||||
+
|
||||
+static const struct of_device_id clk_hifiberry_dacpro_dt_ids[] = {
|
||||
+ { .compatible = "hifiberry,dacpro-clk",},
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids);
|
||||
+
|
||||
+static unsigned long clk_hifiberry_dacpro_recalc_rate(struct clk_hw *hw,
|
||||
+ unsigned long parent_rate)
|
||||
+{
|
||||
+ return (to_hifiberry_clk(hw)->mode == 0) ? CLK_44EN_RATE :
|
||||
+ CLK_48EN_RATE;
|
||||
+}
|
||||
+
|
||||
+static long clk_hifiberry_dacpro_round_rate(struct clk_hw *hw,
|
||||
+ unsigned long rate, unsigned long *parent_rate)
|
||||
+{
|
||||
+ long actual_rate;
|
||||
+
|
||||
+ if (rate <= CLK_44EN_RATE) {
|
||||
+ actual_rate = (long)CLK_44EN_RATE;
|
||||
+ } else if (rate >= CLK_48EN_RATE) {
|
||||
+ actual_rate = (long)CLK_48EN_RATE;
|
||||
+ } else {
|
||||
+ long diff44Rate = (long)(rate - CLK_44EN_RATE);
|
||||
+ long diff48Rate = (long)(CLK_48EN_RATE - rate);
|
||||
+
|
||||
+ if (diff44Rate < diff48Rate)
|
||||
+ actual_rate = (long)CLK_44EN_RATE;
|
||||
+ else
|
||||
+ actual_rate = (long)CLK_48EN_RATE;
|
||||
+ }
|
||||
+ return actual_rate;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int clk_hifiberry_dacpro_set_rate(struct clk_hw *hw,
|
||||
+ unsigned long rate, unsigned long parent_rate)
|
||||
+{
|
||||
+ unsigned long actual_rate;
|
||||
+ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
|
||||
+
|
||||
+ actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate,
|
||||
+ &parent_rate);
|
||||
+ clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+const struct clk_ops clk_hifiberry_dacpro_rate_ops = {
|
||||
+ .recalc_rate = clk_hifiberry_dacpro_recalc_rate,
|
||||
+ .round_rate = clk_hifiberry_dacpro_round_rate,
|
||||
+ .set_rate = clk_hifiberry_dacpro_set_rate,
|
||||
+};
|
||||
+
|
||||
+static int clk_hifiberry_dacpro_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct clk_hifiberry_hw *proclk;
|
||||
+ struct clk *clk;
|
||||
+ struct device *dev;
|
||||
+ struct clk_init_data init;
|
||||
+
|
||||
+ dev = &pdev->dev;
|
||||
+
|
||||
+ proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL);
|
||||
+ if (!proclk)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ init.name = "clk-hifiberry-dacpro";
|
||||
+ init.ops = &clk_hifiberry_dacpro_rate_ops;
|
||||
+ init.flags = 0;
|
||||
+ init.parent_names = NULL;
|
||||
+ init.num_parents = 0;
|
||||
+
|
||||
+ proclk->mode = 0;
|
||||
+ proclk->hw.init = &init;
|
||||
+
|
||||
+ clk = devm_clk_register(dev, &proclk->hw);
|
||||
+ if (!IS_ERR(clk)) {
|
||||
+ ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
|
||||
+ clk);
|
||||
+ } else {
|
||||
+ dev_err(dev, "Fail to register clock driver\n");
|
||||
+ kfree(proclk);
|
||||
+ ret = PTR_ERR(clk);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int clk_hifiberry_dacpro_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ of_clk_del_provider(pdev->dev.of_node);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver clk_hifiberry_dacpro_driver = {
|
||||
+ .probe = clk_hifiberry_dacpro_probe,
|
||||
+ .remove = clk_hifiberry_dacpro_remove,
|
||||
+ .driver = {
|
||||
+ .name = "clk-hifiberry-dacpro",
|
||||
+ .of_match_table = clk_hifiberry_dacpro_dt_ids,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int __init clk_hifiberry_dacpro_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&clk_hifiberry_dacpro_driver);
|
||||
+}
|
||||
+core_initcall(clk_hifiberry_dacpro_init);
|
||||
+
|
||||
+static void __exit clk_hifiberry_dacpro_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&clk_hifiberry_dacpro_driver);
|
||||
+}
|
||||
+module_exit(clk_hifiberry_dacpro_exit);
|
||||
+
|
||||
+MODULE_DESCRIPTION("HiFiBerry DAC Pro clock driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+MODULE_ALIAS("platform:clk-hifiberry-dacpro");
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/hifiberry_dacplus.c
|
||||
@@ -0,0 +1,352 @@
|
||||
+/*
|
||||
+ * ASoC Driver for HiFiBerry DAC+ / DAC Pro
|
||||
+ *
|
||||
+ * Author: Daniel Matuschek, Stuart MacLean <stuart@hifiberry.com>
|
||||
+ * Copyright 2014-2015
|
||||
+ * based on code by Florian Meier <florian.meier@koalo.de>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/delay.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+
|
||||
+#include "../codecs/pcm512x.h"
|
||||
+
|
||||
+#define HIFIBERRY_DACPRO_NOCLOCK 0
|
||||
+#define HIFIBERRY_DACPRO_CLK44EN 1
|
||||
+#define HIFIBERRY_DACPRO_CLK48EN 2
|
||||
+
|
||||
+struct pcm512x_priv {
|
||||
+ struct regmap *regmap;
|
||||
+ struct clk *sclk;
|
||||
+};
|
||||
+
|
||||
+/* Clock rate of CLK44EN attached to GPIO6 pin */
|
||||
+#define CLK_44EN_RATE 22579200UL
|
||||
+/* Clock rate of CLK48EN attached to GPIO3 pin */
|
||||
+#define CLK_48EN_RATE 24576000UL
|
||||
+
|
||||
+static bool slave;
|
||||
+static bool snd_rpi_hifiberry_is_dacpro;
|
||||
+static bool digital_gain_0db_limit = true;
|
||||
+
|
||||
+static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component,
|
||||
+ int clk_id)
|
||||
+{
|
||||
+ switch (clk_id) {
|
||||
+ case HIFIBERRY_DACPRO_NOCLOCK:
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
|
||||
+ break;
|
||||
+ case HIFIBERRY_DACPRO_CLK44EN:
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
|
||||
+ break;
|
||||
+ case HIFIBERRY_DACPRO_CLK48EN:
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void snd_rpi_hifiberry_dacplus_clk_gpio(struct snd_soc_component *component)
|
||||
+{
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
|
||||
+}
|
||||
+
|
||||
+static bool snd_rpi_hifiberry_dacplus_is_sclk(struct snd_soc_component *component)
|
||||
+{
|
||||
+ unsigned int sck;
|
||||
+
|
||||
+ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
|
||||
+ return (!(sck & 0x40));
|
||||
+}
|
||||
+
|
||||
+static bool snd_rpi_hifiberry_dacplus_is_sclk_sleep(
|
||||
+ struct snd_soc_component *component)
|
||||
+{
|
||||
+ msleep(2);
|
||||
+ return snd_rpi_hifiberry_dacplus_is_sclk(component);
|
||||
+}
|
||||
+
|
||||
+static bool snd_rpi_hifiberry_dacplus_is_pro_card(struct snd_soc_component *component)
|
||||
+{
|
||||
+ bool isClk44EN, isClk48En, isNoClk;
|
||||
+
|
||||
+ snd_rpi_hifiberry_dacplus_clk_gpio(component);
|
||||
+
|
||||
+ snd_rpi_hifiberry_dacplus_select_clk(component, HIFIBERRY_DACPRO_CLK44EN);
|
||||
+ isClk44EN = snd_rpi_hifiberry_dacplus_is_sclk_sleep(component);
|
||||
+
|
||||
+ snd_rpi_hifiberry_dacplus_select_clk(component, HIFIBERRY_DACPRO_NOCLOCK);
|
||||
+ isNoClk = snd_rpi_hifiberry_dacplus_is_sclk_sleep(component);
|
||||
+
|
||||
+ snd_rpi_hifiberry_dacplus_select_clk(component, HIFIBERRY_DACPRO_CLK48EN);
|
||||
+ isClk48En = snd_rpi_hifiberry_dacplus_is_sclk_sleep(component);
|
||||
+
|
||||
+ return (isClk44EN && isClk48En && !isNoClk);
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_hifiberry_dacplus_clk_for_rate(int sample_rate)
|
||||
+{
|
||||
+ int type;
|
||||
+
|
||||
+ switch (sample_rate) {
|
||||
+ case 11025:
|
||||
+ case 22050:
|
||||
+ case 44100:
|
||||
+ case 88200:
|
||||
+ case 176400:
|
||||
+ case 352800:
|
||||
+ type = HIFIBERRY_DACPRO_CLK44EN;
|
||||
+ break;
|
||||
+ default:
|
||||
+ type = HIFIBERRY_DACPRO_CLK48EN;
|
||||
+ break;
|
||||
+ }
|
||||
+ return type;
|
||||
+}
|
||||
+
|
||||
+static void snd_rpi_hifiberry_dacplus_set_sclk(struct snd_soc_component *component,
|
||||
+ int sample_rate)
|
||||
+{
|
||||
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ if (!IS_ERR(pcm512x->sclk)) {
|
||||
+ int ctype;
|
||||
+
|
||||
+ ctype = snd_rpi_hifiberry_dacplus_clk_for_rate(sample_rate);
|
||||
+ clk_set_rate(pcm512x->sclk, (ctype == HIFIBERRY_DACPRO_CLK44EN)
|
||||
+ ? CLK_44EN_RATE : CLK_48EN_RATE);
|
||||
+ snd_rpi_hifiberry_dacplus_select_clk(component, ctype);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct pcm512x_priv *priv;
|
||||
+
|
||||
+ if (slave)
|
||||
+ snd_rpi_hifiberry_is_dacpro = false;
|
||||
+ else
|
||||
+ snd_rpi_hifiberry_is_dacpro =
|
||||
+ snd_rpi_hifiberry_dacplus_is_pro_card(component);
|
||||
+
|
||||
+ if (snd_rpi_hifiberry_is_dacpro) {
|
||||
+ struct snd_soc_dai_link *dai = rtd->dai_link;
|
||||
+
|
||||
+ dai->name = "HiFiBerry DAC+ Pro";
|
||||
+ dai->stream_name = "HiFiBerry DAC+ Pro HiFi";
|
||||
+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
+ | SND_SOC_DAIFMT_CBM_CFM;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
|
||||
+ } else {
|
||||
+ priv = snd_soc_component_get_drvdata(component);
|
||||
+ priv->sclk = ERR_PTR(-ENOENT);
|
||||
+ }
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
|
||||
+
|
||||
+ if (digital_gain_0db_limit)
|
||||
+ {
|
||||
+ int ret;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_hifiberry_dacplus_update_rate_den(
|
||||
+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
|
||||
+ struct snd_ratnum *rats_no_pll;
|
||||
+ unsigned int num = 0, den = 0;
|
||||
+ int err;
|
||||
+
|
||||
+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
|
||||
+ if (!rats_no_pll)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
|
||||
+ rats_no_pll->den_min = 1;
|
||||
+ rats_no_pll->den_max = 128;
|
||||
+ rats_no_pll->den_step = 1;
|
||||
+
|
||||
+ err = snd_interval_ratnum(hw_param_interval(params,
|
||||
+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
|
||||
+ if (err >= 0 && den) {
|
||||
+ params->rate_num = num;
|
||||
+ params->rate_den = den;
|
||||
+ }
|
||||
+
|
||||
+ devm_kfree(rtd->dev, rats_no_pll);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_hifiberry_dacplus_hw_params(
|
||||
+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ int channels = params_channels(params);
|
||||
+ int width = 32;
|
||||
+
|
||||
+ if (snd_rpi_hifiberry_is_dacpro) {
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+
|
||||
+ width = snd_pcm_format_physical_width(params_format(params));
|
||||
+
|
||||
+ snd_rpi_hifiberry_dacplus_set_sclk(component,
|
||||
+ params_rate(params));
|
||||
+
|
||||
+ ret = snd_rpi_hifiberry_dacplus_update_rate_den(
|
||||
+ substream, params);
|
||||
+ }
|
||||
+
|
||||
+ ret = snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, channels * width);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = snd_soc_dai_set_bclk_ratio(rtd->codec_dai, channels * width);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_hifiberry_dacplus_startup(
|
||||
+ struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void snd_rpi_hifiberry_dacplus_shutdown(
|
||||
+ struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
|
||||
+}
|
||||
+
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops snd_rpi_hifiberry_dacplus_ops = {
|
||||
+ .hw_params = snd_rpi_hifiberry_dacplus_hw_params,
|
||||
+ .startup = snd_rpi_hifiberry_dacplus_startup,
|
||||
+ .shutdown = snd_rpi_hifiberry_dacplus_shutdown,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(rpi_hifiberry_dacplus,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplus_dai[] = {
|
||||
+{
|
||||
+ .name = "HiFiBerry DAC+",
|
||||
+ .stream_name = "HiFiBerry DAC+ HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ .ops = &snd_rpi_hifiberry_dacplus_ops,
|
||||
+ .init = snd_rpi_hifiberry_dacplus_init,
|
||||
+ SND_SOC_DAILINK_REG(rpi_hifiberry_dacplus),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
|
||||
+ .name = "snd_rpi_hifiberry_dacplus",
|
||||
+ .driver_name = "HifiberryDacp",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = snd_rpi_hifiberry_dacplus_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai;
|
||||
+
|
||||
+ dai = &snd_rpi_hifiberry_dacplus_dai[0];
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+
|
||||
+ digital_gain_0db_limit = !of_property_read_bool(
|
||||
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
|
||||
+ slave = of_property_read_bool(pdev->dev.of_node,
|
||||
+ "hifiberry-dacplus,slave");
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev,
|
||||
+ &snd_rpi_hifiberry_dacplus);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "snd_soc_register_card() failed: %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id snd_rpi_hifiberry_dacplus_of_match[] = {
|
||||
+ { .compatible = "hifiberry,hifiberry-dacplus", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplus_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_rpi_hifiberry_dacplus_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-hifiberry-dacplus",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_rpi_hifiberry_dacplus_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_hifiberry_dacplus_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_rpi_hifiberry_dacplus_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,647 @@
|
|||
From 224b9c7168311ae0e9e33f07a5c9c9d741d27fbd Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Matuschek <info@crazy-audio.com>
|
||||
Date: Mon, 4 Aug 2014 11:09:58 +0200
|
||||
Subject: [PATCH] Added driver for HiFiBerry Amp amplifier add-on board
|
||||
|
||||
The driver contains a low-level hardware driver for the TAS5713 and the
|
||||
drivers for the Raspberry Pi I2S subsystem.
|
||||
|
||||
TAS5713: return error if initialisation fails
|
||||
|
||||
Existing TAS5713 driver logs errors during initialisation, but does not return
|
||||
an error code. Therefore even if initialisation fails, the driver will still be
|
||||
loaded, but won't work. This patch fixes this. I2C communication error will now
|
||||
reported correctly by a non-zero return code.
|
||||
|
||||
HiFiBerry Amp: fix device-tree problems
|
||||
|
||||
Some code to load the driver based on device-tree-overlays was missing. This is added by this patch.
|
||||
---
|
||||
sound/soc/codecs/Kconfig | 4 +
|
||||
sound/soc/codecs/Makefile | 2 +
|
||||
sound/soc/codecs/tas5713.c | 366 +++++++++++++++++++++++++++++++++++++
|
||||
sound/soc/codecs/tas5713.h | 210 +++++++++++++++++++++
|
||||
4 files changed, 582 insertions(+)
|
||||
create mode 100644 sound/soc/codecs/tas5713.c
|
||||
create mode 100644 sound/soc/codecs/tas5713.h
|
||||
|
||||
--- a/sound/soc/codecs/Kconfig
|
||||
+++ b/sound/soc/codecs/Kconfig
|
||||
@@ -188,6 +188,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_TFA9879 if I2C
|
||||
select SND_SOC_TLV320AIC23_I2C if I2C
|
||||
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
|
||||
+ select SND_SOC_TAS5713 if I2C
|
||||
select SND_SOC_TLV320AIC26 if SPI_MASTER
|
||||
select SND_SOC_TLV320AIC31XX if I2C
|
||||
select SND_SOC_TLV320AIC32X4_I2C if I2C && COMMON_CLK
|
||||
@@ -1143,6 +1144,9 @@ config SND_SOC_TFA9879
|
||||
tristate "NXP Semiconductors TFA9879 amplifier"
|
||||
depends on I2C
|
||||
|
||||
+config SND_SOC_TAS5713
|
||||
+ tristate
|
||||
+
|
||||
config SND_SOC_TLV320AIC23
|
||||
tristate
|
||||
|
||||
--- a/sound/soc/codecs/Makefile
|
||||
+++ b/sound/soc/codecs/Makefile
|
||||
@@ -198,6 +198,7 @@ snd-soc-tas5720-objs := tas5720.o
|
||||
snd-soc-tas6424-objs := tas6424.o
|
||||
snd-soc-tda7419-objs := tda7419.o
|
||||
snd-soc-tfa9879-objs := tfa9879.o
|
||||
+snd-soc-tas5713-objs := tas5713.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
|
||||
snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
|
||||
@@ -482,6 +483,7 @@ obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc
|
||||
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
|
||||
obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o
|
||||
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
|
||||
+obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/codecs/tas5713.c
|
||||
@@ -0,0 +1,366 @@
|
||||
+/*
|
||||
+ * ASoC Driver for TAS5713
|
||||
+ *
|
||||
+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
|
||||
+ * Copyright 2014
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/moduleparam.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/pm.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/regulator/consumer.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/initval.h>
|
||||
+#include <sound/tlv.h>
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/string.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <asm/uaccess.h>
|
||||
+
|
||||
+#include "tas5713.h"
|
||||
+
|
||||
+
|
||||
+static struct i2c_client *i2c;
|
||||
+
|
||||
+struct tas5713_priv {
|
||||
+ struct regmap *regmap;
|
||||
+ int mclk_div;
|
||||
+ struct snd_soc_component *component;
|
||||
+};
|
||||
+
|
||||
+static struct tas5713_priv *priv_data;
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * _ _ ___ _ ___ _ _
|
||||
+ * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___
|
||||
+ * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-<
|
||||
+ * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);
|
||||
+
|
||||
+
|
||||
+static const struct snd_kcontrol_new tas5713_snd_controls[] = {
|
||||
+ SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
|
||||
+ SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
|
||||
+};
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * __ __ _ _ ___ _
|
||||
+ * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _
|
||||
+ * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_|
|
||||
+ * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_|
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+static int tas5713_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ u16 blen = 0x00;
|
||||
+
|
||||
+ struct snd_soc_component *component = dai->component;
|
||||
+ priv_data->component = component;
|
||||
+
|
||||
+ switch (params_format(params)) {
|
||||
+ case SNDRV_PCM_FORMAT_S16_LE:
|
||||
+ blen = 0x03;
|
||||
+ break;
|
||||
+ case SNDRV_PCM_FORMAT_S20_3LE:
|
||||
+ blen = 0x1;
|
||||
+ break;
|
||||
+ case SNDRV_PCM_FORMAT_S24_LE:
|
||||
+ blen = 0x04;
|
||||
+ break;
|
||||
+ case SNDRV_PCM_FORMAT_S32_LE:
|
||||
+ blen = 0x05;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(dai->dev, "Unsupported word length: %u\n",
|
||||
+ params_format(params));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ // set word length
|
||||
+ snd_soc_component_update_bits(component, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
|
||||
+{
|
||||
+ unsigned int val = 0;
|
||||
+
|
||||
+ struct tas5713_priv *tas5713;
|
||||
+ struct snd_soc_component *component = dai->component;
|
||||
+ tas5713 = snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ if (mute) {
|
||||
+ val = TAS5713_SOFT_MUTE_ALL;
|
||||
+ }
|
||||
+
|
||||
+ return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const struct snd_soc_dai_ops tas5713_dai_ops = {
|
||||
+ .hw_params = tas5713_hw_params,
|
||||
+ .mute_stream = tas5713_mute_stream,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static struct snd_soc_dai_driver tas5713_dai = {
|
||||
+ .name = "tas5713-hifi",
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_48000,
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ),
|
||||
+ },
|
||||
+ .ops = &tas5713_dai_ops,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * ___ _ ___ _
|
||||
+ * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _
|
||||
+ * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_|
|
||||
+ * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_|
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+static void tas5713_remove(struct snd_soc_component *component)
|
||||
+{
|
||||
+ struct tas5713_priv *tas5713;
|
||||
+
|
||||
+ tas5713 = snd_soc_component_get_drvdata(component);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int tas5713_probe(struct snd_soc_component *component)
|
||||
+{
|
||||
+ struct tas5713_priv *tas5713;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ i2c = container_of(component->dev, struct i2c_client, dev);
|
||||
+
|
||||
+ tas5713 = snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ // Reset error
|
||||
+ ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00);
|
||||
+ if (ret < 0) return ret;
|
||||
+
|
||||
+ // Trim oscillator
|
||||
+ ret = snd_soc_component_write(component, TAS5713_OSC_TRIM, 0x00);
|
||||
+ if (ret < 0) return ret;
|
||||
+ msleep(1000);
|
||||
+
|
||||
+ // Reset error
|
||||
+ ret = snd_soc_component_write(component, TAS5713_ERROR_STATUS, 0x00);
|
||||
+ if (ret < 0) return ret;
|
||||
+
|
||||
+ // Clock mode: 44/48kHz, MCLK=64xfs
|
||||
+ ret = snd_soc_component_write(component, TAS5713_CLOCK_CTRL, 0x60);
|
||||
+ if (ret < 0) return ret;
|
||||
+
|
||||
+ // I2S 24bit
|
||||
+ ret = snd_soc_component_write(component, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
|
||||
+ if (ret < 0) return ret;
|
||||
+
|
||||
+ // Unmute
|
||||
+ ret = snd_soc_component_write(component, TAS5713_SYSTEM_CTRL2, 0x00);
|
||||
+ if (ret < 0) return ret;
|
||||
+ ret = snd_soc_component_write(component, TAS5713_SOFT_MUTE, 0x00);
|
||||
+ if (ret < 0) return ret;
|
||||
+
|
||||
+ // Set volume to 0db
|
||||
+ ret = snd_soc_component_write(component, TAS5713_VOL_MASTER, 0x00);
|
||||
+ if (ret < 0) return ret;
|
||||
+
|
||||
+ // Now start programming the default initialization sequence
|
||||
+ for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) {
|
||||
+ ret = i2c_master_send(i2c,
|
||||
+ tas5713_init_sequence[i].data,
|
||||
+ tas5713_init_sequence[i].size);
|
||||
+ if (ret < 0) {
|
||||
+ printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Unmute
|
||||
+ ret = snd_soc_component_write(component, TAS5713_SYSTEM_CTRL2, 0x00);
|
||||
+ if (ret < 0) return ret;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static struct snd_soc_component_driver soc_codec_dev_tas5713 = {
|
||||
+ .probe = tas5713_probe,
|
||||
+ .remove = tas5713_remove,
|
||||
+ .controls = tas5713_snd_controls,
|
||||
+ .num_controls = ARRAY_SIZE(tas5713_snd_controls),
|
||||
+};
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * ___ ___ ___ ___ _
|
||||
+ * |_ _|_ ) __| | \ _ _(_)_ _____ _ _
|
||||
+ * | | / / (__ | |) | '_| \ V / -_) '_|
|
||||
+ * |___/___\___| |___/|_| |_|\_/\___|_|
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+static const struct reg_default tas5713_reg_defaults[] = {
|
||||
+ { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB
|
||||
+ { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB
|
||||
+ { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB
|
||||
+ { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static bool tas5713_reg_volatile(struct device *dev, unsigned int reg)
|
||||
+{
|
||||
+ switch (reg) {
|
||||
+ case TAS5713_DEVICE_ID:
|
||||
+ case TAS5713_ERROR_STATUS:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const struct of_device_id tas5713_of_match[] = {
|
||||
+ { .compatible = "ti,tas5713", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, tas5713_of_match);
|
||||
+
|
||||
+
|
||||
+static struct regmap_config tas5713_regmap_config = {
|
||||
+ .reg_bits = 8,
|
||||
+ .val_bits = 8,
|
||||
+
|
||||
+ .max_register = TAS5713_MAX_REGISTER,
|
||||
+ .volatile_reg = tas5713_reg_volatile,
|
||||
+
|
||||
+ .cache_type = REGCACHE_RBTREE,
|
||||
+ .reg_defaults = tas5713_reg_defaults,
|
||||
+ .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults),
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static int tas5713_i2c_probe(struct i2c_client *i2c,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL);
|
||||
+ if (!priv_data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config);
|
||||
+ if (IS_ERR(priv_data->regmap)) {
|
||||
+ ret = PTR_ERR(priv_data->regmap);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ i2c_set_clientdata(i2c, priv_data);
|
||||
+
|
||||
+ ret = snd_soc_register_component(&i2c->dev,
|
||||
+ &soc_codec_dev_tas5713, &tas5713_dai, 1);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int tas5713_i2c_remove(struct i2c_client *i2c)
|
||||
+{
|
||||
+ snd_soc_unregister_component(&i2c->dev);
|
||||
+ i2c_set_clientdata(i2c, NULL);
|
||||
+
|
||||
+ kfree(priv_data);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const struct i2c_device_id tas5713_i2c_id[] = {
|
||||
+ { "tas5713", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id);
|
||||
+
|
||||
+
|
||||
+static struct i2c_driver tas5713_i2c_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "tas5713",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = tas5713_of_match,
|
||||
+ },
|
||||
+ .probe = tas5713_i2c_probe,
|
||||
+ .remove = tas5713_i2c_remove,
|
||||
+ .id_table = tas5713_i2c_id
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static int __init tas5713_modinit(void)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ ret = i2c_add_driver(&tas5713_i2c_driver);
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n",
|
||||
+ ret);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+module_init(tas5713_modinit);
|
||||
+
|
||||
+
|
||||
+static void __exit tas5713_exit(void)
|
||||
+{
|
||||
+ i2c_del_driver(&tas5713_i2c_driver);
|
||||
+}
|
||||
+module_exit(tas5713_exit);
|
||||
+
|
||||
+
|
||||
+MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
|
||||
+MODULE_DESCRIPTION("ASoC driver for TAS5713");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/codecs/tas5713.h
|
||||
@@ -0,0 +1,210 @@
|
||||
+/*
|
||||
+ * ASoC Driver for TAS5713
|
||||
+ *
|
||||
+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
|
||||
+ * Copyright 2014
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _TAS5713_H
|
||||
+#define _TAS5713_H
|
||||
+
|
||||
+
|
||||
+// TAS5713 I2C-bus register addresses
|
||||
+
|
||||
+#define TAS5713_CLOCK_CTRL 0x00
|
||||
+#define TAS5713_DEVICE_ID 0x01
|
||||
+#define TAS5713_ERROR_STATUS 0x02
|
||||
+#define TAS5713_SYSTEM_CTRL1 0x03
|
||||
+#define TAS5713_SERIAL_DATA_INTERFACE 0x04
|
||||
+#define TAS5713_SYSTEM_CTRL2 0x05
|
||||
+#define TAS5713_SOFT_MUTE 0x06
|
||||
+#define TAS5713_VOL_MASTER 0x07
|
||||
+#define TAS5713_VOL_CH1 0x08
|
||||
+#define TAS5713_VOL_CH2 0x09
|
||||
+#define TAS5713_VOL_HEADPHONE 0x0A
|
||||
+#define TAS5713_VOL_CONFIG 0x0E
|
||||
+#define TAS5713_MODULATION_LIMIT 0x10
|
||||
+#define TAS5713_IC_DLY_CH1 0x11
|
||||
+#define TAS5713_IC_DLY_CH2 0x12
|
||||
+#define TAS5713_IC_DLY_CH3 0x13
|
||||
+#define TAS5713_IC_DLY_CH4 0x14
|
||||
+
|
||||
+#define TAS5713_START_STOP_PERIOD 0x1A
|
||||
+#define TAS5713_OSC_TRIM 0x1B
|
||||
+#define TAS5713_BKND_ERR 0x1C
|
||||
+
|
||||
+#define TAS5713_INPUT_MUX 0x20
|
||||
+#define TAS5713_SRC_SELECT_CH4 0x21
|
||||
+#define TAS5713_PWM_MUX 0x25
|
||||
+
|
||||
+#define TAS5713_CH1_BQ0 0x29
|
||||
+#define TAS5713_CH1_BQ1 0x2A
|
||||
+#define TAS5713_CH1_BQ2 0x2B
|
||||
+#define TAS5713_CH1_BQ3 0x2C
|
||||
+#define TAS5713_CH1_BQ4 0x2D
|
||||
+#define TAS5713_CH1_BQ5 0x2E
|
||||
+#define TAS5713_CH1_BQ6 0x2F
|
||||
+#define TAS5713_CH1_BQ7 0x58
|
||||
+#define TAS5713_CH1_BQ8 0x59
|
||||
+
|
||||
+#define TAS5713_CH2_BQ0 0x30
|
||||
+#define TAS5713_CH2_BQ1 0x31
|
||||
+#define TAS5713_CH2_BQ2 0x32
|
||||
+#define TAS5713_CH2_BQ3 0x33
|
||||
+#define TAS5713_CH2_BQ4 0x34
|
||||
+#define TAS5713_CH2_BQ5 0x35
|
||||
+#define TAS5713_CH2_BQ6 0x36
|
||||
+#define TAS5713_CH2_BQ7 0x5C
|
||||
+#define TAS5713_CH2_BQ8 0x5D
|
||||
+
|
||||
+#define TAS5713_CH4_BQ0 0x5A
|
||||
+#define TAS5713_CH4_BQ1 0x5B
|
||||
+#define TAS5713_CH3_BQ0 0x5E
|
||||
+#define TAS5713_CH3_BQ1 0x5F
|
||||
+
|
||||
+#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B
|
||||
+#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C
|
||||
+#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E
|
||||
+#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F
|
||||
+#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40
|
||||
+#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43
|
||||
+#define TAS5713_DRC_CTRL 0x46
|
||||
+
|
||||
+#define TAS5713_BANK_SW_CTRL 0x50
|
||||
+#define TAS5713_CH1_OUTPUT_MIXER 0x51
|
||||
+#define TAS5713_CH2_OUTPUT_MIXER 0x52
|
||||
+#define TAS5713_CH1_INPUT_MIXER 0x53
|
||||
+#define TAS5713_CH2_INPUT_MIXER 0x54
|
||||
+#define TAS5713_OUTPUT_POST_SCALE 0x56
|
||||
+#define TAS5713_OUTPUT_PRESCALE 0x57
|
||||
+
|
||||
+#define TAS5713_IDF_POST_SCALE 0x62
|
||||
+
|
||||
+#define TAS5713_CH1_INLINE_MIXER 0x70
|
||||
+#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71
|
||||
+#define TAS5713_CH1_R_CHANNEL_MIXER 0x72
|
||||
+#define TAS5713_CH1_L_CHANNEL_MIXER 0x73
|
||||
+#define TAS5713_CH2_INLINE_MIXER 0x74
|
||||
+#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75
|
||||
+#define TAS5713_CH2_L_CHANNEL_MIXER 0x76
|
||||
+#define TAS5713_CH2_R_CHANNEL_MIXER 0x77
|
||||
+
|
||||
+#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8
|
||||
+#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9
|
||||
+
|
||||
+#define TAS5713_REGISTER_COUNT 0x46
|
||||
+#define TAS5713_MAX_REGISTER 0xF9
|
||||
+
|
||||
+
|
||||
+// Bitmasks for registers
|
||||
+#define TAS5713_SOFT_MUTE_ALL 0x07
|
||||
+
|
||||
+
|
||||
+
|
||||
+struct tas5713_init_command {
|
||||
+ const int size;
|
||||
+ const char *const data;
|
||||
+};
|
||||
+
|
||||
+static const struct tas5713_init_command tas5713_init_sequence[] = {
|
||||
+
|
||||
+ // Trim oscillator
|
||||
+ { .size = 2, .data = "\x1B\x00" },
|
||||
+ // System control register 1 (0x03): block DC
|
||||
+ { .size = 2, .data = "\x03\x80" },
|
||||
+ // Mute everything
|
||||
+ { .size = 2, .data = "\x05\x40" },
|
||||
+ // Modulation limit register (0x10): 97.7%
|
||||
+ { .size = 2, .data = "\x10\x02" },
|
||||
+ // Interchannel delay registers
|
||||
+ // (0x11, 0x12, 0x13, and 0x14): BD mode
|
||||
+ { .size = 2, .data = "\x11\xB8" },
|
||||
+ { .size = 2, .data = "\x12\x60" },
|
||||
+ { .size = 2, .data = "\x13\xA0" },
|
||||
+ { .size = 2, .data = "\x14\x48" },
|
||||
+ // PWM shutdown group register (0x19): no shutdown
|
||||
+ { .size = 2, .data = "\x19\x00" },
|
||||
+ // Input multiplexer register (0x20): BD mode
|
||||
+ { .size = 2, .data = "\x20\x00\x89\x77\x72" },
|
||||
+ // PWM output mux register (0x25)
|
||||
+ // Channel 1 --> OUTA, channel 1 neg --> OUTB
|
||||
+ // Channel 2 --> OUTC, channel 2 neg --> OUTD
|
||||
+ { .size = 5, .data = "\x25\x01\x02\x13\x45" },
|
||||
+ // DRC control (0x46): DRC off
|
||||
+ { .size = 5, .data = "\x46\x00\x00\x00\x00" },
|
||||
+ // BKND_ERR register (0x1C): 299ms reset period
|
||||
+ { .size = 2, .data = "\x1C\x07" },
|
||||
+ // Mute channel 3
|
||||
+ { .size = 2, .data = "\x0A\xFF" },
|
||||
+ // Volume configuration register (0x0E): volume slew 512 steps
|
||||
+ { .size = 2, .data = "\x0E\x90" },
|
||||
+ // Clock control register (0x00): 44/48kHz, MCLK=64xfs
|
||||
+ { .size = 2, .data = "\x00\x60" },
|
||||
+ // Bank switch and eq control (0x50): no bank switching
|
||||
+ { .size = 5, .data = "\x50\x00\x00\x00\x00" },
|
||||
+ // Volume registers (0x07, 0x08, 0x09, 0x0A)
|
||||
+ { .size = 2, .data = "\x07\x20" },
|
||||
+ { .size = 2, .data = "\x08\x30" },
|
||||
+ { .size = 2, .data = "\x09\x30" },
|
||||
+ { .size = 2, .data = "\x0A\xFF" },
|
||||
+ // 0x72, 0x73, 0x76, 0x77 input mixer:
|
||||
+ // no intermix between channels
|
||||
+ { .size = 5, .data = "\x72\x00\x00\x00\x00" },
|
||||
+ { .size = 5, .data = "\x73\x00\x80\x00\x00" },
|
||||
+ { .size = 5, .data = "\x76\x00\x00\x00\x00" },
|
||||
+ { .size = 5, .data = "\x77\x00\x80\x00\x00" },
|
||||
+ // 0x70, 0x71, 0x74, 0x75 inline DRC mixer:
|
||||
+ // no inline DRC inmix
|
||||
+ { .size = 5, .data = "\x70\x00\x80\x00\x00" },
|
||||
+ { .size = 5, .data = "\x71\x00\x00\x00\x00" },
|
||||
+ { .size = 5, .data = "\x74\x00\x80\x00\x00" },
|
||||
+ { .size = 5, .data = "\x75\x00\x00\x00\x00" },
|
||||
+ // 0x56, 0x57 Output scale
|
||||
+ { .size = 5, .data = "\x56\x00\x80\x00\x00" },
|
||||
+ { .size = 5, .data = "\x57\x00\x02\x00\x00" },
|
||||
+ // 0x3B, 0x3c
|
||||
+ { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" },
|
||||
+ { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
|
||||
+ { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" },
|
||||
+ { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
|
||||
+ { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
|
||||
+ { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
|
||||
+ // 0x51, 0x52: output mixer
|
||||
+ { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" },
|
||||
+ // PEQ defaults
|
||||
+ { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+ { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+#endif /* _TAS5713_H */
|
|
@ -0,0 +1,174 @@
|
|||
From b3cf65c5d12ff3bd52843a35dc912a705371d5b6 Mon Sep 17 00:00:00 2001
|
||||
From: Waldemar Brodkorb <wbrodkorb@conet.de>
|
||||
Date: Wed, 25 Mar 2015 09:26:17 +0100
|
||||
Subject: [PATCH] Add driver for rpi-proto
|
||||
|
||||
Forward port of 3.10.x driver from https://github.com/koalo
|
||||
We are using a custom board and would like to use rpi 3.18.x
|
||||
kernel. Patch works fine for our embedded system.
|
||||
|
||||
URL to the audio chip:
|
||||
http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/
|
||||
|
||||
Playback tested with devicetree enabled.
|
||||
|
||||
Signed-off-by: Waldemar Brodkorb <wbrodkorb@conet.de>
|
||||
|
||||
ASoC: rpi-proto: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/rpi-proto.c | 147 ++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 147 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/rpi-proto.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/rpi-proto.c
|
||||
@@ -0,0 +1,147 @@
|
||||
+/*
|
||||
+ * ASoC driver for PROTO AudioCODEC (with a WM8731)
|
||||
+ * connected to a Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Florian Meier, <koalo@koalo.de>
|
||||
+ * Copyright 2013
|
||||
+ *
|
||||
+ * 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/platform_device.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+
|
||||
+#include "../codecs/wm8731.h"
|
||||
+
|
||||
+static const unsigned int wm8731_rates_12288000[] = {
|
||||
+ 8000, 32000, 48000, 96000,
|
||||
+};
|
||||
+
|
||||
+static struct snd_pcm_hw_constraint_list wm8731_constraints_12288000 = {
|
||||
+ .list = wm8731_rates_12288000,
|
||||
+ .count = ARRAY_SIZE(wm8731_rates_12288000),
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_proto_startup(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ /* Setup constraints, because there is a 12.288 MHz XTAL on the board */
|
||||
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_RATE,
|
||||
+ &wm8731_constraints_12288000);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
+ int sysclk = 12288000; /* This is fixed on this board */
|
||||
+
|
||||
+ /* Set proto bclk */
|
||||
+ int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2);
|
||||
+ if (ret < 0){
|
||||
+ dev_err(rtd->card->dev,
|
||||
+ "Failed to set BCLK ratio %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Set proto sysclk */
|
||||
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
+ sysclk, SND_SOC_CLOCK_IN);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(rtd->card->dev,
|
||||
+ "Failed to set WM8731 SYSCLK: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops snd_rpi_proto_ops = {
|
||||
+ .startup = snd_rpi_proto_startup,
|
||||
+ .hw_params = snd_rpi_proto_hw_params,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(rpi_proto,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.1-001a", "wm8731-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_proto_dai[] = {
|
||||
+{
|
||||
+ .name = "WM8731",
|
||||
+ .stream_name = "WM8731 HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S
|
||||
+ | SND_SOC_DAIFMT_NB_NF
|
||||
+ | SND_SOC_DAIFMT_CBM_CFM,
|
||||
+ .ops = &snd_rpi_proto_ops,
|
||||
+ SND_SOC_DAILINK_REG(rpi_proto),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_rpi_proto = {
|
||||
+ .name = "snd_rpi_proto",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = snd_rpi_proto_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_rpi_proto_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_proto_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_rpi_proto.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai = &snd_rpi_proto_dai[0];
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_proto);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "snd_soc_register_card() failed: %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id snd_rpi_proto_of_match[] = {
|
||||
+ { .compatible = "rpi,rpi-proto", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_rpi_proto_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_rpi_proto_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-proto",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_rpi_proto_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_proto_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_rpi_proto_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Florian Meier");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,179 @@
|
|||
From 752d2f2029aa9b3710e9fef40757d834899e3ff1 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Shaw <shawaj@gmail.com>
|
||||
Date: Thu, 7 Apr 2016 21:26:21 +0100
|
||||
Subject: [PATCH] Add Support for JustBoom Audio boards
|
||||
|
||||
justboom-dac: Adjust for ALSA API change
|
||||
|
||||
As of 4.4, snd_soc_limit_volume now takes a struct snd_soc_card *
|
||||
rather than a struct snd_soc_codec *.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
ASoC: justboom-dac: fix S24_LE format
|
||||
|
||||
Remove set_bclk_ratio call so 24-bit data is transmitted in
|
||||
24 bclk cycles.
|
||||
|
||||
Also remove hw_params as it's no longer needed.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: justboom-dac: use modern dai_link style
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/justboom-dac.c | 147 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 147 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/justboom-dac.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/justboom-dac.c
|
||||
@@ -0,0 +1,147 @@
|
||||
+/*
|
||||
+ * ASoC Driver for JustBoom DAC Raspberry Pi HAT Sound Card
|
||||
+ *
|
||||
+ * Author: Milan Neskovic
|
||||
+ * Copyright 2016
|
||||
+ * based on code by Daniel Matuschek <info@crazy-audio.com>
|
||||
+ * based on code by Florian Meier <florian.meier@koalo.de>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+
|
||||
+#include "../codecs/pcm512x.h"
|
||||
+
|
||||
+static bool digital_gain_0db_limit = true;
|
||||
+
|
||||
+static int snd_rpi_justboom_dac_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
|
||||
+
|
||||
+ if (digital_gain_0db_limit)
|
||||
+ {
|
||||
+ int ret;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_justboom_dac_startup(struct snd_pcm_substream *substream) {
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void snd_rpi_justboom_dac_shutdown(struct snd_pcm_substream *substream) {
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
|
||||
+}
|
||||
+
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops snd_rpi_justboom_dac_ops = {
|
||||
+ .startup = snd_rpi_justboom_dac_startup,
|
||||
+ .shutdown = snd_rpi_justboom_dac_shutdown,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(hifi,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_justboom_dac_dai[] = {
|
||||
+{
|
||||
+ .name = "JustBoom DAC",
|
||||
+ .stream_name = "JustBoom DAC HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ .ops = &snd_rpi_justboom_dac_ops,
|
||||
+ .init = snd_rpi_justboom_dac_init,
|
||||
+ SND_SOC_DAILINK_REG(hifi),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_rpi_justboom_dac = {
|
||||
+ .name = "snd_rpi_justboom_dac",
|
||||
+ .driver_name = "JustBoomDac",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = snd_rpi_justboom_dac_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_rpi_justboom_dac_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_justboom_dac_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_rpi_justboom_dac.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai = &snd_rpi_justboom_dac_dai[0];
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+
|
||||
+ digital_gain_0db_limit = !of_property_read_bool(
|
||||
+ pdev->dev.of_node, "justboom,24db_digital_gain");
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_justboom_dac);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "snd_soc_register_card() failed: %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id snd_rpi_justboom_dac_of_match[] = {
|
||||
+ { .compatible = "justboom,justboom-dac", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_rpi_justboom_dac_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_rpi_justboom_dac_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-justboom-dac",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_rpi_justboom_dac_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_justboom_dac_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_rpi_justboom_dac_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Milan Neskovic <info@justboom.co>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for JustBoom PI DAC HAT Sound Card");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,213 @@
|
|||
From 511bf354a97f00d12e1ffc3c51083699914de610 Mon Sep 17 00:00:00 2001
|
||||
From: Matt Flax <flatmax@flatmax.org>
|
||||
Date: Mon, 16 May 2016 21:36:31 +1000
|
||||
Subject: [PATCH] New AudioInjector.net Pi soundcard with low jitter
|
||||
audio in and out.
|
||||
|
||||
Contains the sound/soc/bcm ALSA machine driver and necessary alterations to the Kconfig and Makefile.
|
||||
Adds the dts overlay and updates the Makefile and README.
|
||||
Updates the relevant defconfig files to enable building for the Raspberry Pi.
|
||||
Thanks to Phil Elwell (pelwell) for the review, simple-card concepts and discussion. Thanks to Clive Messer for overlay naming suggestions.
|
||||
|
||||
Added support for headphones, microphone and bclk_ratio settings.
|
||||
|
||||
This patch adds headphone and microphone capability to the Audio Injector sound card. The patch also sets the bit clock ratio for use in the bcm2835-i2s driver. The bcm2835-i2s can't handle an 8 kHz sample rate when the bit clock is at 12 MHz because its register is only 10 bits wide which can't represent the ch2 offset of 1508. For that reason, the rate constraint is added.
|
||||
|
||||
ASoC: audioinjector-pi-soundcard: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/audioinjector-pi-soundcard.c | 187 +++++++++++++++++++++
|
||||
1 file changed, 187 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/audioinjector-pi-soundcard.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/audioinjector-pi-soundcard.c
|
||||
@@ -0,0 +1,187 @@
|
||||
+/*
|
||||
+ * ASoC Driver for AudioInjector Pi add on soundcard
|
||||
+ *
|
||||
+ * Created on: 13-May-2016
|
||||
+ * Author: flatmax@flatmax.org
|
||||
+ * based on code by Cliff Cai <Cliff.Cai@analog.com> for the ssm2602 machine blackfin.
|
||||
+ * with help from Lars-Peter Clausen for simplifying the original code to use the dai_fmt field.
|
||||
+ * i2s_node code taken from the other sound/soc/bcm machine drivers.
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Flatmax Pty. 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.
|
||||
+ *
|
||||
+ * 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/module.h>
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/control.h>
|
||||
+
|
||||
+#include "../codecs/wm8731.h"
|
||||
+
|
||||
+static const unsigned int bcm2835_rates_12000000[] = {
|
||||
+ 8000, 16000, 32000, 44100, 48000, 96000, 88200,
|
||||
+};
|
||||
+
|
||||
+static struct snd_pcm_hw_constraint_list bcm2835_constraints_12000000 = {
|
||||
+ .list = bcm2835_rates_12000000,
|
||||
+ .count = ARRAY_SIZE(bcm2835_rates_12000000),
|
||||
+};
|
||||
+
|
||||
+static int snd_audioinjector_pi_soundcard_startup(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ /* Setup constraints, because there is a 12 MHz XTAL on the board */
|
||||
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_RATE,
|
||||
+ &bcm2835_constraints_12000000);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_audioinjector_pi_soundcard_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
+
|
||||
+ switch (params_rate(params)){
|
||||
+ case 8000:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 1);
|
||||
+ case 16000:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 750);
|
||||
+ case 32000:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 375);
|
||||
+ case 44100:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 272);
|
||||
+ case 48000:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 250);
|
||||
+ case 88200:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 136);
|
||||
+ case 96000:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 125);
|
||||
+ default:
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 125);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops snd_audioinjector_pi_soundcard_ops = {
|
||||
+ .startup = snd_audioinjector_pi_soundcard_startup,
|
||||
+ .hw_params = snd_audioinjector_pi_soundcard_hw_params,
|
||||
+};
|
||||
+
|
||||
+static int audioinjector_pi_soundcard_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, WM8731_SYSCLK_XTAL, 12000000, SND_SOC_CLOCK_IN);
|
||||
+}
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(audioinjector_pi,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.1-001a", "wm8731-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link audioinjector_pi_soundcard_dai[] = {
|
||||
+ {
|
||||
+ .name = "AudioInjector audio",
|
||||
+ .stream_name = "AudioInjector audio",
|
||||
+ .ops = &snd_audioinjector_pi_soundcard_ops,
|
||||
+ .init = audioinjector_pi_soundcard_dai_init,
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF,
|
||||
+ SND_SOC_DAILINK_REG(audioinjector_pi),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
|
||||
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
+ SND_SOC_DAPM_LINE("Line In Jacks", NULL),
|
||||
+ SND_SOC_DAPM_MIC("Microphone", NULL),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route audioinjector_audio_map[] = {
|
||||
+ /* headphone connected to LHPOUT, RHPOUT */
|
||||
+ {"Headphone Jack", NULL, "LHPOUT"},
|
||||
+ {"Headphone Jack", NULL, "RHPOUT"},
|
||||
+
|
||||
+ /* speaker connected to LOUT, ROUT */
|
||||
+ {"Ext Spk", NULL, "ROUT"},
|
||||
+ {"Ext Spk", NULL, "LOUT"},
|
||||
+
|
||||
+ /* line inputs */
|
||||
+ {"Line In Jacks", NULL, "Line Input"},
|
||||
+
|
||||
+ /* mic is connected to Mic Jack, with WM8731 Mic Bias */
|
||||
+ {"Microphone", NULL, "Mic Bias"},
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_card snd_soc_audioinjector = {
|
||||
+ .name = "audioinjector-pi-soundcard",
|
||||
+ .dai_link = audioinjector_pi_soundcard_dai,
|
||||
+ .num_links = ARRAY_SIZE(audioinjector_pi_soundcard_dai),
|
||||
+
|
||||
+ .dapm_widgets = wm8731_dapm_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
|
||||
+ .dapm_routes = audioinjector_audio_map,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(audioinjector_audio_map),
|
||||
+};
|
||||
+
|
||||
+static int audioinjector_pi_soundcard_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct snd_soc_card *card = &snd_soc_audioinjector;
|
||||
+ int ret;
|
||||
+
|
||||
+ card->dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct snd_soc_dai_link *dai = &audioinjector_pi_soundcard_dai[0];
|
||||
+ struct device_node *i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ } else
|
||||
+ if (!dai->cpus->of_node) {
|
||||
+ dev_err(&pdev->dev, "Property 'i2s-controller' missing or invalid\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if ((ret = devm_snd_soc_register_card(&pdev->dev, card))) {
|
||||
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id audioinjector_pi_soundcard_of_match[] = {
|
||||
+ { .compatible = "ai,audioinjector-pi-soundcard", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, audioinjector_pi_soundcard_of_match);
|
||||
+
|
||||
+static struct platform_driver audioinjector_pi_soundcard_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "audioinjector-stereo",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = audioinjector_pi_soundcard_of_match,
|
||||
+ },
|
||||
+ .probe = audioinjector_pi_soundcard_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(audioinjector_pi_soundcard_driver);
|
||||
+MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
|
||||
+MODULE_DESCRIPTION("AudioInjector.net Pi Soundcard");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+MODULE_ALIAS("platform:audioinjector-pi-soundcard");
|
||||
+
|
|
@ -0,0 +1,438 @@
|
|||
From 2e0deecb1e303b2808c9c84486d20039741b773b Mon Sep 17 00:00:00 2001
|
||||
From: escalator2015 <jmtasende@gmail.com>
|
||||
Date: Tue, 24 May 2016 16:20:09 +0100
|
||||
Subject: [PATCH] New driver for RRA DigiDAC1 soundcard using WM8741 +
|
||||
WM8804
|
||||
|
||||
ASoC: digidac1-soundcard: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/digidac1-soundcard.c | 421 +++++++++++++++++++++++++++++
|
||||
1 file changed, 421 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/digidac1-soundcard.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/digidac1-soundcard.c
|
||||
@@ -0,0 +1,421 @@
|
||||
+/*
|
||||
+ * ASoC Driver for RRA DigiDAC1
|
||||
+ * Copyright 2016
|
||||
+ * Author: José M. Tasende <vintage@redrocksaudio.es>
|
||||
+ * based on the HifiBerry DAC driver by Florian Meier <florian.meier@koalo.de>
|
||||
+ * and the Wolfson card driver by Nikesh Oswal, <Nikesh.Oswal@wolfsonmicro.com>
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+#include <sound/soc-dapm.h>
|
||||
+#include <sound/tlv.h>
|
||||
+#include <linux/regulator/consumer.h>
|
||||
+
|
||||
+#include "../codecs/wm8804.h"
|
||||
+#include "../codecs/wm8741.h"
|
||||
+
|
||||
+#define WM8741_NUM_SUPPLIES 2
|
||||
+
|
||||
+/* codec private data */
|
||||
+struct wm8741_priv {
|
||||
+ struct wm8741_platform_data pdata;
|
||||
+ struct regmap *regmap;
|
||||
+ struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
|
||||
+ unsigned int sysclk;
|
||||
+ const struct snd_pcm_hw_constraint_list *sysclk_constraints;
|
||||
+};
|
||||
+
|
||||
+static int samplerate = 44100;
|
||||
+
|
||||
+/* New Alsa Controls not exposed by original wm8741 codec driver */
|
||||
+/* in actual driver the att. adjustment is wrong because */
|
||||
+/* this DAC has a coarse attenuation register with 4dB steps */
|
||||
+/* and a fine level register with 0.125dB steps */
|
||||
+/* each register has 32 steps so combining both we have 1024 steps */
|
||||
+/* of 0.125 dB. */
|
||||
+/* The original level controls from driver are removed at startup */
|
||||
+/* and replaced by the corrected ones. */
|
||||
+/* The same wm8741 driver can be used for wm8741 and wm8742 devices */
|
||||
+
|
||||
+static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, 0, 13, 0);
|
||||
+static const DECLARE_TLV_DB_SCALE(dac_tlv_coarse, -12700, 400, 1);
|
||||
+static const char *w8741_dither[4] = {"Off", "RPDF", "TPDF", "HPDF"};
|
||||
+static const char *w8741_filter[5] = {
|
||||
+ "Type 1", "Type 2", "Type 3", "Type 4", "Type 5"};
|
||||
+static const char *w8741_switch[2] = {"Off", "On"};
|
||||
+static const struct soc_enum w8741_enum[] = {
|
||||
+SOC_ENUM_SINGLE(WM8741_MODE_CONTROL_2, 0, 4, w8741_dither),/* dithering type */
|
||||
+SOC_ENUM_SINGLE(WM8741_FILTER_CONTROL, 0, 5, w8741_filter),/* filter type */
|
||||
+SOC_ENUM_SINGLE(WM8741_FORMAT_CONTROL, 6, 2, w8741_switch),/* phase invert */
|
||||
+SOC_ENUM_SINGLE(WM8741_VOLUME_CONTROL, 0, 2, w8741_switch),/* volume ramp */
|
||||
+SOC_ENUM_SINGLE(WM8741_VOLUME_CONTROL, 3, 2, w8741_switch),/* soft mute */
|
||||
+};
|
||||
+
|
||||
+static const struct snd_kcontrol_new w8741_snd_controls_stereo[] = {
|
||||
+SOC_DOUBLE_R_TLV("DAC Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
|
||||
+ WM8741_DACRLSB_ATTENUATION, 0, 31, 1, dac_tlv_fine),
|
||||
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8741_DACLMSB_ATTENUATION,
|
||||
+ WM8741_DACRMSB_ATTENUATION, 0, 31, 1, dac_tlv_coarse),
|
||||
+SOC_ENUM("DAC Dither", w8741_enum[0]),
|
||||
+SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
|
||||
+SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
|
||||
+SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
|
||||
+SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_kcontrol_new w8741_snd_controls_mono_left[] = {
|
||||
+SOC_SINGLE_TLV("DAC Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
|
||||
+ 0, 31, 0, dac_tlv_fine),
|
||||
+SOC_SINGLE_TLV("Digital Playback Volume", WM8741_DACLMSB_ATTENUATION,
|
||||
+ 0, 31, 1, dac_tlv_coarse),
|
||||
+SOC_ENUM("DAC Dither", w8741_enum[0]),
|
||||
+SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
|
||||
+SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
|
||||
+SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
|
||||
+SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_kcontrol_new w8741_snd_controls_mono_right[] = {
|
||||
+SOC_SINGLE_TLV("DAC Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
|
||||
+ 0, 31, 0, dac_tlv_fine),
|
||||
+SOC_SINGLE_TLV("Digital Playback Volume", WM8741_DACRMSB_ATTENUATION,
|
||||
+ 0, 31, 1, dac_tlv_coarse),
|
||||
+SOC_ENUM("DAC Dither", w8741_enum[0]),
|
||||
+SOC_ENUM("DAC Digital Filter", w8741_enum[1]),
|
||||
+SOC_ENUM("DAC Phase Invert", w8741_enum[2]),
|
||||
+SOC_ENUM("DAC Volume Ramp", w8741_enum[3]),
|
||||
+SOC_ENUM("DAC Soft Mute", w8741_enum[4]),
|
||||
+};
|
||||
+
|
||||
+static int w8741_add_controls(struct snd_soc_component *component)
|
||||
+{
|
||||
+ struct wm8741_priv *wm8741 = snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ switch (wm8741->pdata.diff_mode) {
|
||||
+ case WM8741_DIFF_MODE_STEREO:
|
||||
+ case WM8741_DIFF_MODE_STEREO_REVERSED:
|
||||
+ snd_soc_add_component_controls(component,
|
||||
+ w8741_snd_controls_stereo,
|
||||
+ ARRAY_SIZE(w8741_snd_controls_stereo));
|
||||
+ break;
|
||||
+ case WM8741_DIFF_MODE_MONO_LEFT:
|
||||
+ snd_soc_add_component_controls(component,
|
||||
+ w8741_snd_controls_mono_left,
|
||||
+ ARRAY_SIZE(w8741_snd_controls_mono_left));
|
||||
+ break;
|
||||
+ case WM8741_DIFF_MODE_MONO_RIGHT:
|
||||
+ snd_soc_add_component_controls(component,
|
||||
+ w8741_snd_controls_mono_right,
|
||||
+ ARRAY_SIZE(w8741_snd_controls_mono_right));
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int digidac1_soundcard_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+ struct snd_soc_pcm_runtime *wm8741_rtd;
|
||||
+ struct snd_soc_component *wm8741_component;
|
||||
+ struct snd_card *sound_card = card->snd_card;
|
||||
+ struct snd_kcontrol *kctl;
|
||||
+ int ret;
|
||||
+
|
||||
+ wm8741_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
|
||||
+ if (!wm8741_rtd) {
|
||||
+ dev_warn(card->dev, "digidac1_soundcard_init: couldn't get wm8741 rtd\n");
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ wm8741_component = wm8741_rtd->codec_dai->component;
|
||||
+ ret = w8741_add_controls(wm8741_component);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to add new wm8741 controls: %d\n",
|
||||
+ ret);
|
||||
+
|
||||
+ /* enable TX output */
|
||||
+ snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, 0x0);
|
||||
+
|
||||
+ kctl = snd_soc_card_get_kcontrol(card,
|
||||
+ "Playback Volume");
|
||||
+ if (kctl) {
|
||||
+ kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
+ snd_ctl_remove(sound_card, kctl);
|
||||
+ }
|
||||
+ kctl = snd_soc_card_get_kcontrol(card,
|
||||
+ "Fine Playback Volume");
|
||||
+ if (kctl) {
|
||||
+ kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
+ snd_ctl_remove(sound_card, kctl);
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int digidac1_soundcard_startup(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ /* turn on wm8804 digital output */
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+ struct snd_soc_pcm_runtime *wm8741_rtd;
|
||||
+ struct snd_soc_component *wm8741_component;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, WM8804_PWRDN, 0x3c, 0x00);
|
||||
+ wm8741_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
|
||||
+ if (!wm8741_rtd) {
|
||||
+ dev_warn(card->dev, "digidac1_soundcard_startup: couldn't get WM8741 rtd\n");
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ wm8741_component = wm8741_rtd->codec_dai->component;
|
||||
+
|
||||
+ /* latch wm8741 level */
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_DACLLSB_ATTENUATION,
|
||||
+ WM8741_UPDATELL, WM8741_UPDATELL);
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_DACLMSB_ATTENUATION,
|
||||
+ WM8741_UPDATELM, WM8741_UPDATELM);
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_DACRLSB_ATTENUATION,
|
||||
+ WM8741_UPDATERL, WM8741_UPDATERL);
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_DACRMSB_ATTENUATION,
|
||||
+ WM8741_UPDATERM, WM8741_UPDATERM);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void digidac1_soundcard_shutdown(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ /* turn off wm8804 digital output */
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, WM8804_PWRDN, 0x3c, 0x3c);
|
||||
+}
|
||||
+
|
||||
+static int digidac1_soundcard_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+ struct snd_soc_pcm_runtime *wm8741_rtd;
|
||||
+ struct snd_soc_component *wm8741_component;
|
||||
+
|
||||
+ int sysclk = 27000000;
|
||||
+ long mclk_freq = 0;
|
||||
+ int mclk_div = 1;
|
||||
+ int sampling_freq = 1;
|
||||
+ int ret;
|
||||
+
|
||||
+ wm8741_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name);
|
||||
+ if (!wm8741_rtd) {
|
||||
+ dev_warn(card->dev, "digidac1_soundcard_hw_params: couldn't get WM8741 rtd\n");
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+ wm8741_component = wm8741_rtd->codec_dai->component;
|
||||
+ samplerate = params_rate(params);
|
||||
+
|
||||
+ if (samplerate <= 96000) {
|
||||
+ mclk_freq = samplerate*256;
|
||||
+ mclk_div = WM8804_MCLKDIV_256FS;
|
||||
+ } else {
|
||||
+ mclk_freq = samplerate*128;
|
||||
+ mclk_div = WM8804_MCLKDIV_128FS;
|
||||
+ }
|
||||
+
|
||||
+ switch (samplerate) {
|
||||
+ case 32000:
|
||||
+ sampling_freq = 0x03;
|
||||
+ break;
|
||||
+ case 44100:
|
||||
+ sampling_freq = 0x00;
|
||||
+ break;
|
||||
+ case 48000:
|
||||
+ sampling_freq = 0x02;
|
||||
+ break;
|
||||
+ case 88200:
|
||||
+ sampling_freq = 0x08;
|
||||
+ break;
|
||||
+ case 96000:
|
||||
+ sampling_freq = 0x0a;
|
||||
+ break;
|
||||
+ case 176400:
|
||||
+ sampling_freq = 0x0c;
|
||||
+ break;
|
||||
+ case 192000:
|
||||
+ sampling_freq = 0x0e;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(card->dev,
|
||||
+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
|
||||
+ samplerate);
|
||||
+ }
|
||||
+
|
||||
+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
|
||||
+ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
|
||||
+
|
||||
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
|
||||
+ sysclk, SND_SOC_CLOCK_OUT);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(card->dev,
|
||||
+ "Failed to set WM8804 SYSCLK: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ /* Enable wm8804 TX output */
|
||||
+ snd_soc_component_update_bits(component, WM8804_PWRDN, 0x4, 0x0);
|
||||
+
|
||||
+ /* wm8804 Power on */
|
||||
+ snd_soc_component_update_bits(component, WM8804_PWRDN, 0x9, 0);
|
||||
+
|
||||
+ /* wm8804 set sampling frequency status bits */
|
||||
+ snd_soc_component_update_bits(component, WM8804_SPDTX4, 0x0f, sampling_freq);
|
||||
+
|
||||
+ /* Now update wm8741 registers for the correct oversampling */
|
||||
+ if (samplerate <= 48000)
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_MODE_CONTROL_1,
|
||||
+ WM8741_OSR_MASK, 0x00);
|
||||
+ else if (samplerate <= 96000)
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_MODE_CONTROL_1,
|
||||
+ WM8741_OSR_MASK, 0x20);
|
||||
+ else
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_MODE_CONTROL_1,
|
||||
+ WM8741_OSR_MASK, 0x40);
|
||||
+
|
||||
+ /* wm8741 bit size */
|
||||
+ switch (params_width(params)) {
|
||||
+ case 16:
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
|
||||
+ WM8741_IWL_MASK, 0x00);
|
||||
+ break;
|
||||
+ case 20:
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
|
||||
+ WM8741_IWL_MASK, 0x01);
|
||||
+ break;
|
||||
+ case 24:
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
|
||||
+ WM8741_IWL_MASK, 0x02);
|
||||
+ break;
|
||||
+ case 32:
|
||||
+ snd_soc_component_update_bits(wm8741_component, WM8741_FORMAT_CONTROL,
|
||||
+ WM8741_IWL_MASK, 0x03);
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_dbg(card->dev, "wm8741_hw_params: Unsupported bit size param = %d",
|
||||
+ params_width(params));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
|
||||
+}
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops digidac1_soundcard_ops = {
|
||||
+ .hw_params = digidac1_soundcard_hw_params,
|
||||
+ .startup = digidac1_soundcard_startup,
|
||||
+ .shutdown = digidac1_soundcard_shutdown,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(digidac1,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("wm8804.1-003b", "wm8804-spdif")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2835-i2s.0")));
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(digidac11,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("wm8804-spdif")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("wm8741.1-001a", "wm8741")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link digidac1_soundcard_dai[] = {
|
||||
+ {
|
||||
+ .name = "RRA DigiDAC1",
|
||||
+ .stream_name = "RRA DigiDAC1 HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBM_CFM,
|
||||
+ .ops = &digidac1_soundcard_ops,
|
||||
+ .init = digidac1_soundcard_init,
|
||||
+ SND_SOC_DAILINK_REG(digidac1),
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "RRA DigiDAC11",
|
||||
+ .stream_name = "RRA DigiDAC11 HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S
|
||||
+ | SND_SOC_DAIFMT_NB_NF
|
||||
+ | SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ SND_SOC_DAILINK_REG(digidac11),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card digidac1_soundcard = {
|
||||
+ .name = "digidac1-soundcard",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = digidac1_soundcard_dai,
|
||||
+ .num_links = ARRAY_SIZE(digidac1_soundcard_dai),
|
||||
+};
|
||||
+
|
||||
+static int digidac1_soundcard_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ digidac1_soundcard.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai = &digidac1_soundcard_dai[0];
|
||||
+
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &digidac1_soundcard);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
|
||||
+ ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id digidac1_soundcard_of_match[] = {
|
||||
+ { .compatible = "rra,digidac1-soundcard", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, digidac1_soundcard_of_match);
|
||||
+
|
||||
+static struct platform_driver digidac1_soundcard_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "digidac1-audio",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = digidac1_soundcard_of_match,
|
||||
+ },
|
||||
+ .probe = digidac1_soundcard_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(digidac1_soundcard_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("José M. Tasende <vintage@redrocksaudio.es>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for RRA DigiDAC1");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,137 @@
|
|||
From 12b182ee61ee6654c480f6643fcf818c6fe43e33 Mon Sep 17 00:00:00 2001
|
||||
From: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
|
||||
Date: Sat, 2 Jul 2016 16:26:19 +0100
|
||||
Subject: [PATCH] Add support for Dion Audio LOCO DAC-AMP HAT
|
||||
|
||||
Using dedicated machine driver and pcm5102a codec driver.
|
||||
|
||||
Signed-off-by: DigitalDreamtime <clive.messer@digitaldreamtime.co.uk>
|
||||
|
||||
ASoC: dionaudio_loco: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/dionaudio_loco.c | 117 +++++++++++++++++++++++++++++++++
|
||||
1 file changed, 117 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/dionaudio_loco.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/dionaudio_loco.c
|
||||
@@ -0,0 +1,117 @@
|
||||
+/*
|
||||
+ * ASoC Driver for Dion Audio LOCO DAC-AMP
|
||||
+ *
|
||||
+ * Author: Miquel Blauw <info@dionaudio.nl>
|
||||
+ * Copyright 2016
|
||||
+ *
|
||||
+ * Based on the software of the RPi-DAC writen by Florian Meier
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+
|
||||
+static int snd_rpi_dionaudio_loco_hw_params(
|
||||
+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
+
|
||||
+ unsigned int sample_bits =
|
||||
+ snd_pcm_format_physical_width(params_format(params));
|
||||
+
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
|
||||
+}
|
||||
+
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops snd_rpi_dionaudio_loco_ops = {
|
||||
+ .hw_params = snd_rpi_dionaudio_loco_hw_params,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(dionaudio_loco,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm5102a-codec", "pcm5102a-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_dionaudio_loco_dai[] = {
|
||||
+{
|
||||
+ .name = "DionAudio LOCO",
|
||||
+ .stream_name = "DionAudio LOCO DAC-AMP",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
+ SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ .ops = &snd_rpi_dionaudio_loco_ops,
|
||||
+ SND_SOC_DAILINK_REG(dionaudio_loco),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_rpi_dionaudio_loco = {
|
||||
+ .name = "snd_rpi_dionaudio_loco",
|
||||
+ .dai_link = snd_rpi_dionaudio_loco_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_rpi_dionaudio_loco_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_dionaudio_loco_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *np;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_rpi_dionaudio_loco.dev = &pdev->dev;
|
||||
+
|
||||
+ np = pdev->dev.of_node;
|
||||
+ if (np) {
|
||||
+ struct snd_soc_dai_link *dai = &snd_rpi_dionaudio_loco_dai[0];
|
||||
+ struct device_node *i2s_np;
|
||||
+
|
||||
+ i2s_np = of_parse_phandle(np, "i2s-controller", 0);
|
||||
+ if (i2s_np) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_np;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_np;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_dionaudio_loco);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
|
||||
+ ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id snd_rpi_dionaudio_loco_of_match[] = {
|
||||
+ { .compatible = "dionaudio,loco-pcm5242-tpa3118", },
|
||||
+ { /* sentinel */ },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_rpi_dionaudio_loco_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_rpi_dionaudio_loco_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-dionaudio-loco",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_rpi_dionaudio_loco_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_dionaudio_loco_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_rpi_dionaudio_loco_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Miquel Blauw <info@dionaudio.nl>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,163 @@
|
|||
From 9d9f0aa59569bf2aa826aea3a4a2d1ace3a155f4 Mon Sep 17 00:00:00 2001
|
||||
From: Clive Messer <clive.m.messer@gmail.com>
|
||||
Date: Mon, 19 Sep 2016 14:01:04 +0100
|
||||
Subject: [PATCH] Allo Piano DAC boards: Initial 2 channel (stereo)
|
||||
support (#1645)
|
||||
|
||||
Add initial 2 channel (stereo) support for Allo Piano DAC (2.0/2.1) boards,
|
||||
using allo-piano-dac-pcm512x-audio overlay and allo-piano-dac ALSA ASoC
|
||||
machine driver.
|
||||
|
||||
NB. The initial support is 2 channel (stereo) ONLY!
|
||||
(The Piano DAC 2.1 will only support 2 channel (stereo) left/right output,
|
||||
pending an update to the upstream pcm512x codec driver, which will have
|
||||
to be submitted via upstream. With the initial downstream support,
|
||||
provided by this patch, the Piano DAC 2.1 subwoofer outputs will
|
||||
not function.)
|
||||
|
||||
Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
|
||||
Signed-off-by: Clive Messer <clive.messer@digitaldreamtime.co.uk>
|
||||
Tested-by: Clive Messer <clive.messer@digitaldreamtime.co.uk>
|
||||
|
||||
ASoC: allo-piano-dac: fix S24_LE format
|
||||
|
||||
Remove set_bclk_ratio call so 24-bit data is transmitted in
|
||||
24 bclk cycles.
|
||||
|
||||
Also remove hw_params and ops as they are no longer needed.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: allo-piano-dac: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/allo-piano-dac.c | 122 +++++++++++++++++++++++++++++++++
|
||||
1 file changed, 122 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/allo-piano-dac.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/allo-piano-dac.c
|
||||
@@ -0,0 +1,122 @@
|
||||
+/*
|
||||
+ * ALSA ASoC Machine Driver for Allo Piano DAC
|
||||
+ *
|
||||
+ * Author: Baswaraj K <jaikumar@cem-solutions.net>
|
||||
+ * Copyright 2016
|
||||
+ * based on code by Daniel Matuschek <info@crazy-audio.com>
|
||||
+ * based on code by Florian Meier <florian.meier@koalo.de>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+static bool digital_gain_0db_limit = true;
|
||||
+
|
||||
+static int snd_allo_piano_dac_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ if (digital_gain_0db_limit) {
|
||||
+ int ret;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "Digital Playback Volume",
|
||||
+ 207);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set volume limit: %d\n",
|
||||
+ ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(allo_piano_dai,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004c", "pcm512x-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_allo_piano_dac_dai[] = {
|
||||
+{
|
||||
+ .name = "Piano DAC",
|
||||
+ .stream_name = "Piano DAC HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
+ SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ .init = snd_allo_piano_dac_init,
|
||||
+ SND_SOC_DAILINK_REG(allo_piano_dai),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_allo_piano_dac = {
|
||||
+ .name = "PianoDAC",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = snd_allo_piano_dac_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_allo_piano_dac_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_allo_piano_dac_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_allo_piano_dac.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai;
|
||||
+
|
||||
+ dai = &snd_allo_piano_dac_dai[0];
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+
|
||||
+ digital_gain_0db_limit = !of_property_read_bool(
|
||||
+ pdev->dev.of_node, "allo,24db_digital_gain");
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_allo_piano_dac);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "snd_soc_register_card() failed: %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id snd_allo_piano_dac_of_match[] = {
|
||||
+ { .compatible = "allo,piano-dac", },
|
||||
+ { /* sentinel */ },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_allo_piano_dac_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_allo_piano_dac_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-allo-piano-dac",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_allo_piano_dac_of_match,
|
||||
+ },
|
||||
+ .probe = snd_allo_piano_dac_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_allo_piano_dac_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
|
||||
+MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC");
|
||||
+MODULE_LICENSE("GPL v2");
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,675 @@
|
|||
From 7a13759deeaae55840571574e32e00f0e5902661 Mon Sep 17 00:00:00 2001
|
||||
From: BabuSubashChandar <babuenir@gmail.com>
|
||||
Date: Tue, 28 Mar 2017 20:04:42 +0530
|
||||
Subject: [PATCH] Add support for Allo Boss DAC add-on board for
|
||||
Raspberry Pi. (#1924)
|
||||
|
||||
Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
|
||||
Reviewed-by: Deepak <deepak@zilogic.com>
|
||||
Reviewed-by: BabuSubashChandar <babusubashchandar@zilogic.com>
|
||||
|
||||
Add support for new clock rate and mute gpios.
|
||||
|
||||
Signed-off-by: Baswaraj K <jaikumar@cem-solutions.net>
|
||||
Reviewed-by: Deepak <deepak@zilogic.com>
|
||||
Reviewed-by: BabuSubashChandar <babusubashchandar@zilogic.com>
|
||||
|
||||
ASoC: allo-boss-dac: fix S24_LE format
|
||||
|
||||
Remove set_bclk_ratio call so 24-bit data is transmitted in
|
||||
24 bclk cycles.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: allo-boss-dac: transmit S24_LE with 64 BCLK cycles
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
allo-boss-dac: switch to snd_soc_dai_set_bclk_ratio
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: allo-boss-dac: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
drivers/clk/Makefile | 1 +
|
||||
drivers/clk/clk-allo-dac.c | 161 ++++++++++++
|
||||
sound/soc/bcm/allo-boss-dac.c | 456 ++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 618 insertions(+)
|
||||
create mode 100644 drivers/clk/clk-allo-dac.c
|
||||
create mode 100644 sound/soc/bcm/allo-boss-dac.c
|
||||
|
||||
--- a/drivers/clk/Makefile
|
||||
+++ b/drivers/clk/Makefile
|
||||
@@ -18,6 +18,7 @@ endif
|
||||
|
||||
# hardware specific clock types
|
||||
# please keep this section sorted lexicographically by file path name
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC) += clk-allo-dac.o
|
||||
obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
|
||||
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/clk-allo-dac.c
|
||||
@@ -0,0 +1,161 @@
|
||||
+/*
|
||||
+ * Clock Driver for Allo DAC
|
||||
+ *
|
||||
+ * Author: Baswaraj K <jaikumar@cem-solutions.net>
|
||||
+ * Copyright 2016
|
||||
+ * based on code by Stuart MacLean
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk-provider.h>
|
||||
+#include <linux/clkdev.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+/* Clock rate of CLK44EN attached to GPIO6 pin */
|
||||
+#define CLK_44EN_RATE 45158400UL
|
||||
+/* Clock rate of CLK48EN attached to GPIO3 pin */
|
||||
+#define CLK_48EN_RATE 49152000UL
|
||||
+
|
||||
+/**
|
||||
+ * struct allo_dac_clk - Common struct to the Allo DAC
|
||||
+ * @hw: clk_hw for the common clk framework
|
||||
+ * @mode: 0 => CLK44EN, 1 => CLK48EN
|
||||
+ */
|
||||
+struct clk_allo_hw {
|
||||
+ struct clk_hw hw;
|
||||
+ uint8_t mode;
|
||||
+};
|
||||
+
|
||||
+#define to_allo_clk(_hw) container_of(_hw, struct clk_allo_hw, hw)
|
||||
+
|
||||
+static const struct of_device_id clk_allo_dac_dt_ids[] = {
|
||||
+ { .compatible = "allo,dac-clk",},
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, clk_allo_dac_dt_ids);
|
||||
+
|
||||
+static unsigned long clk_allo_dac_recalc_rate(struct clk_hw *hw,
|
||||
+ unsigned long parent_rate)
|
||||
+{
|
||||
+ return (to_allo_clk(hw)->mode == 0) ? CLK_44EN_RATE :
|
||||
+ CLK_48EN_RATE;
|
||||
+}
|
||||
+
|
||||
+static long clk_allo_dac_round_rate(struct clk_hw *hw,
|
||||
+ unsigned long rate, unsigned long *parent_rate)
|
||||
+{
|
||||
+ long actual_rate;
|
||||
+
|
||||
+ if (rate <= CLK_44EN_RATE) {
|
||||
+ actual_rate = (long)CLK_44EN_RATE;
|
||||
+ } else if (rate >= CLK_48EN_RATE) {
|
||||
+ actual_rate = (long)CLK_48EN_RATE;
|
||||
+ } else {
|
||||
+ long diff44Rate = (long)(rate - CLK_44EN_RATE);
|
||||
+ long diff48Rate = (long)(CLK_48EN_RATE - rate);
|
||||
+
|
||||
+ if (diff44Rate < diff48Rate)
|
||||
+ actual_rate = (long)CLK_44EN_RATE;
|
||||
+ else
|
||||
+ actual_rate = (long)CLK_48EN_RATE;
|
||||
+ }
|
||||
+ return actual_rate;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int clk_allo_dac_set_rate(struct clk_hw *hw,
|
||||
+ unsigned long rate, unsigned long parent_rate)
|
||||
+{
|
||||
+ unsigned long actual_rate;
|
||||
+ struct clk_allo_hw *clk = to_allo_clk(hw);
|
||||
+
|
||||
+ actual_rate = (unsigned long)clk_allo_dac_round_rate(hw, rate,
|
||||
+ &parent_rate);
|
||||
+ clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+const struct clk_ops clk_allo_dac_rate_ops = {
|
||||
+ .recalc_rate = clk_allo_dac_recalc_rate,
|
||||
+ .round_rate = clk_allo_dac_round_rate,
|
||||
+ .set_rate = clk_allo_dac_set_rate,
|
||||
+};
|
||||
+
|
||||
+static int clk_allo_dac_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct clk_allo_hw *proclk;
|
||||
+ struct clk *clk;
|
||||
+ struct device *dev;
|
||||
+ struct clk_init_data init;
|
||||
+
|
||||
+ dev = &pdev->dev;
|
||||
+
|
||||
+ proclk = kzalloc(sizeof(struct clk_allo_hw), GFP_KERNEL);
|
||||
+ if (!proclk)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ init.name = "clk-allo-dac";
|
||||
+ init.ops = &clk_allo_dac_rate_ops;
|
||||
+ init.flags = 0;
|
||||
+ init.parent_names = NULL;
|
||||
+ init.num_parents = 0;
|
||||
+
|
||||
+ proclk->mode = 0;
|
||||
+ proclk->hw.init = &init;
|
||||
+
|
||||
+ clk = devm_clk_register(dev, &proclk->hw);
|
||||
+ if (!IS_ERR(clk)) {
|
||||
+ ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
|
||||
+ clk);
|
||||
+ } else {
|
||||
+ dev_err(dev, "Fail to register clock driver\n");
|
||||
+ kfree(proclk);
|
||||
+ ret = PTR_ERR(clk);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int clk_allo_dac_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ of_clk_del_provider(pdev->dev.of_node);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver clk_allo_dac_driver = {
|
||||
+ .probe = clk_allo_dac_probe,
|
||||
+ .remove = clk_allo_dac_remove,
|
||||
+ .driver = {
|
||||
+ .name = "clk-allo-dac",
|
||||
+ .of_match_table = clk_allo_dac_dt_ids,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int __init clk_allo_dac_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&clk_allo_dac_driver);
|
||||
+}
|
||||
+core_initcall(clk_allo_dac_init);
|
||||
+
|
||||
+static void __exit clk_allo_dac_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&clk_allo_dac_driver);
|
||||
+}
|
||||
+module_exit(clk_allo_dac_exit);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Allo DAC clock driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+MODULE_ALIAS("platform:clk-allo-dac");
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/allo-boss-dac.c
|
||||
@@ -0,0 +1,456 @@
|
||||
+/*
|
||||
+ * ALSA ASoC Machine Driver for Allo Boss DAC
|
||||
+ *
|
||||
+ * Author: Baswaraj K <jaikumar@cem-solutions.net>
|
||||
+ * Copyright 2017
|
||||
+ * based on code by Daniel Matuschek,
|
||||
+ * Stuart MacLean <stuart@hifiberry.com>
|
||||
+ * based on code by Florian Meier <florian.meier@koalo.de>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include "../codecs/pcm512x.h"
|
||||
+
|
||||
+#define ALLO_BOSS_NOCLOCK 0
|
||||
+#define ALLO_BOSS_CLK44EN 1
|
||||
+#define ALLO_BOSS_CLK48EN 2
|
||||
+
|
||||
+struct pcm512x_priv {
|
||||
+ struct regmap *regmap;
|
||||
+ struct clk *sclk;
|
||||
+};
|
||||
+
|
||||
+static struct gpio_desc *mute_gpio;
|
||||
+
|
||||
+/* Clock rate of CLK44EN attached to GPIO6 pin */
|
||||
+#define CLK_44EN_RATE 45158400UL
|
||||
+/* Clock rate of CLK48EN attached to GPIO3 pin */
|
||||
+#define CLK_48EN_RATE 49152000UL
|
||||
+
|
||||
+static bool slave;
|
||||
+static bool snd_soc_allo_boss_master;
|
||||
+static bool digital_gain_0db_limit = true;
|
||||
+
|
||||
+static void snd_allo_boss_select_clk(struct snd_soc_component *component,
|
||||
+ int clk_id)
|
||||
+{
|
||||
+ switch (clk_id) {
|
||||
+ case ALLO_BOSS_NOCLOCK:
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x00);
|
||||
+ break;
|
||||
+ case ALLO_BOSS_CLK44EN:
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x20);
|
||||
+ break;
|
||||
+ case ALLO_BOSS_CLK48EN:
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x24, 0x04);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void snd_allo_boss_clk_gpio(struct snd_soc_component *component)
|
||||
+{
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x24, 0x24);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_3, 0x0f, 0x02);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_6, 0x0f, 0x02);
|
||||
+}
|
||||
+
|
||||
+static bool snd_allo_boss_is_sclk(struct snd_soc_component *component)
|
||||
+{
|
||||
+ unsigned int sck;
|
||||
+
|
||||
+ snd_soc_component_read(component, PCM512x_RATE_DET_4, &sck);
|
||||
+ return (!(sck & 0x40));
|
||||
+}
|
||||
+
|
||||
+static bool snd_allo_boss_is_sclk_sleep(
|
||||
+ struct snd_soc_component *component)
|
||||
+{
|
||||
+ msleep(2);
|
||||
+ return snd_allo_boss_is_sclk(component);
|
||||
+}
|
||||
+
|
||||
+static bool snd_allo_boss_is_master_card(struct snd_soc_component *component)
|
||||
+{
|
||||
+ bool isClk44EN, isClk48En, isNoClk;
|
||||
+
|
||||
+ snd_allo_boss_clk_gpio(component);
|
||||
+
|
||||
+ snd_allo_boss_select_clk(component, ALLO_BOSS_CLK44EN);
|
||||
+ isClk44EN = snd_allo_boss_is_sclk_sleep(component);
|
||||
+
|
||||
+ snd_allo_boss_select_clk(component, ALLO_BOSS_NOCLOCK);
|
||||
+ isNoClk = snd_allo_boss_is_sclk_sleep(component);
|
||||
+
|
||||
+ snd_allo_boss_select_clk(component, ALLO_BOSS_CLK48EN);
|
||||
+ isClk48En = snd_allo_boss_is_sclk_sleep(component);
|
||||
+
|
||||
+ return (isClk44EN && isClk48En && !isNoClk);
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_clk_for_rate(int sample_rate)
|
||||
+{
|
||||
+ int type;
|
||||
+
|
||||
+ switch (sample_rate) {
|
||||
+ case 11025:
|
||||
+ case 22050:
|
||||
+ case 44100:
|
||||
+ case 88200:
|
||||
+ case 176400:
|
||||
+ case 352800:
|
||||
+ type = ALLO_BOSS_CLK44EN;
|
||||
+ break;
|
||||
+ default:
|
||||
+ type = ALLO_BOSS_CLK48EN;
|
||||
+ break;
|
||||
+ }
|
||||
+ return type;
|
||||
+}
|
||||
+
|
||||
+static void snd_allo_boss_set_sclk(struct snd_soc_component *component,
|
||||
+ int sample_rate)
|
||||
+{
|
||||
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ if (!IS_ERR(pcm512x->sclk)) {
|
||||
+ int ctype;
|
||||
+
|
||||
+ ctype = snd_allo_boss_clk_for_rate(sample_rate);
|
||||
+ clk_set_rate(pcm512x->sclk, (ctype == ALLO_BOSS_CLK44EN)
|
||||
+ ? CLK_44EN_RATE : CLK_48EN_RATE);
|
||||
+ snd_allo_boss_select_clk(component, ctype);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct pcm512x_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ if (slave)
|
||||
+ snd_soc_allo_boss_master = false;
|
||||
+ else
|
||||
+ snd_soc_allo_boss_master =
|
||||
+ snd_allo_boss_is_master_card(component);
|
||||
+
|
||||
+ if (snd_soc_allo_boss_master) {
|
||||
+ struct snd_soc_dai_link *dai = rtd->dai_link;
|
||||
+
|
||||
+ dai->name = "BossDAC";
|
||||
+ dai->stream_name = "Boss DAC HiFi [Master]";
|
||||
+ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
+ | SND_SOC_DAIFMT_CBM_CFM;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_BCLK_LRCLK_CFG, 0x31, 0x11);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_MASTER_MODE, 0x03, 0x03);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_MASTER_CLKDIV_2, 0x7f, 63);
|
||||
+ /*
|
||||
+ * Default sclk to CLK_48EN_RATE, otherwise codec
|
||||
+ * pcm512x_dai_startup_master method could call
|
||||
+ * snd_pcm_hw_constraint_ratnums using CLK_44EN/64
|
||||
+ * which will mask 384k sample rate.
|
||||
+ */
|
||||
+ if (!IS_ERR(priv->sclk))
|
||||
+ clk_set_rate(priv->sclk, CLK_48EN_RATE);
|
||||
+ } else {
|
||||
+ priv->sclk = ERR_PTR(-ENOENT);
|
||||
+ }
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
|
||||
+
|
||||
+ if (digital_gain_0db_limit) {
|
||||
+ int ret;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "Digital Playback Volume",
|
||||
+ 207);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set volume limit: %d\n",
|
||||
+ ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_update_rate_den(
|
||||
+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
|
||||
+ struct snd_ratnum *rats_no_pll;
|
||||
+ unsigned int num = 0, den = 0;
|
||||
+ int err;
|
||||
+
|
||||
+ rats_no_pll = devm_kzalloc(rtd->dev, sizeof(*rats_no_pll), GFP_KERNEL);
|
||||
+ if (!rats_no_pll)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
|
||||
+ rats_no_pll->den_min = 1;
|
||||
+ rats_no_pll->den_max = 128;
|
||||
+ rats_no_pll->den_step = 1;
|
||||
+
|
||||
+ err = snd_interval_ratnum(hw_param_interval(params,
|
||||
+ SNDRV_PCM_HW_PARAM_RATE), 1, rats_no_pll, &num, &den);
|
||||
+ if (err >= 0 && den) {
|
||||
+ params->rate_num = num;
|
||||
+ params->rate_den = den;
|
||||
+ }
|
||||
+
|
||||
+ devm_kfree(rtd->dev, rats_no_pll);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void snd_allo_boss_gpio_mute(struct snd_soc_card *card)
|
||||
+{
|
||||
+ if (mute_gpio)
|
||||
+ gpiod_set_value_cansleep(mute_gpio, 1);
|
||||
+}
|
||||
+
|
||||
+static void snd_allo_boss_gpio_unmute(struct snd_soc_card *card)
|
||||
+{
|
||||
+ if (mute_gpio)
|
||||
+ gpiod_set_value_cansleep(mute_gpio, 0);
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_set_bias_level(struct snd_soc_card *card,
|
||||
+ struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd;
|
||||
+ struct snd_soc_dai *codec_dai;
|
||||
+
|
||||
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
|
||||
+ codec_dai = rtd->codec_dai;
|
||||
+
|
||||
+ if (dapm->dev != codec_dai->dev)
|
||||
+ return 0;
|
||||
+
|
||||
+ switch (level) {
|
||||
+ case SND_SOC_BIAS_PREPARE:
|
||||
+ if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
|
||||
+ break;
|
||||
+ /* UNMUTE DAC */
|
||||
+ snd_allo_boss_gpio_unmute(card);
|
||||
+ break;
|
||||
+
|
||||
+ case SND_SOC_BIAS_STANDBY:
|
||||
+ if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
|
||||
+ break;
|
||||
+ /* MUTE DAC */
|
||||
+ snd_allo_boss_gpio_mute(card);
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_hw_params(
|
||||
+ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ int channels = params_channels(params);
|
||||
+ int width = snd_pcm_format_physical_width(params_format(params));
|
||||
+
|
||||
+ if (snd_soc_allo_boss_master) {
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+
|
||||
+ snd_allo_boss_set_sclk(component,
|
||||
+ params_rate(params));
|
||||
+
|
||||
+ ret = snd_allo_boss_update_rate_den(
|
||||
+ substream, params);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, channels * width);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = snd_soc_dai_set_bclk_ratio(rtd->codec_dai, channels * width);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_startup(
|
||||
+ struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
|
||||
+ snd_allo_boss_gpio_mute(card);
|
||||
+
|
||||
+ if (snd_soc_allo_boss_master) {
|
||||
+ struct pcm512x_priv *priv = snd_soc_component_get_drvdata(component);
|
||||
+ /*
|
||||
+ * Default sclk to CLK_48EN_RATE, otherwise codec
|
||||
+ * pcm512x_dai_startup_master method could call
|
||||
+ * snd_pcm_hw_constraint_ratnums using CLK_44EN/64
|
||||
+ * which will mask 384k sample rate.
|
||||
+ */
|
||||
+ if (!IS_ERR(priv->sclk))
|
||||
+ clk_set_rate(priv->sclk, CLK_48EN_RATE);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void snd_allo_boss_shutdown(
|
||||
+ struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_prepare(
|
||||
+ struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ snd_allo_boss_gpio_unmute(card);
|
||||
+ return 0;
|
||||
+}
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops snd_allo_boss_ops = {
|
||||
+ .hw_params = snd_allo_boss_hw_params,
|
||||
+ .startup = snd_allo_boss_startup,
|
||||
+ .shutdown = snd_allo_boss_shutdown,
|
||||
+ .prepare = snd_allo_boss_prepare,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(allo_boss,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_allo_boss_dai[] = {
|
||||
+{
|
||||
+ .name = "Boss DAC",
|
||||
+ .stream_name = "Boss DAC HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
+ SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ .ops = &snd_allo_boss_ops,
|
||||
+ .init = snd_allo_boss_init,
|
||||
+ SND_SOC_DAILINK_REG(allo_boss),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_allo_boss = {
|
||||
+ .name = "BossDAC",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = snd_allo_boss_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_allo_boss_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_allo_boss_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_allo_boss.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai;
|
||||
+
|
||||
+ dai = &snd_allo_boss_dai[0];
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+
|
||||
+ digital_gain_0db_limit = !of_property_read_bool(
|
||||
+ pdev->dev.of_node, "allo,24db_digital_gain");
|
||||
+ slave = of_property_read_bool(pdev->dev.of_node,
|
||||
+ "allo,slave");
|
||||
+
|
||||
+ mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute",
|
||||
+ GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(mute_gpio)) {
|
||||
+ ret = PTR_ERR(mute_gpio);
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "failed to get mute gpio: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (mute_gpio)
|
||||
+ snd_allo_boss.set_bias_level =
|
||||
+ snd_allo_boss_set_bias_level;
|
||||
+
|
||||
+ ret = snd_soc_register_card(&snd_allo_boss);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "snd_soc_register_card() failed: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (mute_gpio)
|
||||
+ snd_allo_boss_gpio_mute(&snd_allo_boss);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int snd_allo_boss_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ snd_allo_boss_gpio_mute(&snd_allo_boss);
|
||||
+ return snd_soc_unregister_card(&snd_allo_boss);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id snd_allo_boss_of_match[] = {
|
||||
+ { .compatible = "allo,boss-dac", },
|
||||
+ { /* sentinel */ },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_allo_boss_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_allo_boss_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-allo-boss-dac",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_allo_boss_of_match,
|
||||
+ },
|
||||
+ .probe = snd_allo_boss_probe,
|
||||
+ .remove = snd_allo_boss_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_allo_boss_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Baswaraj K <jaikumar@cem-solutions.net>");
|
||||
+MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Boss DAC");
|
||||
+MODULE_LICENSE("GPL v2");
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,144 @@
|
|||
From a1a8a4fb0f50f92f1c42164827dbdfb57007f183 Mon Sep 17 00:00:00 2001
|
||||
From: Miquel <miquelblauw@hotmail.com>
|
||||
Date: Fri, 24 Feb 2017 20:51:06 +0100
|
||||
Subject: [PATCH] sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT
|
||||
|
||||
Signed-off-by: Miquel Blauw <info@dionaudio.nl>
|
||||
|
||||
ASoC: dionaudio_loco-v2: fix S24_LE format
|
||||
|
||||
Remove set_bclk_ratio call so 24-bit data is transmitted in
|
||||
24 bclk cycles.
|
||||
|
||||
Also remove hw_params and ops as they are no longer needed.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
ASoC: dionaudio_loco-v2: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/dionaudio_loco-v2.c | 117 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 117 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/dionaudio_loco-v2.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/dionaudio_loco-v2.c
|
||||
@@ -0,0 +1,117 @@
|
||||
+/*
|
||||
+ * ASoC Driver for Dion Audio LOCO-V2 DAC-AMP
|
||||
+ *
|
||||
+ * Author: Miquel Blauw <info@dionaudio.nl>
|
||||
+ * Copyright 2017
|
||||
+ *
|
||||
+ * Based on the software of the RPi-DAC writen by Florian Meier
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+
|
||||
+static bool digital_gain_0db_limit = true;
|
||||
+
|
||||
+static int snd_rpi_dionaudio_loco_v2_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ if (digital_gain_0db_limit) {
|
||||
+ int ret;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(dionaudio_loco_v2,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_dionaudio_loco_v2_dai[] = {
|
||||
+{
|
||||
+ .name = "DionAudio LOCO-V2",
|
||||
+ .stream_name = "DionAudio LOCO-V2 DAC-AMP",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ .init = snd_rpi_dionaudio_loco_v2_init,
|
||||
+ SND_SOC_DAILINK_REG(dionaudio_loco_v2),
|
||||
+},};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_rpi_dionaudio_loco_v2 = {
|
||||
+ .name = "Dion Audio LOCO-V2",
|
||||
+ .dai_link = snd_rpi_dionaudio_loco_v2_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_rpi_dionaudio_loco_v2_dai),
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_dionaudio_loco_v2_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_rpi_dionaudio_loco_v2.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai =
|
||||
+ &snd_rpi_dionaudio_loco_v2_dai[0];
|
||||
+
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+ if (i2s_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+
|
||||
+ digital_gain_0db_limit = !of_property_read_bool(
|
||||
+ pdev->dev.of_node, "dionaudio,24db_digital_gain");
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_dionaudio_loco_v2);
|
||||
+ if (ret)
|
||||
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
|
||||
+ ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id dionaudio_of_match[] = {
|
||||
+ { .compatible = "dionaudio,dionaudio-loco-v2", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, dionaudio_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_rpi_dionaudio_loco_v2_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-dionaudio-loco-v2",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = dionaudio_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_dionaudio_loco_v2_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_rpi_dionaudio_loco_v2_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Miquel Blauw <info@dionaudio.nl>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO-V2");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,176 @@
|
|||
From b3d295a256e2649444f91dd8a30bfd31873e714c Mon Sep 17 00:00:00 2001
|
||||
From: Fe-Pi <fe-pi@cox.net>
|
||||
Date: Wed, 1 Mar 2017 04:42:43 -0700
|
||||
Subject: [PATCH] Add support for Fe-Pi audio sound card. (#1867)
|
||||
|
||||
Fe-Pi Audio Sound Card is based on NXP SGTL5000 codec.
|
||||
Mechanical specification of the board is the same the Raspberry Pi Zero.
|
||||
3.5mm jacks for Headphone/Mic, Line In, and Line Out.
|
||||
|
||||
Signed-off-by: Henry Kupis <fe-pi@cox.net>
|
||||
|
||||
ASoC: fe-pi-audio: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/fe-pi-audio.c | 154 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 154 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/fe-pi-audio.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/fe-pi-audio.c
|
||||
@@ -0,0 +1,154 @@
|
||||
+/*
|
||||
+ * ASoC Driver for Fe-Pi Audio Sound Card
|
||||
+ *
|
||||
+ * Author: Henry Kupis <kuupaz@gmail.com>
|
||||
+ * Copyright 2016
|
||||
+ * based on code by Florian Meier <florian.meier@koalo.de>
|
||||
+ * based on code by Shawn Guo <shawn.guo@linaro.org>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/io.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/jack.h>
|
||||
+
|
||||
+#include "../codecs/sgtl5000.h"
|
||||
+
|
||||
+static int snd_fe_pi_audio_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+
|
||||
+ snd_soc_dapm_force_enable_pin(&card->dapm, "LO");
|
||||
+ snd_soc_dapm_force_enable_pin(&card->dapm, "ADC");
|
||||
+ snd_soc_dapm_force_enable_pin(&card->dapm, "DAC");
|
||||
+ snd_soc_dapm_force_enable_pin(&card->dapm, "HP");
|
||||
+ snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER,
|
||||
+ SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_fe_pi_audio_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct device *dev = rtd->card->dev;
|
||||
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
+
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Set SGTL5000's SYSCLK */
|
||||
+ ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, 12288000, SND_SOC_CLOCK_IN);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "could not set codec driver clock params\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static struct snd_soc_ops snd_fe_pi_audio_ops = {
|
||||
+ .hw_params = snd_fe_pi_audio_hw_params,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(fe_pi,
|
||||
+ DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("sgtl5000.1-000a", "sgtl5000")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_fe_pi_audio_dai[] = {
|
||||
+ {
|
||||
+ .name = "FE-PI",
|
||||
+ .stream_name = "Fe-Pi HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBM_CFM,
|
||||
+ .ops = &snd_fe_pi_audio_ops,
|
||||
+ .init = snd_fe_pi_audio_init,
|
||||
+ SND_SOC_DAILINK_REG(fe_pi),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route fe_pi_audio_dapm_routes[] = {
|
||||
+ {"ADC", NULL, "Mic Bias"},
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static struct snd_soc_card fe_pi_audio = {
|
||||
+ .name = "Fe-Pi Audio",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = snd_fe_pi_audio_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_fe_pi_audio_dai),
|
||||
+
|
||||
+ .dapm_routes = fe_pi_audio_dapm_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(fe_pi_audio_dapm_routes),
|
||||
+};
|
||||
+
|
||||
+static int snd_fe_pi_audio_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ struct snd_soc_card *card = &fe_pi_audio;
|
||||
+ struct device_node *np = pdev->dev.of_node;
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai = &snd_fe_pi_audio_dai[0];
|
||||
+
|
||||
+ fe_pi_audio.dev = &pdev->dev;
|
||||
+
|
||||
+ i2s_node = of_parse_phandle(np, "i2s-controller", 0);
|
||||
+ if (!i2s_node) {
|
||||
+ dev_err(&pdev->dev, "i2s_node phandle missing or invalid\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+
|
||||
+ of_node_put(i2s_node);
|
||||
+
|
||||
+ card->dev = &pdev->dev;
|
||||
+ platform_set_drvdata(pdev, card);
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id snd_fe_pi_audio_of_match[] = {
|
||||
+ { .compatible = "fe-pi,fe-pi-audio", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_fe_pi_audio_of_match);
|
||||
+
|
||||
+static struct platform_driver snd_fe_pi_audio_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-fe-pi-audio",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_fe_pi_audio_of_match,
|
||||
+ },
|
||||
+ .probe = snd_fe_pi_audio_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_fe_pi_audio_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Henry Kupis <fe-pi@cox.net>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for Fe-Pi Audio");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,435 @@
|
|||
From 471f12c73cf73db88695d5161ec5c29f94fde1d0 Mon Sep 17 00:00:00 2001
|
||||
From: Matt Flax <flatmax@flatmax.org>
|
||||
Date: Wed, 8 Mar 2017 20:04:13 +1100
|
||||
Subject: [PATCH] Add support for the AudioInjector.net Octo sound card
|
||||
|
||||
AudioInjector Octo: sample rates, regulators, reset
|
||||
|
||||
This patch adds new sample rates to the Audioinjector Octo sound card. The
|
||||
new supported rates are (in kHz) :
|
||||
96, 48, 32, 24, 16, 8, 88.2, 44.1, 29.4, 22.05, 14.7
|
||||
|
||||
Reference the bcm270x DT regulators in the overlay.
|
||||
|
||||
This patch adds a reset GPIO for the AudioInjector.net octo sound card.
|
||||
|
||||
Audioinjector octo : Make the playback and capture symmetric
|
||||
|
||||
This patch ensures that the sample rate and channel count of the audioinjector
|
||||
octo sound card are symmetric.
|
||||
|
||||
audioinjector-octo: Add continuous clock feature
|
||||
|
||||
By user request, add a switch to prevent the clocks being stopped when
|
||||
the stream is paused, stopped or shutdown. Provide access to the switch
|
||||
by adding a 'non-stop-clocks' parameter to the audioinjector-addons
|
||||
overlay.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/2409
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
sound: Fixes for audioinjector-octo under 4.19
|
||||
|
||||
1. Move the DT alias declaration to the I2C shim in the cases
|
||||
where the shim is enabled. This works around a problem caused by a
|
||||
4.19 commit [1] that generates DT/OF uevents for I2C drivers.
|
||||
|
||||
2. Fix the diagnostics in an error path of the soundcard driver to
|
||||
correctly identify the reason for the failure to load.
|
||||
|
||||
3. Move the declaration of the clock node in the overlay outside
|
||||
the I2C node to avoid warnings.
|
||||
|
||||
4. Sort the overlay nodes so that dependencies are only to earlier
|
||||
fragments, in an attempt to get runtime dtoverlay application to
|
||||
work (it still doesn't...)
|
||||
|
||||
See: https://github.com/Audio-Injector/Octo/issues/14
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
[1] af503716ac14 ("i2c: core: report OF style module alias for devices registered via OF")
|
||||
|
||||
ASoC: audioinjector-octo-soundcard: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/audioinjector-octo-soundcard.c | 341 +++++++++++++++++++
|
||||
sound/soc/codecs/cs42xx8-i2c.c | 7 +
|
||||
sound/soc/codecs/cs42xx8.c | 2 +
|
||||
3 files changed, 350 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/audioinjector-octo-soundcard.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/audioinjector-octo-soundcard.c
|
||||
@@ -0,0 +1,341 @@
|
||||
+/*
|
||||
+ * ASoC Driver for AudioInjector Pi octo channel soundcard (hat)
|
||||
+ *
|
||||
+ * Created on: 27-October-2016
|
||||
+ * Author: flatmax@flatmax.org
|
||||
+ * based on audioinjector-pi-soundcard.c
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Flatmax Pty. 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.
|
||||
+ *
|
||||
+ * 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/module.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/control.h>
|
||||
+
|
||||
+static struct gpio_descs *mult_gpios;
|
||||
+static struct gpio_desc *codec_rst_gpio;
|
||||
+static unsigned int audioinjector_octo_rate;
|
||||
+static bool non_stop_clocks;
|
||||
+
|
||||
+static const unsigned int audioinjector_octo_rates[] = {
|
||||
+ 96000, 48000, 32000, 24000, 16000, 8000, 88200, 44100, 29400, 22050, 14700,
|
||||
+};
|
||||
+
|
||||
+static struct snd_pcm_hw_constraint_list audioinjector_octo_constraints = {
|
||||
+ .list = audioinjector_octo_rates,
|
||||
+ .count = ARRAY_SIZE(audioinjector_octo_rates),
|
||||
+};
|
||||
+
|
||||
+static int audioinjector_octo_dai_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ return snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, 64);
|
||||
+}
|
||||
+
|
||||
+static int audioinjector_octo_startup(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ rtd->cpu_dai->driver->playback.channels_min = 8;
|
||||
+ rtd->cpu_dai->driver->playback.channels_max = 8;
|
||||
+ rtd->cpu_dai->driver->capture.channels_min = 8;
|
||||
+ rtd->cpu_dai->driver->capture.channels_max = 8;
|
||||
+ rtd->codec_dai->driver->capture.channels_max = 8;
|
||||
+
|
||||
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_RATE,
|
||||
+ &audioinjector_octo_constraints);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void audioinjector_octo_shutdown(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ rtd->cpu_dai->driver->playback.channels_min = 2;
|
||||
+ rtd->cpu_dai->driver->playback.channels_max = 2;
|
||||
+ rtd->cpu_dai->driver->capture.channels_min = 2;
|
||||
+ rtd->cpu_dai->driver->capture.channels_max = 2;
|
||||
+ rtd->codec_dai->driver->capture.channels_max = 6;
|
||||
+}
|
||||
+
|
||||
+static int audioinjector_octo_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+
|
||||
+ // set codec DAI configuration
|
||||
+ int ret = snd_soc_dai_set_fmt(rtd->codec_dai,
|
||||
+ SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_DSP_A|
|
||||
+ SND_SOC_DAIFMT_NB_NF);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ // set cpu DAI configuration
|
||||
+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
+ SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|
|
||||
+ SND_SOC_DAIFMT_NB_NF);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ audioinjector_octo_rate = params_rate(params);
|
||||
+
|
||||
+ // Set the correct sysclock for the codec
|
||||
+ switch (audioinjector_octo_rate) {
|
||||
+ case 96000:
|
||||
+ case 48000:
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 49152000,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ case 24000:
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 49152000/2,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ case 32000:
|
||||
+ case 16000:
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 49152000/3,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ case 8000:
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 49152000/6,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ case 88200:
|
||||
+ case 44100:
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 45185400,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ case 22050:
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 45185400/2,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ case 29400:
|
||||
+ case 14700:
|
||||
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 45185400/3,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int audioinjector_octo_trigger(struct snd_pcm_substream *substream,
|
||||
+ int cmd){
|
||||
+ DECLARE_BITMAP(mult, 4);
|
||||
+
|
||||
+ memset(mult, 0, sizeof(mult));
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ if (!non_stop_clocks)
|
||||
+ break;
|
||||
+ /* Drop through... */
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ switch (audioinjector_octo_rate) {
|
||||
+ case 96000:
|
||||
+ __assign_bit(3, mult, 1);
|
||||
+ case 88200:
|
||||
+ __assign_bit(1, mult, 1);
|
||||
+ __assign_bit(2, mult, 1);
|
||||
+ break;
|
||||
+ case 48000:
|
||||
+ __assign_bit(3, mult, 1);
|
||||
+ case 44100:
|
||||
+ __assign_bit(2, mult, 1);
|
||||
+ break;
|
||||
+ case 32000:
|
||||
+ __assign_bit(3, mult, 1);
|
||||
+ case 29400:
|
||||
+ __assign_bit(0, mult, 1);
|
||||
+ __assign_bit(1, mult, 1);
|
||||
+ break;
|
||||
+ case 24000:
|
||||
+ __assign_bit(3, mult, 1);
|
||||
+ case 22050:
|
||||
+ __assign_bit(1, mult, 1);
|
||||
+ break;
|
||||
+ case 16000:
|
||||
+ __assign_bit(3, mult, 1);
|
||||
+ case 14700:
|
||||
+ __assign_bit(0, mult, 1);
|
||||
+ break;
|
||||
+ case 8000:
|
||||
+ __assign_bit(3, mult, 1);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ gpiod_set_array_value_cansleep(mult_gpios->ndescs, mult_gpios->desc,
|
||||
+ NULL, mult);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct snd_soc_ops audioinjector_octo_ops = {
|
||||
+ .startup = audioinjector_octo_startup,
|
||||
+ .shutdown = audioinjector_octo_shutdown,
|
||||
+ .hw_params = audioinjector_octo_hw_params,
|
||||
+ .trigger = audioinjector_octo_trigger,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(audioinjector_octo,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42448")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link audioinjector_octo_dai[] = {
|
||||
+ {
|
||||
+ .name = "AudioInjector Octo",
|
||||
+ .stream_name = "AudioInject-HIFI",
|
||||
+ .ops = &audioinjector_octo_ops,
|
||||
+ .init = audioinjector_octo_dai_init,
|
||||
+ .symmetric_rates = 1,
|
||||
+ .symmetric_channels = 1,
|
||||
+ SND_SOC_DAILINK_REG(audioinjector_octo),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget audioinjector_octo_widgets[] = {
|
||||
+ SND_SOC_DAPM_OUTPUT("OUTPUTS0"),
|
||||
+ SND_SOC_DAPM_OUTPUT("OUTPUTS1"),
|
||||
+ SND_SOC_DAPM_OUTPUT("OUTPUTS2"),
|
||||
+ SND_SOC_DAPM_OUTPUT("OUTPUTS3"),
|
||||
+ SND_SOC_DAPM_INPUT("INPUTS0"),
|
||||
+ SND_SOC_DAPM_INPUT("INPUTS1"),
|
||||
+ SND_SOC_DAPM_INPUT("INPUTS2"),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route audioinjector_octo_route[] = {
|
||||
+ /* Balanced outputs */
|
||||
+ {"OUTPUTS0", NULL, "AOUT1L"},
|
||||
+ {"OUTPUTS0", NULL, "AOUT1R"},
|
||||
+ {"OUTPUTS1", NULL, "AOUT2L"},
|
||||
+ {"OUTPUTS1", NULL, "AOUT2R"},
|
||||
+ {"OUTPUTS2", NULL, "AOUT3L"},
|
||||
+ {"OUTPUTS2", NULL, "AOUT3R"},
|
||||
+ {"OUTPUTS3", NULL, "AOUT4L"},
|
||||
+ {"OUTPUTS3", NULL, "AOUT4R"},
|
||||
+
|
||||
+ /* Balanced inputs */
|
||||
+ {"AIN1L", NULL, "INPUTS0"},
|
||||
+ {"AIN1R", NULL, "INPUTS0"},
|
||||
+ {"AIN2L", NULL, "INPUTS1"},
|
||||
+ {"AIN2R", NULL, "INPUTS1"},
|
||||
+ {"AIN3L", NULL, "INPUTS2"},
|
||||
+ {"AIN3R", NULL, "INPUTS2"},
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_card snd_soc_audioinjector_octo = {
|
||||
+ .name = "audioinjector-octo-soundcard",
|
||||
+ .dai_link = audioinjector_octo_dai,
|
||||
+ .num_links = ARRAY_SIZE(audioinjector_octo_dai),
|
||||
+
|
||||
+ .dapm_widgets = audioinjector_octo_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(audioinjector_octo_widgets),
|
||||
+ .dapm_routes = audioinjector_octo_route,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(audioinjector_octo_route),
|
||||
+};
|
||||
+
|
||||
+static int audioinjector_octo_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct snd_soc_card *card = &snd_soc_audioinjector_octo;
|
||||
+ int ret;
|
||||
+
|
||||
+ card->dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct snd_soc_dai_link *dai = &audioinjector_octo_dai[0];
|
||||
+ struct device_node *i2s_node =
|
||||
+ of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+ struct device_node *codec_node =
|
||||
+ of_parse_phandle(pdev->dev.of_node,
|
||||
+ "codec", 0);
|
||||
+
|
||||
+ mult_gpios = devm_gpiod_get_array_optional(&pdev->dev, "mult",
|
||||
+ GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(mult_gpios))
|
||||
+ return PTR_ERR(mult_gpios);
|
||||
+
|
||||
+ codec_rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
|
||||
+ GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(codec_rst_gpio))
|
||||
+ return PTR_ERR(codec_rst_gpio);
|
||||
+
|
||||
+ non_stop_clocks = of_property_read_bool(pdev->dev.of_node, "non-stop-clocks");
|
||||
+
|
||||
+ if (codec_rst_gpio)
|
||||
+ gpiod_set_value(codec_rst_gpio, 1);
|
||||
+ msleep(500);
|
||||
+ if (codec_rst_gpio)
|
||||
+ gpiod_set_value(codec_rst_gpio, 0);
|
||||
+ msleep(500);
|
||||
+ if (codec_rst_gpio)
|
||||
+ gpiod_set_value(codec_rst_gpio, 1);
|
||||
+ msleep(500);
|
||||
+
|
||||
+ if (i2s_node && codec_node) {
|
||||
+ dai->cpus->dai_name = NULL;
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->name = NULL;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ dai->codecs->name = NULL;
|
||||
+ dai->codecs->of_node = codec_node;
|
||||
+ } else
|
||||
+ if (!i2s_node) {
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "i2s-controller missing or invalid in DT\n");
|
||||
+ return -EINVAL;
|
||||
+ } else {
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "Property 'codec' missing or invalid\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
+ if (ret != 0)
|
||||
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id audioinjector_octo_of_match[] = {
|
||||
+ { .compatible = "ai,audioinjector-octo-soundcard", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, audioinjector_octo_of_match);
|
||||
+
|
||||
+static struct platform_driver audioinjector_octo_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "audioinjector-octo",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = audioinjector_octo_of_match,
|
||||
+ },
|
||||
+ .probe = audioinjector_octo_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(audioinjector_octo_driver);
|
||||
+MODULE_AUTHOR("Matt Flax <flatmax@flatmax.org>");
|
||||
+MODULE_DESCRIPTION("AudioInjector.net octo Soundcard");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+MODULE_ALIAS("platform:audioinjector-octo-soundcard");
|
||||
--- a/sound/soc/codecs/cs42xx8-i2c.c
|
||||
+++ b/sound/soc/codecs/cs42xx8-i2c.c
|
||||
@@ -45,6 +45,13 @@ static struct i2c_device_id cs42xx8_i2c_
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
|
||||
|
||||
+const struct of_device_id cs42xx8_of_match[] = {
|
||||
+ { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
|
||||
+ { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
|
||||
+
|
||||
static struct i2c_driver cs42xx8_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs42xx8",
|
||||
--- a/sound/soc/codecs/cs42xx8.c
|
||||
+++ b/sound/soc/codecs/cs42xx8.c
|
||||
@@ -516,8 +516,10 @@ const struct of_device_id cs42xx8_of_mat
|
||||
{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
+#if !IS_ENABLED(CONFIG_SND_SOC_CS42XX8_I2C)
|
||||
MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
|
||||
EXPORT_SYMBOL_GPL(cs42xx8_of_match);
|
||||
+#endif
|
||||
|
||||
int cs42xx8_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
|
@ -0,0 +1,254 @@
|
|||
From 687f439933392b66432c03929da378ae2f2216db Mon Sep 17 00:00:00 2001
|
||||
From: Peter Malkin <petermalkin@google.com>
|
||||
Date: Mon, 27 Mar 2017 16:38:21 -0700
|
||||
Subject: [PATCH] Driver support for Google voiceHAT soundcard.
|
||||
|
||||
ASoC: googlevoicehat-codec: Use correct device when grabbing GPIO
|
||||
|
||||
The fixup for the VoiceHAT in 4.18 incorrectly tried to find the
|
||||
sdmode GPIO pin under the card device, not the codec device.
|
||||
This failed, and therefore caused the device probe to fail.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
|
||||
ASoC: googlevoicehat-codec: Reformat for kernel coding standards
|
||||
|
||||
Fix all whitespace, indentation, and bracing errors.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
|
||||
ASoC: googlevoicehat-codec: Make driver function structure const
|
||||
|
||||
Make voicehat_component_driver a const structure.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
|
||||
ASoC: googlevoicehat-codec: Only convert from ms to jiffies once
|
||||
|
||||
Minor optimisation and allows to become checkpatch clean.
|
||||
A msec value is read out of DT or from a define, and convert once to
|
||||
jiffies, rather than every time that it is used.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||||
---
|
||||
sound/soc/bcm/googlevoicehat-codec.c | 214 +++++++++++++++++++++++++++
|
||||
1 file changed, 214 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/googlevoicehat-codec.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/googlevoicehat-codec.c
|
||||
@@ -0,0 +1,214 @@
|
||||
+/*
|
||||
+ * Driver for the Google voiceHAT audio codec for Raspberry Pi.
|
||||
+ *
|
||||
+ * Author: Peter Malkin <petermalkin@google.com>
|
||||
+ * Copyright 2016
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mod_devicetable.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/version.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+#include <sound/soc-dapm.h>
|
||||
+
|
||||
+#define ICS43432_RATE_MIN_HZ 7190 /* from data sheet */
|
||||
+#define ICS43432_RATE_MAX_HZ 52800 /* from data sheet */
|
||||
+/* Delay in enabling SDMODE after clock settles to remove pop */
|
||||
+#define SDMODE_DELAY_MS 5
|
||||
+
|
||||
+struct voicehat_priv {
|
||||
+ struct delayed_work enable_sdmode_work;
|
||||
+ struct gpio_desc *sdmode_gpio;
|
||||
+ unsigned long sdmode_delay_jiffies;
|
||||
+};
|
||||
+
|
||||
+static void voicehat_enable_sdmode_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct voicehat_priv *voicehat = container_of(work,
|
||||
+ struct voicehat_priv,
|
||||
+ enable_sdmode_work.work);
|
||||
+ gpiod_set_value(voicehat->sdmode_gpio, 1);
|
||||
+}
|
||||
+
|
||||
+static int voicehat_component_probe(struct snd_soc_component *component)
|
||||
+{
|
||||
+ struct voicehat_priv *voicehat =
|
||||
+ snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ voicehat->sdmode_gpio = devm_gpiod_get(component->dev, "sdmode",
|
||||
+ GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(voicehat->sdmode_gpio)) {
|
||||
+ dev_err(component->dev, "Unable to allocate GPIO pin\n");
|
||||
+ return PTR_ERR(voicehat->sdmode_gpio);
|
||||
+ }
|
||||
+
|
||||
+ INIT_DELAYED_WORK(&voicehat->enable_sdmode_work,
|
||||
+ voicehat_enable_sdmode_work);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void voicehat_component_remove(struct snd_soc_component *component)
|
||||
+{
|
||||
+ struct voicehat_priv *voicehat =
|
||||
+ snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ cancel_delayed_work_sync(&voicehat->enable_sdmode_work);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget voicehat_dapm_widgets[] = {
|
||||
+ SND_SOC_DAPM_OUTPUT("Speaker"),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route voicehat_dapm_routes[] = {
|
||||
+ {"Speaker", NULL, "HiFi Playback"},
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver voicehat_component_driver = {
|
||||
+ .probe = voicehat_component_probe,
|
||||
+ .remove = voicehat_component_remove,
|
||||
+ .dapm_widgets = voicehat_dapm_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(voicehat_dapm_widgets),
|
||||
+ .dapm_routes = voicehat_dapm_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(voicehat_dapm_routes),
|
||||
+};
|
||||
+
|
||||
+static int voicehat_daiops_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_soc_component *component = dai->component;
|
||||
+ struct voicehat_priv *voicehat =
|
||||
+ snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ if (voicehat->sdmode_delay_jiffies == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ dev_dbg(dai->dev, "CMD %d", cmd);
|
||||
+ dev_dbg(dai->dev, "Playback Active %d", dai->playback_active);
|
||||
+ dev_dbg(dai->dev, "Capture Active %d", dai->capture_active);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ if (dai->playback_active) {
|
||||
+ dev_info(dai->dev, "Enabling audio amp...\n");
|
||||
+ queue_delayed_work(
|
||||
+ system_power_efficient_wq,
|
||||
+ &voicehat->enable_sdmode_work,
|
||||
+ voicehat->sdmode_delay_jiffies);
|
||||
+ }
|
||||
+ break;
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ if (dai->playback_active) {
|
||||
+ cancel_delayed_work(&voicehat->enable_sdmode_work);
|
||||
+ dev_info(dai->dev, "Disabling audio amp...\n");
|
||||
+ gpiod_set_value(voicehat->sdmode_gpio, 0);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops voicehat_dai_ops = {
|
||||
+ .trigger = voicehat_daiops_trigger,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_dai_driver voicehat_dai = {
|
||||
+ .name = "voicehat-hifi",
|
||||
+ .capture = {
|
||||
+ .stream_name = "HiFi Capture",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = SNDRV_PCM_RATE_48000,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S32_LE
|
||||
+ },
|
||||
+ .playback = {
|
||||
+ .stream_name = "HiFi Playback",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = SNDRV_PCM_RATE_48000,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S32_LE
|
||||
+ },
|
||||
+ .ops = &voicehat_dai_ops,
|
||||
+ .symmetric_rates = 1
|
||||
+};
|
||||
+
|
||||
+#ifdef CONFIG_OF
|
||||
+static const struct of_device_id voicehat_ids[] = {
|
||||
+ { .compatible = "google,voicehat", }, {}
|
||||
+ };
|
||||
+ MODULE_DEVICE_TABLE(of, voicehat_ids);
|
||||
+#endif
|
||||
+
|
||||
+static int voicehat_platform_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct voicehat_priv *voicehat;
|
||||
+ unsigned int sdmode_delay;
|
||||
+ int ret;
|
||||
+
|
||||
+ voicehat = devm_kzalloc(&pdev->dev, sizeof(*voicehat), GFP_KERNEL);
|
||||
+ if (!voicehat)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ret = device_property_read_u32(&pdev->dev, "voicehat_sdmode_delay",
|
||||
+ &sdmode_delay);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ sdmode_delay = SDMODE_DELAY_MS;
|
||||
+ dev_info(&pdev->dev,
|
||||
+ "property 'voicehat_sdmode_delay' not found default 5 mS");
|
||||
+ } else {
|
||||
+ dev_info(&pdev->dev, "property 'voicehat_sdmode_delay' found delay= %d mS",
|
||||
+ sdmode_delay);
|
||||
+ }
|
||||
+ voicehat->sdmode_delay_jiffies = msecs_to_jiffies(sdmode_delay);
|
||||
+
|
||||
+ dev_set_drvdata(&pdev->dev, voicehat);
|
||||
+
|
||||
+ return snd_soc_register_component(&pdev->dev,
|
||||
+ &voicehat_component_driver,
|
||||
+ &voicehat_dai,
|
||||
+ 1);
|
||||
+}
|
||||
+
|
||||
+static int voicehat_platform_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ snd_soc_unregister_component(&pdev->dev);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver voicehat_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "voicehat-codec",
|
||||
+ .of_match_table = of_match_ptr(voicehat_ids),
|
||||
+ },
|
||||
+ .probe = voicehat_platform_probe,
|
||||
+ .remove = voicehat_platform_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(voicehat_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Google voiceHAT Codec driver");
|
||||
+MODULE_AUTHOR("Peter Malkin <petermalkin@google.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,414 @@
|
|||
From 32e71104fac52cd0dfe3614ac0d74e4eb50c509b Mon Sep 17 00:00:00 2001
|
||||
From: allocom <sparky-dev@allo.com>
|
||||
Date: Thu, 19 Apr 2018 12:12:26 +0530
|
||||
Subject: [PATCH] Driver and overlay for Allo Katana DAC
|
||||
|
||||
Allo Katana DAC: Updated default values
|
||||
|
||||
Signed-off-by: Jaikumar <jaikumar@cem-solutions.com>
|
||||
|
||||
Added mute stream func
|
||||
|
||||
Signed-off-by: Jaikumar <jaikumar@cem-solutions.net>
|
||||
|
||||
codecs: Correct Katana minimum volume
|
||||
|
||||
Update Katana minimum volume to get the exact 0.5 dB value in each step.
|
||||
|
||||
Signed-off-by: Sudeep Kumar <sudeepkumar@cem-solutions.net>
|
||||
---
|
||||
sound/soc/bcm/allo-katana-codec.c | 388 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 388 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/allo-katana-codec.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/allo-katana-codec.c
|
||||
@@ -0,0 +1,388 @@
|
||||
+/*
|
||||
+ * Driver for the ALLO KATANA CODEC
|
||||
+ *
|
||||
+ * Author: Jaikumar <jaikumar@cem-solutions.net>
|
||||
+ * Copyright 2018
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/regulator/consumer.h>
|
||||
+#include <linux/gcd.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dapm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/tlv.h>
|
||||
+#include <linux/i2c.h>
|
||||
+
|
||||
+
|
||||
+#define KATANA_CODEC_CHIP_ID 0x30
|
||||
+#define KATANA_CODEC_VIRT_BASE 0x100
|
||||
+#define KATANA_CODEC_PAGE 0
|
||||
+
|
||||
+#define KATANA_CODEC_CHIP_ID_REG (KATANA_CODEC_VIRT_BASE + 0)
|
||||
+#define KATANA_CODEC_RESET (KATANA_CODEC_VIRT_BASE + 1)
|
||||
+#define KATANA_CODEC_VOLUME_1 (KATANA_CODEC_VIRT_BASE + 2)
|
||||
+#define KATANA_CODEC_VOLUME_2 (KATANA_CODEC_VIRT_BASE + 3)
|
||||
+#define KATANA_CODEC_MUTE (KATANA_CODEC_VIRT_BASE + 4)
|
||||
+#define KATANA_CODEC_DSP_PROGRAM (KATANA_CODEC_VIRT_BASE + 5)
|
||||
+#define KATANA_CODEC_DEEMPHASIS (KATANA_CODEC_VIRT_BASE + 6)
|
||||
+#define KATANA_CODEC_DOP (KATANA_CODEC_VIRT_BASE + 7)
|
||||
+#define KATANA_CODEC_FORMAT (KATANA_CODEC_VIRT_BASE + 8)
|
||||
+#define KATANA_CODEC_COMMAND (KATANA_CODEC_VIRT_BASE + 9)
|
||||
+#define KATANA_CODEC_MUTE_STREAM (KATANA_CODEC_VIRT_BASE + 10)
|
||||
+
|
||||
+#define KATANA_CODEC_MAX_REGISTER (KATANA_CODEC_VIRT_BASE + 10)
|
||||
+
|
||||
+#define KATANA_CODEC_FMT 0xff
|
||||
+#define KATANA_CODEC_CHAN_MONO 0x00
|
||||
+#define KATANA_CODEC_CHAN_STEREO 0x80
|
||||
+#define KATANA_CODEC_ALEN_16 0x10
|
||||
+#define KATANA_CODEC_ALEN_24 0x20
|
||||
+#define KATANA_CODEC_ALEN_32 0x30
|
||||
+#define KATANA_CODEC_RATE_11025 0x01
|
||||
+#define KATANA_CODEC_RATE_22050 0x02
|
||||
+#define KATANA_CODEC_RATE_32000 0x03
|
||||
+#define KATANA_CODEC_RATE_44100 0x04
|
||||
+#define KATANA_CODEC_RATE_48000 0x05
|
||||
+#define KATANA_CODEC_RATE_88200 0x06
|
||||
+#define KATANA_CODEC_RATE_96000 0x07
|
||||
+#define KATANA_CODEC_RATE_176400 0x08
|
||||
+#define KATANA_CODEC_RATE_192000 0x09
|
||||
+#define KATANA_CODEC_RATE_352800 0x0a
|
||||
+#define KATANA_CODEC_RATE_384000 0x0b
|
||||
+
|
||||
+
|
||||
+struct katana_codec_priv {
|
||||
+ struct regmap *regmap;
|
||||
+ int fmt;
|
||||
+};
|
||||
+
|
||||
+static const struct reg_default katana_codec_reg_defaults[] = {
|
||||
+ { KATANA_CODEC_RESET, 0x00 },
|
||||
+ { KATANA_CODEC_VOLUME_1, 0xF0 },
|
||||
+ { KATANA_CODEC_VOLUME_2, 0xF0 },
|
||||
+ { KATANA_CODEC_MUTE, 0x00 },
|
||||
+ { KATANA_CODEC_DSP_PROGRAM, 0x04 },
|
||||
+ { KATANA_CODEC_DEEMPHASIS, 0x00 },
|
||||
+ { KATANA_CODEC_DOP, 0x00 },
|
||||
+ { KATANA_CODEC_FORMAT, 0xb4 },
|
||||
+};
|
||||
+
|
||||
+static const char * const katana_codec_dsp_program_texts[] = {
|
||||
+ "Linear Phase Fast Roll-off Filter",
|
||||
+ "Linear Phase Slow Roll-off Filter",
|
||||
+ "Minimum Phase Fast Roll-off Filter",
|
||||
+ "Minimum Phase Slow Roll-off Filter",
|
||||
+ "Apodizing Fast Roll-off Filter",
|
||||
+ "Corrected Minimum Phase Fast Roll-off Filter",
|
||||
+ "Brick Wall Filter",
|
||||
+};
|
||||
+
|
||||
+static const unsigned int katana_codec_dsp_program_values[] = {
|
||||
+ 0,
|
||||
+ 1,
|
||||
+ 2,
|
||||
+ 3,
|
||||
+ 4,
|
||||
+ 6,
|
||||
+ 7,
|
||||
+};
|
||||
+
|
||||
+static SOC_VALUE_ENUM_SINGLE_DECL(katana_codec_dsp_program,
|
||||
+ KATANA_CODEC_DSP_PROGRAM, 0, 0x07,
|
||||
+ katana_codec_dsp_program_texts,
|
||||
+ katana_codec_dsp_program_values);
|
||||
+
|
||||
+static const char * const katana_codec_deemphasis_texts[] = {
|
||||
+ "Bypass",
|
||||
+ "32kHz",
|
||||
+ "44.1kHz",
|
||||
+ "48kHz",
|
||||
+};
|
||||
+
|
||||
+static const unsigned int katana_codec_deemphasis_values[] = {
|
||||
+ 0,
|
||||
+ 1,
|
||||
+ 2,
|
||||
+ 3,
|
||||
+};
|
||||
+
|
||||
+static SOC_VALUE_ENUM_SINGLE_DECL(katana_codec_deemphasis,
|
||||
+ KATANA_CODEC_DEEMPHASIS, 0, 0x03,
|
||||
+ katana_codec_deemphasis_texts,
|
||||
+ katana_codec_deemphasis_values);
|
||||
+
|
||||
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(master_tlv, -12750, 0);
|
||||
+
|
||||
+static const struct snd_kcontrol_new katana_codec_controls[] = {
|
||||
+ SOC_DOUBLE_R_TLV("Master Playback Volume", KATANA_CODEC_VOLUME_1,
|
||||
+ KATANA_CODEC_VOLUME_2, 0, 255, 1, master_tlv),
|
||||
+ SOC_DOUBLE("Master Playback Switch", KATANA_CODEC_MUTE, 0, 0, 1, 1),
|
||||
+ SOC_ENUM("DSP Program Route", katana_codec_dsp_program),
|
||||
+ SOC_ENUM("Deemphasis Route", katana_codec_deemphasis),
|
||||
+ SOC_SINGLE("DoP Playback Switch", KATANA_CODEC_DOP, 0, 1, 1)
|
||||
+};
|
||||
+
|
||||
+static bool katana_codec_readable_register(struct device *dev,
|
||||
+ unsigned int reg)
|
||||
+{
|
||||
+ switch (reg) {
|
||||
+ case KATANA_CODEC_CHIP_ID_REG:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return reg < 0xff;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int katana_codec_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_soc_component *component = dai->component;
|
||||
+ struct katana_codec_priv *katana_codec =
|
||||
+ snd_soc_component_get_drvdata(component);
|
||||
+ int fmt = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_dbg(component->card->dev, "hw_params %u Hz, %u channels, %u bits\n",
|
||||
+ params_rate(params),
|
||||
+ params_channels(params),
|
||||
+ params_width(params));
|
||||
+
|
||||
+ switch (katana_codec->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
+ case SND_SOC_DAIFMT_CBM_CFM: // master
|
||||
+ if (params_channels(params) == 2)
|
||||
+ fmt = KATANA_CODEC_CHAN_STEREO;
|
||||
+ else
|
||||
+ fmt = KATANA_CODEC_CHAN_MONO;
|
||||
+
|
||||
+ switch (params_width(params)) {
|
||||
+ case 16:
|
||||
+ fmt |= KATANA_CODEC_ALEN_16;
|
||||
+ break;
|
||||
+ case 24:
|
||||
+ fmt |= KATANA_CODEC_ALEN_24;
|
||||
+ break;
|
||||
+ case 32:
|
||||
+ fmt |= KATANA_CODEC_ALEN_32;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(component->card->dev, "Bad frame size: %d\n",
|
||||
+ params_width(params));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ switch (params_rate(params)) {
|
||||
+ case 44100:
|
||||
+ fmt |= KATANA_CODEC_RATE_44100;
|
||||
+ break;
|
||||
+ case 48000:
|
||||
+ fmt |= KATANA_CODEC_RATE_48000;
|
||||
+ break;
|
||||
+ case 88200:
|
||||
+ fmt |= KATANA_CODEC_RATE_88200;
|
||||
+ break;
|
||||
+ case 96000:
|
||||
+ fmt |= KATANA_CODEC_RATE_96000;
|
||||
+ break;
|
||||
+ case 176400:
|
||||
+ fmt |= KATANA_CODEC_RATE_176400;
|
||||
+ break;
|
||||
+ case 192000:
|
||||
+ fmt |= KATANA_CODEC_RATE_192000;
|
||||
+ break;
|
||||
+ case 352800:
|
||||
+ fmt |= KATANA_CODEC_RATE_352800;
|
||||
+ break;
|
||||
+ case 384000:
|
||||
+ fmt |= KATANA_CODEC_RATE_384000;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(component->card->dev, "Bad sample rate: %d\n",
|
||||
+ params_rate(params));
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_write(katana_codec->regmap, KATANA_CODEC_FORMAT,
|
||||
+ fmt);
|
||||
+ if (ret != 0) {
|
||||
+ dev_err(component->card->dev, "Failed to set format: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case SND_SOC_DAIFMT_CBS_CFS:
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int katana_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
+{
|
||||
+ struct snd_soc_component *component = dai->component;
|
||||
+ struct katana_codec_priv *katana_codec =
|
||||
+ snd_soc_component_get_drvdata(component);
|
||||
+
|
||||
+ katana_codec->fmt = fmt;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int katana_codec_dai_mute_stream(struct snd_soc_dai *dai, int mute,
|
||||
+ int stream)
|
||||
+{
|
||||
+ struct snd_soc_component *component = dai->component;
|
||||
+ struct katana_codec_priv *katana_codec =
|
||||
+ snd_soc_component_get_drvdata(component);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ ret = regmap_write(katana_codec->regmap, KATANA_CODEC_MUTE_STREAM,
|
||||
+ mute);
|
||||
+ if (ret != 0) {
|
||||
+ dev_err(component->card->dev, "Failed to set mute: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops katana_codec_dai_ops = {
|
||||
+ .mute_stream = katana_codec_dai_mute_stream,
|
||||
+ .hw_params = katana_codec_hw_params,
|
||||
+ .set_fmt = katana_codec_set_fmt,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_dai_driver katana_codec_dai = {
|
||||
+ .name = "allo-katana-codec",
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
+ .rate_min = 44100,
|
||||
+ .rate_max = 384000,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE
|
||||
+ },
|
||||
+ .ops = &katana_codec_dai_ops,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_component_driver katana_codec_component_driver = {
|
||||
+ .idle_bias_on = true,
|
||||
+
|
||||
+ .controls = katana_codec_controls,
|
||||
+ .num_controls = ARRAY_SIZE(katana_codec_controls),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_range_cfg katana_codec_range = {
|
||||
+ .name = "Pages", .range_min = KATANA_CODEC_VIRT_BASE,
|
||||
+ .range_max = KATANA_CODEC_MAX_REGISTER,
|
||||
+ .selector_reg = KATANA_CODEC_PAGE,
|
||||
+ .selector_mask = 0xff,
|
||||
+ .window_start = 0, .window_len = 0x100,
|
||||
+};
|
||||
+
|
||||
+const struct regmap_config katana_codec_regmap = {
|
||||
+ .reg_bits = 8,
|
||||
+ .val_bits = 8,
|
||||
+
|
||||
+ .ranges = &katana_codec_range,
|
||||
+ .num_ranges = 1,
|
||||
+
|
||||
+ .max_register = KATANA_CODEC_MAX_REGISTER,
|
||||
+ .readable_reg = katana_codec_readable_register,
|
||||
+ .reg_defaults = katana_codec_reg_defaults,
|
||||
+ .num_reg_defaults = ARRAY_SIZE(katana_codec_reg_defaults),
|
||||
+ .cache_type = REGCACHE_RBTREE,
|
||||
+};
|
||||
+
|
||||
+static int allo_katana_component_probe(struct i2c_client *i2c,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ struct regmap *regmap;
|
||||
+ struct regmap_config config = katana_codec_regmap;
|
||||
+ struct device *dev = &i2c->dev;
|
||||
+ struct katana_codec_priv *katana_codec;
|
||||
+ unsigned int chip_id = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ regmap = devm_regmap_init_i2c(i2c, &config);
|
||||
+ if (IS_ERR(regmap))
|
||||
+ return PTR_ERR(regmap);
|
||||
+
|
||||
+ katana_codec = devm_kzalloc(dev, sizeof(struct katana_codec_priv),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!katana_codec)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ dev_set_drvdata(dev, katana_codec);
|
||||
+ katana_codec->regmap = regmap;
|
||||
+
|
||||
+ ret = regmap_read(regmap, KATANA_CODEC_CHIP_ID_REG, &chip_id);
|
||||
+ if ((ret != 0) || (chip_id != KATANA_CODEC_CHIP_ID)) {
|
||||
+ dev_err(dev, "Failed to read Chip or wrong Chip id: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ regmap_update_bits(regmap, KATANA_CODEC_RESET, 0x01, 0x01);
|
||||
+ msleep(10);
|
||||
+
|
||||
+ ret = snd_soc_register_component(dev, &katana_codec_component_driver,
|
||||
+ &katana_codec_dai, 1);
|
||||
+ if (ret != 0) {
|
||||
+ dev_err(dev, "failed to register codec: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int allo_katana_component_remove(struct i2c_client *i2c)
|
||||
+{
|
||||
+ snd_soc_unregister_component(&i2c->dev);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct i2c_device_id allo_katana_component_id[] = {
|
||||
+ { "allo-katana-codec", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, allo_katana_component_id);
|
||||
+
|
||||
+static const struct of_device_id allo_katana_codec_of_match[] = {
|
||||
+ { .compatible = "allo,allo-katana-codec", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, allo_katana_codec_of_match);
|
||||
+
|
||||
+static struct i2c_driver allo_katana_component_driver = {
|
||||
+ .probe = allo_katana_component_probe,
|
||||
+ .remove = allo_katana_component_remove,
|
||||
+ .id_table = allo_katana_component_id,
|
||||
+ .driver = {
|
||||
+ .name = "allo-katana-codec",
|
||||
+ .of_match_table = allo_katana_codec_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_i2c_driver(allo_katana_component_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("ASoC Allo Katana Codec Driver");
|
||||
+MODULE_AUTHOR("Jaikumar <jaikumar@cem-solutions.net>");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,324 @@
|
|||
From f3dc9ad69589abbf6572636fc2e2a120462a229a Mon Sep 17 00:00:00 2001
|
||||
From: Tim Gover <tim.gover@raspberrypi.org>
|
||||
Date: Wed, 27 Jun 2018 15:59:12 +0100
|
||||
Subject: [PATCH] ASoC: Add generic RPI driver for simple soundcards.
|
||||
|
||||
The RPI simple sound card driver provides a generic ALSA SOC card driver
|
||||
supporting a variety of Pi HAT soundcards. The intention is to avoid
|
||||
the duplication of code for cards that can't be fully supported by
|
||||
the soc simple/graph cards but are otherwise almost identical.
|
||||
|
||||
This initial commit adds support for the ADAU1977 ADC, Google VoiceHat,
|
||||
HifiBerry AMP, HifiBerry DAC and RPI DAC.
|
||||
|
||||
Signed-off-by: Tim Gover <tim.gover@raspberrypi.org>
|
||||
|
||||
ASoC: Use correct card name in rpi-simple driver
|
||||
|
||||
Use the specific card name from drvdata instead of the snd_rpi_simple
|
||||
|
||||
rpi-simple-soundcard: Use nicer driver name "RPi-simple"
|
||||
|
||||
Rename the driver from "RPI simple soundcard" to "RPi-simple" so that
|
||||
the driver name won't be mangled allowing to be used unaltered as the
|
||||
card conf filename.
|
||||
|
||||
ASoC: rpi-simple-soundcard: use modern dai_link style
|
||||
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
---
|
||||
sound/soc/bcm/rpi-simple-soundcard.c | 288 +++++++++++++++++++++++++++
|
||||
1 file changed, 288 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/rpi-simple-soundcard.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/rpi-simple-soundcard.c
|
||||
@@ -0,0 +1,288 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * rpi-simple-soundcard.c -- ALSA SoC Raspberry Pi soundcard.
|
||||
+ *
|
||||
+ * Copyright (C) 2018 Raspberry Pi.
|
||||
+ *
|
||||
+ * Authors: Tim Gover <tim.gover@raspberrypi.org>
|
||||
+ *
|
||||
+ * Based on code:
|
||||
+ * hifiberry_amp.c, hifiberry_dac.c, rpi-dac.c
|
||||
+ * by Florian Meier <florian.meier@koalo.de>
|
||||
+ *
|
||||
+ * googlevoicehat-soundcard.c
|
||||
+ * by Peter Malkin <petermalkin@google.com>
|
||||
+ *
|
||||
+ * adau1977-adc.c
|
||||
+ * by Andrey Grodzovsky <andrey2805@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+/* Parameters for generic RPI functions */
|
||||
+struct snd_rpi_simple_drvdata {
|
||||
+ struct snd_soc_dai_link *dai;
|
||||
+ const char* card_name;
|
||||
+ unsigned int fixed_bclk_ratio;
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_simple_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_rpi_simple_drvdata *drvdata =
|
||||
+ snd_soc_card_get_drvdata(rtd->card);
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
+
|
||||
+ if (drvdata->fixed_bclk_ratio > 0)
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai,
|
||||
+ drvdata->fixed_bclk_ratio);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_simple_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
+ struct snd_rpi_simple_drvdata *drvdata;
|
||||
+ unsigned int sample_bits;
|
||||
+
|
||||
+ drvdata = snd_soc_card_get_drvdata(rtd->card);
|
||||
+
|
||||
+ if (drvdata->fixed_bclk_ratio > 0)
|
||||
+ return 0; // BCLK is configured in .init
|
||||
+
|
||||
+ /* The simple drivers just set the bclk_ratio to sample_bits * 2 so
|
||||
+ * hard-code this for now. More complex drivers could just replace
|
||||
+ * the hw_params routine.
|
||||
+ */
|
||||
+ sample_bits = snd_pcm_format_physical_width(params_format(params));
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
|
||||
+}
|
||||
+
|
||||
+static struct snd_soc_ops snd_rpi_simple_ops = {
|
||||
+ .hw_params = snd_rpi_simple_hw_params,
|
||||
+};
|
||||
+
|
||||
+enum adau1977_clk_id {
|
||||
+ ADAU1977_SYSCLK,
|
||||
+};
|
||||
+
|
||||
+enum adau1977_sysclk_src {
|
||||
+ ADAU1977_SYSCLK_SRC_MCLK,
|
||||
+ ADAU1977_SYSCLK_SRC_LRCLK,
|
||||
+};
|
||||
+
|
||||
+static int adau1977_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
+
|
||||
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 0);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return snd_soc_component_set_sysclk(codec_dai->component,
|
||||
+ ADAU1977_SYSCLK, ADAU1977_SYSCLK_SRC_MCLK,
|
||||
+ 11289600, SND_SOC_CLOCK_IN);
|
||||
+}
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(adau1977,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("adau1977.1-0011", "adau1977-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_adau1977_dai[] = {
|
||||
+ {
|
||||
+ .name = "adau1977",
|
||||
+ .stream_name = "ADAU1977",
|
||||
+ .init = adau1977_init,
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
+ SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBM_CFM,
|
||||
+ SND_SOC_DAILINK_REG(adau1977),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_simple_drvdata drvdata_adau1977 = {
|
||||
+ .card_name = "snd_rpi_adau1977_adc",
|
||||
+ .dai = snd_rpi_adau1977_dai,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(gvchat,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("voicehat-codec", "voicehat-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_googlevoicehat_soundcard_dai[] = {
|
||||
+{
|
||||
+ .name = "Google voiceHAT SoundCard",
|
||||
+ .stream_name = "Google voiceHAT SoundCard HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ SND_SOC_DAILINK_REG(gvchat),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_simple_drvdata drvdata_googlevoicehat = {
|
||||
+ .card_name = "snd_rpi_googlevoicehat_soundcard",
|
||||
+ .dai = snd_googlevoicehat_soundcard_dai,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(hifiberry_amp,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_hifiberry_amp_dai[] = {
|
||||
+ {
|
||||
+ .name = "HifiBerry AMP",
|
||||
+ .stream_name = "HifiBerry AMP HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
+ SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ SND_SOC_DAILINK_REG(hifiberry_amp),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_simple_drvdata drvdata_hifiberry_amp = {
|
||||
+ .card_name = "snd_rpi_hifiberry_amp",
|
||||
+ .dai = snd_hifiberry_amp_dai,
|
||||
+ .fixed_bclk_ratio = 64,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(hifiberry_dac,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm5102a-codec", "pcm5102a-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_hifiberry_dac_dai[] = {
|
||||
+ {
|
||||
+ .name = "HifiBerry DAC",
|
||||
+ .stream_name = "HifiBerry DAC HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
+ SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ SND_SOC_DAILINK_REG(hifiberry_dac),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_simple_drvdata drvdata_hifiberry_dac = {
|
||||
+ .card_name = "snd_rpi_hifiberry_dac",
|
||||
+ .dai = snd_hifiberry_dac_dai,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(rpi_dac,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_rpi_dac_dai[] = {
|
||||
+{
|
||||
+ .name = "RPi-DAC",
|
||||
+ .stream_name = "RPi-DAC HiFi",
|
||||
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBS_CFS,
|
||||
+ SND_SOC_DAILINK_REG(rpi_dac),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_simple_drvdata drvdata_rpi_dac = {
|
||||
+ .card_name = "snd_rpi_rpi_dac",
|
||||
+ .dai = snd_rpi_dac_dai,
|
||||
+ .fixed_bclk_ratio = 64,
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id snd_rpi_simple_of_match[] = {
|
||||
+ { .compatible = "adi,adau1977-adc",
|
||||
+ .data = (void *) &drvdata_adau1977 },
|
||||
+ { .compatible = "googlevoicehat,googlevoicehat-soundcard",
|
||||
+ .data = (void *) &drvdata_googlevoicehat },
|
||||
+ { .compatible = "hifiberry,hifiberry-amp",
|
||||
+ .data = (void *) &drvdata_hifiberry_amp },
|
||||
+ { .compatible = "hifiberry,hifiberry-dac",
|
||||
+ .data = (void *) &drvdata_hifiberry_dac },
|
||||
+ { .compatible = "rpi,rpi-dac", &drvdata_rpi_dac},
|
||||
+ {},
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_card snd_rpi_simple = {
|
||||
+ .driver_name = "RPi-simple",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = NULL,
|
||||
+ .num_links = 1, /* Only a single DAI supported at the moment */
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_simple_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ const struct of_device_id *of_id;
|
||||
+
|
||||
+ snd_rpi_simple.dev = &pdev->dev;
|
||||
+ of_id = of_match_node(snd_rpi_simple_of_match, pdev->dev.of_node);
|
||||
+
|
||||
+ if (pdev->dev.of_node && of_id->data) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_rpi_simple_drvdata *drvdata =
|
||||
+ (struct snd_rpi_simple_drvdata *) of_id->data;
|
||||
+ struct snd_soc_dai_link *dai = drvdata->dai;
|
||||
+
|
||||
+ snd_soc_card_set_drvdata(&snd_rpi_simple, drvdata);
|
||||
+
|
||||
+ /* More complex drivers might override individual functions */
|
||||
+ if (!dai->init)
|
||||
+ dai->init = snd_rpi_simple_init;
|
||||
+ if (!dai->ops)
|
||||
+ dai->ops = &snd_rpi_simple_ops;
|
||||
+
|
||||
+ snd_rpi_simple.name = drvdata->card_name;
|
||||
+
|
||||
+ snd_rpi_simple.dai_link = dai;
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+ if (!i2s_node) {
|
||||
+ pr_err("Failed to find i2s-controller DT node\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_simple);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev, "Failed to register card %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver snd_rpi_simple_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-simple",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_rpi_simple_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_simple_probe,
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_rpi_simple_of_match);
|
||||
+
|
||||
+module_platform_driver(snd_rpi_simple_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
|
||||
+MODULE_DESCRIPTION("ASoC Raspberry Pi simple soundcard driver ");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,264 @@
|
|||
From 67813a037a07538c207f8771bc9922bf82281241 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Mon, 3 Sep 2018 17:00:36 +0100
|
||||
Subject: [PATCH] ASoC: Add Kconfig and Makefile for sound/soc/bcm
|
||||
|
||||
Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
---
|
||||
sound/soc/bcm/Kconfig | 199 +++++++++++++++++++++++++++++++++++++++++
|
||||
sound/soc/bcm/Makefile | 42 +++++++++
|
||||
2 files changed, 241 insertions(+)
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -17,3 +17,202 @@ config SND_SOC_CYGNUS
|
||||
Cygnus chips (bcm958300, bcm958305, bcm911360)
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
+
|
||||
+config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
|
||||
+ tristate "Support for Google voiceHAT soundcard"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_VOICEHAT
|
||||
+ select SND_RPI_SIMPLE_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for voiceHAT soundcard.
|
||||
+
|
||||
+config SND_BCM2708_SOC_HIFIBERRY_DAC
|
||||
+ tristate "Support for HifiBerry DAC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM5102A
|
||||
+ select SND_RPI_SIMPLE_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for HifiBerry DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
|
||||
+ tristate "Support for HifiBerry DAC+"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM512x
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for HifiBerry DAC+.
|
||||
+
|
||||
+config SND_BCM2708_SOC_HIFIBERRY_DIGI
|
||||
+ tristate "Support for HifiBerry Digi"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM8804
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
|
||||
+
|
||||
+config SND_BCM2708_SOC_HIFIBERRY_AMP
|
||||
+ tristate "Support for the HifiBerry Amp"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_TAS5713
|
||||
+ select SND_RPI_SIMPLE_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
|
||||
+
|
||||
+config SND_BCM2708_SOC_RPI_CIRRUS
|
||||
+ tristate "Support for Cirrus Logic Audio Card"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM5102
|
||||
+ select SND_SOC_WM8804
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for the Wolfson and
|
||||
+ Cirrus Logic audio cards.
|
||||
+
|
||||
+config SND_BCM2708_SOC_RPI_DAC
|
||||
+ tristate "Support for RPi-DAC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM1794A
|
||||
+ select SND_RPI_SIMPLE_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for RPi-DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_RPI_PROTO
|
||||
+ tristate "Support for Rpi-PROTO"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM8731
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
|
||||
+
|
||||
+config SND_BCM2708_SOC_JUSTBOOM_DAC
|
||||
+ tristate "Support for JustBoom DAC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM512x
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for JustBoom DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_JUSTBOOM_DIGI
|
||||
+ tristate "Support for JustBoom Digi"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM8804
|
||||
+ select SND_RPI_WM8804_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for JustBoom Digi.
|
||||
+
|
||||
+config SND_BCM2708_SOC_IQAUDIO_DAC
|
||||
+ tristate "Support for IQaudIO-DAC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM512x_I2C
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for IQaudIO-DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_IQAUDIO_DIGI
|
||||
+ tristate "Support for IQAudIO Digi"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM8804
|
||||
+ select SND_RPI_WM8804_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for IQAudIO Digital IO board.
|
||||
+
|
||||
+config SND_BCM2708_SOC_ADAU1977_ADC
|
||||
+ tristate "Support for ADAU1977 ADC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_ADAU1977_I2C
|
||||
+ select SND_RPI_SIMPLE_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for ADAU1977 ADC.
|
||||
+
|
||||
+config SND_AUDIOINJECTOR_PI_SOUNDCARD
|
||||
+ tristate "Support for audioinjector.net Pi add on soundcard"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM8731
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for audioinjector.net Pi Hat
|
||||
+
|
||||
+config SND_AUDIOINJECTOR_OCTO_SOUNDCARD
|
||||
+ tristate "Support for audioinjector.net Octo channel (Hat) soundcard"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_CS42XX8_I2C
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for audioinjector.net octo add on
|
||||
+
|
||||
+config SND_DIGIDAC1_SOUNDCARD
|
||||
+ tristate "Support for Red Rocks Audio DigiDAC1"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM8804
|
||||
+ select SND_SOC_WM8741
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Red Rocks Audio DigiDAC1 board.
|
||||
+
|
||||
+config SND_BCM2708_SOC_DIONAUDIO_LOCO
|
||||
+ tristate "Support for Dion Audio LOCO DAC-AMP"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM5102a
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Dion Audio LOCO.
|
||||
+
|
||||
+config SND_BCM2708_SOC_DIONAUDIO_LOCO_V2
|
||||
+ tristate "Support for Dion Audio LOCO-V2 DAC-AMP"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM5122
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Dion Audio LOCO-V2.
|
||||
+
|
||||
+config SND_BCM2708_SOC_ALLO_PIANO_DAC
|
||||
+ tristate "Support for Allo Piano DAC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM512x_I2C
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Allo Piano DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS
|
||||
+ tristate "Support for Allo Piano DAC Plus"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM512x_I2C
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Allo Piano DAC Plus.
|
||||
+
|
||||
+config SND_BCM2708_SOC_ALLO_BOSS_DAC
|
||||
+ tristate "Support for Allo Boss DAC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM512x_I2C
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Allo Boss DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_ALLO_DIGIONE
|
||||
+ tristate "Support for Allo DigiOne"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_WM8804
|
||||
+ select SND_RPI_WM8804_SOUNDCARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Allo DigiOne.
|
||||
+
|
||||
+config SND_BCM2708_SOC_ALLO_KATANA_DAC
|
||||
+ tristate "Support for Allo Katana DAC"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ depends on I2C
|
||||
+ select REGMAP_I2C
|
||||
+ select SND_AUDIO_GRAPH_CARD
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Allo Katana DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_FE_PI_AUDIO
|
||||
+ tristate "Support for Fe-Pi-Audio"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_SGTL5000
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Fe-Pi-Audio.
|
||||
+
|
||||
+config SND_PISOUND
|
||||
+ tristate "Support for Blokas Labs pisound"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_RAWMIDI
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for Blokas Labs pisound.
|
||||
+
|
||||
+config SND_RPI_SIMPLE_SOUNDCARD
|
||||
+ tristate "Support for Raspberry Pi simple soundcards"
|
||||
+ help
|
||||
+ Say Y or M if you want to add support Raspbery Pi simple soundcards
|
||||
+
|
||||
+config SND_RPI_WM8804_SOUNDCARD
|
||||
+ tristate "Support for Raspberry Pi generic WM8804 soundcards"
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for the Raspberry Pi
|
||||
+ generic driver for WM8804 based soundcards.
|
||||
--- a/sound/soc/bcm/Makefile
|
||||
+++ b/sound/soc/bcm/Makefile
|
||||
@@ -9,3 +9,45 @@ snd-soc-cygnus-objs := cygnus-pcm.o cygn
|
||||
|
||||
obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o
|
||||
|
||||
+# Google voiceHAT custom codec support
|
||||
+snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o
|
||||
+
|
||||
+# BCM2708 Machine Support
|
||||
+snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
|
||||
+snd-soc-justboom-dac-objs := justboom-dac.o
|
||||
+snd-soc-rpi-cirrus-objs := rpi-cirrus.o
|
||||
+snd-soc-rpi-proto-objs := rpi-proto.o
|
||||
+snd-soc-iqaudio-dac-objs := iqaudio-dac.o
|
||||
+snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
|
||||
+snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o
|
||||
+snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o
|
||||
+snd-soc-dionaudio-loco-objs := dionaudio_loco.o
|
||||
+snd-soc-dionaudio-loco-v2-objs := dionaudio_loco-v2.o
|
||||
+snd-soc-allo-boss-dac-objs := allo-boss-dac.o
|
||||
+snd-soc-allo-piano-dac-objs := allo-piano-dac.o
|
||||
+snd-soc-allo-piano-dac-plus-objs := allo-piano-dac-plus.o
|
||||
+snd-soc-allo-katana-codec-objs := allo-katana-codec.o
|
||||
+snd-soc-pisound-objs := pisound.o
|
||||
+snd-soc-fe-pi-audio-objs := fe-pi-audio.o
|
||||
+snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
|
||||
+snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
|
||||
+
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
|
||||
+obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o
|
||||
+obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o
|
||||
+obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO_V2) += snd-soc-dionaudio-loco-v2.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC) += snd-soc-allo-boss-dac.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS) += snd-soc-allo-piano-dac-plus.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_ALLO_KATANA_DAC) += snd-soc-allo-katana-codec.o
|
||||
+obj-$(CONFIG_SND_PISOUND) += snd-soc-pisound.o
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_FE_PI_AUDIO) += snd-soc-fe-pi-audio.o
|
||||
+obj-$(CONFIG_SND_RPI_SIMPLE_SOUNDCARD) += snd-soc-rpi-simple-soundcard.o
|
||||
+obj-$(CONFIG_SND_RPI_WM8804_SOUNDCARD) += snd-soc-rpi-wm8804-soundcard.o
|
|
@ -0,0 +1,470 @@
|
|||
From e211a67304ac3104fb9ee1a2524f3ffbed5c2284 Mon Sep 17 00:00:00 2001
|
||||
From: Tim Gover <tim.gover@raspberrypi.org>
|
||||
Date: Sat, 21 Jul 2018 20:07:46 +0100
|
||||
Subject: [PATCH] ASoC: Create a generic Pi Hat WM8804 driver
|
||||
|
||||
Reduce the amount of duplicated code by creating a generic driver for
|
||||
Pi Hat digi cards using the WM8804 codec.
|
||||
|
||||
This replaces the
|
||||
Allo DigiOne, Hifiberry Digi/Pro, JustBoom Digi and IQAudIO Digi
|
||||
dedicate soundcard drivers with a generic driver.
|
||||
|
||||
There are no significant changes to the runtime behavior of the drivers
|
||||
and end users should not have to change any configuration settings
|
||||
after upgrading.
|
||||
|
||||
Minor changes
|
||||
* Check the return value of snd_soc_component_update_bits
|
||||
* Added some pr_debug tracing
|
||||
* Various checkpatch tidyups
|
||||
* Updated allodigi-one to use use 128FS at > 96 Khz. This appears to
|
||||
be an omission in the original driver code so followed the Hifiberry
|
||||
DAC driver approach.
|
||||
|
||||
ASoC: rpi-wm8804-soundcard: use modern dai_link style
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
rpi-wm8804-soundcard: drop PWRDN register writes
|
||||
|
||||
Since kernel 4.0 the PWRDN register bits are under DAPM
|
||||
control from the wm8804 driver.
|
||||
|
||||
Drop code that modifies that register to avoid interfering
|
||||
with DAPM.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
rpi-wm8804-soundcard: configure wm8804 clocks only on rate change
|
||||
|
||||
This should avoid clicks when stopping and immediately afterwards
|
||||
starting a stream with the same samplerate as before.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
|
||||
rpi-wm8804-soundcard: Fixed MCLKDIV for Allo Digione
|
||||
|
||||
The Allo Digione board wants a fixed MCLKDIV of 256.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/3296
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
sound/soc/bcm/rpi-wm8804-soundcard.c | 410 +++++++++++++++++++++++++++
|
||||
1 file changed, 410 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/rpi-wm8804-soundcard.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/rpi-wm8804-soundcard.c
|
||||
@@ -0,0 +1,410 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
|
||||
+ *
|
||||
+ * Copyright (C) 2018 Raspberry Pi.
|
||||
+ *
|
||||
+ * Authors: Tim Gover <tim.gover@raspberrypi.org>
|
||||
+ *
|
||||
+ * Generic driver for Pi Hat WM8804 digi sounds cards
|
||||
+ *
|
||||
+ * Based upon code from:
|
||||
+ * justboom-digi.c
|
||||
+ * by Milan Neskovic <info@justboom.co>
|
||||
+ *
|
||||
+ * iqaudio_digi.c
|
||||
+ * by Daniel Matuschek <info@crazy-audio.com>
|
||||
+ *
|
||||
+ * allo-digione.c
|
||||
+ * by Baswaraj <jaikumar@cem-solutions.net>
|
||||
+ *
|
||||
+ * hifiberry-digi.c
|
||||
+ * Daniel Matuschek <info@crazy-audio.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License
|
||||
+ * version 2 as published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/module.h>
|
||||
+
|
||||
+#include <sound/core.h>
|
||||
+#include <sound/pcm.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+#include "../codecs/wm8804.h"
|
||||
+
|
||||
+struct wm8804_clk_cfg {
|
||||
+ unsigned int sysclk_freq;
|
||||
+ unsigned int mclk_freq;
|
||||
+ unsigned int mclk_div;
|
||||
+};
|
||||
+
|
||||
+/* Parameters for generic functions */
|
||||
+struct snd_rpi_wm8804_drvdata {
|
||||
+ /* Required - pointer to the DAI structure */
|
||||
+ struct snd_soc_dai_link *dai;
|
||||
+ /* Required - snd_soc_card name */
|
||||
+ const char *card_name;
|
||||
+ /* Optional DT node names if card info is defined in DT */
|
||||
+ const char *card_name_dt;
|
||||
+ const char *dai_name_dt;
|
||||
+ const char *dai_stream_name_dt;
|
||||
+ /* Optional probe extension - called prior to register_card */
|
||||
+ int (*probe)(struct platform_device *pdev);
|
||||
+};
|
||||
+
|
||||
+static struct gpio_desc *snd_clk44gpio;
|
||||
+static struct gpio_desc *snd_clk48gpio;
|
||||
+static int wm8804_samplerate = 0;
|
||||
+
|
||||
+/* Forward declarations */
|
||||
+static struct snd_soc_dai_link snd_allo_digione_dai[];
|
||||
+static struct snd_soc_card snd_rpi_wm8804;
|
||||
+
|
||||
+
|
||||
+#define CLK_44EN_RATE 22579200UL
|
||||
+#define CLK_48EN_RATE 24576000UL
|
||||
+
|
||||
+static unsigned int snd_rpi_wm8804_enable_clock(unsigned int samplerate)
|
||||
+{
|
||||
+ switch (samplerate) {
|
||||
+ case 11025:
|
||||
+ case 22050:
|
||||
+ case 44100:
|
||||
+ case 88200:
|
||||
+ case 176400:
|
||||
+ gpiod_set_value_cansleep(snd_clk44gpio, 1);
|
||||
+ gpiod_set_value_cansleep(snd_clk48gpio, 0);
|
||||
+ return CLK_44EN_RATE;
|
||||
+ default:
|
||||
+ gpiod_set_value_cansleep(snd_clk48gpio, 1);
|
||||
+ gpiod_set_value_cansleep(snd_clk44gpio, 0);
|
||||
+ return CLK_48EN_RATE;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void snd_rpi_wm8804_clk_cfg(unsigned int samplerate,
|
||||
+ struct wm8804_clk_cfg *clk_cfg)
|
||||
+{
|
||||
+ clk_cfg->sysclk_freq = 27000000;
|
||||
+
|
||||
+ if (samplerate <= 96000 ||
|
||||
+ snd_rpi_wm8804.dai_link == snd_allo_digione_dai) {
|
||||
+ clk_cfg->mclk_freq = samplerate * 256;
|
||||
+ clk_cfg->mclk_div = WM8804_MCLKDIV_256FS;
|
||||
+ } else {
|
||||
+ clk_cfg->mclk_freq = samplerate * 128;
|
||||
+ clk_cfg->mclk_div = WM8804_MCLKDIV_128FS;
|
||||
+ }
|
||||
+
|
||||
+ if (!(IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)))
|
||||
+ clk_cfg->sysclk_freq = snd_rpi_wm8804_enable_clock(samplerate);
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_wm8804_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
+ struct snd_soc_component *component = rtd->codec_dai->component;
|
||||
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
+ int sampling_freq = 1;
|
||||
+ int ret;
|
||||
+ struct wm8804_clk_cfg clk_cfg;
|
||||
+ int samplerate = params_rate(params);
|
||||
+
|
||||
+ if (samplerate == wm8804_samplerate)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* clear until all clocks are setup properly */
|
||||
+ wm8804_samplerate = 0;
|
||||
+
|
||||
+ snd_rpi_wm8804_clk_cfg(samplerate, &clk_cfg);
|
||||
+
|
||||
+ pr_debug("%s samplerate: %d mclk_freq: %u mclk_div: %u sysclk: %u\n",
|
||||
+ __func__, samplerate, clk_cfg.mclk_freq,
|
||||
+ clk_cfg.mclk_div, clk_cfg.sysclk_freq);
|
||||
+
|
||||
+ switch (samplerate) {
|
||||
+ case 32000:
|
||||
+ sampling_freq = 0x03;
|
||||
+ break;
|
||||
+ case 44100:
|
||||
+ sampling_freq = 0x00;
|
||||
+ break;
|
||||
+ case 48000:
|
||||
+ sampling_freq = 0x02;
|
||||
+ break;
|
||||
+ case 88200:
|
||||
+ sampling_freq = 0x08;
|
||||
+ break;
|
||||
+ case 96000:
|
||||
+ sampling_freq = 0x0a;
|
||||
+ break;
|
||||
+ case 176400:
|
||||
+ sampling_freq = 0x0c;
|
||||
+ break;
|
||||
+ case 192000:
|
||||
+ sampling_freq = 0x0e;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(rtd->card->dev,
|
||||
+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
|
||||
+ samplerate);
|
||||
+ }
|
||||
+
|
||||
+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, clk_cfg.mclk_div);
|
||||
+ snd_soc_dai_set_pll(codec_dai, 0, 0,
|
||||
+ clk_cfg.sysclk_freq, clk_cfg.mclk_freq);
|
||||
+
|
||||
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
|
||||
+ clk_cfg.sysclk_freq, SND_SOC_CLOCK_OUT);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(rtd->card->dev,
|
||||
+ "Failed to set WM8804 SYSCLK: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ wm8804_samplerate = samplerate;
|
||||
+
|
||||
+ /* set sampling frequency status bits */
|
||||
+ snd_soc_component_update_bits(component, WM8804_SPDTX4, 0x0f,
|
||||
+ sampling_freq);
|
||||
+
|
||||
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
|
||||
+}
|
||||
+
|
||||
+static struct snd_soc_ops snd_rpi_wm8804_ops = {
|
||||
+ .hw_params = snd_rpi_wm8804_hw_params,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(justboom_digi,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_justboom_digi_dai[] = {
|
||||
+{
|
||||
+ .name = "JustBoom Digi",
|
||||
+ .stream_name = "JustBoom Digi HiFi",
|
||||
+ SND_SOC_DAILINK_REG(justboom_digi),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_wm8804_drvdata drvdata_justboom_digi = {
|
||||
+ .card_name = "snd_rpi_justboom_digi",
|
||||
+ .dai = snd_justboom_digi_dai,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(iqaudio_digi,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_iqaudio_digi_dai[] = {
|
||||
+{
|
||||
+ .name = "IQAudIO Digi",
|
||||
+ .stream_name = "IQAudIO Digi HiFi",
|
||||
+ SND_SOC_DAILINK_REG(iqaudio_digi),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_wm8804_drvdata drvdata_iqaudio_digi = {
|
||||
+ .card_name = "IQAudIODigi",
|
||||
+ .dai = snd_iqaudio_digi_dai,
|
||||
+ .card_name_dt = "wm8804-digi,card-name",
|
||||
+ .dai_name_dt = "wm8804-digi,dai-name",
|
||||
+ .dai_stream_name_dt = "wm8804-digi,dai-stream-name",
|
||||
+};
|
||||
+
|
||||
+static int snd_allo_digione_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ pr_debug("%s\n", __func__);
|
||||
+
|
||||
+ if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)) {
|
||||
+ dev_err(&pdev->dev, "devm_gpiod_get() failed\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(allo_digione,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_allo_digione_dai[] = {
|
||||
+{
|
||||
+ .name = "Allo DigiOne",
|
||||
+ .stream_name = "Allo DigiOne HiFi",
|
||||
+ SND_SOC_DAILINK_REG(allo_digione),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+static struct snd_rpi_wm8804_drvdata drvdata_allo_digione = {
|
||||
+ .card_name = "snd_allo_digione",
|
||||
+ .dai = snd_allo_digione_dai,
|
||||
+ .probe = snd_allo_digione_probe,
|
||||
+};
|
||||
+
|
||||
+SND_SOC_DAILINK_DEFS(hifiberry_digi,
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
|
||||
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
|
||||
+
|
||||
+static struct snd_soc_dai_link snd_hifiberry_digi_dai[] = {
|
||||
+{
|
||||
+ .name = "HifiBerry Digi",
|
||||
+ .stream_name = "HifiBerry Digi HiFi",
|
||||
+ SND_SOC_DAILINK_REG(hifiberry_digi),
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+static int snd_hifiberry_digi_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ pr_debug("%s\n", __func__);
|
||||
+
|
||||
+ if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio))
|
||||
+ return 0;
|
||||
+
|
||||
+ snd_hifiberry_digi_dai->name = "HiFiBerry Digi+ Pro";
|
||||
+ snd_hifiberry_digi_dai->stream_name = "HiFiBerry Digi+ Pro HiFi";
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct snd_rpi_wm8804_drvdata drvdata_hifiberry_digi = {
|
||||
+ .card_name = "snd_rpi_hifiberry_digi",
|
||||
+ .dai = snd_hifiberry_digi_dai,
|
||||
+ .probe = snd_hifiberry_digi_probe,
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id snd_rpi_wm8804_of_match[] = {
|
||||
+ { .compatible = "justboom,justboom-digi",
|
||||
+ .data = (void *) &drvdata_justboom_digi },
|
||||
+ { .compatible = "iqaudio,wm8804-digi",
|
||||
+ .data = (void *) &drvdata_iqaudio_digi },
|
||||
+ { .compatible = "allo,allo-digione",
|
||||
+ .data = (void *) &drvdata_allo_digione },
|
||||
+ { .compatible = "hifiberry,hifiberry-digi",
|
||||
+ .data = (void *) &drvdata_hifiberry_digi },
|
||||
+ {},
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_card snd_rpi_wm8804 = {
|
||||
+ .driver_name = "RPi-WM8804",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .dai_link = NULL,
|
||||
+ .num_links = 1,
|
||||
+};
|
||||
+
|
||||
+static int snd_rpi_wm8804_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ const struct of_device_id *of_id;
|
||||
+
|
||||
+ snd_rpi_wm8804.dev = &pdev->dev;
|
||||
+ of_id = of_match_node(snd_rpi_wm8804_of_match, pdev->dev.of_node);
|
||||
+
|
||||
+ if (pdev->dev.of_node && of_id->data) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_rpi_wm8804_drvdata *drvdata =
|
||||
+ (struct snd_rpi_wm8804_drvdata *) of_id->data;
|
||||
+ struct snd_soc_dai_link *dai = drvdata->dai;
|
||||
+
|
||||
+ snd_soc_card_set_drvdata(&snd_rpi_wm8804, drvdata);
|
||||
+
|
||||
+ if (!dai->ops)
|
||||
+ dai->ops = &snd_rpi_wm8804_ops;
|
||||
+ if (!dai->codecs->dai_name)
|
||||
+ dai->codecs->dai_name = "wm8804-spdif";
|
||||
+ if (!dai->codecs->name)
|
||||
+ dai->codecs->name = "wm8804.1-003b";
|
||||
+ if (!dai->dai_fmt)
|
||||
+ dai->dai_fmt = SND_SOC_DAIFMT_I2S |
|
||||
+ SND_SOC_DAIFMT_NB_NF |
|
||||
+ SND_SOC_DAIFMT_CBM_CFM;
|
||||
+
|
||||
+ snd_rpi_wm8804.dai_link = dai;
|
||||
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "i2s-controller", 0);
|
||||
+ if (!i2s_node) {
|
||||
+ pr_err("Failed to find i2s-controller DT node\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ snd_rpi_wm8804.name = drvdata->card_name;
|
||||
+
|
||||
+ /* If requested by in drvdata get card & DAI names from DT */
|
||||
+ if (drvdata->card_name_dt)
|
||||
+ of_property_read_string(i2s_node,
|
||||
+ drvdata->card_name_dt,
|
||||
+ &snd_rpi_wm8804.name);
|
||||
+
|
||||
+ if (drvdata->dai_name_dt)
|
||||
+ of_property_read_string(i2s_node,
|
||||
+ drvdata->dai_name_dt,
|
||||
+ &dai->name);
|
||||
+
|
||||
+ if (drvdata->dai_stream_name_dt)
|
||||
+ of_property_read_string(i2s_node,
|
||||
+ drvdata->dai_stream_name_dt,
|
||||
+ &dai->stream_name);
|
||||
+
|
||||
+ dai->cpus->of_node = i2s_node;
|
||||
+ dai->platforms->of_node = i2s_node;
|
||||
+
|
||||
+ /*
|
||||
+ * clk44gpio and clk48gpio are not required by all cards so
|
||||
+ * don't check the error status.
|
||||
+ */
|
||||
+ snd_clk44gpio =
|
||||
+ devm_gpiod_get(&pdev->dev, "clock44", GPIOD_OUT_LOW);
|
||||
+
|
||||
+ snd_clk48gpio =
|
||||
+ devm_gpiod_get(&pdev->dev, "clock48", GPIOD_OUT_LOW);
|
||||
+
|
||||
+ if (drvdata->probe) {
|
||||
+ ret = drvdata->probe(pdev);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&pdev->dev, "Custom probe failed %d\n",
|
||||
+ ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pr_debug("%s card: %s dai: %s stream: %s\n", __func__,
|
||||
+ snd_rpi_wm8804.name,
|
||||
+ dai->name, dai->stream_name);
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_wm8804);
|
||||
+ if (ret && ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev, "Failed to register card %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver snd_rpi_wm8804_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-wm8804",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = snd_rpi_wm8804_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_wm8804_probe,
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, snd_rpi_wm8804_of_match);
|
||||
+
|
||||
+module_platform_driver(snd_rpi_wm8804_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
|
||||
+MODULE_DESCRIPTION("ASoC Raspberry Pi Hat generic digi driver for WM8804 based cards");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,172 @@
|
|||
From 9cad45e26ed0fc4cd640438c57a566f531f82ee5 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
|
||||
@@ -50,6 +50,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pand
|
||||
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o
|
||||
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.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");
|
|
@ -0,0 +1,256 @@
|
|||
From fce8ca644475a27f51c5c3c155f1786700b246c1 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
|
||||
@@ -147,6 +147,12 @@ config GPIO_BCM_KONA
|
||||
help
|
||||
Turn on GPIO support for Broadcom "Kona" chips.
|
||||
|
||||
+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
|
||||
@@ -34,6 +34,7 @@ obj-$(CONFIG_GPIO_ARIZONA) += gpio-ariz
|
||||
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
|
||||
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
+obj-$(CONFIG_GPIO_BCM_VIRT) += gpio-bcm-virt.o
|
||||
obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
|
||||
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.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");
|
|
@ -0,0 +1,427 @@
|
|||
From 4f974caf1122f57ae6786b8b8a506389a19646c5 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
|
||||
@@ -107,4 +107,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);
|
|
@ -0,0 +1,23 @@
|
|||
From 34cb3c9d88a81018a291d3ed37f081d5cc41d00e 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
|
||||
@@ -339,7 +339,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);
|
|
@ -0,0 +1,72 @@
|
|||
From 60600ec89d18710e7643cfdddc488a113dd6cc2a 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
|
||||
@@ -153,10 +153,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
|
||||
@@ -86,6 +86,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,
|
|
@ -0,0 +1,28 @@
|
|||
From 6d77425f3aaf68a9c643860c9c18394f4be48a28 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;
|
|
@ -0,0 +1,53 @@
|
|||
From d2b4f3d3ae91ea8fca9efebe0ac7a6b0c0567883 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
|
|
@ -0,0 +1,688 @@
|
|||
From 8bbc2e7ef3aa9cffc8e6fb859be9b3c45e480027 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 | 7 +
|
||||
drivers/perf/Makefile | 1 +
|
||||
drivers/perf/raspberrypi_axi_monitor.c | 637 +++++++++++++++++++++++++
|
||||
3 files changed, 645 insertions(+)
|
||||
create mode 100644 drivers/perf/raspberrypi_axi_monitor.c
|
||||
|
||||
--- a/drivers/perf/Kconfig
|
||||
+++ b/drivers/perf/Kconfig
|
||||
@@ -129,4 +129,11 @@ 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.
|
||||
endmenu
|
||||
--- a/drivers/perf/Makefile
|
||||
+++ b/drivers/perf/Makefile
|
||||
@@ -12,3 +12,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");
|
||||
+
|
|
@ -0,0 +1,70 @@
|
|||
From 0f95a2f2688ff44dc7080beaa2076741a0bdf510 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 27 Nov 2017 17:14:54 +0000
|
||||
Subject: [PATCH] cgroup: Disable cgroup "memory" by default
|
||||
|
||||
Some Raspberry Pis have limited RAM and most users won't use the
|
||||
cgroup memory support so it is disabled by default. Enable with:
|
||||
|
||||
cgroup_enable=memory
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1950
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
kernel/cgroup/cgroup.c | 30 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 30 insertions(+)
|
||||
|
||||
--- a/kernel/cgroup/cgroup.c
|
||||
+++ b/kernel/cgroup/cgroup.c
|
||||
@@ -5707,6 +5707,8 @@ int __init cgroup_init_early(void)
|
||||
}
|
||||
|
||||
static u16 cgroup_disable_mask __initdata;
|
||||
+static u16 cgroup_enable_mask __initdata;
|
||||
+static int __init cgroup_disable(char *str);
|
||||
|
||||
/**
|
||||
* cgroup_init - cgroup initialization
|
||||
@@ -5746,6 +5748,12 @@ int __init cgroup_init(void)
|
||||
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
|
||||
+ /* Apply an implicit disable... */
|
||||
+ cgroup_disable("memory");
|
||||
+
|
||||
+ /* ...knowing that an explicit enable will override it. */
|
||||
+ cgroup_disable_mask &= ~cgroup_enable_mask;
|
||||
+
|
||||
for_each_subsys(ss, ssid) {
|
||||
if (ss->early_init) {
|
||||
struct cgroup_subsys_state *css =
|
||||
@@ -6165,6 +6173,28 @@ static int __init cgroup_disable(char *s
|
||||
}
|
||||
__setup("cgroup_disable=", cgroup_disable);
|
||||
|
||||
+static int __init cgroup_enable(char *str)
|
||||
+{
|
||||
+ struct cgroup_subsys *ss;
|
||||
+ char *token;
|
||||
+ int i;
|
||||
+
|
||||
+ while ((token = strsep(&str, ",")) != NULL) {
|
||||
+ if (!*token)
|
||||
+ continue;
|
||||
+
|
||||
+ for_each_subsys(ss, i) {
|
||||
+ if (strcmp(token, ss->name) &&
|
||||
+ strcmp(token, ss->legacy_name))
|
||||
+ continue;
|
||||
+
|
||||
+ cgroup_enable_mask |= 1 << i;
|
||||
+ }
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("cgroup_enable=", cgroup_enable);
|
||||
+
|
||||
void __init __weak enable_debug_cgroup(void) { }
|
||||
|
||||
static int __init enable_cgroup_debug(char *str)
|
|
@ -0,0 +1,63 @@
|
|||
From 2ccf1246eb5ae4faad4cccc01b16f51d7717609e 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
|
|
@ -0,0 +1,116 @@
|
|||
From 92fdfb919ab0efdcd7d177ff85272e80bf0f844e 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),
|
|
@ -0,0 +1,36 @@
|
|||
From a32b114d39a51c28eb22f742a6f66d71aa8915fa 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
From 0be798c7e5f6bab2af57b79e9fde89dcccc7d5ba Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 22 Jan 2018 17:26:38 +0000
|
||||
Subject: [PATCH] serial: 8250: bcm2835aux - suppress EPROBE_DEFER
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
---
|
||||
drivers/tty/serial/8250/8250_bcm2835aux.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
|
||||
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
|
||||
@@ -50,7 +50,8 @@ static int bcm2835aux_serial_probe(struc
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
ret = PTR_ERR_OR_ZERO(data->clk);
|
||||
if (ret) {
|
||||
- dev_err(&pdev->dev, "could not get clk: %d\n", ret);
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ dev_err(&pdev->dev, "could not get clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From e8d812ff247c8d194bee2d353baf8cc3bbd52690 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
|
|
@ -0,0 +1,762 @@
|
|||
From dbe5aadb7ededc77902bad876421eb730bd1daeb Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 14 Sep 2016 08:39:33 +0100
|
||||
Subject: [PATCH] drm/vc4: Add a mode for using the closed firmware for
|
||||
display.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/Makefile | 1 +
|
||||
drivers/gpu/drm/vc4/vc4_crtc.c | 17 +
|
||||
drivers/gpu/drm/vc4/vc4_drv.c | 1 +
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 7 +
|
||||
drivers/gpu/drm/vc4/vc4_firmware_kms.c | 656 +++++++++++++++++++++++++
|
||||
5 files changed, 682 insertions(+)
|
||||
create mode 100644 drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/Makefile
|
||||
+++ b/drivers/gpu/drm/vc4/Makefile
|
||||
@@ -9,6 +9,7 @@ vc4-y := \
|
||||
vc4_dpi.o \
|
||||
vc4_dsi.o \
|
||||
vc4_fence.o \
|
||||
+ vc4_firmware_kms.o \
|
||||
vc4_kms.o \
|
||||
vc4_gem.o \
|
||||
vc4_hdmi.o \
|
||||
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||||
@@ -97,6 +97,9 @@ bool vc4_crtc_get_scanoutpos(struct drm_
|
||||
int vblank_lines;
|
||||
bool ret = false;
|
||||
|
||||
+ if (vc4->firmware_kms)
|
||||
+ return 0;
|
||||
+
|
||||
/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
|
||||
|
||||
/* Get optional system timestamp before query. */
|
||||
@@ -764,8 +767,15 @@ static void vc4_crtc_atomic_flush(struct
|
||||
|
||||
static int vc4_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
+ struct drm_device *dev = crtc->dev;
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
|
||||
+ if (vc4->firmware_kms) {
|
||||
+ /* XXX: Can we mask the SMI interrupt? */
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
CRTC_WRITE(PV_INTEN, PV_INT_VFP_START);
|
||||
|
||||
return 0;
|
||||
@@ -773,8 +783,15 @@ static int vc4_enable_vblank(struct drm_
|
||||
|
||||
static void vc4_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
+ struct drm_device *dev = crtc->dev;
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
|
||||
+ if (vc4->firmware_kms) {
|
||||
+ /* XXX: Can we mask the SMI interrupt? */
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
CRTC_WRITE(PV_INTEN, 0);
|
||||
}
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
|
||||
@@ -345,6 +345,7 @@ static struct platform_driver *const com
|
||||
&vc4_txp_driver,
|
||||
&vc4_hvs_driver,
|
||||
&vc4_crtc_driver,
|
||||
+ &vc4_firmware_kms_driver,
|
||||
&vc4_v3d_driver,
|
||||
};
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -71,6 +71,9 @@ struct vc4_perfmon {
|
||||
struct vc4_dev {
|
||||
struct drm_device *dev;
|
||||
|
||||
+ bool firmware_kms;
|
||||
+ struct rpi_firmware *firmware;
|
||||
+
|
||||
struct vc4_hdmi *hdmi;
|
||||
struct vc4_hvs *hvs;
|
||||
struct vc4_v3d *v3d;
|
||||
@@ -790,6 +793,10 @@ extern struct platform_driver vc4_dsi_dr
|
||||
/* vc4_fence.c */
|
||||
extern const struct dma_fence_ops vc4_fence_ops;
|
||||
|
||||
+/* vc4_firmware_kms.c */
|
||||
+extern struct platform_driver vc4_firmware_kms_driver;
|
||||
+void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
|
||||
+
|
||||
/* vc4_gem.c */
|
||||
void vc4_gem_init(struct drm_device *dev);
|
||||
void vc4_gem_destroy(struct drm_device *dev);
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_firmware_kms.c
|
||||
@@ -0,0 +1,656 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2016 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.
|
||||
+ */
|
||||
+
|
||||
+/**
|
||||
+ * DOC: VC4 firmware KMS module.
|
||||
+ *
|
||||
+ * As a hack to get us from the current closed source driver world
|
||||
+ * toward a totally open stack, implement KMS on top of the Raspberry
|
||||
+ * Pi's firmware display stack.
|
||||
+ */
|
||||
+
|
||||
+#include "drm/drm_atomic_helper.h"
|
||||
+#include "drm/drm_plane_helper.h"
|
||||
+#include "drm/drm_crtc_helper.h"
|
||||
+#include "linux/clk.h"
|
||||
+#include "linux/debugfs.h"
|
||||
+#include "drm/drm_fb_cma_helper.h"
|
||||
+#include "linux/component.h"
|
||||
+#include "linux/of_device.h"
|
||||
+#include "vc4_drv.h"
|
||||
+#include "vc4_regs.h"
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+/* The firmware delivers a vblank interrupt to us through the SMI
|
||||
+ * hardware, which has only this one register.
|
||||
+ */
|
||||
+#define SMICS 0x0
|
||||
+#define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
|
||||
+
|
||||
+struct vc4_crtc {
|
||||
+ struct drm_crtc base;
|
||||
+ struct drm_encoder *encoder;
|
||||
+ struct drm_connector *connector;
|
||||
+ void __iomem *regs;
|
||||
+
|
||||
+ struct drm_pending_vblank_event *event;
|
||||
+};
|
||||
+
|
||||
+static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
|
||||
+{
|
||||
+ return container_of(crtc, struct vc4_crtc, base);
|
||||
+}
|
||||
+
|
||||
+struct vc4_fkms_encoder {
|
||||
+ struct drm_encoder base;
|
||||
+};
|
||||
+
|
||||
+static inline struct vc4_fkms_encoder *
|
||||
+to_vc4_fkms_encoder(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ return container_of(encoder, struct vc4_fkms_encoder, base);
|
||||
+}
|
||||
+
|
||||
+/* VC4 FKMS connector KMS struct */
|
||||
+struct vc4_fkms_connector {
|
||||
+ struct drm_connector base;
|
||||
+
|
||||
+ /* Since the connector is attached to just the one encoder,
|
||||
+ * this is the reference to it so we can do the best_encoder()
|
||||
+ * hook.
|
||||
+ */
|
||||
+ struct drm_encoder *encoder;
|
||||
+};
|
||||
+
|
||||
+static inline struct vc4_fkms_connector *
|
||||
+to_vc4_fkms_connector(struct drm_connector *connector)
|
||||
+{
|
||||
+ return container_of(connector, struct vc4_fkms_connector, base);
|
||||
+}
|
||||
+
|
||||
+/* Firmware's structure for making an FB mbox call. */
|
||||
+struct fbinfo_s {
|
||||
+ u32 xres, yres, xres_virtual, yres_virtual;
|
||||
+ u32 pitch, bpp;
|
||||
+ u32 xoffset, yoffset;
|
||||
+ u32 base;
|
||||
+ u32 screen_size;
|
||||
+ u16 cmap[256];
|
||||
+};
|
||||
+
|
||||
+struct vc4_fkms_plane {
|
||||
+ struct drm_plane base;
|
||||
+ struct fbinfo_s *fbinfo;
|
||||
+ dma_addr_t fbinfo_bus_addr;
|
||||
+ u32 pitch;
|
||||
+};
|
||||
+
|
||||
+static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
|
||||
+{
|
||||
+ return (struct vc4_fkms_plane *)plane;
|
||||
+}
|
||||
+
|
||||
+/* Turns the display on/off. */
|
||||
+static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank)
|
||||
+{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
|
||||
+
|
||||
+ u32 packet = blank;
|
||||
+ return rpi_firmware_property(vc4->firmware,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_BLANK,
|
||||
+ &packet, sizeof(packet));
|
||||
+}
|
||||
+
|
||||
+static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
|
||||
+ struct drm_plane_state *old_state)
|
||||
+{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
|
||||
+ struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
|
||||
+ struct drm_plane_state *state = plane->state;
|
||||
+ struct drm_framebuffer *fb = state->fb;
|
||||
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
+ volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo;
|
||||
+ u32 bpp = 32;
|
||||
+ int ret;
|
||||
+
|
||||
+ vc4_plane_set_primary_blank(plane, false);
|
||||
+
|
||||
+ fbinfo->xres = state->crtc_w;
|
||||
+ fbinfo->yres = state->crtc_h;
|
||||
+ fbinfo->xres_virtual = state->crtc_w;
|
||||
+ fbinfo->yres_virtual = state->crtc_h;
|
||||
+ fbinfo->bpp = bpp;
|
||||
+ fbinfo->xoffset = state->crtc_x;
|
||||
+ fbinfo->yoffset = state->crtc_y;
|
||||
+ fbinfo->base = bo->paddr + fb->offsets[0];
|
||||
+ fbinfo->pitch = fb->pitches[0];
|
||||
+ /* A bug in the firmware makes it so that if the fb->base is
|
||||
+ * set to nonzero, the configured pitch gets overwritten with
|
||||
+ * the previous pitch. So, to get the configured pitch
|
||||
+ * recomputed, we have to make it allocate itself a new buffer
|
||||
+ * in VC memory, first.
|
||||
+ */
|
||||
+ if (vc4_plane->pitch != fb->pitches[0]) {
|
||||
+ u32 saved_base = fbinfo->base;
|
||||
+ fbinfo->base = 0;
|
||||
+
|
||||
+ ret = rpi_firmware_transaction(vc4->firmware,
|
||||
+ RPI_FIRMWARE_CHAN_FB,
|
||||
+ vc4_plane->fbinfo_bus_addr);
|
||||
+ fbinfo->base = saved_base;
|
||||
+
|
||||
+ vc4_plane->pitch = fbinfo->pitch;
|
||||
+ WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
|
||||
+ }
|
||||
+
|
||||
+ ret = rpi_firmware_transaction(vc4->firmware,
|
||||
+ RPI_FIRMWARE_CHAN_FB,
|
||||
+ vc4_plane->fbinfo_bus_addr);
|
||||
+ WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]);
|
||||
+ WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]);
|
||||
+}
|
||||
+
|
||||
+static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
|
||||
+ struct drm_plane_state *old_state)
|
||||
+{
|
||||
+ vc4_plane_set_primary_blank(plane, true);
|
||||
+}
|
||||
+
|
||||
+static void vc4_cursor_plane_atomic_update(struct drm_plane *plane,
|
||||
+ struct drm_plane_state *old_state)
|
||||
+{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
|
||||
+ struct drm_plane_state *state = plane->state;
|
||||
+ struct drm_framebuffer *fb = state->fb;
|
||||
+ struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
+ int ret;
|
||||
+ u32 packet_state[] = { true, state->crtc_x, state->crtc_y, 0 };
|
||||
+ u32 packet_info[] = { state->crtc_w, state->crtc_h,
|
||||
+ 0, /* unused */
|
||||
+ bo->paddr + fb->offsets[0],
|
||||
+ 0, 0, /* hotx, hoty */};
|
||||
+ WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
|
||||
+
|
||||
+ ret = rpi_firmware_property(vc4->firmware,
|
||||
+ RPI_FIRMWARE_SET_CURSOR_STATE,
|
||||
+ &packet_state,
|
||||
+ sizeof(packet_state));
|
||||
+ if (ret || packet_state[0] != 0)
|
||||
+ DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
|
||||
+
|
||||
+ ret = rpi_firmware_property(vc4->firmware,
|
||||
+ RPI_FIRMWARE_SET_CURSOR_INFO,
|
||||
+ &packet_info,
|
||||
+ sizeof(packet_info));
|
||||
+ if (ret || packet_info[0] != 0)
|
||||
+ DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]);
|
||||
+}
|
||||
+
|
||||
+static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane,
|
||||
+ struct drm_plane_state *old_state)
|
||||
+{
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
|
||||
+ u32 packet_state[] = { false, 0, 0, 0 };
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = rpi_firmware_property(vc4->firmware,
|
||||
+ RPI_FIRMWARE_SET_CURSOR_STATE,
|
||||
+ &packet_state,
|
||||
+ sizeof(packet_state));
|
||||
+ if (ret || packet_state[0] != 0)
|
||||
+ DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
|
||||
+}
|
||||
+
|
||||
+static int vc4_plane_atomic_check(struct drm_plane *plane,
|
||||
+ struct drm_plane_state *state)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void vc4_plane_destroy(struct drm_plane *plane)
|
||||
+{
|
||||
+ drm_plane_helper_disable(plane);
|
||||
+ drm_plane_cleanup(plane);
|
||||
+}
|
||||
+
|
||||
+static const struct drm_plane_funcs vc4_plane_funcs = {
|
||||
+ .update_plane = drm_atomic_helper_update_plane,
|
||||
+ .disable_plane = drm_atomic_helper_disable_plane,
|
||||
+ .destroy = vc4_plane_destroy,
|
||||
+ .set_property = NULL,
|
||||
+ .reset = drm_atomic_helper_plane_reset,
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
|
||||
+};
|
||||
+
|
||||
+static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
|
||||
+ .prepare_fb = NULL,
|
||||
+ .cleanup_fb = NULL,
|
||||
+ .atomic_check = vc4_plane_atomic_check,
|
||||
+ .atomic_update = vc4_primary_plane_atomic_update,
|
||||
+ .atomic_disable = vc4_primary_plane_atomic_disable,
|
||||
+};
|
||||
+
|
||||
+static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
|
||||
+ .prepare_fb = NULL,
|
||||
+ .cleanup_fb = NULL,
|
||||
+ .atomic_check = vc4_plane_atomic_check,
|
||||
+ .atomic_update = vc4_cursor_plane_atomic_update,
|
||||
+ .atomic_disable = vc4_cursor_plane_atomic_disable,
|
||||
+};
|
||||
+
|
||||
+static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
|
||||
+ enum drm_plane_type type)
|
||||
+{
|
||||
+ struct drm_plane *plane = NULL;
|
||||
+ struct vc4_fkms_plane *vc4_plane;
|
||||
+ u32 xrgb8888 = DRM_FORMAT_XRGB8888;
|
||||
+ u32 argb8888 = DRM_FORMAT_ARGB8888;
|
||||
+ int ret = 0;
|
||||
+ bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
|
||||
+
|
||||
+ vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!vc4_plane) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ plane = &vc4_plane->base;
|
||||
+ ret = drm_universal_plane_init(dev, plane, 0xff,
|
||||
+ &vc4_plane_funcs,
|
||||
+ primary ? &xrgb8888 : &argb8888, 1, NULL,
|
||||
+ type, NULL);
|
||||
+
|
||||
+ if (type == DRM_PLANE_TYPE_PRIMARY) {
|
||||
+ vc4_plane->fbinfo =
|
||||
+ dma_alloc_coherent(dev->dev,
|
||||
+ sizeof(*vc4_plane->fbinfo),
|
||||
+ &vc4_plane->fbinfo_bus_addr,
|
||||
+ GFP_KERNEL);
|
||||
+ memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo));
|
||||
+
|
||||
+ drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
|
||||
+ } else {
|
||||
+ drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
|
||||
+ }
|
||||
+
|
||||
+ return plane;
|
||||
+fail:
|
||||
+ if (plane)
|
||||
+ vc4_plane_destroy(plane);
|
||||
+
|
||||
+ return ERR_PTR(ret);
|
||||
+}
|
||||
+
|
||||
+static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
+{
|
||||
+ /* Everyting is handled in the planes. */
|
||||
+}
|
||||
+
|
||||
+static void vc4_crtc_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void vc4_crtc_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
+ struct drm_crtc_state *state)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
+ struct drm_crtc_state *old_state)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
|
||||
+{
|
||||
+ struct drm_crtc *crtc = &vc4_crtc->base;
|
||||
+ struct drm_device *dev = crtc->dev;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&dev->event_lock, flags);
|
||||
+ if (vc4_crtc->event) {
|
||||
+ drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
|
||||
+ vc4_crtc->event = NULL;
|
||||
+ drm_crtc_vblank_put(crtc);
|
||||
+ }
|
||||
+ spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
|
||||
+{
|
||||
+ struct vc4_crtc *vc4_crtc = data;
|
||||
+ u32 stat = readl(vc4_crtc->regs + SMICS);
|
||||
+ irqreturn_t ret = IRQ_NONE;
|
||||
+
|
||||
+ if (stat & SMICS_INTERRUPTS) {
|
||||
+ writel(0, vc4_crtc->regs + SMICS);
|
||||
+ drm_crtc_handle_vblank(&vc4_crtc->base);
|
||||
+ vc4_crtc_handle_page_flip(vc4_crtc);
|
||||
+ ret = IRQ_HANDLED;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int vc4_page_flip(struct drm_crtc *crtc,
|
||||
+ struct drm_framebuffer *fb,
|
||||
+ struct drm_pending_vblank_event *event,
|
||||
+ uint32_t flags, struct drm_modeset_acquire_ctx *ctx)
|
||||
+{
|
||||
+ if (flags & DRM_MODE_PAGE_FLIP_ASYNC) {
|
||||
+ DRM_ERROR("Async flips aren't allowed\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
|
||||
+}
|
||||
+
|
||||
+static const struct drm_crtc_funcs vc4_crtc_funcs = {
|
||||
+ .set_config = drm_atomic_helper_set_config,
|
||||
+ .destroy = drm_crtc_cleanup,
|
||||
+ .page_flip = vc4_page_flip,
|
||||
+ .set_property = NULL,
|
||||
+ .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
|
||||
+ .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
|
||||
+ .reset = drm_atomic_helper_crtc_reset,
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
|
||||
+};
|
||||
+
|
||||
+static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
|
||||
+ .mode_set_nofb = vc4_crtc_mode_set_nofb,
|
||||
+ .atomic_disable = vc4_crtc_disable,
|
||||
+ .atomic_enable = vc4_crtc_enable,
|
||||
+ .atomic_check = vc4_crtc_atomic_check,
|
||||
+ .atomic_flush = vc4_crtc_atomic_flush,
|
||||
+};
|
||||
+
|
||||
+/* Frees the page flip event when the DRM device is closed with the
|
||||
+ * event still outstanding.
|
||||
+ */
|
||||
+void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
|
||||
+{
|
||||
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
|
||||
+ struct drm_device *dev = crtc->dev;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&dev->event_lock, flags);
|
||||
+
|
||||
+ if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) {
|
||||
+ kfree(&vc4_crtc->event->base);
|
||||
+ drm_crtc_vblank_put(crtc);
|
||||
+ vc4_crtc->event = NULL;
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id vc4_firmware_kms_dt_match[] = {
|
||||
+ { .compatible = "raspberrypi,rpi-firmware-kms" },
|
||||
+ {}
|
||||
+};
|
||||
+
|
||||
+static enum drm_connector_status
|
||||
+vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
|
||||
+{
|
||||
+ return connector_status_connected;
|
||||
+}
|
||||
+
|
||||
+static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
|
||||
+{
|
||||
+ struct drm_device *dev = connector->dev;
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
+ u32 wh[2] = {0, 0};
|
||||
+ int ret;
|
||||
+ struct drm_display_mode *mode;
|
||||
+
|
||||
+ ret = rpi_firmware_property(vc4->firmware,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
|
||||
+ &wh, sizeof(wh));
|
||||
+ if (ret) {
|
||||
+ DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
|
||||
+ ret, wh[0], wh[1]);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */,
|
||||
+ 0, 0, false);
|
||||
+ drm_mode_probed_add(connector, mode);
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static struct drm_encoder *
|
||||
+vc4_fkms_connector_best_encoder(struct drm_connector *connector)
|
||||
+{
|
||||
+ struct vc4_fkms_connector *fkms_connector =
|
||||
+ to_vc4_fkms_connector(connector);
|
||||
+ return fkms_connector->encoder;
|
||||
+}
|
||||
+
|
||||
+static void vc4_fkms_connector_destroy(struct drm_connector *connector)
|
||||
+{
|
||||
+ drm_connector_unregister(connector);
|
||||
+ drm_connector_cleanup(connector);
|
||||
+}
|
||||
+
|
||||
+static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
|
||||
+ .detect = vc4_fkms_connector_detect,
|
||||
+ .fill_modes = drm_helper_probe_single_connector_modes,
|
||||
+ .destroy = vc4_fkms_connector_destroy,
|
||||
+ .reset = drm_atomic_helper_connector_reset,
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
+};
|
||||
+
|
||||
+static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
|
||||
+ .get_modes = vc4_fkms_connector_get_modes,
|
||||
+ .best_encoder = vc4_fkms_connector_best_encoder,
|
||||
+};
|
||||
+
|
||||
+static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev,
|
||||
+ struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct drm_connector *connector = NULL;
|
||||
+ struct vc4_fkms_connector *fkms_connector;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!fkms_connector) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ connector = &fkms_connector->base;
|
||||
+
|
||||
+ fkms_connector->encoder = encoder;
|
||||
+
|
||||
+ drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
|
||||
+ DRM_MODE_CONNECTOR_HDMIA);
|
||||
+ drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs);
|
||||
+
|
||||
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
|
||||
+ DRM_CONNECTOR_POLL_DISCONNECT);
|
||||
+
|
||||
+ connector->interlace_allowed = 0;
|
||||
+ connector->doublescan_allowed = 0;
|
||||
+
|
||||
+ drm_mode_connector_attach_encoder(connector, encoder);
|
||||
+
|
||||
+ return connector;
|
||||
+
|
||||
+ fail:
|
||||
+ if (connector)
|
||||
+ vc4_fkms_connector_destroy(connector);
|
||||
+
|
||||
+ return ERR_PTR(ret);
|
||||
+}
|
||||
+
|
||||
+static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
|
||||
+{
|
||||
+ drm_encoder_cleanup(encoder);
|
||||
+}
|
||||
+
|
||||
+static const struct drm_encoder_funcs vc4_fkms_encoder_funcs = {
|
||||
+ .destroy = vc4_fkms_encoder_destroy,
|
||||
+};
|
||||
+
|
||||
+static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
|
||||
+ .enable = vc4_fkms_encoder_enable,
|
||||
+ .disable = vc4_fkms_encoder_disable,
|
||||
+};
|
||||
+
|
||||
+static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
+{
|
||||
+ struct platform_device *pdev = to_platform_device(dev);
|
||||
+ struct drm_device *drm = dev_get_drvdata(master);
|
||||
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
|
||||
+ struct vc4_crtc *vc4_crtc;
|
||||
+ struct vc4_fkms_encoder *vc4_encoder;
|
||||
+ struct drm_crtc *crtc;
|
||||
+ struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
|
||||
+ struct device_node *firmware_node;
|
||||
+ int ret;
|
||||
+
|
||||
+ vc4->firmware_kms = true;
|
||||
+
|
||||
+ vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
|
||||
+ if (!vc4_crtc)
|
||||
+ return -ENOMEM;
|
||||
+ crtc = &vc4_crtc->base;
|
||||
+
|
||||
+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
|
||||
+ vc4->firmware = rpi_firmware_get(firmware_node);
|
||||
+ if (!vc4->firmware) {
|
||||
+ DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
|
||||
+ return -EPROBE_DEFER;
|
||||
+ }
|
||||
+ of_node_put(firmware_node);
|
||||
+
|
||||
+ /* Map the SMI interrupt reg */
|
||||
+ vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
|
||||
+ if (IS_ERR(vc4_crtc->regs))
|
||||
+ return PTR_ERR(vc4_crtc->regs);
|
||||
+
|
||||
+ /* For now, we create just the primary and the legacy cursor
|
||||
+ * planes. We should be able to stack more planes on easily,
|
||||
+ * but to do that we would need to compute the bandwidth
|
||||
+ * requirement of the plane configuration, and reject ones
|
||||
+ * that will take too much.
|
||||
+ */
|
||||
+ primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
|
||||
+ if (IS_ERR(primary_plane)) {
|
||||
+ dev_err(dev, "failed to construct primary plane\n");
|
||||
+ ret = PTR_ERR(primary_plane);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
|
||||
+ if (IS_ERR(cursor_plane)) {
|
||||
+ dev_err(dev, "failed to construct cursor plane\n");
|
||||
+ ret = PTR_ERR(cursor_plane);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane,
|
||||
+ &vc4_crtc_funcs, NULL);
|
||||
+ drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
|
||||
+ primary_plane->crtc = crtc;
|
||||
+ cursor_plane->crtc = crtc;
|
||||
+
|
||||
+ vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
|
||||
+ if (!vc4_encoder)
|
||||
+ return -ENOMEM;
|
||||
+ vc4_crtc->encoder = &vc4_encoder->base;
|
||||
+ vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
|
||||
+ drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
|
||||
+ DRM_MODE_ENCODER_TMDS, NULL);
|
||||
+ drm_encoder_helper_add(&vc4_encoder->base,
|
||||
+ &vc4_fkms_encoder_helper_funcs);
|
||||
+
|
||||
+ vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base);
|
||||
+ if (IS_ERR(vc4_crtc->connector)) {
|
||||
+ ret = PTR_ERR(vc4_crtc->connector);
|
||||
+ goto err_destroy_encoder;
|
||||
+ }
|
||||
+
|
||||
+ writel(0, vc4_crtc->regs + SMICS);
|
||||
+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
|
||||
+ vc4_crtc_irq_handler, 0, "vc4 firmware kms",
|
||||
+ vc4_crtc);
|
||||
+ if (ret)
|
||||
+ goto err_destroy_connector;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, vc4_crtc);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_destroy_connector:
|
||||
+ vc4_fkms_connector_destroy(vc4_crtc->connector);
|
||||
+err_destroy_encoder:
|
||||
+ vc4_fkms_encoder_destroy(vc4_crtc->encoder);
|
||||
+ list_for_each_entry_safe(destroy_plane, temp,
|
||||
+ &drm->mode_config.plane_list, head) {
|
||||
+ if (destroy_plane->possible_crtcs == 1 << drm_crtc_index(crtc))
|
||||
+ destroy_plane->funcs->destroy(destroy_plane);
|
||||
+ }
|
||||
+err:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void vc4_fkms_unbind(struct device *dev, struct device *master,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct platform_device *pdev = to_platform_device(dev);
|
||||
+ struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
|
||||
+
|
||||
+ vc4_fkms_connector_destroy(vc4_crtc->connector);
|
||||
+ vc4_fkms_encoder_destroy(vc4_crtc->encoder);
|
||||
+ drm_crtc_cleanup(&vc4_crtc->base);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+}
|
||||
+
|
||||
+static const struct component_ops vc4_fkms_ops = {
|
||||
+ .bind = vc4_fkms_bind,
|
||||
+ .unbind = vc4_fkms_unbind,
|
||||
+};
|
||||
+
|
||||
+static int vc4_fkms_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ return component_add(&pdev->dev, &vc4_fkms_ops);
|
||||
+}
|
||||
+
|
||||
+static int vc4_fkms_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ component_del(&pdev->dev, &vc4_fkms_ops);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct platform_driver vc4_firmware_kms_driver = {
|
||||
+ .probe = vc4_fkms_probe,
|
||||
+ .remove = vc4_fkms_remove,
|
||||
+ .driver = {
|
||||
+ .name = "vc4_firmware_kms",
|
||||
+ .of_match_table = vc4_firmware_kms_dt_match,
|
||||
+ },
|
||||
+};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue