From 8f651897094a423fb62ba2740e20b363a90129d9 Mon Sep 17 00:00:00 2001 From: Igor Pecovnik Date: Tue, 22 Mar 2016 10:42:47 +0100 Subject: [PATCH] Added Hardkernel C1 to the build script. Building is working while result untested. WIP --- boards.sh | 6 +- common.sh | 21 +- config/boot-odroid-c1.ini | 33 + .../{boot-odroid.ini => boot-odroid-xu4.ini} | 0 config/linux-odroidc1-default.config | 4695 ++++++ configuration.sh | 35 +- .../odroidc1-default/fbtft_drivers.patch | 12012 ++++++++++++++++ .../odroidc1-default/packagin-guitar.patch | 311 + .../odroidc1-default/patch-3.10.96-97.patch | 2341 +++ .../odroidc1-default/patch-3.10.97-98.patch | 1792 +++ .../odroidc1-default/patch-3.10.98-99.patch | 2573 ++++ .../odroidc1-default/patch-3.10.99-100.patch | 1156 ++ .../rpatch-3.10.100-101.patch | 1493 ++ 13 files changed, 26461 insertions(+), 7 deletions(-) create mode 100644 config/boot-odroid-c1.ini rename config/{boot-odroid.ini => boot-odroid-xu4.ini} (100%) create mode 100644 config/linux-odroidc1-default.config create mode 100644 patch/kernel/odroidc1-default/fbtft_drivers.patch create mode 100644 patch/kernel/odroidc1-default/packagin-guitar.patch create mode 100644 patch/kernel/odroidc1-default/patch-3.10.96-97.patch create mode 100644 patch/kernel/odroidc1-default/patch-3.10.97-98.patch create mode 100644 patch/kernel/odroidc1-default/patch-3.10.98-99.patch create mode 100644 patch/kernel/odroidc1-default/patch-3.10.99-100.patch create mode 100644 patch/kernel/odroidc1-default/rpatch-3.10.100-101.patch diff --git a/boards.sh b/boards.sh index c12227ee97..a5eb1022a1 100644 --- a/boards.sh +++ b/boards.sh @@ -129,8 +129,10 @@ install_board_specific (){ cp $SRC/lib/config/boot-guitar.cmd $CACHEDIR/sdcard/boot/boot.cmd elif [[ $BOARD == armada* ]]; then cp $SRC/lib/config/boot-marvell.cmd $CACHEDIR/sdcard/boot/boot.cmd - elif [[ $BOARD == odroid* ]]; then - cp $SRC/lib/config/boot-odroid.ini $CACHEDIR/sdcard/boot/boot.ini + elif [[ $BOARD == odroidxu4 ]]; then + cp $SRC/lib/config/boot-odroid-xu4.ini $CACHEDIR/sdcard/boot/boot.ini + elif [[ $BOARD == odroidc1 ]]; then + cp $SRC/lib/config/boot-odroid-c1.ini $CACHEDIR/sdcard/boot/boot.ini else cp $SRC/lib/config/boot.cmd $CACHEDIR/sdcard/boot/boot.cmd # orangepi h3 temp exceptions diff --git a/common.sh b/common.sh index 8e20f8b54f..a4ff70ab40 100644 --- a/common.sh +++ b/common.sh @@ -80,12 +80,17 @@ if [[ \$DPKG_MAINTSCRIPT_PACKAGE == *cubox* ]] ; then elif [[ \$DPKG_MAINTSCRIPT_PACKAGE == *guitar* ]] ; then ( dd if=/usr/lib/$uboot_name/bootloader.bin of=\$DEVICE bs=512 seek=4097 conv=fsync ) > /dev/null 2>&1 ( dd if=/usr/lib/$uboot_name/u-boot-dtb.bin of=\$DEVICE bs=512 seek=6144 conv=fsync ) > /dev/null 2>&1 -elif [[ \$DPKG_MAINTSCRIPT_PACKAGE == *odroid* ]] ; then +elif [[ \$DPKG_MAINTSCRIPT_PACKAGE == *odroidxu4* ]] ; then ( dd if=/usr/lib/$uboot_name/bl1.bin.hardkernel of=\$DEVICE seek=1 conv=fsync ) > /dev/null 2>&1 ( dd if=/usr/lib/$uboot_name/bl2.bin.hardkernel of=\$DEVICE seek=31 conv=fsync ) > /dev/null 2>&1 ( dd if=/usr/lib/$uboot_name/u-boot.bin of=\$DEVICE bs=512 seek=63 conv=fsync ) > /dev/null 2>&1 ( dd if=/usr/lib/$uboot_name/tzsw.bin.hardkernel of=\$DEVICE seek=719 conv=fsync ) > /dev/null 2>&1 ( dd if=/dev/zero of=\$DEVICE seek=1231 count=32 bs=512 conv=fsync ) > /dev/null 2>&1 +elif [[ \$DPKG_MAINTSCRIPT_PACKAGE == *odroidc1* ]] ; then + ( dd if=/usr/lib/$uboot_name/bl1.bin.hardkernel of=\$DEVICE seek=1 seek=442 conv=fsync ) > /dev/null 2>&1 + ( dd if=/usr/lib/$uboot_name/bl1.bin.hardkernel of=\$DEVICE seek=512 skip=1 seek=1 conv=fsync ) > /dev/null 2>&1 + ( dd if=/usr/lib/$uboot_name/u-boot.bin of=\$DEVICE bs=512 seek=64 conv=fsync ) > /dev/null 2>&1 + ( dd if=/dev/zero of=\$DEVICE seek=1024 count=32 bs=512 conv=fsync ) > /dev/null 2>&1 elif [[ \$DPKG_MAINTSCRIPT_PACKAGE == *udoo* ]] ; then ( dd if=/usr/lib/$uboot_name/SPL of=\$DEVICE bs=1k seek=1 status=noxfer ) > /dev/null 2>&1 ( dd if=/usr/lib/$uboot_name/u-boot.img of=\$DEVICE bs=1K seek=69 status=noxfer ) > /dev/null 2>&1 @@ -118,11 +123,14 @@ END elif [[ $BOARD == guitar* ]] ; then [ ! -f "u-boot-dtb.bin" ] || cp u-boot-dtb.bin $DEST/debs/$uboot_name/usr/lib/$uboot_name [ ! -f "$SRC/lib/bin/s500-bootloader.bin" ] || cp $SRC/lib/bin/s500-bootloader.bin $DEST/debs/$uboot_name/usr/lib/$uboot_name/bootloader.bin - elif [[ $BOARD == odroid* ]] ; then + elif [[ $BOARD == odroidxu4 ]] ; then [ ! -f "sd_fuse/hardkernel/bl1.bin.hardkernel" ] || cp sd_fuse/hardkernel/bl1.bin.hardkernel $DEST/debs/$uboot_name/usr/lib/$uboot_name [ ! -f "sd_fuse/hardkernel/bl2.bin.hardkernel" ] || cp sd_fuse/hardkernel/bl2.bin.hardkernel $DEST/debs/$uboot_name/usr/lib/$uboot_name [ ! -f "sd_fuse/hardkernel/tzsw.bin.hardkernel" ] || cp sd_fuse/hardkernel/tzsw.bin.hardkernel $DEST/debs/$uboot_name/usr/lib/$uboot_name [ ! -f "u-boot.bin" ] || cp u-boot.bin $DEST/debs/$uboot_name/usr/lib/$uboot_name/ + elif [[ $BOARD == odroidc1 ]] ; then + [ ! -f "sd_fuse/bl1.bin.hardkernel" ] || cp sd_fuse/bl1.bin.hardkernel $DEST/debs/$uboot_name/usr/lib/$uboot_name + [ ! -f "sd_fuse/u-boot.bin" ] || cp sd_fuse/u-boot.bin $DEST/debs/$uboot_name/usr/lib/$uboot_name elif [[ $BOARD == udoo* ]] ; then [ ! -f "u-boot.img" ] || cp SPL u-boot.img $DEST/debs/$uboot_name/usr/lib/$uboot_name elif [[ $BOARD == armada* ]] ; then @@ -404,12 +412,17 @@ write_uboot() elif [[ $BOARD == *guitar* ]] ; then ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/bootloader.bin of=$LOOP bs=512 seek=4097 conv=fsync > /dev/null 2>&1) ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/u-boot-dtb.bin of=$LOOP bs=512 seek=6144 conv=fsync > /dev/null 2>&1) - elif [[ $BOARD == *odroid* ]] ; then + elif [[ $BOARD == *odroidxu4* ]] ; then ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/bl1.bin.hardkernel of=$LOOP seek=1 conv=fsync ) > /dev/null 2>&1 ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/bl2.bin.hardkernel of=$LOOP seek=31 conv=fsync ) > /dev/null 2>&1 ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/u-boot.bin of=$LOOP bs=512 seek=63 conv=fsync ) > /dev/null 2>&1 ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/tzsw.bin.hardkernel of=$LOOP seek=719 conv=fsync ) > /dev/null 2>&1 - ( dd if=/dev/zero of=$LOOP seek=1231 count=32 bs=512 conv=fsync ) > /dev/null 2>&1 + ( dd if=/dev/zero of=$LOOP seek=1231 count=32 bs=512 conv=fsync ) > /dev/null 2>&1 + elif [[ $BOARD == *odroidc1* ]] ; then + ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/bl1.bin.hardkernel of=$LOOP seek=1 seek=442 conv=fsync ) > /dev/null 2>&1 + ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/bl1.bin.hardkernel of=$LOOP seek=512 skip=1 seek=1 conv=fsync ) > /dev/null 2>&1 + ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/u-boot.bin of=$LOOP bs=512 seek=64 conv=fsync ) > /dev/null 2>&1 + ( dd if=/dev/zero of=\$DEVICE seek=1024 count=32 bs=512 conv=fsync ) > /dev/null 2>&1 else ( dd if=/tmp/usr/lib/${CHOSEN_UBOOT}_${REVISION}_armhf/u-boot-sunxi-with-spl.bin of=$LOOP bs=1024 seek=8 status=noxfer >/dev/null 2>&1) fi diff --git a/config/boot-odroid-c1.ini b/config/boot-odroid-c1.ini new file mode 100644 index 0000000000..fe8fe14361 --- /dev/null +++ b/config/boot-odroid-c1.ini @@ -0,0 +1,33 @@ +ODROIDC-UBOOT-CONFIG + +# Possible screen resolutions +# Uncomment only a single Line! The line with setenv written. +# At least one mode must be selected. + +# setenv m "vga" # VGA 640x480 +# setenv m "480p" # 480p 720x480 +# setenv m "576p" # 576p 720x576 +# setenv m "800x480p60hz" # WVGA 800x480 +# setenv m "720p" # 720p 1280x720 +# setenv m "800p" # 800p(WXGA) 1280x800 +# setenv m "sxga" # SXGA 1280x1024 +setenv m "1080p" # 1080P 1920x1080 +# setenv m "1920x1200" # 1920x1200 + +# HDMI/DVI Mode Configuration +setenv vout_mode "hdmi" +# setenv vout_mode "dvi" + +# HDMI BPP Mode +setenv m_bpp "32" +# setenv m_bpp "16" + +# UHS Card Configuration +# Uncomment the line below to __DISABLE__ UHS-1 MicroSD support +# This might break boot for some brand/models of cards. +setenv disableuhs "disableuhs" + +setenv bootargs "console=ttyS0,115200n8 console=tty0 root=${ROOT_DEV} rootwait rw no_console_suspend vdaccfg=0xa000 logo=osd1,loaded,0x7900000,720p,full dmfc=3 cvbsmode=576cvbs hdmimode=${m} m_bpp=${m_bpp} vout=${vout_mode} ${disableuhs}" +setenv bootcmd "fatload mmc 0:1 0x21000000 zImage; fatload mmc 0:1 0x21800000 dtb/meson8b_odroidc.dtb; bootz 0x21000000 0x21800000" +run bootcmd + diff --git a/config/boot-odroid.ini b/config/boot-odroid-xu4.ini similarity index 100% rename from config/boot-odroid.ini rename to config/boot-odroid-xu4.ini diff --git a/config/linux-odroidc1-default.config b/config/linux-odroidc1-default.config new file mode 100644 index 0000000000..fdbac5654b --- /dev/null +++ b/config/linux-odroidc1-default.config @@ -0,0 +1,4695 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm 3.10.96 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_NEED_MACH_MEMORY_H=y +CONFIG_GENERIC_BUG=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +CONFIG_KERNEL_LZO=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_FHANDLE=y +CONFIG_AUDIT=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_KTIME_SCALAR=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_IRQ_TIME_ACCOUNTING is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_USER_QS is not set +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_SWAP_ENABLED=y +# CONFIG_MEMCG_KMEM is not set +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_BLK_CGROUP=y +# CONFIG_DEBUG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_UIDGID_CONVERTED=y +CONFIG_UIDGID_STRICT_TYPE_CHECKS=y +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_MM_OWNER=y +# CONFIG_SYSFS_DEPRECATED is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_XZ=y +CONFIG_RD_LZO=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_HOTPLUG=y +CONFIG_PANIC_TIMEOUT=0 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_THROTTLING is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CFQ_GROUP_IOSCHED is not set +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_PXA is not set +CONFIG_PLAT_MESON=y +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP1 is not set + +# +# Amlogic Meson platform +# +# CONFIG_ARCH_MESON6 is not set +# CONFIG_ARCH_MESON6TV is not set +# CONFIG_ARCH_MESON6TVD is not set +# CONFIG_ARCH_MESON8 is not set +CONFIG_ARCH_MESON8B=y +# CONFIG_ARCH_MESON8M2 is not set +# CONFIG_ARCH_MESONG9TV is not set + +# +# Meson development boards +# +# CONFIG_MACH_MESON8B_COMMON_BOARD is not set +CONFIG_MACH_MESON8B_ODROIDC=y +# CONFIG_MESON_IRQ is not set +CONFIG_MESON_ARM_GIC=y +CONFIG_MESON_CLOCK_TICK_RATE=24000000 +# CONFIG_MESON_ARM_GIC_FIQ is not set +CONFIG_MESON_SUSPEND=y +# CONFIG_SUSPEND_WATCHDOG is not set +# CONFIG_MESON_SUSPEND_TEST is not set +# CONFIG_SCREEN_ON_EARLY is not set +# CONFIG_CLK81_DFS is not set +CONFIG_MESON_LEGACY_REGISTER_API=y +# CONFIG_MESON_CPU_EMULATOR is not set +CONFIG_CLKTREE_DEBUG=y +# CONFIG_MESON_CPU_TEMP_SENSOR is not set +CONFIG_MESON_SUSPEND_FIRMWARE_BASE=0x04f00000 +# CONFIG_MESON_TRUSTZONE is not set +# CONFIG_MESON_CUSTOM_BOARD_SUPPORT is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_PLAT_SPEAR is not set + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +CONFIG_ARM_THUMB=y +# CONFIG_ARM_THUMBEE is not set +CONFIG_ARM_VIRT_EXT=y +CONFIG_SWP_EMULATE=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_KUSER_HELPERS=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_CACHE_L2X0=y +CONFIG_CACHE_PL310=y +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_ARM_NR_BANKS=8 +CONFIG_MULTI_IRQ_HANDLER=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_PL310_ERRATA_753970 is not set +CONFIG_ARM_ERRATA_754322=y +# CONFIG_ARM_ERRATA_754327 is not set +CONFIG_ARM_ERRATA_764369=y +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_FIQ_DEBUGGER is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_HAVE_ARM_SCU=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +# CONFIG_MCPM is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +# CONFIG_ARM_PSCI is not set +CONFIG_LOCAL_TIMERS=y +CONFIG_ARCH_NR_GPIO=0 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_HZ=100 +CONFIG_SCHED_HRTICK=y +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HW_PERF_EVENTS=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_BOUNCE=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +# CONFIG_FRONTSWAP is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_XEN is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set + +# +# Boot options +# +CONFIG_USE_OF=y +CONFIG_ATAGS=y +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_ARM_APPENDED_DTB is not set +CONFIG_CMDLINE="" +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_HOTPLUG=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +CONFIG_AMLOGIC_MESON_CPUFREQ=y +CONFIG_FIX_SYSPLL=y +# CONFIG_CPU_IDLE is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +# CONFIG_CONSOLE_EARLYSUSPEND is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_PM_RUNTIME is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +# CONFIG_APM_EMULATION is not set +CONFIG_PM_CLK=y +CONFIG_CPU_PM=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=m +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_ROUTE_CLASSID=y +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_LRO=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=m +CONFIG_TCP_CONG_CUBIC=m +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_DEFAULT_RENO=y +CONFIG_DEFAULT_TCP_CONG="reno" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +# CONFIG_ANDROID_PARANOID_NETWORK is not set +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_NETLINK_ACCT=m +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CT_PROTO_DCCP=m +CONFIG_NF_CT_PROTO_GRE=m +CONFIG_NF_CT_PROTO_SCTP=m +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_BROADCAST=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_QUEUE_CT=y +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=m +CONFIG_NF_NAT_PROTO_UDPLITE=m +CONFIG_NF_NAT_PROTO_SCTP=m +CONFIG_NF_NAT_AMANDA=m +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_TFTP=m +CONFIG_NETFILTER_TPROXY=m +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=m +CONFIG_NETFILTER_XT_SET=m + +# +# Xtables targets +# +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HL=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NETMAP=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_RATEEST=m +CONFIG_NETFILTER_XT_TARGET_REDIRECT=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ECN=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_HL=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +# CONFIG_NETFILTER_XT_MATCH_QUOTA2 is not set +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_SET=m +CONFIG_IP_SET_MAX=256 +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_DEBUG=y +CONFIG_IP_VS_TAB_BITS=12 + +# +# IPVS transport protocol load balancing support +# +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_AH_ESP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y + +# +# IPVS scheduler +# +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m + +# +# IPVS SH scheduler +# +CONFIG_IP_VS_SH_TAB_BITS=8 + +# +# IPVS application helper +# +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_NFCT=y +CONFIG_IP_VS_PE_SIP=m + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT_IPV4=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_NF_NAT_SNMP_BASIC=m +CONFIG_NF_NAT_PROTO_GRE=m +CONFIG_NF_NAT_PPTP=m +CONFIG_NF_NAT_H323=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_NF_NAT_IPV6=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_STP=y +CONFIG_GARP=m +CONFIG_MRP=m +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_IGMP_SNOOPING is not set +# CONFIG_BRIDGE_VLAN_FILTERING is not set +CONFIG_HAVE_NET_DSA=y +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +# CONFIG_DECNET is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_PHONET=y +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_PLUG=m + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_CANID is not set +# CONFIG_NET_EMATCH_IPSET is not set +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=m +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +CONFIG_CAN=m +CONFIG_CAN_RAW=m +CONFIG_CAN_BCM=m +CONFIG_CAN_GW=m + +# +# CAN Device Drivers +# +CONFIG_CAN_VCAN=m +# CONFIG_CAN_SLCAN is not set +CONFIG_CAN_DEV=m +CONFIG_CAN_CALC_BITTIMING=y +# CONFIG_CAN_LEDS is not set +# CONFIG_CAN_AT91 is not set +CONFIG_CAN_MCP251X=m +# CONFIG_CAN_GRCAN is not set +# CONFIG_CAN_SJA1000 is not set +# CONFIG_CAN_C_CAN is not set +# CONFIG_CAN_CC770 is not set + +# +# CAN USB interfaces +# +# CONFIG_CAN_EMS_USB is not set +# CONFIG_CAN_ESD_USB2 is not set +# CONFIG_CAN_KVASER_USB is not set +# CONFIG_CAN_PEAK_USB is not set +# CONFIG_CAN_8DEV_USB is not set +# CONFIG_CAN_SOFTING is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_3WIRE=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIVHCI=m +CONFIG_BT_MRVL=m +# CONFIG_BT_MRVL_SDIO is not set +CONFIG_BT_ATH3K=m +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WEXT_PRIV=y +# CONFIG_CFG80211 is not set +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_LEDS=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +CONFIG_HAVE_BPF_JIT=y + +# +# Device Drivers +# + +# +# Amlogic Device Drivers +# + +# +# Char devices +# +# CONFIG_EARLY_INIT is not set + +# +# Register Debug Support +# +# CONFIG_AML_REG_DEBUG is not set +CONFIG_AM_UART=y +CONFIG_AM_UART_CONSOLE=y +CONFIG_OF_LM=y +CONFIG_AML_RTC=y + +# +# I2C Hardware Bus support +# +CONFIG_I2C_AML=m +# CONFIG_I2C_SW_AML is not set +# CONFIG_BCM2079X_I2C is not set +CONFIG_AM_INPUT=y +CONFIG_SARADC_AM=y +# CONFIG_MESON_INPUT_REMOTE is not set +CONFIG_MESON_NEW_INPUT_REMOTE=y +CONFIG_NEW_AM_REMOTE=y +CONFIG_NEW_AM_IR_TX=y +# CONFIG_MESON_INPUT_KEYBOARD is not set +CONFIG_MESON_INPUT_TOUCHSCREEN=y +# CONFIG_ADC_TOUCHSCREEN_AM is not set +# CONFIG_ITK_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_PIXCIR_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_PIXCIR_NEW_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_SINTEK_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_EETI_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_SIS92XX_CAPACITIVE_TOUCHSCREEN is not set +CONFIG_FOCALTECH_CAPACITIVE_TOUCHSCREEN=y +# CONFIG_SITRONIX_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_HX8520_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_RAYDIUM_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_GOODIX_CAPACITIVE_TOUCHSCREEN is not set +CONFIG_GOODIX_GT81XX_CAPACITIVE_TOUCHSCREEN=y +# CONFIG_GOODIX_GT82X_CAPACITIVE_TOUCHSCREEN is not set +# CONFIG_UOR7X5X_RESISTIVE_TOUCHSCREEN is not set +# CONFIG_UOR6X5X_RESISTIVE_TOUCHSCREEN is not set +# CONFIG_GSLX680_CAPACITIVE_TOUCHSCREEN is not set +CONFIG_GSLX680_COMPATIBLE_CAPACITIVE_TOUCHSCREEN=y +# CONFIG_GSLX680B_CAPACITIVE_TOUCHSCREEN is not set +CONFIG_GOODIX_GT9XX_CAPACITIVE_TOUCHSCREEN=y +# CONFIG_FT5X02_CAPACITIVE_TOUCHSCREEN is not set +CONFIG_NOVATEK_CAPACITIVE_TOUCHSCREEN=y + +# +# Ct36x Touch device support +# +CONFIG_TOUCHSCREEN_CT36X=y +CONFIG_TOUCHSCREEN_CT36X_PLATFORM_AMLCHIP=y +# CONFIG_TOUCHSCREEN_CT36X_PLATFORM_GENERIC is not set +# CONFIG_TOUCHSCREEN_CT36X_PLATFORM_ROCKCHIP is not set +# CONFIG_TOUCHSCREEN_CT36X_PLATFORM_ALLWINNER is not set +# CONFIG_TOUCHSCREEN_CT36X_CHIP_CT360 is not set +CONFIG_TOUCHSCREEN_CT36X_CHIP_CT365=y +CONFIG_TOUCHSCREEN_CT36X_MISC=y +# CONFIG_TOUCHSCREEN_CT36X_MISC_X_REVERSE is not set +# CONFIG_TOUCHSCREEN_CT36X_MISC_Y_REVERSE is not set +# CONFIG_TOUCHSCREEN_CT36X_MISC_XY_SWAP is not set +CONFIG_TOUCHSCREEN_CT36X_MISC_NEW_TPS=y +# CONFIG_SIMCARD_DETECT_AM is not set +# CONFIG_AML_HOLD_KEY is not set +# CONFIG_AML_CALL_KEY is not set +CONFIG_SENSOR_DEVICES=y +CONFIG_GRAVITY_BMA250=y +CONFIG_GRAVITY_BMA222=y +CONFIG_GRAVITY_MMA7660=y +CONFIG_GRAVITY_MIR3DA=y +CONFIG_GRAVITY_LIS3DH=y +CONFIG_GRAVITY_MMA8452=y +CONFIG_GRAVITY_MC32X0=y +CONFIG_GRAVITY_DMARD06=y +CONFIG_GRAVITY_MMA865X=y +CONFIG_GRAVITY_LSM303D=y +CONFIG_GRAVITY_DMARD10=y +CONFIG_GRAVITY_KXTJ9=y +CONFIG_GRAVITY_STK8313=y +CONFIG_GRAVITY_STK8312=y +CONFIG_GRAVITY_MM3A310=y +CONFIG_GRAVITY_MXC622X=y +CONFIG_GRAVITY_MXC6255XC=y +# CONFIG_GYROSCOPE_L3GD20 is not set +CONFIG_LIGHT_CM36283=y +CONFIG_LIGHT_CM3232=y +CONFIG_LIGHT_CM3217=y +CONFIG_LIGHT_LTR501=y +CONFIG_LIGHT_EPL6814=y +CONFIG_LIGHT_ISL29023=y +CONFIG_LIGHT_STK220X=y +CONFIG_LIGHT_LTR558=y +# CONFIG_AML_GPIO_KEY is not set +CONFIG_GPIO_AMLOGIC=y +CONFIG_PINCTRL_AMLOGIC=y + +# +# Power Management Support +# +# CONFIG_AMLOGIC_BOARD_HAS_PMU is not set +# CONFIG_AML_PMU_ALGORITHM_SUPPORT is not set +# CONFIG_AML_DVFS is not set +# CONFIG_MESON_CS_DCDC_REGULATOR is not set + +# +# Security key Support +# +# CONFIG_SECURITYKEY is not set + +# +# key management Support +# +# CONFIG_UNIFY_KEY_MANAGE is not set + +# +# EFUSE Support +# +CONFIG_EFUSE=y +# CONFIG_EFUSE_WRITE_VERSION_PERMIT is not set +CONFIG_EFUSE_LAYOUT_VERSION=3 + +# +# Smartcard support +# +# CONFIG_AM_SMARTCARD is not set +CONFIG_AML_VIRTUAL_THERMAL=y +CONFIG_AMLOGIC_THERMAL=y +CONFIG_AML_WDT=y + +# +# AMLOGIC SPI Hardware bus support +# +CONFIG_AMLOGIC_SPICC_MASTER=m +# CONFIG_AMLOGIC_SPICC_MASTER_DEBUG is not set +CONFIG_MESON_PWM=m +CONFIG_MESON_PWM_CTRL=m + +# +# USB Support +# +CONFIG_AMLOGIC_USB=y +CONFIG_USB_DWC_OTG_HCD=y +CONFIG_USB_HOST_ELECT_TEST=y + +# +# MMC/SD/SDIO Host Controller Drivers +# + +# +# Multimedia Card support +# +CONFIG_MMC_AML=y +# CONFIG_MMC_AML_DEBUG is not set +# CONFIG_AML_MMC_DEBUG_FORCE_SINGLE_BLOCK_RW is not set + +# +# SPI NOR Flash support +# +# CONFIG_AMLOGIC_SPI_NOR is not set + +# +# Network devices +# + +# +# Ethernet Support +# +CONFIG_AM_ETHERNET=y +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +CONFIG_AML_PHY=y +# CONFIG_AML_LAN8720 is not set +# CONFIG_AML_IP101_PHY is not set +# CONFIG_AML_KSZ8091 is not set +CONFIG_AML_RTL8211F=y +CONFIG_AM_ETHERNET_DEBUG_LEVEL=1 +CONFIG_AM_WIFI=y +# CONFIG_AM_WIFI_SD_MMC is not set +# CONFIG_DHD_USE_STATIC_BUF is not set +CONFIG_AM_WIFI_USB=y + +# +# Bluetooth Device Support +# +CONFIG_BT_DEVICE=y +CONFIG_BT_WAKE_CTRL=y +# CONFIG_BT_RTKBTUSB is not set +# CONFIG_MESON_NFC is not set + +# +# Audio devices +# + +# +# Audio Interface +# +CONFIG_AMAUDIO=y + +# +# Amlogic Audio Interface V2 +# +# CONFIG_AMAUDIO2 is not set + +# +# Audio dsp process +# +CONFIG_AML_AUDIO_DSP=y + +# +# Video devices +# +CONFIG_AML_VFM=y +CONFIG_AM_PTSSERVER=y +# CONFIG_H264_4K2K_SINGLE_CORE is not set +CONFIG_VSYNC_RDMA=y +CONFIG_AM_VIDEO=y +# CONFIG_AM_VIDEO2 is not set +# CONFIG_KEEP_FRAME_RESERVED is not set +# CONFIG_SUPPORT_VIDEO_ON_VPP2 is not set +CONFIG_GE2D_KEEP_FRAME=y + +# +# Video Decoders +# +CONFIG_AM_VDEC_MPEG12=y +CONFIG_AM_VDEC_MPEG4=y +CONFIG_AM_VDEC_VC1=y +CONFIG_AM_VDEC_H264=y +# CONFIG_AM_VDEC_H264MVC is not set +CONFIG_AM_VDEC_H265=y +CONFIG_AM_VDEC_MJPEG=y +CONFIG_AM_ENCODER=y +CONFIG_AM_JPEG_ENCODER=y +CONFIG_AM_PIC_DEC=y +CONFIG_AM_VDEC_REAL=y +CONFIG_AM_VDEC_AVS=y +CONFIG_AM_JPEGDEC=y +CONFIG_AM_TIMESYNC=y +CONFIG_AM_STREAMING=y +CONFIG_AM_SUBTITLE=y +CONFIG_AM_VIDEOCAPTURE=y + +# +# Canvas management driver +# +CONFIG_AM_CANVAS=y +CONFIG_AM_DISPLAY_MODULE=y + +# +# Amlogic video output module +# +CONFIG_AM_TV_OUTPUT=y +CONFIG_AML_VOUT_FRAMERATE_AUTOMATION=y +# CONFIG_AM_LCD_OUTPUT is not set + +# +# Amlogic video output2 module +# +# CONFIG_AM_TV_OUTPUT2 is not set + +# +# Amlogic TV LCD Support +# +# CONFIG_AML_TV_LCD is not set + +# +# Amlogic osd module +# +CONFIG_FB_AM=y +CONFIG_FB_OSD2_ENABLE=y +CONFIG_FB_OSD2_CURSOR=y +CONFIG_FB_OSD2_DEFAULT_BITS_PER_PIXEL=32 +CONFIG_FB_OSD2_DEFAULT_WIDTH=32 +CONFIG_FB_OSD2_DEFAULT_HEIGHT=32 +CONFIG_FB_OSD2_DEFAULT_WIDTH_VIRTUAL=32 +CONFIG_FB_OSD2_DEFAULT_HEIGHT_VIRTUAL=32 +CONFIG_FB_OSD1_DEFAULT_BITS_PER_PIXEL=16 +CONFIG_FB_OSD1_DEFAULT_WIDTH=720 +CONFIG_FB_OSD1_DEFAULT_HEIGHT=480 +CONFIG_FB_OSD1_DEFAULT_WIDTH_VIRTUAL=720 +CONFIG_FB_OSD1_DEFAULT_HEIGHT_VIRTUAL=480 +CONFIG_FB_AMLOGIC_UMP=y + +# +# Amlogic osd_ext module +# + +# +# Amlogic Backlight Support +# +# CONFIG_AMLOGIC_BACKLIGHT is not set +# CONFIG_AML_BL_PWM_ATTR is not set +# CONFIG_AML_LOCAL_DIMMING is not set +# CONFIG_IW7023_BACKLIGHT is not set +# CONFIG_IW7023_USE_EEPROM is not set +CONFIG_AM_GE2D=y +CONFIG_AM_LOGO=y +CONFIG_AM_HDMI_ONLY=y + +# +# HDMI TX Support +# +CONFIG_AML_HDMI_TX=y +# CONFIG_AML_HDMI_TX_HDCP is not set +# CONFIG_AML_HDMI_TX_CTS_DVI is not set +CONFIG_TVIN=y +CONFIG_TVIN_VDIN=y +# CONFIG_TVIN_AFE is not set +# CONFIG_TVIN_HDMI is not set +CONFIG_TVIN_BT656=y +CONFIG_TVIN_CSI=y +CONFIG_VIUIN=y +# CONFIG_GAMMA_AUTO_TUNE is not set +# CONFIG_AM_HDMI_REPEATER is not set +# CONFIG_TVIN_IT660X is not set +# CONFIG_TVIN_ISP is not set +# CONFIG_TVIN_VDIN_CTRL is not set +# CONFIG_AML_EXT_HDMIIN is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Post Process Manager driver +# +CONFIG_POST_PROCESS_MANAGER=y +CONFIG_POST_PROCESS_MANAGER_PPSCALER=y +# CONFIG_POST_PROCESS_MANAGER_3D_PROCESS is not set + +# +# Amlogic Camera Support +# +CONFIG_VIDEO_AMLOGIC_CAPTURE=y +CONFIG_AMLOGIC_CAPTURE_FRAME_ROTATE=y +CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER=y +# CONFIG_VIDEO_AMLOGIC_CAPTURE_PROBE is not set +# CONFIG_AMLCAP_LOG_TIME_USEFORFRAMES is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_GT2005 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_GC0307 is not set +CONFIG_VIDEO_AMLOGIC_CAPTURE_GC0308=y +CONFIG_VIDEO_AMLOGIC_CAPTURE_GC0328=y +# CONFIG_VIDEO_AMLOGIC_CAPTURE_GC0329 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_GC2015 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_GC2035 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_GC2155 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_OV5640 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_OV5642 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_OV7675 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_OV2655 is not set +CONFIG_VIDEO_AMLOGIC_CAPTURE_SP0838=y +CONFIG_VIDEO_AMLOGIC_CAPTURE_SP2518=y +# CONFIG_VIDEO_AMLOGIC_CAPTURE_SP0A19 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_SP1628 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_HI253 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_HI704 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_HM2057 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_HM5065 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_OV3660 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_OV5647 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_HI2056 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_NT99250 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_NT99252 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_NT99340 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_AR0543 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_AR0833 is not set +# CONFIG_VIDEO_AMLOGIC_CAPTURE_BF3720 is not set +CONFIG_AMLOGIC_VIDEOIN_MANAGER=y + +# +# V4L2 Video Support +# +CONFIG_V4L_AMLOGIC_VIDEO=y +CONFIG_V4L_AMLOGIC_VIDEO2=y + +# +# Amlogic ion video support +# +CONFIG_VIDEOBUF2_ION=y +CONFIG_AMLOGIC_IONVIDEO=y + +# +# Deinterlace driver +# +CONFIG_DEINTERLACE=y +# CONFIG_AM_DEINTERLACE_SD_ONLY is not set + +# +# MIPI Support +# +# CONFIG_AMLOGIC_MIPI is not set +# CONFIG_D2D3_PROCESS is not set + +# +# Amlogic VE & CM +# +# CONFIG_AM_VECM is not set + +# +# Amlogic DVB driver +# +# CONFIG_AM_DVB is not set + +# +# AMLOGIC CI Driver +# +# CONFIG_AM_PCMCIA is not set +# CONFIG_AM_IOBUS is not set + +# +# Amlogic Crypto Support +# +CONFIG_CRYPTO_AML_HW_CRYPRO=y +CONFIG_CRYPTO_DEVICE_DRIVER=y + +# +# MHL Support +# +# CONFIG_PANEL_IT6681 is not set + +# +# Amlogic PMU battery algorithm Support +# + +# +# Amlogic touch algorithm Support +# +# CONFIG_AML_TOUCH_ALGORITHM_SUPPORT is not set + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_FW_LOADER_USER_HELPER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=8 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_SWAP is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +CONFIG_OF_SELFTEST=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_MTD=y +CONFIG_PARPORT=m +# CONFIG_PARPORT_PC is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_1284 is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_DRBD=m +# CONFIG_DRBD_FAULT_INJECTION is not set +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +CONFIG_BMP085=y +CONFIG_BMP085_I2C=m +# CONFIG_BMP085_SPI is not set +CONFIG_SI1132=m +CONFIG_SI702X=m +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=m +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID10=m +CONFIG_MD_RAID456=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_BUFIO=m +CONFIG_DM_BIO_PRISON=m +CONFIG_DM_PERSISTENT_DATA=m +CONFIG_DM_CRYPT=y +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set +CONFIG_DM_CACHE=m +CONFIG_DM_CACHE_MQ=m +CONFIG_DM_CACHE_CLEANER=m +CONFIG_DM_MIRROR=m +CONFIG_DM_RAID=m +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +CONFIG_BONDING=m +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +CONFIG_VETH=m + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_MACB is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CIRRUS=y +# CONFIG_CS89x0 is not set +# CONFIG_DM9000 is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_FARADAY=y +# CONFIG_FTMAC100 is not set +# CONFIG_FTGMAC100 is not set +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_MARVELL=y +# CONFIG_MVMDIO is not set +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_8390=y +# CONFIG_AX88796 is not set +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_SMC91X is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NET_VENDOR_WIZNET=y +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_AMLOGIC_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_PLIP is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPPOL2TP=m +CONFIG_PPPOLAC=m +CONFIG_PPPOPNS=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=m +# CONFIG_USB_NET_CDC_MBIM is not set +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_NET1080=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_NET_CDC_SUBSET=m +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=m +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_HSO=m +# CONFIG_USB_NET_INT51X1 is not set +CONFIG_USB_CDC_PHONET=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +# CONFIG_USB_VL600 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=m +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_DB9 is not set +CONFIG_JOYSTICK_GAMECON=m +# CONFIG_JOYSTICK_TURBOGRAFX is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +# CONFIG_JOYSTICK_WALKERA0701 is not set +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_GTCO=m +CONFIG_TABLET_USB_HANWANG=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_WACOM=m +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_TOUCHSCREEN_DWAV_USB_MT=m +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +CONFIG_INPUT_ATI_REMOTE2=m +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=m +CONFIG_INPUT_GPIO=m +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +CONFIG_GAMEPORT=m +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_ATMEL is not set +CONFIG_HW_RANDOM_MESON=y +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_TLE62X0 is not set + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +CONFIG_PPS=m +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +CONFIG_PPS_CLIENT_GPIO=m + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +CONFIG_W1=m + +# +# 1-wire Bus Masters +# +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS1WM is not set +CONFIG_W1_MASTER_GPIO=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=m +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_ANDROID is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +CONFIG_CPU_THERMAL=y +CONFIG_CPUCORE_THERMAL=y +CONFIG_GPU_THERMAL=y +CONFIG_GPUCORE_THERMAL=y +# CONFIG_THERMAL_EMULATION is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=m +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +# CONFIG_MEDIA_RADIO_SUPPORT is not set +CONFIG_MEDIA_RC_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_MEDIA_CONTROLLER_DVB=y +CONFIG_VIDEO_DEV=y +# CONFIG_VIDEO_V4L2_SUBDEV_API is not set +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_TUNER=m +CONFIG_VIDEOBUF_GEN=y +CONFIG_VIDEOBUF_VMALLOC=y +CONFIG_VIDEOBUF_RESOURCE=y +CONFIG_VIDEOBUF_DVB=m +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_VMALLOC=m +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +CONFIG_DVB_CORE=y +CONFIG_DVB_NET=y +CONFIG_TTPCI_EEPROM=m +CONFIG_DVB_MAX_ADAPTERS=8 +CONFIG_DVB_DYNAMIC_MINORS=y + +# +# Media drivers +# +CONFIG_RC_CORE=y +CONFIG_RC_MAP=y +CONFIG_RC_DECODERS=y +CONFIG_LIRC=m +CONFIG_IR_LIRC_CODEC=m +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_RC5_SZ_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_RC_DEVICES=y +CONFIG_RC_ATI_REMOTE=m +CONFIG_IR_IMON=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_MESON=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_IGUANA=m +CONFIG_IR_TTUSBIR=m +CONFIG_RC_LOOPBACK=m +CONFIG_IR_GPIO_CIR=m +CONFIG_MEDIA_USB_SUPPORT=y + +# +# Webcam devices +# +CONFIG_USB_VIDEO_CLASS=m +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +CONFIG_USB_GSPCA=m +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_GL860=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_KONICA=m +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_MR97310A=m +CONFIG_USB_GSPCA_NW80X=m +CONFIG_USB_GSPCA_OV519=m +CONFIG_USB_GSPCA_OV534=m +CONFIG_USB_GSPCA_OV534_9=m +CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7302=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SE401=m +CONFIG_USB_GSPCA_SN9C2028=m +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m +CONFIG_USB_GSPCA_SPCA500=m +CONFIG_USB_GSPCA_SPCA501=m +CONFIG_USB_GSPCA_SPCA505=m +CONFIG_USB_GSPCA_SPCA506=m +CONFIG_USB_GSPCA_SPCA508=m +CONFIG_USB_GSPCA_SPCA561=m +CONFIG_USB_GSPCA_SPCA1528=m +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_XIRLINK_CIT=m +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_USB_PWC=m +CONFIG_USB_PWC_DEBUG=y +CONFIG_USB_PWC_INPUT_EVDEV=y +CONFIG_VIDEO_CPIA2=m +CONFIG_USB_ZR364XX=m +CONFIG_USB_STKWEBCAM=m +CONFIG_USB_S2255=m +CONFIG_USB_SN9C102=m + +# +# Analog TV USB devices +# +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_PVRUSB2_DVB=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_TLG2300=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_STK1160=m +CONFIG_VIDEO_STK1160_AC97=y + +# +# Analog/digital TV USB devices +# +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_V4L2=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_RC=y +CONFIG_VIDEO_CX231XX_ALSA=m +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_VIDEO_TM6000=m +CONFIG_VIDEO_TM6000_ALSA=m +CONFIG_VIDEO_TM6000_DVB=m + +# +# Digital TV USB devices +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_FRIIO=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_IT913X=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_DVBSKY=m +CONFIG_SMS_USB_DRV=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set + +# +# Webcam, TV (analog/digital) USB devices +# +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_EM28XX_RC=m +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_SOC_CAMERA is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_SMS_SDIO_DRV is not set +# CONFIG_MEDIA_PARPORT_SUPPORT is not set +CONFIG_MEDIA_COMMON_OPTIONS=y + +# +# common driver options +# +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_CYPRESS_FIRMWARE=m +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_SMS_SIANO_MDTV=m +CONFIG_SMS_SIANO_RC=y +# CONFIG_SMS_SIANO_DEBUGFS is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_MEDIA_ATTACH=y +CONFIG_VIDEO_IR_I2C=y + +# +# Audio decoders, processors and mixers +# +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_WM8775=m + +# +# RDS decoders +# + +# +# Video decoders +# +CONFIG_VIDEO_SAA711X=m +CONFIG_VIDEO_TVP5150=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# Video encoders +# + +# +# Camera sensor devices +# +CONFIG_VIDEO_MT9V011=m + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# +CONFIG_MEDIA_TUNER=y +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_MT2060=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_MEDIA_TUNER_MT2266=m +CONFIG_MEDIA_TUNER_QT1010=m +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_XC4000=y +CONFIG_MEDIA_TUNER_MXL5005S=m +CONFIG_MEDIA_TUNER_MXL5007T=m +CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_MEDIA_TUNER_MAX2165=m +CONFIG_MEDIA_TUNER_TDA18218=m +CONFIG_MEDIA_TUNER_FC0011=m +CONFIG_MEDIA_TUNER_FC0012=m +CONFIG_MEDIA_TUNER_FC0013=m +CONFIG_MEDIA_TUNER_TDA18212=m +CONFIG_MEDIA_TUNER_E4000=m +CONFIG_MEDIA_TUNER_FC2580=m +CONFIG_MEDIA_TUNER_M88TS2022=m +CONFIG_MEDIA_TUNER_TUA9001=m +CONFIG_MEDIA_TUNER_SI2157=m +CONFIG_MEDIA_TUNER_IT913X=m +CONFIG_MEDIA_TUNER_R820T=m + +# +# Multistandard (satellite) frontends +# +CONFIG_DVB_STB0899=m +CONFIG_DVB_STB6100=m +CONFIG_DVB_STV090x=m +CONFIG_DVB_STV6110x=m +CONFIG_DVB_M88DS3103=m + +# +# Multistandard (cable + terrestrial) frontends +# +CONFIG_DVB_DRXK=m +CONFIG_DVB_TDA18271C2DD=m + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_CX24123=m +CONFIG_DVB_MT312=m +CONFIG_DVB_ZL10039=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_STV0288=m +CONFIG_DVB_STB6000=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_STV6110=m +CONFIG_DVB_STV0900=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TUNER_ITD1000=m +CONFIG_DVB_TUNER_CX24113=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_CX24116=m +CONFIG_DVB_SI21XX=m +CONFIG_DVB_TS2020=m +CONFIG_DVB_DS3000=m +CONFIG_DVB_TDA10071=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_CX22702=m +CONFIG_DVB_DRXD=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +CONFIG_DVB_TDA10048=m +CONFIG_DVB_AF9013=m +CONFIG_DVB_EC100=m +CONFIG_DVB_CXD2820R=m +CONFIG_DVB_RTL2830=m +CONFIG_DVB_RTL2832=m +CONFIG_DVB_SI2168=m +# CONFIG_DVB_AS102_FE is not set + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LGDT3305=m +CONFIG_DVB_LG2160=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_AU8522=m +CONFIG_DVB_AU8522_DTV=m +CONFIG_DVB_AU8522_V4L=m +CONFIG_DVB_S5H1411=m + +# +# ISDB-T (terrestrial) frontends +# +CONFIG_DVB_S921=m +CONFIG_DVB_DIB8000=m +CONFIG_DVB_MB86A20S=m + +# +# Digital terrestrial only tuners/PLL +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_DIB0090=m + +# +# SEC control devices for DVB-S +# +CONFIG_DVB_LNBP21=m +CONFIG_DVB_LNBP22=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_ISL6423=m +CONFIG_DVB_A8293=m +CONFIG_DVB_SP2=m +CONFIG_DVB_LGS8GXX=m +CONFIG_DVB_ATBM8830=m +CONFIG_DVB_IX2505V=m +CONFIG_DVB_IT913X_FE=m +CONFIG_DVB_M88RS2000=m +CONFIG_DVB_AF9033=m + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set + +# +# Graphics support +# +CONFIG_DRM=y +CONFIG_DRM_USB=m +CONFIG_DRM_KMS_HELPER=m +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +CONFIG_DRM_MALI=y +CONFIG_DRM_UDL=m +# CONFIG_DRM_TILCDC is not set +CONFIG_ION=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_HDMI=y +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +CONFIG_FB_SYS_FILLRECT=m +CONFIG_FB_SYS_COPYAREA=m +CONFIG_FB_SYS_IMAGEBLIT=m +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=m +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +CONFIG_FB_BACKLIGHT=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_SMSCUFX is not set +CONFIG_FB_UDL=m +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_EXYNOS_VIDEO is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=m +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +CONFIG_FONT_PEARL_8x8=y +CONFIG_FONT_ACORN_8x8=y +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_FB_SSD1307 is not set +CONFIG_FB_TFT=m +CONFIG_FB_TFT_ODROIDC32=m +CONFIG_FB_TFT_ST7565=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m +CONFIG_FB_TFT_HX8340BN=m +CONFIG_FB_TFT_HX8347D=m +CONFIG_FB_TFT_HX8353D=m +CONFIG_FB_TFT_ILI9320=m +CONFIG_FB_TFT_ILI9325=m +CONFIG_FB_TFT_ILI9340=m +CONFIG_FB_TFT_ILI9341=m +CONFIG_FB_TFT_ILI9481=m +CONFIG_FB_TFT_ILI9486=m +CONFIG_FB_TFT_PCD8544=m +CONFIG_FB_TFT_RA8875=m +CONFIG_FB_TFT_S6D02A1=m +CONFIG_FB_TFT_S6D1121=m +CONFIG_FB_TFT_SSD1289=m +CONFIG_FB_TFT_SSD1306=m +CONFIG_FB_TFT_SSD1331=m +CONFIG_FB_TFT_SSD1351=m +CONFIG_FB_TFT_ST7735R=m +CONFIG_FB_TFT_TINYLCD=m +CONFIG_FB_TFT_TLS8204=m +CONFIG_FB_TFT_UC1701=m +CONFIG_FB_TFT_UPD161704=m +CONFIG_FB_TFT_WATTEROTT=m +CONFIG_FB_FLEX=m +CONFIG_FB_TFT_FBTFT_DEVICE=m +CONFIG_SOUND=y +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_VMASTER=y +CONFIG_SND_RAWMIDI_SEQ=m +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_AC97_CODEC=m +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +CONFIG_SND_ALOOP=m +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_CAIAQ=m +# CONFIG_SND_USB_CAIAQ_INPUT is not set +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +# CONFIG_SND_AML_M6_SOC is not set +CONFIG_SND_AML_M8_SOC=y +# CONFIG_SND_AML_M_DUMMY_CODEC is not set +CONFIG_SND_AML_M8=y +CONFIG_SND_ODROID_HIFI1=m +# CONFIG_SND_AML_M8_PCM is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_AML_M8_CODEC=y +CONFIG_SND_SOC_DUMMY_CODEC=y +CONFIG_SND_SOC_PCM5102=m +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=m + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=m +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=m +# CONFIG_HID_APPLEIR is not set +CONFIG_HID_AUREAL=m +CONFIG_HID_BELKIN=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_PRODIKEYS=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=m +CONFIG_HID_ELECOM=m +CONFIG_HID_EZKEY=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_KYE=m +CONFIG_HID_UCLOGIC=m +CONFIG_HID_WALTOP=m +CONFIG_HID_GYRATION=m +CONFIG_HID_ICADE=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO_TPKBD=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +CONFIG_HID_MAGICMOUSE=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PICOLCD_CIR is not set +CONFIG_HID_PRIMAX=m +CONFIG_HID_PS3REMOTE=m +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAITEK=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SONY=m +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_STEELSERIES=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_GREENASIA=m +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THINGM=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_WACOM=m +CONFIG_HID_WIIMOTE=m +CONFIG_HID_WIIMOTE_EXT=y +CONFIG_HID_XINMO=m +CONFIG_HID_ZEROPLUS=m +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=m +CONFIG_HID_SENSOR_HUB=m + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB_ARCH_HAS_XHCI is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=m +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +CONFIG_USB_WDM=m +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CONSOLE=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_QCAUX=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SAFE_PADDED=y +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SYMBOL=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_WWAN=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTICON=m +CONFIG_USB_SERIAL_XSENS_MT=m +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_ZTE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_EZUSB_FX2=m +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_OTG_WAKELOCK is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +CONFIG_USB_GADGET_DWC_OTG=y +CONFIG_USB_DWC_OTG=y +# CONFIG_USB_M66592 is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=m +CONFIG_USB_F_ACM=m +CONFIG_USB_F_SS_LB=m +CONFIG_USB_U_SERIAL=m +CONFIG_USB_F_SERIAL=m +CONFIG_USB_F_OBEX=m +CONFIG_USB_ZERO=m +CONFIG_USB_AUDIO=m +CONFIG_GADGET_UAC1=y +CONFIG_USB_ETH=m +CONFIG_USB_ETH_RNDIS=y +# CONFIG_USB_ETH_EEM is not set +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_FUNCTIONFS=m +# CONFIG_USB_FUNCTIONFS_ETH is not set +# CONFIG_USB_FUNCTIONFS_RNDIS is not set +CONFIG_USB_FUNCTIONFS_GENERIC=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_USB_MIDI_GADGET=m +CONFIG_USB_G_PRINTER=m +CONFIG_USB_CDC_COMPOSITE=m +# CONFIG_USB_G_NOKIA is not set +CONFIG_USB_G_ACM_MS=m +CONFIG_USB_G_MULTI=m +CONFIG_USB_G_MULTI_RNDIS=y +# CONFIG_USB_G_MULTI_CDC is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +CONFIG_USB_G_WEBCAM=m +CONFIG_MMC=y +CONFIG_MMC_DEBUG=y +CONFIG_MMC_UNSAFE_RESUME=y +# CONFIG_MMC_CLKGATE is not set +# CONFIG_MMC_EMBEDDED_SDIO is not set +# CONFIG_MMC_PARANOID_SD_INIT is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_EMMC_SECURE_STORAGE is not set +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_DW is not set +CONFIG_MMC_VUB300=m +CONFIG_MMC_USHC=m +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=m +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_TRIGGER_DEFAULT_ON=m + +# +# iptables trigger is under Netfilter config (LED target) +# +CONFIG_LEDS_TRIGGER_TRANSIENT=m +# CONFIG_LEDS_TRIGGER_CAMERA is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_EDAC is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_SNVS is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +CONFIG_UIO=y +CONFIG_UIO_PDRV=y +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_DMEM_GENIRQ is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_HOST=m +# CONFIG_USBIP_DEBUG is not set +# CONFIG_ECHO is not set +# CONFIG_COMEDI is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_PANEL is not set +CONFIG_R8712U=m +CONFIG_RTS5139=m +CONFIG_RTS5139_DEBUG=y +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +CONFIG_USB_SERIAL_QUATECH2=m +CONFIG_ZSMALLOC=y +CONFIG_ZRAM=m +CONFIG_ZRAM_DEBUG=y +CONFIG_USB_ENESTORAGE=m +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +# CONFIG_ANDROID_BINDER_IPC is not set +# CONFIG_ASHMEM is not set +# CONFIG_ANDROID_LOGGER is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +# CONFIG_ANDROID_TIMED_GPIO is not set +# CONFIG_ANDROID_LOW_MEMORY_KILLER is not set +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_SYNC=y +# CONFIG_SW_SYNC is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set +CONFIG_CLKDEV_LOOKUP=y + +# +# Hardware Spinlock drivers +# +# CONFIG_MAILBOX is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +CONFIG_PWM=y +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set +CONFIG_MALI400=y +CONFIG_MALI450=y +# CONFIG_MALI400_DEBUG is not set +# CONFIG_MALI400_PROFILING is not set +CONFIG_MALI400_UMP=y +CONFIG_MALI_DVFS=y +CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH=y +CONFIG_MALI_SHARED_INTERRUPTS=y +# CONFIG_MALI_PMU_PARALLEL_POWER_UP is not set +# CONFIG_MALI_QUIET is not set +CONFIG_UMP=y +# CONFIG_UMP_DEBUG is not set +CONFIG_UMPLOCK=y + +# +# ODROID Specific Hardware +# +CONFIG_ODROID_TOUCHSCREEN_ADS7846=m +CONFIG_ODROID_AML_GPIO_LIB=m + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_DEBUG=y +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +CONFIG_REISERFS_PROC_INFO=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_PRINT_QUOTA_WARNING=y +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +CONFIG_OVERLAYFS_FS=y +CONFIG_GENERIC_ACL=y + +# +# Caches +# +CONFIG_FSCACHE=m +# CONFIG_FSCACHE_STATS is not set +# CONFIG_FSCACHE_HISTOGRAM is not set +# CONFIG_FSCACHE_DEBUG is not set +# CONFIG_FSCACHE_OBJECT_LIST is not set +# CONFIG_CACHEFILES is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=m +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_F2FS_FS=m +CONFIG_F2FS_STAT_FS=y +CONFIG_F2FS_FS_XATTR=y +CONFIG_F2FS_FS_POSIX_ACL=y +# CONFIG_AUFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=m +CONFIG_NFS_V2=m +CONFIG_NFS_V3=m +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=m +# CONFIG_NFS_SWAP is not set +CONFIG_NFS_V4_1=y +CONFIG_PNFS_FILE_LAYOUT=m +CONFIG_PNFS_BLOCK=m +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFSD=m +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +# CONFIG_NFSD_FAULT_INJECTION is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=m +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=m +CONFIG_SUNRPC_GSS=m +CONFIG_SUNRPC_BACKCHANNEL=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +CONFIG_CIFS_XATTR=y +# CONFIG_CIFS_POSIX is not set +# CONFIG_CIFS_ACL is not set +# CONFIG_CIFS_DEBUG is not set +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_SMB2=y +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_MAC_ROMAN=m +CONFIG_NLS_MAC_CELTIC=m +CONFIG_NLS_MAC_CENTEURO=m +CONFIG_NLS_MAC_CROATIAN=m +CONFIG_NLS_MAC_CYRILLIC=m +CONFIG_NLS_MAC_GAELIC=m +CONFIG_NLS_MAC_GREEK=m +CONFIG_NLS_MAC_ICELAND=m +CONFIG_NLS_MAC_INUIT=m +CONFIG_NLS_MAC_ROMANIAN=m +CONFIG_NLS_MAC_TURKISH=m +CONFIG_NLS_UTF8=m +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_READABLE_ASM=y +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1 +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1 +CONFIG_SCHED_DEBUG=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +CONFIG_DEBUG_PREEMPT=y +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_FTRACE_SYSCALLS is not set +# CONFIG_TRACER_SNAPSHOT is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_PROBE_EVENTS is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_ARM_UNWIND=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_RODATA is not set +# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h" +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEYS_DEBUG_PROC_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y +CONFIG_LSM_MMAP_MIN_ADDR=32768 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +# CONFIG_SECURITY_YAMA is not set +# CONFIG_IMA is not set +# CONFIG_EVM is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="apparmor" +CONFIG_XOR_BLOCKS=m +CONFIG_ASYNC_CORE=m +CONFIG_ASYNC_MEMCPY=m +CONFIG_ASYNC_XOR=m +CONFIG_ASYNC_PQ=m +CONFIG_ASYNC_RAID6_RECOV=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP=m +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=m +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=y +# CONFIG_CRYPTO_GCM is not set +CONFIG_CRYPTO_SEQIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=y +CONFIG_CRYPTO_XTS=m + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA1_ARM is not set +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_AES_ARM=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_BLOWFISH_COMMON=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST_COMMON=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_TWOFISH_COMMON=m + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_ZLIB=m +CONFIG_CRYPTO_LZO=m + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=m +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_RAID6_PQ=m +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +CONFIG_CRC7=y +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +# CONFIG_XZ_DEC_SPARC is not set +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +CONFIG_LRU_CACHE=m +CONFIG_AVERAGE=y +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +CONFIG_OID_REGISTRY=m +# CONFIG_VIRTUALIZATION is not set +CONFIG_BACKPORT_INTEGRATE=y +CONFIG_BACKPORT_DIR="backports" +CONFIG_BACKPORT_VERSION="backports-20150129-0-gdd4a670" +CONFIG_BACKPORT_KERNEL_VERSION="next-20150129-0-g828f79f" +CONFIG_BACKPORT_KERNEL_NAME="Linux" +CONFIG_BACKPORT_LINUX=y +CONFIG_BACKPORT_KERNEL_3_11=y +CONFIG_BACKPORT_KERNEL_3_12=y +CONFIG_BACKPORT_KERNEL_3_13=y +CONFIG_BACKPORT_KERNEL_3_14=y +CONFIG_BACKPORT_KERNEL_3_15=y +CONFIG_BACKPORT_KERNEL_3_16=y +CONFIG_BACKPORT_KERNEL_3_17=y +CONFIG_BACKPORT_KERNEL_3_18=y +CONFIG_BACKPORT_KERNEL_3_19=y +CONFIG_BACKPORT_KERNEL_3_20=y +CONFIG_BACKPORT_KERNEL_3_21=y +CONFIG_BACKPORT_KERNEL_3_22=y +CONFIG_BACKPORT_KERNEL_3_23=y +CONFIG_BACKPORT_KERNEL_3_24=y +CONFIG_BACKPORT_KERNEL_3_25=y +CONFIG_BACKPORT_KERNEL_3_26=y +CONFIG_BACKPORT_KERNEL_3_27=y +CONFIG_BACKPORT_KERNEL_3_28=y +CONFIG_BACKPORT_KERNEL_3_29=y +CONFIG_BACKPORT_KERNEL_3_30=y +CONFIG_BACKPORT_KERNEL_3_31=y +CONFIG_BACKPORT_KERNEL_3_32=y +CONFIG_BACKPORT_KERNEL_3_33=y +CONFIG_BACKPORT_KERNEL_3_34=y +CONFIG_BACKPORT_KERNEL_3_35=y +CONFIG_BACKPORT_KERNEL_3_36=y +CONFIG_BACKPORT_KERNEL_3_37=y +CONFIG_BACKPORT_KERNEL_3_38=y +CONFIG_BACKPORT_KERNEL_3_39=y +CONFIG_BACKPORT_KERNEL_3_40=y +CONFIG_BACKPORT_KERNEL_3_41=y +CONFIG_BACKPORT_KERNEL_3_42=y +CONFIG_BACKPORT_KERNEL_3_43=y +CONFIG_BACKPORT_KERNEL_3_44=y +CONFIG_BACKPORT_KERNEL_3_45=y +CONFIG_BACKPORT_KERNEL_3_46=y +CONFIG_BACKPORT_KERNEL_3_47=y +CONFIG_BACKPORT_KERNEL_3_48=y +CONFIG_BACKPORT_KERNEL_3_49=y +CONFIG_BACKPORT_KERNEL_3_50=y +CONFIG_BACKPORT_KERNEL_3_51=y +CONFIG_BACKPORT_KERNEL_3_52=y +CONFIG_BACKPORT_KERNEL_3_53=y +CONFIG_BACKPORT_KERNEL_3_54=y +CONFIG_BACKPORT_KERNEL_3_55=y +CONFIG_BACKPORT_KERNEL_3_56=y +CONFIG_BACKPORT_KERNEL_3_57=y +CONFIG_BACKPORT_KERNEL_3_58=y +CONFIG_BACKPORT_KERNEL_3_59=y +CONFIG_BACKPORT_KERNEL_3_60=y +CONFIG_BACKPORT_KERNEL_3_61=y +CONFIG_BACKPORT_KERNEL_3_62=y +CONFIG_BACKPORT_KERNEL_3_63=y +CONFIG_BACKPORT_KERNEL_3_64=y +CONFIG_BACKPORT_KERNEL_3_65=y +CONFIG_BACKPORT_KERNEL_3_66=y +CONFIG_BACKPORT_KERNEL_3_67=y +CONFIG_BACKPORT_KERNEL_3_68=y +CONFIG_BACKPORT_KERNEL_3_69=y +CONFIG_BACKPORT_KERNEL_3_70=y +CONFIG_BACKPORT_KERNEL_3_71=y +CONFIG_BACKPORT_KERNEL_3_72=y +CONFIG_BACKPORT_KERNEL_3_73=y +CONFIG_BACKPORT_KERNEL_3_74=y +CONFIG_BACKPORT_KERNEL_3_75=y +CONFIG_BACKPORT_KERNEL_3_76=y +CONFIG_BACKPORT_KERNEL_3_77=y +CONFIG_BACKPORT_KERNEL_3_78=y +CONFIG_BACKPORT_KERNEL_3_79=y +CONFIG_BACKPORT_KERNEL_3_80=y +CONFIG_BACKPORT_KERNEL_3_81=y +CONFIG_BACKPORT_KERNEL_3_82=y +CONFIG_BACKPORT_KERNEL_3_83=y +CONFIG_BACKPORT_KERNEL_3_84=y +CONFIG_BACKPORT_KERNEL_3_85=y +CONFIG_BACKPORT_KERNEL_3_86=y +CONFIG_BACKPORT_KERNEL_3_87=y +CONFIG_BACKPORT_KERNEL_3_88=y +CONFIG_BACKPORT_KERNEL_3_89=y +CONFIG_BACKPORT_KERNEL_3_90=y +CONFIG_BACKPORT_KERNEL_3_91=y +CONFIG_BACKPORT_KERNEL_3_92=y +CONFIG_BACKPORT_KERNEL_3_93=y +CONFIG_BACKPORT_KERNEL_3_94=y +CONFIG_BACKPORT_KERNEL_3_95=y +CONFIG_BACKPORT_KERNEL_3_96=y +CONFIG_BACKPORT_KERNEL_3_97=y +CONFIG_BACKPORT_KERNEL_3_98=y +CONFIG_BACKPORT_BPAUTO_BUILD_CORDIC=m +CONFIG_BACKPORT_BPAUTO_USERSEL_BUILD_ALL=y +# CONFIG_BACKPORT_BPAUTO_BUILD_CRYPTO_CCM is not set +CONFIG_BACKPORT_CFG80211=y +# CONFIG_BACKPORT_NL80211_TESTMODE is not set +# CONFIG_BACKPORT_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_BACKPORT_CFG80211_REG_DEBUG is not set +# CONFIG_BACKPORT_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_BACKPORT_CFG80211_DEFAULT_PS is not set +CONFIG_BACKPORT_CFG80211_DEBUGFS=y +# CONFIG_BACKPORT_CFG80211_INTERNAL_REGDB is not set +CONFIG_BACKPORT_CFG80211_WEXT=y +# CONFIG_BACKPORT_LIB80211 is not set +CONFIG_BACKPORT_MAC80211=y +CONFIG_BACKPORT_MAC80211_HAS_RC=y +CONFIG_BACKPORT_MAC80211_RC_MINSTREL=y +CONFIG_BACKPORT_MAC80211_RC_MINSTREL_HT=y +# CONFIG_BACKPORT_MAC80211_RC_MINSTREL_VHT is not set +CONFIG_BACKPORT_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_BACKPORT_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_BACKPORT_MAC80211_MESH is not set +CONFIG_BACKPORT_MAC80211_LEDS=y +# CONFIG_BACKPORT_MAC80211_DEBUGFS is not set +# CONFIG_BACKPORT_MAC80211_MESSAGE_TRACING is not set +# CONFIG_BACKPORT_MAC80211_DEBUG_MENU is not set +CONFIG_BACKPORT_WLAN=y +# CONFIG_BACKPORT_LIBERTAS_THINFIRM is not set +CONFIG_BACKPORT_AT76C50X_USB=m +CONFIG_BACKPORT_USB_NET_RNDIS_WLAN=m +CONFIG_BACKPORT_RTL8187=m +CONFIG_BACKPORT_MAC80211_HWSIM=m +CONFIG_BACKPORT_ATH_COMMON=m +CONFIG_BACKPORT_ATH_CARDS=m +# CONFIG_BACKPORT_ATH_DEBUG is not set +CONFIG_BACKPORT_ATH9K_HW=m +CONFIG_BACKPORT_ATH9K_COMMON=m +CONFIG_BACKPORT_ATH9K_BTCOEX_SUPPORT=y +CONFIG_BACKPORT_ATH9K=m +CONFIG_BACKPORT_ATH9K_AHB=y +# CONFIG_BACKPORT_ATH9K_DEBUGFS is not set +CONFIG_BACKPORT_ATH9K_DYNACK=y +# CONFIG_BACKPORT_ATH9K_WOW is not set +CONFIG_BACKPORT_ATH9K_RFKILL=y +# CONFIG_BACKPORT_ATH9K_CHANNEL_CONTEXT is not set +CONFIG_BACKPORT_ATH9K_PCOEM=y +CONFIG_BACKPORT_ATH9K_HTC=m +# CONFIG_BACKPORT_ATH9K_HTC_DEBUGFS is not set +CONFIG_BACKPORT_CARL9170=m +CONFIG_BACKPORT_CARL9170_LEDS=y +CONFIG_BACKPORT_CARL9170_WPC=y +CONFIG_BACKPORT_CARL9170_HWRNG=y +CONFIG_BACKPORT_ATH6KL=m +# CONFIG_BACKPORT_ATH6KL_SDIO is not set +CONFIG_BACKPORT_ATH6KL_USB=m +# CONFIG_BACKPORT_ATH6KL_DEBUG is not set +CONFIG_BACKPORT_AR5523=m +CONFIG_BACKPORT_ATH10K=m +# CONFIG_BACKPORT_ATH10K_DEBUG is not set +# CONFIG_BACKPORT_ATH10K_DEBUGFS is not set +CONFIG_BACKPORT_WCN36XX=m +# CONFIG_BACKPORT_WCN36XX_DEBUGFS is not set +# CONFIG_BACKPORT_BRCMFMAC is not set +# CONFIG_BACKPORT_LIBERTAS is not set +CONFIG_BACKPORT_P54_COMMON=m +CONFIG_BACKPORT_P54_USB=m +# CONFIG_BACKPORT_P54_SPI is not set +CONFIG_BACKPORT_RT2X00=m +CONFIG_BACKPORT_RT2500USB=m +CONFIG_BACKPORT_RT73USB=m +CONFIG_BACKPORT_RT2800USB=m +CONFIG_BACKPORT_RT2800USB_RT33XX=y +CONFIG_BACKPORT_RT2800USB_RT35XX=y +CONFIG_BACKPORT_RT2800USB_RT3573=y +CONFIG_BACKPORT_RT2800USB_RT53XX=y +CONFIG_BACKPORT_RT2800USB_RT55XX=y +CONFIG_BACKPORT_RT2800USB_UNKNOWN=y +CONFIG_BACKPORT_RT2800_LIB=m +CONFIG_BACKPORT_RT2X00_LIB_USB=m +CONFIG_BACKPORT_RT2X00_LIB=m +CONFIG_BACKPORT_RT2X00_LIB_FIRMWARE=y +CONFIG_BACKPORT_RT2X00_LIB_CRYPTO=y +CONFIG_BACKPORT_RT2X00_LIB_LEDS=y +# CONFIG_BACKPORT_RT2X00_DEBUG is not set +CONFIG_BACKPORT_RTL_CARDS=m +# CONFIG_BACKPORT_RTL8192CU is not set +CONFIG_BACKPORT_RTL8192C_COMMON=m +CONFIG_BACKPORT_WL_TI=y +# CONFIG_BACKPORT_WL1251 is not set +# CONFIG_BACKPORT_WL12XX is not set +# CONFIG_BACKPORT_WL18XX is not set +CONFIG_BACKPORT_ZD1211RW=m +# CONFIG_BACKPORT_ZD1211RW_DEBUG is not set +CONFIG_BACKPORT_MWIFIEX=m +# CONFIG_BACKPORT_MWIFIEX_SDIO is not set +CONFIG_BACKPORT_MWIFIEX_USB=m +CONFIG_BACKPORT_RSI_91X=m +# CONFIG_BACKPORT_RSI_DEBUGFS is not set +# CONFIG_BACKPORT_RSI_SDIO is not set +CONFIG_BACKPORT_RSI_USB=m +CONFIG_BACKPORT_USB_NET_DRIVERS=y +CONFIG_BACKPORT_USB_USBNET=m +CONFIG_BACKPORT_USB_NET_CDCETHER=m +CONFIG_BACKPORT_USB_NET_CDC_NCM=m +CONFIG_BACKPORT_USB_NET_CDC_MBIM=m +CONFIG_BACKPORT_USB_NET_RNDIS_HOST=m +CONFIG_BACKPORT_USB_NET_QMI_WWAN=m +CONFIG_BACKPORT_USB_SIERRA_NET=m +# CONFIG_BACKPORT_NFC is not set +# CONFIG_BACKPORT_6LOWPAN is not set +# CONFIG_BACKPORT_IEEE802154 is not set + +# +# USB Device Class drivers +# +CONFIG_BACKPORT_USB_WDM=m +CONFIG_RTL8192CU=m +CONFIG_RTL8812AU=m +CONFIG_RTL8188EU=m +CONFIG_RTL8192DU=m diff --git a/configuration.sh b/configuration.sh index 15f9285f2d..4cfb4a72fb 100644 --- a/configuration.sh +++ b/configuration.sh @@ -318,6 +318,7 @@ case $BOARD in #build 1 LINUXFAMILY="odroidxu4" BOOTSIZE="16" + OFFSET="2" BOOTCONFIG="odroid_config" MODULES="bonding" MODULES_NEXT="" @@ -326,6 +327,20 @@ case $BOARD in DESKTOP_TARGET="jessie,default" ;; + odroidc1)#enabled + #description S805 C1 quad core + #build 1wip + LINUXFAMILY="odroidc1" + BOOTSIZE="16" + OFFSET="2" + BOOTCONFIG="odroidc_config" + MODULES="bonding" + MODULES_NEXT="" + SERIALCON="ttyS0" + CLI_TARGET="%,%" + DESKTOP_TARGET="jessie,default" + ;; + toradex)#disabled LINUXFAMILY="toradex" BOOTCONFIG="colibri_imx6_defconfig" @@ -397,7 +412,7 @@ case $LINUXFAMILY in odroidxu4) KERNEL_DEFAULT='https://github.com/hardkernel/linux' KERNEL_DEFAULT_BRANCH="odroidxu3-3.10.y" - KERNEL_DEFAULT_SOURCE="linux-odroidxu" + KERNEL_DEFAULT_SOURCE="linux-odroid" KERNEL_NEXT='https://github.com/tobetter/linux' KERNEL_NEXT_BRANCH="odroidxu4-v4.2" KERNEL_NEXT_SOURCE="linux-odroidxu-next" @@ -412,6 +427,24 @@ case $LINUXFAMILY in UBOOT_DEV_SOURCE=$UBOOT_DEFAULT_SOURCE ;; + odroidc1) + KERNEL_DEFAULT='https://github.com/hardkernel/linux' + KERNEL_DEFAULT_BRANCH="odroidc-3.10.y" + KERNEL_DEFAULT_SOURCE="linux-odroid" + KERNEL_NEXT='https://github.com/tobetter/linux' + KERNEL_NEXT_BRANCH="odroidxu4-v4.2" + KERNEL_NEXT_SOURCE="linux-odroidxu-next" + UBOOT_DEFAULT="https://github.com/hardkernel/u-boot.git" + UBOOT_DEFAULT_BRANCH="odroidc-v2011.03" + UBOOT_DEFAULT_SOURCE="u-boot-odroidxu" + UBOOT_NEXT=$UBOOT_DEFAULT + UBOOT_NEXT_BRANCH=$UBOOT_DEFAULT_BRANCH + UBOOT_NEXT_SOURCE=$UBOOT_DEFAULT_SOURCE + UBOOT_DEV=$UBOOT_DEFAULT + UBOOT_DEV_BRANCH=$UBOOT_DEFAULT_BRANCH + UBOOT_DEV_SOURCE=$UBOOT_DEFAULT_SOURCE + ;; + udoo) KERNEL_DEFAULT="https://github.com/UDOOboard/linux_kernel" KERNEL_DEFAULT_BRANCH="3.14-1.0.x-udoo" diff --git a/patch/kernel/odroidc1-default/fbtft_drivers.patch b/patch/kernel/odroidc1-default/fbtft_drivers.patch new file mode 100644 index 0000000000..8ecb55230a --- /dev/null +++ b/patch/kernel/odroidc1-default/fbtft_drivers.patch @@ -0,0 +1,12012 @@ +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 03bed11..48f1f71 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -17,6 +17,8 @@ config SH_LCD_MIPI_DSI + + source "drivers/char/agp/Kconfig" + ++source "drivers/video/fbtft/Kconfig" ++ + source "drivers/gpu/vga/Kconfig" + + source "drivers/gpu/host1x/Kconfig" +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 07905d0..14810e4 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -4,6 +4,7 @@ + + # Each configuration option enables a list of files. + ++obj-y += fbtft/ + obj-$(CONFIG_VGASTATE) += vgastate.o + obj-$(CONFIG_HDMI) += hdmi.o + obj-y += fb_notify.o +diff --git a/drivers/video/fbtft/Kconfig b/drivers/video/fbtft/Kconfig +new file mode 100644 +index 0000000..995a910 +--- /dev/null ++++ b/drivers/video/fbtft/Kconfig +@@ -0,0 +1,169 @@ ++menuconfig FB_TFT ++ tristate "Support for small TFT LCD display modules" ++ depends on FB && SPI && GPIOLIB ++ select FB_SYS_FILLRECT ++ select FB_SYS_COPYAREA ++ select FB_SYS_IMAGEBLIT ++ select FB_SYS_FOPS ++ select FB_DEFERRED_IO ++ select FB_BACKLIGHT ++ ++config FB_TFT_AGM1264K_FL ++ tristate "FB driver for the AGM1264K-FL LCD display" ++ depends on FB_TFT ++ help ++ Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatable chips) ++ ++config FB_TFT_BD663474 ++ tristate "FB driver for the BD663474 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for BD663474 ++ ++config FB_TFT_HX8340BN ++ tristate "FB driver for the HX8340BN LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for HX8340BN ++ ++config FB_TFT_HX8347D ++ tristate "FB driver for the HX8347D LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for HX8347D ++ ++config FB_TFT_HX8353D ++ tristate "FB driver for the HX8353D LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for HX8353D ++ ++config FB_TFT_ILI9320 ++ tristate "FB driver for the ILI9320 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9320 ++ ++config FB_TFT_ILI9325 ++ tristate "FB driver for the ILI9325 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9325 ++ ++config FB_TFT_ILI9340 ++ tristate "FB driver for the ILI9340 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9340 ++ ++config FB_TFT_ILI9341 ++ tristate "FB driver for the ILI9341 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9341 ++ ++config FB_TFT_ILI9481 ++ tristate "FB driver for the ILI9481 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9481 ++ ++config FB_TFT_ILI9486 ++ tristate "FB driver for the ILI9486 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9486 ++ ++config FB_TFT_PCD8544 ++ tristate "FB driver for the PCD8544 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for PCD8544 ++ ++config FB_TFT_RA8875 ++ tristate "FB driver for the RA8875 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for RA8875 ++ ++config FB_TFT_S6D02A1 ++ tristate "FB driver for the S6D02A1 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for S6D02A1 ++ ++config FB_TFT_S6D1121 ++ tristate "FB driver for the S6D1211 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for S6D1121 ++ ++config FB_TFT_SSD1289 ++ tristate "FB driver for the SSD1289 LCD Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1289 ++ ++config FB_TFT_SSD1306 ++ tristate "FB driver for the SSD1306 OLED Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1306 ++ ++config FB_TFT_SSD1331 ++ tristate "FB driver for the SSD1331 LCD Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1331 ++ ++config FB_TFT_SSD1351 ++ tristate "FB driver for the SSD1351 LCD Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1351 ++ ++config FB_TFT_ST7735R ++ tristate "FB driver for the ST7735R LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ST7735R ++ ++config FB_TFT_TINYLCD ++ tristate "FB driver for tinylcd.com display" ++ depends on FB_TFT ++ help ++ Custom Framebuffer support for tinylcd.com display ++ ++config FB_TFT_TLS8204 ++ tristate "FB driver for the TLS8204 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for TLS8204 ++ ++config FB_TFT_UC1701 ++ tristate "FB driver for the UC1701 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for UC1701 ++ ++config FB_TFT_UPD161704 ++ tristate "FB driver for the uPD161704 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for uPD161704 ++ ++config FB_TFT_WATTEROTT ++ tristate "FB driver for the WATTEROTT LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for WATTEROTT ++ ++config FB_FLEX ++ tristate "Generic FB driver for TFT LCD displays" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for TFT LCD displays. ++ ++config FB_TFT_FBTFT_DEVICE ++ tristate "Module to for adding FBTFT devices" ++ depends on FB_TFT +diff --git a/drivers/video/fbtft/Makefile b/drivers/video/fbtft/Makefile +new file mode 100644 +index 0000000..71c755d +--- /dev/null ++++ b/drivers/video/fbtft/Makefile +@@ -0,0 +1,60 @@ ++ifneq ($(KERNELRELEASE),) ++# kbuild part of makefile ++ ++# Optionally, include config file to allow out of tree kernel modules build ++-include $(src)/.config ++ ++# Core module ++obj-$(CONFIG_FB_TFT) += fbtft.o ++fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o ++ ++# drivers ++obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o ++obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o ++obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o ++obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o ++obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o ++obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o ++obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o ++obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o ++obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o ++obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o ++obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o ++obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o ++obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o ++obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o ++obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o ++obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o ++obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o ++obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o ++obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o ++obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o ++obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o ++obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o ++obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o ++obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o ++obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o ++obj-$(CONFIG_FB_FLEX) += flexfb.o ++ ++# Device modules ++obj-$(CONFIG_FB_TFT_FBTFT_DEVICE) += fbtft_device.o ++ ++else ++# normal makefile ++KDIR ?= /lib/modules/`uname -r`/build ++ ++default: .config ++ $(MAKE) -C $(KDIR) M=$$PWD modules ++ ++.config: ++ grep config Kconfig | cut -d' ' -f2 | sed 's@^@CONFIG_@; s@$$@=m@' > .config ++ ++install: ++ $(MAKE) -C $(KDIR) M=$$PWD modules_install ++ ++ ++clean: ++ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \ ++ modules.order Module.symvers ++ ++endif +diff --git a/drivers/video/fbtft/README b/drivers/video/fbtft/README +new file mode 100644 +index 0000000..9bebc98 +--- /dev/null ++++ b/drivers/video/fbtft/README +@@ -0,0 +1,37 @@ ++ FBTFT ++========= ++ ++2015-01-19 ++The FBTFT drivers are now in the Linux kernel staging tree: https://git.kernel.org/cgit/linux/kernel/git/gregkh/staging.git/tree/drivers/staging/fbtft?h=staging-testing ++Development in this github repo has ceased. ++ ++ ++Linux Framebuffer drivers for small TFT LCD display modules. ++The module 'fbtft' makes writing drivers for some of these displays very easy. ++ ++Development is done on a Raspberry Pi running the Raspbian "wheezy" distribution. ++ ++INSTALLATION ++ Download kernel sources ++ ++ From Linux 3.15 ++ cd drivers/video/fbdev ++ git clone https://github.com/notro/fbtft.git ++ ++ Add to drivers/video/fbdev/Kconfig: source "drivers/video/fbdev/fbtft/Kconfig" ++ Add to drivers/video/fbdev/Makefile: obj-y += fbtft/ ++ ++ Before Linux 3.15 ++ cd drivers/video ++ git clone https://github.com/notro/fbtft.git ++ ++ Add to drivers/video/Kconfig: source "drivers/video/fbtft/Kconfig" ++ Add to drivers/video/Makefile: obj-y += fbtft/ ++ ++ Enable driver(s) in menuconfig and build the kernel ++ ++ ++See wiki for more information: https://github.com/notro/fbtft/wiki ++ ++ ++Source: https://github.com/notro/fbtft/ +diff --git a/drivers/video/fbtft/dts/overlays/rpi/hy28a-overlay.dts b/drivers/video/fbtft/dts/overlays/rpi/hy28a-overlay.dts +new file mode 100644 +index 0000000..621497f +--- /dev/null ++++ b/drivers/video/fbtft/dts/overlays/rpi/hy28a-overlay.dts +@@ -0,0 +1,87 @@ ++/* ++ * Device Tree overlay for HY28A display shield by Texy ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ hy28a_pins: hy28a_pins { ++ brcm,pins = <17 25 18>; ++ brcm,function = <0 1 1>; /* in out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hy28a: hy28a@0{ ++ compatible = "ilitek,ili9320"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hy28a_pins>; ++ ++ spi-max-frequency = <32000000>; ++ spi-cpol; ++ spi-cpha; ++ rotate = <270>; ++ bgr; ++ fps = <50>; ++ buswidth = <8>; ++ startbyte = <0x70>; ++ reset-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ }; ++ ++ hy28a_ts: hy28a-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&hy28a>,"spi-max-frequency:0"; ++ rotate = <&hy28a>,"rotate:0"; ++ fps = <&hy28a>,"fps:0"; ++ debug = <&hy28a>,"debug:0"; ++ xohms = <&hy28a_ts>,"ti,x-plate-ohms;0"; ++ resetgpio = <&hy28a>,"reset-gpios:4", ++ <&hy28a_pins>, "brcm,pins:1"; ++ ledgpio = <&hy28a>,"led-gpios:4", ++ <&hy28a_pins>, "brcm,pins:2"; ++ }; ++}; +diff --git a/drivers/video/fbtft/dts/overlays/rpi/hy28b-overlay.dts b/drivers/video/fbtft/dts/overlays/rpi/hy28b-overlay.dts +new file mode 100644 +index 0000000..f774c4a +--- /dev/null ++++ b/drivers/video/fbtft/dts/overlays/rpi/hy28b-overlay.dts +@@ -0,0 +1,142 @@ ++/* ++ * Device Tree overlay for HY28b display shield by Texy ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ hy28b_pins: hy28b_pins { ++ brcm,pins = <17 25 18>; ++ brcm,function = <0 1 1>; /* in out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hy28b: hy28b@0{ ++ compatible = "ilitek,ili9325"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hy28b_pins>; ++ ++ spi-max-frequency = <48000000>; ++ spi-cpol; ++ spi-cpha; ++ rotate = <270>; ++ bgr; ++ fps = <50>; ++ buswidth = <8>; ++ startbyte = <0x70>; ++ reset-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 1>; ++ ++ gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7"; ++ ++ init = <0x10000e7 0x0010 ++ 0x1000000 0x0001 ++ 0x1000001 0x0100 ++ 0x1000002 0x0700 ++ 0x1000003 0x1030 ++ 0x1000004 0x0000 ++ 0x1000008 0x0207 ++ 0x1000009 0x0000 ++ 0x100000a 0x0000 ++ 0x100000c 0x0001 ++ 0x100000d 0x0000 ++ 0x100000f 0x0000 ++ 0x1000010 0x0000 ++ 0x1000011 0x0007 ++ 0x1000012 0x0000 ++ 0x1000013 0x0000 ++ 0x2000032 ++ 0x1000010 0x1590 ++ 0x1000011 0x0227 ++ 0x2000032 ++ 0x1000012 0x009c ++ 0x2000032 ++ 0x1000013 0x1900 ++ 0x1000029 0x0023 ++ 0x100002b 0x000e ++ 0x2000032 ++ 0x1000020 0x0000 ++ 0x1000021 0x0000 ++ 0x2000032 ++ 0x1000050 0x0000 ++ 0x1000051 0x00ef ++ 0x1000052 0x0000 ++ 0x1000053 0x013f ++ 0x1000060 0xa700 ++ 0x1000061 0x0001 ++ 0x100006a 0x0000 ++ 0x1000080 0x0000 ++ 0x1000081 0x0000 ++ 0x1000082 0x0000 ++ 0x1000083 0x0000 ++ 0x1000084 0x0000 ++ 0x1000085 0x0000 ++ 0x1000090 0x0010 ++ 0x1000092 0x0000 ++ 0x1000093 0x0003 ++ 0x1000095 0x0110 ++ 0x1000097 0x0000 ++ 0x1000098 0x0000 ++ 0x1000007 0x0133 ++ 0x1000020 0x0000 ++ 0x1000021 0x0000 ++ 0x2000064>; ++ debug = <0>; ++ }; ++ ++ hy28b_ts: hy28b-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&hy28b>,"spi-max-frequency:0"; ++ rotate = <&hy28b>,"rotate:0"; ++ fps = <&hy28b>,"fps:0"; ++ debug = <&hy28b>,"debug:0"; ++ xohms = <&hy28b_ts>,"ti,x-plate-ohms;0"; ++ resetgpio = <&hy28b>,"reset-gpios:4", ++ <&hy28b_pins>, "brcm,pins:1"; ++ ledgpio = <&hy28b>,"led-gpios:4", ++ <&hy28b_pins>, "brcm,pins:2"; ++ }; ++}; +diff --git a/drivers/video/fbtft/dts/overlays/rpi/mz61581-overlay.dts b/drivers/video/fbtft/dts/overlays/rpi/mz61581-overlay.dts +new file mode 100644 +index 0000000..c06fe12 +--- /dev/null ++++ b/drivers/video/fbtft/dts/overlays/rpi/mz61581-overlay.dts +@@ -0,0 +1,109 @@ ++/* ++ * Device Tree overlay for MZ61581-PI-EXT 2014.12.28 by Tontec ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ mz61581_pins: mz61581_pins { ++ brcm,pins = <4 15 18 25>; ++ brcm,function = <0 1 1 1>; /* in out out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ mz61581: mz61581@0{ ++ compatible = "samsung,s6d02a1"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mz61581_pins>; ++ ++ spi-max-frequency = <128000000>; ++ spi-cpol; ++ spi-cpha; ++ ++ width = <320>; ++ height = <480>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ ++ reset-gpios = <&gpio 15 0>; ++ dc-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 0>; ++ ++ init = <0x10000b0 00 ++ 0x1000011 ++ 0x20000ff ++ 0x10000b3 0x02 0x00 0x00 0x00 ++ 0x10000c0 0x13 0x3b 0x00 0x02 0x00 0x01 0x00 0x43 ++ 0x10000c1 0x08 0x16 0x08 0x08 ++ 0x10000c4 0x11 0x07 0x03 0x03 ++ 0x10000c6 0x00 ++ 0x10000c8 0x03 0x03 0x13 0x5c 0x03 0x07 0x14 0x08 0x00 0x21 0x08 0x14 0x07 0x53 0x0c 0x13 0x03 0x03 0x21 0x00 ++ 0x1000035 0x00 ++ 0x1000036 0xa0 ++ 0x100003a 0x55 ++ 0x1000044 0x00 0x01 ++ 0x10000d0 0x07 0x07 0x1d 0x03 ++ 0x10000d1 0x03 0x30 0x10 ++ 0x10000d2 0x03 0x14 0x04 ++ 0x1000029 ++ 0x100002c>; ++ ++ /* This is a workaround to make sure the init sequence slows down and doesn't fail */ ++ debug = <3>; ++ }; ++ ++ mz61581_ts: mz61581_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <4 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 4 0>; ++ ++ ti,x-plate-ohms = /bits/ 16 <60>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&mz61581>, "spi-max-frequency:0"; ++ rotate = <&mz61581>, "rotate:0"; ++ fps = <&mz61581>, "fps:0"; ++ debug = <&mz61581>, "debug:0"; ++ xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; ++ }; ++}; +diff --git a/drivers/video/fbtft/dts/overlays/rpi/piscreen-overlay.dts b/drivers/video/fbtft/dts/overlays/rpi/piscreen-overlay.dts +new file mode 100644 +index 0000000..8cd6a95 +--- /dev/null ++++ b/drivers/video/fbtft/dts/overlays/rpi/piscreen-overlay.dts +@@ -0,0 +1,94 @@ ++/* ++ * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ piscreen_pins: piscreen_pins { ++ brcm,pins = <17 25 24 22>; ++ brcm,function = <0 1 1 1>; /* in out out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ piscreen: piscreen@0{ ++ compatible = "ilitek,ili9486"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&piscreen_pins>; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ regwidth = <16>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 22 1>; ++ debug = <0>; ++ ++ init = <0x10000b0 0x00 ++ 0x1000011 ++ 0x20000ff ++ 0x100003a 0x55 ++ 0x1000036 0x28 ++ 0x10000c2 0x44 ++ 0x10000c5 0x00 0x00 0x00 0x00 ++ 0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00 ++ 0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 ++ 0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 ++ 0x1000011 ++ 0x1000029>; ++ }; ++ ++ piscreen-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&piscreen>,"spi-max-frequency:0"; ++ rotate = <&piscreen>,"rotate:0"; ++ fps = <&piscreen>,"fps:0"; ++ debug = <&piscreen>,"debug:0"; ++ }; ++}; +diff --git a/drivers/video/fbtft/dts/overlays/rpi/pitft28-resistive-overlay.dts b/drivers/video/fbtft/dts/overlays/rpi/pitft28-resistive-overlay.dts +new file mode 100644 +index 0000000..e8a9365 +--- /dev/null ++++ b/drivers/video/fbtft/dts/overlays/rpi/pitft28-resistive-overlay.dts +@@ -0,0 +1,115 @@ ++/* ++ * Device Tree overlay for pitft resistive by Adafruit ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ pitft_pins: pitft_pins { ++ brcm,pins = <24 25>; ++ brcm,function = <0 1>; /* in out */ ++ brcm,pull = <2 0>; /* pullup none */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pitft: pitft@0{ ++ compatible = "ilitek,ili9340"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pitft_pins>; ++ ++ spi-max-frequency = <16000000>; ++ rotate = <90>; ++ fps = <25>; ++ bgr; ++ buswidth = <8>; ++ dc-gpios = <&gpio 25 0>; ++ debug = <0>; ++ }; ++ ++ pitft_ts@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stmpe610"; ++ reg = <1>; ++ ++ spi-max-frequency = <500000>; ++ irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */ ++ interrupts = <24 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ interrupt-controller; ++ ++ stmpe_touchscreen { ++ compatible = "st,stmpe-ts"; ++ st,sample-time = <4>; ++ st,mod-12b = <1>; ++ st,ref-sel = <0>; ++ st,adc-freq = <2>; ++ st,ave-ctrl = <3>; ++ st,touch-det-delay = <4>; ++ st,settling = <2>; ++ st,fraction-z = <7>; ++ st,i-drive = <0>; ++ }; ++ ++ stmpe_gpio: stmpe_gpio { ++ #gpio-cells = <2>; ++ compatible = "st,stmpe-gpio"; ++ /* ++ * only GPIO2 is wired/available ++ * and it is wired to the backlight ++ */ ++ st,norequest-mask = <0x7b>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target-path = "/soc"; ++ __overlay__ { ++ backlight { ++ compatible = "gpio-backlight"; ++ gpios = <&stmpe_gpio 2 0>; ++ default-on; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&pitft>,"spi-max-frequency:0"; ++ rotate = <&pitft>,"rotate:0"; ++ fps = <&pitft>,"fps:0"; ++ debug = <&pitft>,"debug:0"; ++ }; ++}; +diff --git a/drivers/video/fbtft/dts/overlays/rpi/rpi-display-overlay.dts b/drivers/video/fbtft/dts/overlays/rpi/rpi-display-overlay.dts +new file mode 100644 +index 0000000..0578810 +--- /dev/null ++++ b/drivers/video/fbtft/dts/overlays/rpi/rpi-display-overlay.dts +@@ -0,0 +1,81 @@ ++/* ++ * Device Tree overlay for rpi-display by Watterott ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ rpi_display_pins: rpi_display_pins { ++ brcm,pins = <18 23 24 25>; ++ brcm,function = <1 1 1 0>; /* out out out in */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rpidisplay: rpi-display@0{ ++ compatible = "ilitek,ili9341"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rpi_display_pins>; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 23 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ }; ++ ++ rpidisplay_ts: rpi-display-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <25 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 25 0>; ++ ti,x-plate-ohms = /bits/ 16 <60>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&rpidisplay>,"spi-max-frequency:0"; ++ rotate = <&rpidisplay>,"rotate:0"; ++ fps = <&rpidisplay>,"fps:0"; ++ debug = <&rpidisplay>,"debug:0"; ++ xohms = <&rpidisplay_ts>,"ti,x-plate-ohms;0"; ++ }; ++}; +diff --git a/drivers/video/fbtft/dts/overlays/rpi/tinylcd35-overlay.dts b/drivers/video/fbtft/dts/overlays/rpi/tinylcd35-overlay.dts +new file mode 100644 +index 0000000..881d2eb +--- /dev/null ++++ b/drivers/video/fbtft/dts/overlays/rpi/tinylcd35-overlay.dts +@@ -0,0 +1,181 @@ ++/* ++ * tinylcd 3.5" display ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ tinylcd35_pins: tinylcd35_pins { ++ brcm,pins = <25 24 18>; ++ brcm,function = <1>; /* out */ ++ }; ++ tinylcd35_ts_pins: tinylcd35_ts_pins { ++ brcm,pins = <5>; ++ brcm,function = <0>; /* in */ ++ }; ++ keypad_pins: keypad_pins { ++ brcm,pins = <4 17 22 23 27>; ++ brcm,function = <0>; /* in */ ++ brcm,pull = <1>; /* down */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ tinylcd35: tinylcd35@0{ ++ compatible = "neosec,tinylcd"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&tinylcd35_pins>, ++ <&tinylcd35_ts_pins>; ++ ++ spi-max-frequency = <48000000>; ++ rotate = <270>; ++ fps = <20>; ++ bgr; ++ buswidth = <8>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ ++ init = <0x10000B0 0x80 ++ 0x10000C0 0x0A 0x0A ++ 0x10000C1 0x01 0x01 ++ 0x10000C2 0x33 ++ 0x10000C5 0x00 0x42 0x80 ++ 0x10000B1 0xD0 0x11 ++ 0x10000B4 0x02 ++ 0x10000B6 0x00 0x22 0x3B ++ 0x10000B7 0x07 ++ 0x1000036 0x58 ++ 0x10000F0 0x36 0xA5 0xD3 ++ 0x10000E5 0x80 ++ 0x10000E5 0x01 ++ 0x10000B3 0x00 ++ 0x10000E5 0x00 ++ 0x10000F0 0x36 0xA5 0x53 ++ 0x10000E0 0x00 0x35 0x33 0x00 0x00 0x00 0x00 0x35 0x33 0x00 0x00 0x00 ++ 0x100003A 0x55 ++ 0x1000011 ++ 0x2000001 ++ 0x1000029>; ++ }; ++ ++ tinylcd35_ts: tinylcd35_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ status = "disabled"; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <5 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 5 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pcf8563: pcf8563@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ /* ++ * Values for input event code is found under the ++ * 'Keys and buttons' heading in include/uapi/linux/input.h ++ */ ++ fragment@4 { ++ target-path = "/soc"; ++ __overlay__ { ++ keypad: keypad { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&keypad_pins>; ++ status = "disabled"; ++ autorepeat; ++ ++ button@17 { ++ label = "GPIO KEY_UP"; ++ linux,code = <103>; ++ gpios = <&gpio 17 0>; ++ }; ++ button@22 { ++ label = "GPIO KEY_DOWN"; ++ linux,code = <108>; ++ gpios = <&gpio 22 0>; ++ }; ++ button@27 { ++ label = "GPIO KEY_LEFT"; ++ linux,code = <105>; ++ gpios = <&gpio 27 0>; ++ }; ++ button@23 { ++ label = "GPIO KEY_RIGHT"; ++ linux,code = <106>; ++ gpios = <&gpio 23 0>; ++ }; ++ button@4 { ++ label = "GPIO KEY_ENTER"; ++ linux,code = <28>; ++ gpios = <&gpio 4 0>; ++ }; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&tinylcd35>,"spi-max-frequency:0"; ++ rotate = <&tinylcd35>,"rotate:0"; ++ fps = <&tinylcd35>,"fps:0"; ++ debug = <&tinylcd35>,"debug:0"; ++ touch = <&tinylcd35_ts>,"status"; ++ touchgpio = <&tinylcd35_ts_pins>,"brcm,pins:0", ++ <&tinylcd35_ts>,"interrupts:0", ++ <&tinylcd35_ts>,"pendown-gpio:4"; ++ xohms = <&tinylcd35_ts>,"ti,x-plate-ohms;0"; ++ rtc = <&i2c1>,"status", ++ <&pcf8563>,"status"; ++ keypad = <&keypad>,"status"; ++ }; ++}; +diff --git a/drivers/video/fbtft/dts/rpi.dts b/drivers/video/fbtft/dts/rpi.dts +new file mode 100644 +index 0000000..6c3ab6e +--- /dev/null ++++ b/drivers/video/fbtft/dts/rpi.dts +@@ -0,0 +1,414 @@ ++ ++/* ++ * FBTFT Device Tree part for the Raspberry Pi ++ * Add this file to the end of the *rpi-b.dts file ++ * ++ * Please keep it sorted alphabetically on display name ++ * ++ * Notes: ++ * - use ads7846 instead of tsc2046 to get module autoloading ++ * - use polarity 1 to drive backlight initially low (off): ++ * led-gpios = <&gpio 18 1>; ++ */ ++ ++&spi0 { ++ /* this is provided here to make it easy to enable SPI when editing this file */ ++// status = "okay"; ++}; ++ ++ ++ ++/* ++ * Texy ++ * 2.8" TFT + Touch Shield Board (320x240) HY28A ++ * ++ */ ++&spi0 { ++ hy28a@0{ ++ compatible = "ilitek,ili9320"; ++ reg = <0>; ++ status = "disabled"; ++ ++ spi-max-frequency = <32000000>; ++ spi-cpol; ++ spi-cpha; ++ rotate = <270>; ++ bgr; ++ fps = <50>; ++ buswidth = <8>; ++ startbyte = <0x70>; ++ reset-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ }; ++ ++ hy28a_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ status = "disabled"; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <3 17>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++}; ++ ++ ++ ++ ++/* ++ * Texy ++ * 2.8" TFT + Touch Shield Board (320x240) HY28B ++ * NOT TESTED ++ */ ++&spi0 { ++ hy28b@0{ ++ compatible = "ilitek,ili9325"; ++ reg = <0>; ++ status = "disabled"; ++ ++ spi-max-frequency = <48000000>; ++ rotate = <270>; ++ bgr; ++ fps = <50>; ++ buswidth = <8>; ++ startbyte = <0x70>; ++ reset-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 1>; ++ ++ gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7"; ++ ++ init = <0x10000e7 0x0010 ++ 0x1000000 0x0001 ++ 0x1000001 0x0100 ++ 0x1000002 0x0700 ++ 0x1000003 0x1030 ++ 0x1000004 0x0000 ++ 0x1000008 0x0207 ++ 0x1000009 0x0000 ++ 0x100000a 0x0000 ++ 0x100000c 0x0001 ++ 0x100000d 0x0000 ++ 0x100000f 0x0000 ++ 0x1000010 0x0000 ++ 0x1000011 0x0007 ++ 0x1000012 0x0000 ++ 0x1000013 0x0000 ++ 0x2000032 ++ 0x1000010 0x1590 ++ 0x1000011 0x0227 ++ 0x2000032 ++ 0x1000012 0x009c ++ 0x2000032 ++ 0x1000013 0x1900 ++ 0x1000029 0x0023 ++ 0x100002b 0x000e ++ 0x2000032 ++ 0x1000020 0x0000 ++ 0x1000021 0x0000 ++ 0x2000032 ++ 0x1000050 0x0000 ++ 0x1000051 0x00ef ++ 0x1000052 0x0000 ++ 0x1000053 0x013f ++ 0x1000060 0xa700 ++ 0x1000061 0x0001 ++ 0x100006a 0x0000 ++ 0x1000080 0x0000 ++ 0x1000081 0x0000 ++ 0x1000082 0x0000 ++ 0x1000083 0x0000 ++ 0x1000084 0x0000 ++ 0x1000085 0x0000 ++ 0x1000090 0x0010 ++ 0x1000092 0x0000 ++ 0x1000093 0x0003 ++ 0x1000095 0x0110 ++ 0x1000097 0x0000 ++ 0x1000098 0x0000 ++ 0x1000007 0x0133 ++ 0x1000020 0x0000 ++ 0x1000021 0x0000 ++ 0x2000064>; ++ debug = <0>; ++ }; ++ ++ hy28b_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ status = "disabled"; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <3 17>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++}; ++ ++ ++ ++ ++/* ++ * ITEAD ++ * ITDB02-2.8 ++ * ++ */ ++/ { ++ itdb28 { ++ compatible = "ilitek,ili9325"; ++ status = "disabled"; ++ ++ rotate = <0>; ++ bgr; ++ buswidth = <8>; ++ reset-gpios = <&gpio 17 0>; ++ dc-gpios = <&gpio 3 0>; ++ cs-gpios = <&gpio 27 0>; ++ wr-gpios = <&gpio 2 0>; ++ db-gpios = <&gpio 9 0>, ++ <&gpio 11 0>, ++ <&gpio 18 0>, ++ <&gpio 23 0>, ++ <&gpio 24 0>, ++ <&gpio 25 0>, ++ <&gpio 8 0>, ++ <&gpio 7 0>; ++ /* LED pin drives backlight directly. Use transistor (50mA) */ ++ /* led-gpios = <&gpio 4 1>; */ ++ debug = <0>; ++ }; ++}; ++ ++ ++ ++ ++/* ++ * Watterott ++ * RPi-Display - 2.8" Touch-Display (320x240) ++ * ++ */ ++&spi0 { ++ rpi-display@0{ ++ compatible = "ilitek,ili9341"; ++ reg = <0>; ++ status = "disabled"; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 23 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ }; ++ ++ rpi-display_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ status = "disabled"; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <3 25>; ++ pendown-gpio = <&gpio 25 0>; ++ ti,x-plate-ohms = /bits/ 16 <60>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++}; ++ ++ ++ ++ ++/* ++ * Ozzmaker ++ * PiScreen - 3.5" TFT touchscreen (480x320) ++ * ++ */ ++&spi0 { ++ piscreen@0{ ++ compatible = "ilitek,ili9486"; ++ reg = <0>; ++ status = "disabled"; ++ ++ spi-max-frequency = <20000000>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 22 1>; ++ ++ init = <0x10000b0 0x00 ++ 0x1000011 ++ 0x20000FF ++ 0x100003A 0x55 ++ 0x1000036 0x28 ++ 0x10000C2 0x44 ++ 0x10000C5 0x00 0x00 0x00 0x00 ++ 0x10000E0 0x0F 0x1F 0x1C 0x0C 0x0F 0x08 0x48 0x98 0x37 0x0A 0x13 0x04 0x11 0x0D 0x00 ++ 0x10000E1 0x0F 0x32 0x2E 0x0B 0x0D 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 ++ 0x10000E2 0x0F 0x32 0x2E 0x0B 0x0D 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 ++ 0x1000011 ++ 0X1000029>; ++ debug = <0>; ++ }; ++ ++ piscreen_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ status = "disabled"; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <3 17>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++}; ++ ++ ++ ++ ++/* ++ * Adafruit ++ * PiTFT Mini Kit - 320x240 2.8" TFT+Touchscreen for Raspberry Pi ++ * ++ * Couldn't get touch controller to work ++ */ ++ ++&gpio { ++ stmpets_pins: stmpets_pins { ++ brcm,pins = <24>; ++ brcm,function = <0>; /* gpio in */ ++ brcm,pull = <2>; /* pull up */ ++ }; ++}; ++ ++&spi0 { ++ pitft@0{ ++ compatible = "ilitek,ili9340"; ++ reg = <0>; ++ status = "disabled"; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <90>; ++ bgr; ++ buswidth = <8>; ++ dc-gpios = <&gpio 25 0>; ++ ++ init = <0x1000001 ++ 0x2000005 ++ 0x1000028 ++ 0x10000EF 0x03 0x80 0x02 ++ 0x10000CF 0x00 0xC1 0x30 ++ 0x10000ED 0x64 0x03 0x12 0x81 ++ 0x10000E8 0x85 0x00 0x78 ++ 0x10000CB 0x39 0x2C 0x00 0x34 0x02 ++ 0x10000F7 0x20 ++ 0x10000EA 0x00 0x00 ++ 0x10000C0 0x23 ++ 0x10000C1 0x10 ++ 0x10000C5 0x3e 0x28 ++ 0x10000C7 0x86 ++ 0x100003A 0x55 ++ 0x10000B1 0x00 0x18 ++ 0x10000B6 0x08 0x82 0x27 ++ 0x10000F2 0x00 ++ 0x1000026 0x01 ++ 0x10000E0 0x0F 0x31 0x2B 0x0C 0x0E 0x08 0x4E 0xF1 0x37 0x07 0x10 0x03 0x0E 0x09 0x00 ++ 0x10000E1 0x00 0x0E 0x14 0x03 0x11 0x07 0x31 0xC1 0x48 0x08 0x0F 0x0C 0x31 0x36 0x0F ++ 0x1000011 ++ 0x2000064 ++ 0x1000029 ++ 0x2000014>; ++ debug = <0>; ++ }; ++/* ++Touchscreen didn't work. I guess it has something to do with it being an interrupt controller. ++I have never tried this before with DT and ARCH_BCM2708. ++On ARCH_BCM2835 it should be OK, since the GPIO controller acts as an interrupt controller as well. ++(stmpe_device can't be used from 3.16, because irq_base can't be set anymore) ++ ++[ 8.889056] irq: irq_create_mapping(0xc3008800, 0xc2) ++[ 8.895698] irq: -> using domain @c3008800 ++[ 8.900796] irq: -> existing mapping on virq 194 ++[ 8.925048] stmpe-spi spi0.1: stmpe610 detected, chip id: 0x811 ++[ 8.936650] irq: Added domain (null) ++[ 8.941780] irq: irq_create_mapping(0xc1dc1a20, 0x0) ++[ 8.949047] irq: -> using domain @c1dc1a20 ++[ 8.954421] irq: -> virq allocation failed ++[ 8.959926] irq: irq_create_mapping(0xc1dc1a20, 0x1) ++[ 8.967366] irq: -> using domain @c1dc1a20 ++[ 8.972870] irq: -> virq allocation failed ++*/ ++ pitft_ts@1 { ++ compatible = "st,stmpe610"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ status = "disabled"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&stmpets_pins>; ++ ++ spi-max-frequency = <500000>; ++ interrupts = <3 24>; ++ interrupt-parent = <&intc>; ++ interrupt-controller; ++ ++ stmpe_touchscreen { ++ compatible = "st,stmpe-ts"; ++ st,sample-time = <4>; ++ st,mod-12b = <1>; ++ st,ref-sel = <0>; ++ st,adc-freq = <2>; ++ st,ave-ctrl = <3>; ++ st,touch-det-delay = <4>; ++ st,settling = <2>; ++ st,fraction-z = <7>; ++ st,i-drive = <0>; ++ }; ++ }; ++}; ++ ++ ++ ++ ++/* ++ * NeoSec LLC ++ * 3.5 inch TFT Display (320x480) ++ * ++ */ ++&spi0 { ++ tinylcd35@0{ ++ compatible = "neosec,tinylcd"; ++ reg = <0>; ++ status = "disabled"; ++ ++ spi-max-frequency = <48000000>; ++ rotate = <270>; ++ bgr; ++ fps = <50>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ }; ++ ++ tinylcd35@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ status = "disabled"; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <3 3>; ++ pendown-gpio = <&gpio 3 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++}; +diff --git a/drivers/video/fbtft/fb_agm1264k-fl.c b/drivers/video/fbtft/fb_agm1264k-fl.c +new file mode 100644 +index 0000000..7fe4fa0 +--- /dev/null ++++ b/drivers/video/fbtft/fb_agm1264k-fl.c +@@ -0,0 +1,462 @@ ++/* ++ * FB driver for Two KS0108 LCD controllers in AGM1264K-FL display ++ * ++ * Copyright (C) 2014 ololoshka2871 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++/* Uncomment text line to use negative image on display */ ++/*#define NEGATIVE*/ ++ ++#define WHITE 0xff ++#define BLACK 0 ++ ++#define DRVNAME "fb_agm1264k-fl" ++#define WIDTH 64 ++#define HEIGHT 64 ++#define TOTALWIDTH (WIDTH * 2) /* because 2 x ks0108 in one display */ ++#define FPS 20 ++ ++#define EPIN gpio.wr ++#define RS gpio.dc ++#define RW gpio.aux[2] ++#define CS0 gpio.aux[0] ++#define CS1 gpio.aux[1] ++ ++ ++/* diffusing error (“Floyd-Steinberg”) */ ++#define DIFFUSING_MATRIX_WIDTH 2 ++#define DIFFUSING_MATRIX_HEIGHT 2 ++ ++static const signed char ++diffusing_matrix[DIFFUSING_MATRIX_WIDTH][DIFFUSING_MATRIX_HEIGHT] = { ++ {-1, 3}, ++ {3, 2}, ++}; ++ ++static const unsigned char gamma_correction_table[] = { ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, ++1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, ++6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, ++13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, ++22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, ++33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 43, 44, 45, ++46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, ++62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 81, ++82, 83, 84, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 98, 99, 100, 102, ++103, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 119, 120, 121, ++123, 124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 141, 143, ++145, 146, 148, 149, 151, 153, 154, 156, 158, 159, 161, 163, 165, 166, ++168, 170, 172, 173, 175, 177, 179, 181, 182, 184, 186, 188, 190, 192, ++194, 196, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, ++221, 223, 225, 227, 229, 231, 234, 236, 238, 240, 242, 244, 246, 248, ++251, 253, 255 ++}; ++ ++static int init_display(struct fbtft_par *par) ++{ ++ u8 i; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ for (i = 0; i < 2; ++i) { ++ write_reg(par, i, 0x3f); /* display on */ ++ write_reg(par, i, 0x40); /* set x to 0 */ ++ write_reg(par, i, 0xb0); /* set page to 0 */ ++ write_reg(par, i, 0xc0); /* set start line to 0 */ ++ } ++ ++ return 0; ++} ++ ++void reset(struct fbtft_par *par) ++{ ++ if (par->gpio.reset == -1) ++ return; ++ ++ fbtft_dev_dbg(DEBUG_RESET, par, par->info->device, "%s()\n", __func__); ++ ++ gpio_set_value(par->gpio.reset, 0); ++ udelay(20); ++ gpio_set_value(par->gpio.reset, 1); ++ mdelay(120); ++} ++ ++/* Check if all necessary GPIOS defined */ ++static int verify_gpios(struct fbtft_par *par) ++{ ++ int i; ++ ++ fbtft_dev_dbg(DEBUG_VERIFY_GPIOS, par, par->info->device, ++ "%s()\n", __func__); ++ ++ if (par->EPIN < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'wr' (aka E) gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ for (i = 0; i < 8; ++i) { ++ if (par->gpio.db[i] < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'db[%i]' gpio. Aborting.\n", ++ i); ++ return -EINVAL; ++ } ++ } ++ if (par->CS0 < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'cs0' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (par->CS1 < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'cs1' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (par->RW < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'rw' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static unsigned long ++request_gpios_match(struct fbtft_par *par, const struct fbtft_gpio *gpio) ++{ ++ fbtft_dev_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, par->info->device, ++ "%s('%s')\n", __func__, gpio->name); ++ ++ if (strcasecmp(gpio->name, "wr") == 0) { ++ /* left ks0108 E pin */ ++ par->EPIN = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (strcasecmp(gpio->name, "cs0") == 0) { ++ /* left ks0108 controller pin */ ++ par->CS0 = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "cs1") == 0) { ++ /* right ks0108 controller pin */ ++ par->CS1 = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } ++ ++ /* if write (rw = 0) e(1->0) perform write */ ++ /* if read (rw = 1) e(0->1) set data on D0-7*/ ++ else if (strcasecmp(gpio->name, "rw") == 0) { ++ par->RW = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } ++ ++ return FBTFT_GPIO_NO_MATCH; ++} ++ ++/* This function oses to enter commands ++ * first byte - destination controller 0 or 1 ++ * folowing - commands ++ */ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = (u8 *)par->buf; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ buf[i] = (u8)va_arg(args, unsigned int); ++ ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, ++ par->info->device, u8, buf, len, "%s: ", __func__); ++ } ++ ++ va_start(args, len); ++ ++ *buf = (u8)va_arg(args, unsigned int); ++ ++ if (*buf > 1) { ++ va_end(args); ++ dev_err(par->info->device, "%s: Incorrect chip sellect request (%d)\n", ++ __func__, *buf); ++ return; ++ } ++ ++ /* select chip */ ++ if (*buf) { ++ /* cs1 */ ++ gpio_set_value(par->CS0, 1); ++ gpio_set_value(par->CS1, 0); ++ } else { ++ /* cs0 */ ++ gpio_set_value(par->CS0, 0); ++ gpio_set_value(par->CS1, 1); ++ } ++ ++ gpio_set_value(par->RS, 0); /* RS->0 (command mode) */ ++ len--; ++ ++ if (len) { ++ i = len; ++ while (i--) ++ *buf++ = (u8)va_arg(args, unsigned int); ++ ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8))); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", ++ __func__, ret); ++ return; ++ } ++ } ++ ++ va_end(args); ++} ++ ++static struct ++{ ++ int xs, ys_page, xe, ye_page; ++} addr_win; ++ ++/* save display writing zone */ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ addr_win.xs = xs; ++ addr_win.ys_page = ys / 8; ++ addr_win.xe = xe; ++ addr_win.ye_page = ye / 8; ++ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys_page=%d, xe=%d, ye_page=%d)\n", __func__, ++ addr_win.xs, addr_win.ys_page, addr_win.xe, addr_win.ye_page); ++} ++ ++static void ++construct_line_bitmap(struct fbtft_par *par, u8 *dest, signed short *src, ++ int xs, int xe, int y) ++{ ++ int x, i; ++ ++ for (x = xs; x < xe; ++x) { ++ u8 res = 0; ++ ++ for (i = 0; i < 8; i++) ++ if (src[(y * 8 + i) * par->info->var.xres + x]) ++ res |= 1 << i; ++#ifdef NEGATIVE ++ *dest++ = res; ++#else ++ *dest++ = ~res; ++#endif ++ } ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y; ++ int ret = 0; ++ ++ /* buffer to convert RGB565 -> grayscale16 -> Ditherd image 1bpp */ ++ signed short *convert_buf = kmalloc(par->info->var.xres * ++ par->info->var.yres * sizeof(signed short), GFP_NOIO); ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ /* converting to grayscale16 */ ++ for (x = 0; x < par->info->var.xres; ++x) ++ for (y = 0; y < par->info->var.yres; ++y) { ++ u16 pixel = vmem16[y * par->info->var.xres + x]; ++ u16 b = pixel & 0x1f; ++ u16 g = (pixel & (0x3f << 5)) >> 5; ++ u16 r = (pixel & (0x1f << (5 + 6))) >> (5 + 6); ++ ++ pixel = (299 * r + 587 * g + 114 * b) / 200; ++ if (pixel > 255) ++ pixel = 255; ++ ++ /* gamma-correction by table */ ++ convert_buf[y * par->info->var.xres + x] = ++ (signed short)gamma_correction_table[pixel]; ++ } ++ ++ /* Image Dithering */ ++ for (x = 0; x < par->info->var.xres; ++x) ++ for (y = 0; y < par->info->var.yres; ++y) { ++ signed short pixel = ++ convert_buf[y * par->info->var.xres + x]; ++ signed short error_b = pixel - BLACK; ++ signed short error_w = pixel - WHITE; ++ signed short error; ++ u16 i, j; ++ ++ /* what color close? */ ++ if (abs(error_b) >= abs(error_w)) { ++ /* white */ ++ error = error_w; ++ pixel = 0xff; ++ } else { ++ /* black */ ++ error = error_b; ++ pixel = 0; ++ } ++ ++ error /= 8; ++ ++ /* diffusion matrix row */ ++ for (i = 0; i < DIFFUSING_MATRIX_WIDTH; ++i) ++ /* diffusion matrix column */ ++ for (j = 0; j < DIFFUSING_MATRIX_HEIGHT; ++j) { ++ signed short *write_pos; ++ signed char coeff; ++ ++ /* skip pixels out of zone */ ++ if (x + i < 0 || ++ x + i >= par->info->var.xres ++ || y + j >= par->info->var.yres) ++ continue; ++ write_pos = &convert_buf[ ++ (y + j) * par->info->var.xres + ++ x + i]; ++ coeff = diffusing_matrix[i][j]; ++ if (coeff == -1) ++ /* pixel itself */ ++ *write_pos = pixel; ++ else { ++ signed short p = *write_pos + ++ error * coeff; ++ ++ if (p > WHITE) ++ p = WHITE; ++ if (p < BLACK) ++ p = BLACK; ++ *write_pos = p; ++ } ++ } ++ } ++ ++ /* 1 string = 2 pages */ ++ for (y = addr_win.ys_page; y <= addr_win.ye_page; ++y) { ++ /* left half of display */ ++ if (addr_win.xs < par->info->var.xres / 2) { ++ construct_line_bitmap(par, buf, convert_buf, ++ addr_win.xs, par->info->var.xres / 2, y); ++ ++ len = par->info->var.xres / 2 - addr_win.xs; ++ ++ /* select left side (sc0) ++ * set addr ++ */ ++ write_reg(par, 0x00, (1 << 6) | (u8)addr_win.xs); ++ write_reg(par, 0x00, (0x17 << 3) | (u8)y); ++ ++ /* write bitmap */ ++ gpio_set_value(par->RS, 1); /* RS->1 (data mode) */ ++ ret = par->fbtftops.write(par, buf, len); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", ++ __func__, ret); ++ } ++ /* right half of display */ ++ if (addr_win.xe >= par->info->var.xres / 2) { ++ construct_line_bitmap(par, buf, ++ convert_buf, par->info->var.xres / 2, ++ addr_win.xe + 1, y); ++ ++ len = addr_win.xe + 1 - par->info->var.xres / 2; ++ ++ /* select right side (sc1) ++ * set addr ++ */ ++ write_reg(par, 0x01, (1 << 6)); ++ write_reg(par, 0x01, (0x17 << 3) | (u8)y); ++ ++ /* write bitmap */ ++ gpio_set_value(par->RS, 1); /* RS->1 (data mode) */ ++ par->fbtftops.write(par, buf, len); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", ++ __func__, ret); ++ } ++ } ++ kfree(convert_buf); ++ ++ gpio_set_value(par->CS0, 1); ++ gpio_set_value(par->CS1, 1); ++ ++ return ret; ++} ++ ++static int write(struct fbtft_par *par, void *buf, size_t len) ++{ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ gpio_set_value(par->RW, 0); /* set write mode */ ++ ++ ++ while (len--) { ++ u8 i, data; ++ ++ data = *(u8 *) buf++; ++ ++ /* set data bus */ ++ for (i = 0; i < 8; ++i) ++ gpio_set_value(par->gpio.db[i], data & (1 << i)); ++ /* set E */ ++ gpio_set_value(par->EPIN, 1); ++ udelay(5); ++ /* unset E - write */ ++ gpio_set_value(par->EPIN, 0); ++ udelay(1); ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = TOTALWIDTH, ++ .height = HEIGHT, ++ .fps = FPS, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .verify_gpios = verify_gpios, ++ .request_gpios_match = request_gpios_match, ++ .reset = reset, ++ .write = write, ++ .write_register = write_reg8_bus8, ++ .write_vmem = write_vmem, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "displaytronic,fb_agm1264k-fl", &display); ++ ++MODULE_ALIAS("platform:" DRVNAME); ++ ++MODULE_DESCRIPTION("Two KS0108 LCD controllers in AGM1264K-FL display"); ++MODULE_AUTHOR("ololoshka2871"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_bd663474.c b/drivers/video/fbtft/fb_bd663474.c +new file mode 100644 +index 0000000..7e00c60 +--- /dev/null ++++ b/drivers/video/fbtft/fb_bd663474.c +@@ -0,0 +1,193 @@ ++/* ++ * FB driver for the uPD161704 LCD Controller ++ * ++ * Copyright (C) 2014 Seong-Woo Kim ++ * ++ * Based on fb_ili9325.c by Noralf Tronnes ++ * Based on ili9325.c by Jeroen Domburg ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_bd663474" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ par->fbtftops.reset(par); ++ ++ /* Initialization sequence from Lib_UTFT */ ++ ++ /* oscillator start */ ++ write_reg(par, 0x000,0x0001); /*oscillator 0: stop, 1: operation */ ++ mdelay(10); ++ ++ /* Power settings */ ++ write_reg(par, 0x100, 0x0000 ); /* power supply setup */ ++ write_reg(par, 0x101, 0x0000 ); ++ write_reg(par, 0x102, 0x3110 ); ++ write_reg(par, 0x103, 0xe200 ); ++ write_reg(par, 0x110, 0x009d ); ++ write_reg(par, 0x111, 0x0022 ); ++ write_reg(par, 0x100, 0x0120 ); ++ mdelay( 20 ); ++ ++ write_reg(par, 0x100, 0x3120 ); ++ mdelay( 80 ); ++ /* Display control */ ++ write_reg(par, 0x001, 0x0100 ); ++ write_reg(par, 0x002, 0x0000 ); ++ write_reg(par, 0x003, 0x1230 ); ++ write_reg(par, 0x006, 0x0000 ); ++ write_reg(par, 0x007, 0x0101 ); ++ write_reg(par, 0x008, 0x0808 ); ++ write_reg(par, 0x009, 0x0000 ); ++ write_reg(par, 0x00b, 0x0000 ); ++ write_reg(par, 0x00c, 0x0000 ); ++ write_reg(par, 0x00d, 0x0018 ); ++ /* LTPS control settings */ ++ write_reg(par, 0x012, 0x0000 ); ++ write_reg(par, 0x013, 0x0000 ); ++ write_reg(par, 0x018, 0x0000 ); ++ write_reg(par, 0x019, 0x0000 ); ++ ++ write_reg(par, 0x203, 0x0000 ); ++ write_reg(par, 0x204, 0x0000 ); ++ ++ write_reg(par, 0x210, 0x0000 ); ++ write_reg(par, 0x211, 0x00ef ); ++ write_reg(par, 0x212, 0x0000 ); ++ write_reg(par, 0x213, 0x013f ); ++ write_reg(par, 0x214, 0x0000 ); ++ write_reg(par, 0x215, 0x0000 ); ++ write_reg(par, 0x216, 0x0000 ); ++ write_reg(par, 0x217, 0x0000 ); ++ ++ /* Gray scale settings */ ++ write_reg(par, 0x300, 0x5343); ++ write_reg(par, 0x301, 0x1021); ++ write_reg(par, 0x302, 0x0003); ++ write_reg(par, 0x303, 0x0011); ++ write_reg(par, 0x304, 0x050a); ++ write_reg(par, 0x305, 0x4342); ++ write_reg(par, 0x306, 0x1100); ++ write_reg(par, 0x307, 0x0003); ++ write_reg(par, 0x308, 0x1201); ++ write_reg(par, 0x309, 0x050a); ++ ++ /* RAM access settings */ ++ write_reg(par, 0x400, 0x4027 ); ++ write_reg(par, 0x401, 0x0000 ); ++ write_reg(par, 0x402, 0x0000 ); /* First screen drive position (1) */ ++ write_reg(par, 0x403, 0x013f ); /* First screen drive position (2) */ ++ write_reg(par, 0x404, 0x0000 ); ++ ++ write_reg(par, 0x200, 0x0000 ); ++ write_reg(par, 0x201, 0x0000 ); ++ write_reg(par, 0x100, 0x7120 ); ++ write_reg(par, 0x007, 0x0103 ); ++ mdelay( 10 ); ++ write_reg(par, 0x007, 0x0113 ); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R200h = Horizontal GRAM Start Address */ ++ /* R201h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0200, xs); ++ write_reg(par, 0x0201, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0200, WIDTH - 1 - xs); ++ write_reg(par, 0x0201, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0200, WIDTH - 1 - ys); ++ write_reg(par, 0x0201, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0200, ys); ++ write_reg(par, 0x0201, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x202); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x003, 0x1230); ++ break; ++ case 180: ++ write_reg(par, 0x003, 0x1200); ++ break; ++ case 270: ++ write_reg(par, 0x003, 0x1228); ++ break; ++ case 90: ++ write_reg(par, 0x003, 0x1218); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .bpp = BPP, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "hitachi,bd663474", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:bd663474"); ++MODULE_ALIAS("platform:bd663474"); ++ ++MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller"); ++MODULE_AUTHOR("Seong-Woo Kim"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_hx8340bn.c b/drivers/video/fbtft/fb_hx8340bn.c +new file mode 100644 +index 0000000..3939502 +--- /dev/null ++++ b/drivers/video/fbtft/fb_hx8340bn.c +@@ -0,0 +1,229 @@ ++/* ++ * FB driver for the HX8340BN LCD Controller ++ * ++ * This display uses 9-bit SPI: Data/Command bit + 8 data bits ++ * For platforms that doesn't support 9-bit, the driver is capable ++ * of emulating this using 8-bit transfer. ++ * This is done by transfering eight 9-bit words in 9 bytes. ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_hx8340bn" ++#define WIDTH 176 ++#define HEIGHT 220 ++#define TXBUFLEN (4 * PAGE_SIZE) ++#define DEFAULT_GAMMA "1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \ ++ "3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 " ++ ++ ++static bool emulate; ++module_param(emulate, bool, 0); ++MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode"); ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* BTL221722-276L startup sequence, from datasheet */ ++ ++ /* SETEXTCOM: Set extended command set (C1h) ++ This command is used to set extended command set access enable. ++ Enable: After command (C1h), must write: ffh,83h,40h */ ++ write_reg(par, 0xC1, 0xFF, 0x83, 0x40); ++ ++ /* Sleep out ++ This command turns off sleep mode. ++ In this mode the DC/DC converter is enabled, Internal oscillator ++ is started, and panel scanning is started. */ ++ write_reg(par, 0x11); ++ mdelay(150); ++ ++ /* Undoc'd register? */ ++ write_reg(par, 0xCA, 0x70, 0x00, 0xD9); ++ ++ /* SETOSC: Set Internal Oscillator (B0h) ++ This command is used to set internal oscillator related settings */ ++ /* OSC_EN: Enable internal oscillator */ ++ /* Internal oscillator frequency: 125% x 2.52MHz */ ++ write_reg(par, 0xB0, 0x01, 0x11); ++ ++ /* Drive ability setting */ ++ write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06); ++ mdelay(20); ++ ++ /* SETPWCTR5: Set Power Control 5(B5h) ++ This command is used to set VCOM Low and VCOM High Voltage */ ++ /* VCOMH 0110101 : 3.925 */ ++ /* VCOML 0100000 : -1.700 */ ++ /* 45h=69 VCOMH: "VMH" + 5d VCOML: "VMH" + 5d */ ++ write_reg(par, 0xB5, 0x35, 0x20, 0x45); ++ ++ /* SETPWCTR4: Set Power Control 4(B4h) ++ VRH[4:0]: Specify the VREG1 voltage adjusting. ++ VREG1 voltage is for gamma voltage setting. ++ BT[2:0]: Switch the output factor of step-up circuit 2 ++ for VGH and VGL voltage generation. */ ++ write_reg(par, 0xB4, 0x33, 0x25, 0x4C); ++ mdelay(10); ++ ++ /* Interface Pixel Format (3Ah) ++ This command is used to define the format of RGB picture data, ++ which is to be transfer via the system and RGB interface. */ ++ /* RGB interface: 16 Bit/Pixel */ ++ write_reg(par, 0x3A, 0x05); ++ ++ /* Display on (29h) ++ This command is used to recover from DISPLAY OFF mode. ++ Output from the Frame Memory is enabled. */ ++ write_reg(par, 0x29); ++ mdelay(10); ++ ++ return 0; ++} ++ ++void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, FBTFT_CASET, 0x00, xs, 0x00, xe); ++ write_reg(par, FBTFT_RASET, 0x00, ys, 0x00, ye); ++ write_reg(par, FBTFT_RAMWR); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* MADCTL - Memory data access control */ ++ /* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */ ++#define MY (1 << 7) ++#define MX (1 << 6) ++#define MV (1 << 5) ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, MX | MV | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, MX | MY | (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, MY | MV | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma Curve selection, GC (only GC0 can be customized): ++ 0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0 ++ Gamma string format: ++ OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1 ++ ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX GC ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b11, 0b11, ++ 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b0, 0b0 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ for (j = 0; j < par->gamma.num_values; j++) ++ CURVE(i, j) &= mask[i * par->gamma.num_values + j]; ++ ++ write_reg(par, 0x26, 1 << CURVE(1, 14)); /* Gamma Set (26h) */ ++ ++ if (CURVE(1, 14)) ++ return 0; /* only GC0 can be customized */ ++ ++ write_reg(par, 0xC2, ++ (CURVE(0, 8) << 4) | CURVE(0, 7), ++ (CURVE(0, 10) << 4) | CURVE(0, 9), ++ (CURVE(0, 12) << 4) | CURVE(0, 11), ++ CURVE(0, 2), ++ (CURVE(0, 4) << 4) | CURVE(0, 3), ++ CURVE(0, 5), ++ CURVE(0, 6), ++ (CURVE(0, 1) << 4) | CURVE(0, 0), ++ (CURVE(0, 14) << 2) | CURVE(0, 13)); ++ ++ write_reg(par, 0xC3, ++ (CURVE(1, 8) << 4) | CURVE(1, 7), ++ (CURVE(1, 10) << 4) | CURVE(1, 9), ++ (CURVE(1, 12) << 4) | CURVE(1, 11), ++ CURVE(1, 2), ++ (CURVE(1, 4) << 4) | CURVE(1, 3), ++ CURVE(1, 5), ++ CURVE(1, 6), ++ (CURVE(1, 1) << 4) | CURVE(1, 0)); ++ ++ mdelay(10); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 2, ++ .gamma_len = 15, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:hx8340bn"); ++MODULE_ALIAS("platform:hx8340bn"); ++ ++MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_hx8347d.c b/drivers/video/fbtft/fb_hx8347d.c +new file mode 100644 +index 0000000..8139a8f +--- /dev/null ++++ b/drivers/video/fbtft/fb_hx8347d.c +@@ -0,0 +1,181 @@ ++/* ++ * FB driver for the HX8347D LCD Controller ++ * ++ * Copyright (C) 2013 Christian Vogelgsang ++ * ++ * Based on driver code found here: https://github.com/watterott/r61505u-Adapter ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_hx8347d" ++#define WIDTH 320 ++#define HEIGHT 240 ++#define DEFAULT_GAMMA "0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" \ ++ "0 0 0 0 0 0 0 0 0 0 0 0 0 0" ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* driving ability */ ++ write_reg(par, 0xEA, 0x00); ++ write_reg(par, 0xEB, 0x20); ++ write_reg(par, 0xEC, 0x0C); ++ write_reg(par, 0xED, 0xC4); ++ write_reg(par, 0xE8, 0x40); ++ write_reg(par, 0xE9, 0x38); ++ write_reg(par, 0xF1, 0x01); ++ write_reg(par, 0xF2, 0x10); ++ write_reg(par, 0x27, 0xA3); ++ ++ /* power voltage */ ++ write_reg(par, 0x1B, 0x1B); ++ write_reg(par, 0x1A, 0x01); ++ write_reg(par, 0x24, 0x2F); ++ write_reg(par, 0x25, 0x57); ++ ++ /* VCOM offset */ ++ write_reg(par, 0x23, 0x8D); /* for flicker adjust */ ++ ++ /* power on */ ++ write_reg(par, 0x18, 0x36); ++ write_reg(par, 0x19, 0x01); /* start osc */ ++ write_reg(par, 0x01, 0x00); /* wakeup */ ++ write_reg(par, 0x1F, 0x88); ++ mdelay(5); ++ write_reg(par, 0x1F, 0x80); ++ mdelay(5); ++ write_reg(par, 0x1F, 0x90); ++ mdelay(5); ++ write_reg(par, 0x1F, 0xD0); ++ mdelay(5); ++ ++ /* color selection */ ++ write_reg(par, 0x17, 0x05); /* 65k */ ++ ++ /*panel characteristic */ ++ write_reg(par, 0x36, 0x00); ++ ++ /*display on */ ++ write_reg(par, 0x28, 0x38); ++ mdelay(40); ++ write_reg(par, 0x28, 0x3C); ++ ++ /* orientation */ ++ write_reg(par, 0x16, 0x60 | (par->bgr << 3)); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x02, (xs >> 8) & 0xFF); ++ write_reg(par, 0x03, xs & 0xFF); ++ write_reg(par, 0x04, (xe >> 8) & 0xFF); ++ write_reg(par, 0x05, xe & 0xFF); ++ write_reg(par, 0x06, (ys >> 8) & 0xFF); ++ write_reg(par, 0x07, ys & 0xFF); ++ write_reg(par, 0x08, (ye >> 8) & 0xFF); ++ write_reg(par, 0x09, ye & 0xFF); ++ write_reg(par, 0x22); ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 VRP2 VRP3 VRP4 VRP5 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 CGM ++ VRN0 VRN1 VRN2 VRN3 VRN4 VRN5 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 CGM ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b1111111, 0b1111111, ++ 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, ++ 0b1111}; ++ int i, j; ++ int acc = 0; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ for (j = 0; j < par->gamma.num_values; j++) { ++ acc += CURVE(i, j); ++ CURVE(i, j) &= mask[j]; ++ } ++ ++ if (acc == 0) /* skip if all values are zero */ ++ return 0; ++ ++ for (i = 0; i < par->gamma.num_curves; i++) { ++ write_reg(par, 0x40 + (i * 0x10), CURVE(i, 0)); ++ write_reg(par, 0x41 + (i * 0x10), CURVE(i, 1)); ++ write_reg(par, 0x42 + (i * 0x10), CURVE(i, 2)); ++ write_reg(par, 0x43 + (i * 0x10), CURVE(i, 3)); ++ write_reg(par, 0x44 + (i * 0x10), CURVE(i, 4)); ++ write_reg(par, 0x45 + (i * 0x10), CURVE(i, 5)); ++ write_reg(par, 0x46 + (i * 0x10), CURVE(i, 6)); ++ write_reg(par, 0x47 + (i * 0x10), CURVE(i, 7)); ++ write_reg(par, 0x48 + (i * 0x10), CURVE(i, 8)); ++ write_reg(par, 0x49 + (i * 0x10), CURVE(i, 9)); ++ write_reg(par, 0x4A + (i * 0x10), CURVE(i, 10)); ++ write_reg(par, 0x4B + (i * 0x10), CURVE(i, 11)); ++ write_reg(par, 0x4C + (i * 0x10), CURVE(i, 12)); ++ } ++ write_reg(par, 0x5D, (CURVE(1, 0) << 4) | CURVE(0, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 2, ++ .gamma_len = 14, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8347d", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:hx8347d"); ++MODULE_ALIAS("platform:hx8347d"); ++ ++MODULE_DESCRIPTION("FB driver for the HX8347D LCD Controller"); ++MODULE_AUTHOR("Christian Vogelgsang"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_hx8353d.c b/drivers/video/fbtft/fb_hx8353d.c +new file mode 100644 +index 0000000..c9512dc +--- /dev/null ++++ b/drivers/video/fbtft/fb_hx8353d.c +@@ -0,0 +1,166 @@ ++/* ++ * FB driver for the HX8353D LCD Controller ++ * ++ * Copyright (c) 2014 Petr Olivka ++ * Copyright (c) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_hx8353d" ++#define DEFAULT_GAMMA "50 77 40 08 BF 00 03 0F 00 01 73 00 72 03 B0 0F 08 00 0F" ++ ++static int init_display(struct fbtft_par *par) ++{ ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ mdelay(150); ++ ++ /* SETEXTC */ ++ write_reg(par, 0xB9, 0xFF, 0x83, 0x53); ++ ++ /* RADJ */ ++ write_reg(par, 0xB0, 0x3C, 0x01); ++ ++ /* VCOM */ ++ write_reg(par, 0xB6, 0x94, 0x6C, 0x50); ++ ++ /* PWR */ ++ write_reg(par, 0xB1, 0x00, 0x01, 0x1B, 0x03, 0x01, 0x08, 0x77, 0x89); ++ ++ /* COLMOD */ ++ write_reg(par, 0x3A, 0x05); ++ ++ /* MEM ACCESS */ ++ write_reg(par, 0x36, 0xC0); ++ ++ /* SLPOUT - Sleep out & booster on */ ++ write_reg(par, 0x11); ++ mdelay(150); ++ ++ /* DISPON - Display On */ ++ write_reg(par, 0x29); ++ ++ /* RGBSET */ ++ write_reg(par, 0x2D, ++ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, ++ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, ++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ++ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ++ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, ++ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, ++ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62); ++ ++ return 0; ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* column address */ ++ write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff); ++ ++ /* row adress */ ++ write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff); ++ ++ /* memory write */ ++ write_reg(par, 0x2c); ++} ++ ++#define my (1 << 7) ++#define mx (1 << 6) ++#define mv (1 << 5) ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* madctl - memory data access control ++ rgb/bgr: ++ 1. mode selection pin srgb ++ rgb h/w pin for color filter setting: 0=rgb, 1=bgr ++ 2. madctl rgb bit ++ rgb-bgr order color filter panel: 0=rgb, 1=bgr */ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, mx | my | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, my | mv | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, mx | mv | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ gamma string format: ++*/ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ write_reg(par, 0xE0, ++ curves[0], curves[1], curves[2], curves[3], ++ curves[4], curves[5], curves[6], curves[7], ++ curves[8], curves[9], curves[10], curves[11], ++ curves[12], curves[13], curves[14], curves[15], ++ curves[16], curves[17], curves[18]); ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = 128, ++ .height = 160, ++ .gamma_num = 1, ++ .gamma_len = 19, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8353d", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:hx8353d"); ++MODULE_ALIAS("platform:hx8353d"); ++ ++MODULE_DESCRIPTION("FB driver for the HX8353D LCD Controller"); ++MODULE_AUTHOR("Petr Olivka"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ili9320.c b/drivers/video/fbtft/fb_ili9320.c +new file mode 100644 +index 0000000..b26d893 +--- /dev/null ++++ b/drivers/video/fbtft/fb_ili9320.c +@@ -0,0 +1,234 @@ ++/* ++ * FB driver for the ILI9320 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9320" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define DEFAULT_GAMMA "07 07 6 0 0 0 5 5 4 0\n" \ ++ "07 08 4 7 5 1 2 0 7 7" ++ ++ ++static unsigned read_devicecode(struct fbtft_par *par) ++{ ++ int ret; ++ u8 rxbuf[8] = {0, }; ++ ++ write_reg(par, 0x0000); ++ ret = par->fbtftops.read(par, rxbuf, 4); ++ return (rxbuf[2] << 8) | rxbuf[3]; ++} ++ ++static int init_display(struct fbtft_par *par) ++{ ++ unsigned devcode; ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ devcode = read_devicecode(par); ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Device code: 0x%04X\n", ++ devcode); ++ if ((devcode != 0x0000) && (devcode != 0x9320)) ++ dev_warn(par->info->device, ++ "Unrecognized Device code: 0x%04X (expected 0x9320)\n", ++ devcode); ++ ++ /* Initialization sequence from ILI9320 Application Notes */ ++ ++ /* *********** Start Initial Sequence ********* */ ++ write_reg(par, 0x00E5, 0x8000); /* Set the Vcore voltage and this setting is must. */ ++ write_reg(par, 0x0000, 0x0001); /* Start internal OSC. */ ++ write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */ ++ write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */ ++ write_reg(par, 0x0004, 0x0000); /* Resize register */ ++ write_reg(par, 0x0008, 0x0202); /* set the back and front porch */ ++ write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */ ++ write_reg(par, 0x000A, 0x0000); /* FMARK function */ ++ write_reg(par, 0x000C, 0x0000); /* RGB interface setting */ ++ write_reg(par, 0x000D, 0x0000); /* Frame marker Position */ ++ write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */ ++ ++ /* ***********Power On sequence *************** */ ++ write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */ ++ write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */ ++ write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ ++ mdelay(200); /* Dis-charge capacitor power voltage */ ++ write_reg(par, 0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ write_reg(par, 0x0011, 0x0031); /* R11h=0x0031 at VCI=3.3V DC1[2:0], DC0[2:0], VC[2:0] */ ++ mdelay(50); ++ write_reg(par, 0x0012, 0x0138); /* R12h=0x0138 at VCI=3.3V VREG1OUT voltage */ ++ mdelay(50); ++ write_reg(par, 0x0013, 0x1800); /* R13h=0x1800 at VCI=3.3V VDV[4:0] for VCOM amplitude */ ++ write_reg(par, 0x0029, 0x0008); /* R29h=0x0008 at VCI=3.3V VCM[4:0] for VCOMH */ ++ mdelay(50); ++ write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */ ++ write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */ ++ ++ /* ------------------ Set GRAM area --------------- */ ++ write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */ ++ write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */ ++ write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0060, 0x2700); /* Gate Scan Line */ ++ write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */ ++ write_reg(par, 0x006A, 0x0000); /* set scrolling line */ ++ ++ /* -------------- Partial Display Control --------- */ ++ write_reg(par, 0x0080, 0x0000); ++ write_reg(par, 0x0081, 0x0000); ++ write_reg(par, 0x0082, 0x0000); ++ write_reg(par, 0x0083, 0x0000); ++ write_reg(par, 0x0084, 0x0000); ++ write_reg(par, 0x0085, 0x0000); ++ ++ /* -------------- Panel Control ------------------- */ ++ write_reg(par, 0x0090, 0x0010); ++ write_reg(par, 0x0092, 0x0000); ++ write_reg(par, 0x0093, 0x0003); ++ write_reg(par, 0x0095, 0x0110); ++ write_reg(par, 0x0097, 0x0000); ++ write_reg(par, 0x0098, 0x0000); ++ write_reg(par, 0x0007, 0x0173); /* 262K color and display ON */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, WIDTH - 1 - xs); ++ write_reg(par, 0x0021, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, WIDTH - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x30); ++ break; ++ case 270: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x28); ++ break; ++ case 180: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x00); ++ break; ++ case 90: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x18); ++ break; ++ } ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5 ++ VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 10; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); ++ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ ++ write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 2, ++ .gamma_len = 10, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9320", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9320"); ++MODULE_ALIAS("platform:ili9320"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9320 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ili9325.c b/drivers/video/fbtft/fb_ili9325.c +new file mode 100644 +index 0000000..5f88145 +--- /dev/null ++++ b/drivers/video/fbtft/fb_ili9325.c +@@ -0,0 +1,291 @@ ++/* ++ * FB driver for the ILI9325 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * Based on ili9325.c by Jeroen Domburg ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9325" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++#define FPS 20 ++#define DEFAULT_GAMMA "0F 00 7 2 0 0 6 5 4 1\n" \ ++ "04 16 2 7 6 3 2 1 7 7" ++ ++ ++static unsigned bt = 6; /* VGL=Vci*4 , VGH=Vci*4 */ ++module_param(bt, uint, 0); ++MODULE_PARM_DESC(bt, "Sets the factor used in the step-up circuits"); ++ ++static unsigned vc = 0b011; /* Vci1=Vci*0.80 */ ++module_param(vc, uint, 0); ++MODULE_PARM_DESC(vc, ++"Sets the ratio factor of Vci to generate the reference voltages Vci1"); ++ ++static unsigned vrh = 0b1101; /* VREG1OUT=Vci*1.85 */ ++module_param(vrh, uint, 0); ++MODULE_PARM_DESC(vrh, ++"Set the amplifying rate (1.6 ~ 1.9) of Vci applied to output the VREG1OUT"); ++ ++static unsigned vdv = 0b10010; /* VCOMH amplitude=VREG1OUT*0.98 */ ++module_param(vdv, uint, 0); ++MODULE_PARM_DESC(vdv, ++"Select the factor of VREG1OUT to set the amplitude of Vcom"); ++ ++static unsigned vcm = 0b001010; /* VCOMH=VREG1OUT*0.735 */ ++module_param(vcm, uint, 0); ++MODULE_PARM_DESC(vcm, "Set the internal VcomH voltage"); ++ ++ ++/* ++Verify that this configuration is within the Voltage limits ++ ++Display module configuration: Vcc = IOVcc = Vci = 3.3V ++ ++ Voltages ++---------- ++Vci = 3.3 ++Vci1 = Vci * 0.80 = 2.64 ++DDVDH = Vci1 * 2 = 5.28 ++VCL = -Vci1 = -2.64 ++VREG1OUT = Vci * 1.85 = 4.88 ++VCOMH = VREG1OUT * 0.735 = 3.59 ++VCOM amplitude = VREG1OUT * 0.98 = 4.79 ++VGH = Vci * 4 = 13.2 ++VGL = -Vci * 4 = -13.2 ++ ++ Limits ++-------- ++Power supplies ++1.65 < IOVcc < 3.30 => 1.65 < 3.3 < 3.30 ++2.40 < Vcc < 3.30 => 2.40 < 3.3 < 3.30 ++2.50 < Vci < 3.30 => 2.50 < 3.3 < 3.30 ++ ++Source/VCOM power supply voltage ++ 4.50 < DDVDH < 6.0 => 4.50 < 5.28 < 6.0 ++-3.0 < VCL < -2.0 => -3.0 < -2.64 < -2.0 ++VCI - VCL < 6.0 => 5.94 < 6.0 ++ ++Gate driver output voltage ++ 10 < VGH < 20 => 10 < 13.2 < 20 ++-15 < VGL < -5 => -15 < -13.2 < -5 ++VGH - VGL < 32 => 26.4 < 32 ++ ++VCOM driver output voltage ++VCOMH - VCOML < 6.0 => 4.79 < 6.0 ++*/ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ bt &= 0b111; ++ vc &= 0b111; ++ vrh &= 0b1111; ++ vdv &= 0b11111; ++ vcm &= 0b111111; ++ ++ /* Initialization sequence from ILI9325 Application Notes */ ++ ++ /* ----------- Start Initial Sequence ----------- */ ++ write_reg(par, 0x00E3, 0x3008); /* Set internal timing */ ++ write_reg(par, 0x00E7, 0x0012); /* Set internal timing */ ++ write_reg(par, 0x00EF, 0x1231); /* Set internal timing */ ++ write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */ ++ write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */ ++ write_reg(par, 0x0004, 0x0000); /* Resize register */ ++ write_reg(par, 0x0008, 0x0207); /* set the back porch and front porch */ ++ write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */ ++ write_reg(par, 0x000A, 0x0000); /* FMARK function */ ++ write_reg(par, 0x000C, 0x0000); /* RGB interface setting */ ++ write_reg(par, 0x000D, 0x0000); /* Frame marker Position */ ++ write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */ ++ ++ /* ----------- Power On sequence ----------- */ ++ write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */ ++ write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */ ++ write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ ++ mdelay(200); /* Dis-charge capacitor power voltage */ ++ write_reg(par, 0x0010, /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ (1 << 12) | (bt << 8) | (1 << 7) | (0b001 << 4)); ++ write_reg(par, 0x0011, 0x220 | vc); /* DC1[2:0], DC0[2:0], VC[2:0] */ ++ mdelay(50); /* Delay 50ms */ ++ write_reg(par, 0x0012, vrh); /* Internal reference voltage= Vci; */ ++ mdelay(50); /* Delay 50ms */ ++ write_reg(par, 0x0013, vdv << 8); /* Set VDV[4:0] for VCOM amplitude */ ++ write_reg(par, 0x0029, vcm); /* Set VCM[5:0] for VCOMH */ ++ write_reg(par, 0x002B, 0x000C); /* Set Frame Rate */ ++ mdelay(50); /* Delay 50ms */ ++ write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */ ++ write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */ ++ ++ /*------------------ Set GRAM area --------------- */ ++ write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */ ++ write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */ ++ write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0060, 0xA700); /* Gate Scan Line */ ++ write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */ ++ write_reg(par, 0x006A, 0x0000); /* set scrolling line */ ++ ++ /*-------------- Partial Display Control --------- */ ++ write_reg(par, 0x0080, 0x0000); ++ write_reg(par, 0x0081, 0x0000); ++ write_reg(par, 0x0082, 0x0000); ++ write_reg(par, 0x0083, 0x0000); ++ write_reg(par, 0x0084, 0x0000); ++ write_reg(par, 0x0085, 0x0000); ++ ++ /*-------------- Panel Control ------------------- */ ++ write_reg(par, 0x0090, 0x0010); ++ write_reg(par, 0x0092, 0x0600); ++ write_reg(par, 0x0007, 0x0133); /* 262K color and display ON */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, WIDTH - 1 - xs); ++ write_reg(par, 0x0021, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, WIDTH - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x03, 0x0030 | (par->bgr << 12)); ++ break; ++ case 180: ++ write_reg(par, 0x03, 0x0000 | (par->bgr << 12)); ++ break; ++ case 270: ++ write_reg(par, 0x03, 0x0028 | (par->bgr << 12)); ++ break; ++ case 90: ++ write_reg(par, 0x03, 0x0018 | (par->bgr << 12)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5 ++ VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 10; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); ++ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ ++ write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .bpp = BPP, ++ .fps = FPS, ++ .gamma_num = 2, ++ .gamma_len = 10, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9325", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9325"); ++MODULE_ALIAS("platform:ili9325"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9325 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ili9340.c b/drivers/video/fbtft/fb_ili9340.c +new file mode 100644 +index 0000000..985687d +--- /dev/null ++++ b/drivers/video/fbtft/fb_ili9340.c +@@ -0,0 +1,163 @@ ++/* ++ * FB driver for the ILI9340 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9340" ++#define WIDTH 240 ++#define HEIGHT 320 ++ ++ ++/* Init sequence taken from: Arduino Library for the Adafruit 2.2" display */ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xEF, 0x03, 0x80, 0x02); ++ write_reg(par, 0xCF, 0x00 , 0XC1 , 0X30); ++ write_reg(par, 0xED, 0x64 , 0x03 , 0X12 , 0X81); ++ write_reg(par, 0xE8, 0x85 , 0x00 , 0x78); ++ write_reg(par, 0xCB, 0x39 , 0x2C , 0x00 , 0x34 , 0x02); ++ write_reg(par, 0xF7, 0x20); ++ write_reg(par, 0xEA, 0x00 , 0x00); ++ ++ /* Power Control 1 */ ++ write_reg(par, 0xC0, 0x23); ++ ++ /* Power Control 2 */ ++ write_reg(par, 0xC1, 0x10); ++ ++ /* VCOM Control 1 */ ++ write_reg(par, 0xC5, 0x3e, 0x28); ++ ++ /* VCOM Control 2 */ ++ write_reg(par, 0xC7, 0x86); ++ ++ /* COLMOD: Pixel Format Set */ ++ /* 16 bits/pixel */ ++ write_reg(par, 0x3A, 0x55); ++ ++ /* Frame Rate Control */ ++ /* Division ratio = fosc, Frame Rate = 79Hz */ ++ write_reg(par, 0xB1, 0x00, 0x18); ++ ++ /* Display Function Control */ ++ write_reg(par, 0xB6, 0x08, 0x82, 0x27); ++ ++ /* Gamma Function Disable */ ++ write_reg(par, 0xF2, 0x00); ++ ++ /* Gamma curve selected */ ++ write_reg(par, 0x26, 0x01); ++ ++ /* Positive Gamma Correction */ ++ write_reg(par, 0xE0, ++ 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, ++ 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00); ++ ++ /* Negative Gamma Correction */ ++ write_reg(par, 0xE1, ++ 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, ++ 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F); ++ ++ /* Sleep OUT */ ++ write_reg(par, 0x11); ++ ++ mdelay(120); ++ ++ /* Display ON */ ++ write_reg(par, 0x29); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define ILI9340_MADCTL_MV 0x20 ++#define ILI9340_MADCTL_MX 0x40 ++#define ILI9340_MADCTL_MY 0x80 ++static int set_var(struct fbtft_par *par) ++{ ++ u8 val; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 270: ++ val = ILI9340_MADCTL_MV; ++ break; ++ case 180: ++ val = ILI9340_MADCTL_MY; ++ break; ++ case 90: ++ val = ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX; ++ break; ++ default: ++ val = ILI9340_MADCTL_MX; ++ break; ++ } ++ /* Memory Access Control */ ++ write_reg(par, 0x36, val | (par->bgr << 3)); ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9340", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9340"); ++MODULE_ALIAS("platform:ili9340"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9340 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ili9341.c b/drivers/video/fbtft/fb_ili9341.c +new file mode 100644 +index 0000000..225b2d8 +--- /dev/null ++++ b/drivers/video/fbtft/fb_ili9341.c +@@ -0,0 +1,179 @@ ++/* ++ * FB driver for the ILI9341 LCD display controller ++ * ++ * This display uses 9-bit SPI: Data/Command bit + 8 data bits ++ * For platforms that doesn't support 9-bit, the driver is capable ++ * of emulating this using 8-bit transfer. ++ * This is done by transfering eight 9-bit words in 9 bytes. ++ * ++ * Copyright (C) 2013 Christian Vogelgsang ++ * Based on adafruit22fb.c by Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9341" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define TXBUFLEN (4 * PAGE_SIZE) ++#define DEFAULT_GAMMA "1F 1A 18 0A 0F 06 45 87 32 0A 07 02 07 05 00\n" \ ++ "00 25 27 05 10 09 3A 78 4D 05 18 0D 38 3A 1F" ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* startup sequence for MI0283QT-9A */ ++ write_reg(par, 0x01); /* software reset */ ++ mdelay(5); ++ write_reg(par, 0x28); /* display off */ ++ /* --------------------------------------------------------- */ ++ write_reg(par, 0xCF, 0x00, 0x83, 0x30); ++ write_reg(par, 0xED, 0x64, 0x03, 0x12, 0x81); ++ write_reg(par, 0xE8, 0x85, 0x01, 0x79); ++ write_reg(par, 0xCB, 0x39, 0X2C, 0x00, 0x34, 0x02); ++ write_reg(par, 0xF7, 0x20); ++ write_reg(par, 0xEA, 0x00, 0x00); ++ /* ------------power control-------------------------------- */ ++ write_reg(par, 0xC0, 0x26); ++ write_reg(par, 0xC1, 0x11); ++ /* ------------VCOM --------- */ ++ write_reg(par, 0xC5, 0x35, 0x3E); ++ write_reg(par, 0xC7, 0xBE); ++ /* ------------memory access control------------------------ */ ++ write_reg(par, 0x3A, 0x55); /* 16bit pixel */ ++ /* ------------frame rate----------------------------------- */ ++ write_reg(par, 0xB1, 0x00, 0x1B); ++ /* ------------Gamma---------------------------------------- */ ++ /* write_reg(par, 0xF2, 0x08); */ /* Gamma Function Disable */ ++ write_reg(par, 0x26, 0x01); ++ /* ------------display-------------------------------------- */ ++ write_reg(par, 0xB7, 0x07); /* entry mode set */ ++ write_reg(par, 0xB6, 0x0A, 0x82, 0x27, 0x00); ++ write_reg(par, 0x11); /* sleep out */ ++ mdelay(100); ++ write_reg(par, 0x29); /* display on */ ++ mdelay(20); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address set */ ++ write_reg(par, 0x2A, ++ (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF); ++ ++ /* Row adress set */ ++ write_reg(par, 0x2B, ++ (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define MEM_Y (7) /* MY row address order */ ++#define MEM_X (6) /* MX column address order */ ++#define MEM_V (5) /* MV row / column exchange */ ++#define MEM_L (4) /* ML vertical refresh order */ ++#define MEM_H (2) /* MH horizontal refresh order */ ++#define MEM_BGR (3) /* RGB-BGR Order */ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, (1 << MEM_X) | (par->bgr << MEM_BGR)); ++ break; ++ case 270: ++ write_reg(par, 0x36, ++ (1<bgr << MEM_BGR)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (1 << MEM_Y) | (par->bgr << MEM_BGR)); ++ break; ++ case 90: ++ write_reg(par, 0x36, (1 << MEM_Y) | (1 << MEM_X) | ++ (1 << MEM_V) | (par->bgr << MEM_BGR)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ Positive: Par1 Par2 [...] Par15 ++ Negative: Par1 Par2 [...] Par15 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ int i; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ write_reg(par, 0xE0 + i, ++ CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), ++ CURVE(i, 3), CURVE(i, 4), CURVE(i, 5), ++ CURVE(i, 6), CURVE(i, 7), CURVE(i, 8), ++ CURVE(i, 9), CURVE(i, 10), CURVE(i, 11), ++ CURVE(i, 12), CURVE(i, 13), CURVE(i, 14)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 2, ++ .gamma_len = 15, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9341", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9341"); ++MODULE_ALIAS("platform:ili9341"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9341 LCD display controller"); ++MODULE_AUTHOR("Christian Vogelgsang"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ili9481.c b/drivers/video/fbtft/fb_ili9481.c +new file mode 100644 +index 0000000..725157a +--- /dev/null ++++ b/drivers/video/fbtft/fb_ili9481.c +@@ -0,0 +1,117 @@ ++/* ++ * FB driver for the ILI9481 LCD Controller ++ * ++ * Copyright (c) 2014 Petr Olivka ++ * Copyright (c) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9481" ++#define WIDTH 320 ++#define HEIGHT 480 ++ ++static int default_init_sequence[] = { ++ ++ /* SLP_OUT - Sleep out */ ++ -1, 0x11, ++ -2, 50, ++ /* Power setting */ ++ -1, 0xD0, 0x07, 0x42, 0x18, ++ /* VCOM */ ++ -1, 0xD1, 0x00, 0x07, 0x10, ++ /* Power setting for norm. mode */ ++ -1, 0xD2, 0x01, 0x02, ++ /* Panel driving setting */ ++ -1, 0xC0, 0x10, 0x3B, 0x00, 0x02, 0x11, ++ /* Frame rate & inv. */ ++ -1, 0xC5, 0x03, ++ /* Pixel format */ ++ -1, 0x3A, 0x55, ++ /* Gamma */ ++ -1, 0xC8, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16, ++ 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00, ++ /* DISP_ON */ ++ -1, 0x29, ++ -3 ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* column address */ ++ write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff); ++ ++ /* row adress */ ++ write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff); ++ ++ /* memory write */ ++ write_reg(par, 0x2c); ++} ++ ++#define HFLIP 0x01 ++#define VFLIP 0x02 ++#define ROWxCOL 0x20 ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 270: ++ write_reg(par, 0x36, ROWxCOL | HFLIP | VFLIP | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, VFLIP | (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, ROWxCOL | (par->bgr << 3)); ++ break; ++ default: ++ write_reg(par, 0x36, HFLIP | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .init_sequence = default_init_sequence, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9481", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9481"); ++MODULE_ALIAS("platform:ili9481"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9481 LCD Controller"); ++MODULE_AUTHOR("Petr Olivka"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ili9486.c b/drivers/video/fbtft/fb_ili9486.c +new file mode 100644 +index 0000000..95b8999 +--- /dev/null ++++ b/drivers/video/fbtft/fb_ili9486.c +@@ -0,0 +1,121 @@ ++/* ++ * FB driver for the ILI9486 LCD Controller ++ * ++ * Copyright (C) 2014 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9486" ++#define WIDTH 320 ++#define HEIGHT 480 ++ ++ ++/* this init sequence matches PiScreen */ ++static int default_init_sequence[] = { ++ /* Interface Mode Control */ ++ -1, 0xb0, 0x0, ++ /* Sleep OUT */ ++ -1, 0x11, ++ -2, 250, ++ /* Interface Pixel Format */ ++ -1, 0x3A, 0x55, ++ /* Power Control 3 */ ++ -1, 0xC2, 0x44, ++ /* VCOM Control 1 */ ++ -1, 0xC5, 0x00, 0x00, 0x00, 0x00, ++ /* PGAMCTRL(Positive Gamma Control) */ ++ -1, 0xE0, 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, ++ 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00, ++ /* NGAMCTRL(Negative Gamma Control) */ ++ -1, 0xE1, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, ++ 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00, ++ /* Digital Gamma Control 1 */ ++ -1, 0xE2, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, ++ 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00, ++ /* Sleep OUT */ ++ -1, 0x11, ++ /* Display ON */ ++ -1, 0x29, ++ /* end marker */ ++ -3 ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, 0x80 | (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, 0x20 | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, 0x40 | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, 0xE0 | (par->bgr << 3)); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .init_sequence = default_init_sequence, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9486", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9486"); ++MODULE_ALIAS("platform:ili9486"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9486 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_pcd8544.c b/drivers/video/fbtft/fb_pcd8544.c +new file mode 100644 +index 0000000..678ab8e +--- /dev/null ++++ b/drivers/video/fbtft/fb_pcd8544.c +@@ -0,0 +1,177 @@ ++/* ++ * FB driver for the PCD8544 LCD Controller ++ * ++ * The display is monochrome and the video memory is RGB565. ++ * Any pixel value except 0 turns the pixel on. ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_pcd8544" ++#define WIDTH 84 ++#define HEIGHT 48 ++#define TXBUFLEN 84*6 ++#define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ ++ ++static unsigned tc = 0; ++module_param(tc, uint, 0); ++MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)"); ++ ++static unsigned bs = 4; ++module_param(bs, uint, 0); ++MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* Function set */ ++ write_reg(par, 0x21); /* 5:1 1 ++ 2:0 PD - Powerdown control: chip is active ++ 1:0 V - Entry mode: horizontal addressing ++ 0:1 H - Extended instruction set control: extended ++ */ ++ ++ /* H=1 Temperature control */ ++ write_reg(par, 0x04 | (tc & 0x3)); /* ++ 2:1 1 ++ 1:x TC1 - Temperature Coefficient: 0x10 ++ 0:x TC0 ++ */ ++ ++ /* H=1 Bias system */ ++ write_reg(par, 0x10 | (bs & 0x7)); /* ++ 4:1 1 ++ 3:0 0 ++ 2:x BS2 - Bias System ++ 1:x BS1 ++ 0:x BS0 ++ */ ++ ++ /* Function set */ ++ write_reg(par, 0x22); /* 5:1 1 ++ 2:0 PD - Powerdown control: chip is active ++ 1:1 V - Entry mode: vertical addressing ++ 0:0 H - Extended instruction set control: basic ++ */ ++ ++ /* H=0 Display control */ ++ write_reg(par, 0x08 | 4); /* ++ 3:1 1 ++ 2:1 D - DE: 10=normal mode ++ 1:0 0 ++ 0:0 E ++ */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* H=0 Set X address of RAM */ ++ write_reg(par, 0x80); /* 7:1 1 ++ 6-0: X[6:0] - 0x00 ++ */ ++ ++ /* H=0 Set Y address of RAM */ ++ write_reg(par, 0x40); /* 7:0 0 ++ 6:1 1 ++ 2-0: Y[2:0] - 0x0 ++ */ ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (x=0;x<84;x++) { ++ for (y=0;y<6;y++) { ++ *buf = 0x00; ++ for (i=0;i<8;i++) { ++ *buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i; ++ } ++ buf++; ++ } ++ } ++ ++ /* Write data */ ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, 6*84); ++ if (ret < 0) ++ dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ curves[0] &= 0x7F; ++ ++ write_reg(par, 0x23); /* turn on extended instruction set */ ++ write_reg(par, 0x80 | curves[0]); ++ write_reg(par, 0x22); /* turn off extended instruction set */ ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 1, ++ .gamma_len = 1, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_vmem = write_vmem, ++ .set_gamma = set_gamma, ++ }, ++ .backlight = 1, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pdc8544", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:pdc8544"); ++ ++MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ra8875.c b/drivers/video/fbtft/fb_ra8875.c +new file mode 100644 +index 0000000..c323c06 +--- /dev/null ++++ b/drivers/video/fbtft/fb_ra8875.c +@@ -0,0 +1,331 @@ ++/****************************************************************************** ++ ++ ProjectName: FBTFT driver ***** ***** ++ for the RA8875 LCD Controller * * ************ ++ * ** ** * * ++ Copyright © by Pf@nne & NOTRO * * * * * **** * ++ * * * * * * * ++ Last modification by: * * * * **** * ++ - Pf@nne (pf@nne-mail.de) * * ***** * ++ * * * ******* ++ ***** * * ++ Date : 10.06.2014 * * ++ Version : V1.13 ***** ++ Revison : 5 ++ ++******************************************************************************* ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ra8875" ++ ++static int write_spi(struct fbtft_par *par, void *buf, size_t len) ++{ ++ struct spi_transfer t = { ++ .tx_buf = buf, ++ .len = len, ++ .speed_hz = 1000000, ++ }; ++ struct spi_message m; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ if (!par->spi) { ++ dev_err(par->info->device, ++ "%s: par->spi is unexpectedly NULL\n", __func__); ++ return -1; ++ } ++ ++ spi_message_init(&m); ++ if (par->txbuf.dma && buf == par->txbuf.buf) { ++ t.tx_dma = par->txbuf.dma; ++ m.is_dma_mapped = 1; ++ } ++ spi_message_add_tail(&t, &m); ++ return spi_sync(par->spi, &m); ++} ++ ++static int init_display(struct fbtft_par *par) ++{ ++ gpio_set_value(par->gpio.dc, 1); ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "%s()\n", __func__); ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "display size %dx%d\n", par->info->var.xres, par->info->var.yres); ++ ++ par->fbtftops.reset(par); ++ ++ if ((par->info->var.xres == 320) && (par->info->var.yres == 240)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0A); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x03); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x27); ++ write_reg(par, 0x15 , 0x00); ++ write_reg(par, 0x16 , 0x05); ++ write_reg(par, 0x17 , 0x04); ++ write_reg(par, 0x18 , 0x03); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0xEF); ++ write_reg(par, 0x1A , 0x00); ++ write_reg(par, 0x1B , 0x05); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x0E); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x02); ++ } else if ((par->info->var.xres == 480) && (par->info->var.yres == 272)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0A); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x82); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x3B); ++ write_reg(par, 0x15 , 0x00); ++ write_reg(par, 0x16 , 0x01); ++ write_reg(par, 0x17 , 0x00); ++ write_reg(par, 0x18 , 0x05); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0x0F); ++ write_reg(par, 0x1A , 0x01); ++ write_reg(par, 0x1B , 0x02); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x07); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x09); ++ } else if ((par->info->var.xres == 640) && (par->info->var.yres == 480)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0B); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x01); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x4F); ++ write_reg(par, 0x15 , 0x05); ++ write_reg(par, 0x16 , 0x0F); ++ write_reg(par, 0x17 , 0x01); ++ write_reg(par, 0x18 , 0x00); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0xDF); ++ write_reg(par, 0x1A , 0x01); ++ write_reg(par, 0x1B , 0x0A); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x0E); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x01); ++ } else if ((par->info->var.xres == 800) && (par->info->var.yres == 480)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0B); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x81); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x63); ++ write_reg(par, 0x15 , 0x03); ++ write_reg(par, 0x16 , 0x03); ++ write_reg(par, 0x17 , 0x02); ++ write_reg(par, 0x18 , 0x00); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0xDF); ++ write_reg(par, 0x1A , 0x01); ++ write_reg(par, 0x1B , 0x14); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x06); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x01); ++ } else { ++ dev_err(par->info->device, "display size is not supported!!"); ++ return -1; ++ } ++ ++ /* PWM clock */ ++ write_reg(par, 0x8a , 0x81); ++ write_reg(par, 0x8b , 0xFF); ++ mdelay(10); ++ ++ /* Display ON */ ++ write_reg(par, 0x01 , 0x80); ++ mdelay(10); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Set_Active_Window */ ++ write_reg(par, 0x30 , xs & 0x00FF); ++ write_reg(par, 0x31 , (xs & 0xFF00) >> 8); ++ write_reg(par, 0x32 , ys & 0x00FF); ++ write_reg(par, 0x33 , (ys & 0xFF00) >> 8); ++ write_reg(par, 0x34 , (xs+xe) & 0x00FF); ++ write_reg(par, 0x35 , ((xs+xe) & 0xFF00) >> 8); ++ write_reg(par, 0x36 , (ys+ye) & 0x00FF); ++ write_reg(par, 0x37 , ((ys+ye) & 0xFF00) >> 8); ++ ++ /* Set_Memory_Write_Cursor */ ++ write_reg(par, 0x46, xs & 0xff); ++ write_reg(par, 0x47, (xs >> 8) & 0x03); ++ write_reg(par, 0x48, ys & 0xff); ++ write_reg(par, 0x49, (ys >> 8) & 0x01); ++ ++ write_reg(par, 0x02); ++} ++ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = (u8 *)par->buf; ++ ++ /* slow down spi-speed for writing registers */ ++ par->fbtftops.write = write_spi; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ buf[i] = (u8)va_arg(args, unsigned int); ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, ++ u8, buf, len, "%s: ", __func__); ++ } ++ ++ va_start(args, len); ++ *buf++ = 0x80; ++ *buf = (u8)va_arg(args, unsigned int); ++ ret = par->fbtftops.write(par, par->buf, 2); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %dn", ++ __func__, ret); ++ return; ++ } ++ len--; ++ ++ udelay(100); ++ ++ if (len) { ++ buf = (u8 *)par->buf; ++ *buf++ = 0x00; ++ i = len; ++ while (i--) ++ *buf++ = (u8)va_arg(args, unsigned int); ++ ++ ret = par->fbtftops.write(par, par->buf, len + 1); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %dn", ++ __func__, ret); ++ return; ++ } ++ } ++ va_end(args); ++ ++ /* restore user spi-speed */ ++ par->fbtftops.write = fbtft_write_spi; ++ udelay(100); ++} ++ ++static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16; ++ u16 *txbuf16 = (u16 *)par->txbuf.buf; ++ size_t remain; ++ size_t to_copy; ++ size_t tx_array_size; ++ int i; ++ int ret = 0; ++ size_t startbyte_size = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ remain = len / 2; ++ vmem16 = (u16 *)(par->info->screen_base + offset); ++ tx_array_size = par->txbuf.len / 2; ++ txbuf16 = (u16 *)(par->txbuf.buf + 1); ++ tx_array_size -= 2; ++ *(u8 *)(par->txbuf.buf) = 0x00; ++ startbyte_size = 1; ++ ++ while (remain) { ++ to_copy = remain > tx_array_size ? tx_array_size : remain; ++ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", ++ to_copy, remain - to_copy); ++ ++ for (i = 0; i < to_copy; i++) ++ txbuf16[i] = cpu_to_be16(vmem16[i]); ++ ++ vmem16 = vmem16 + to_copy; ++ ret = par->fbtftops.write(par, par->txbuf.buf, ++ startbyte_size + to_copy * 2); ++ if (ret < 0) ++ return ret; ++ remain -= to_copy; ++ } ++ ++ return ret; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_register = write_reg8_bus8, ++ .write_vmem = write_vmem16_bus8, ++ .write = write_spi, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "raio,ra8875", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ra8875"); ++MODULE_ALIAS("platform:ra8875"); ++ ++MODULE_DESCRIPTION("FB driver for the RA8875 LCD Controller"); ++MODULE_AUTHOR("Pf@nne"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_s6d02a1.c b/drivers/video/fbtft/fb_s6d02a1.c +new file mode 100644 +index 0000000..e412a42 +--- /dev/null ++++ b/drivers/video/fbtft/fb_s6d02a1.c +@@ -0,0 +1,168 @@ ++/* ++ * FB driver for the S6D02A1 LCD Controller ++ * ++ * Based on fb_st7735r.c by Noralf Tronnes ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_s6d02a1" ++ ++static int default_init_sequence[] = { ++ ++ -1, 0xf0, 0x5a, 0x5a, ++ ++ -1, 0xfc, 0x5a, 0x5a, ++ ++ -1, 0xfa, 0x02, 0x1f, 0x00, 0x10, 0x22, 0x30, 0x38, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3d, 0x02, 0x01, ++ ++ -1, 0xfb, 0x21, 0x00, 0x02, 0x04, 0x07, 0x0a, 0x0b, 0x0c, 0x0c, 0x16, 0x1e, 0x30, 0x3f, 0x01, 0x02, ++ ++ /* power setting sequence */ ++ -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x01, 0x00, 0x1f, 0x1f, ++ ++ -1, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, ++ ++ -1, 0xf5, 0x00, 0x70, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x66, 0x06, ++ ++ -1, 0xf6, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, ++ ++ -1, 0xf2, 0x00, 0x01, 0x03, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x08, 0x08, ++ ++ -1, 0xf8, 0x11, ++ ++ -1, 0xf7, 0xc8, 0x20, 0x00, 0x00, ++ ++ -1, 0xf3, 0x00, 0x00, ++ ++ -1, 0x11, ++ -2, 50, ++ ++ -1, 0xf3, 0x00, 0x01, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x03, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x07, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x0f, ++ -2, 50, ++ ++ -1, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, ++ -2, 50, ++ ++ -1, 0xf3, 0x00, 0x1f, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x7f, ++ -2, 50, ++ ++ -1, 0xf3, 0x00, 0xff, ++ -2, 50, ++ ++ -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x01, 0x00, 0x16, 0x16, ++ ++ -1, 0xf4, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, ++ ++ /* initializing sequence */ ++ ++ -1, 0x36, 0x08, ++ ++ -1, 0x35, 0x00, ++ ++ -1, 0x3a, 0x05, ++ ++ /* gamma setting sequence */ ++ -1, 0x26, 0x01, /* preset gamma curves, possible values 0x01, 0x02, 0x04, 0x08 */ ++ ++ -2, 150, ++ -1, 0x29, ++ -1, 0x2c, ++ /* end marker */ ++ -3 ++ ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define MY (1 << 7) ++#define MX (1 << 6) ++#define MV (1 << 5) ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* MADCTL - Memory data access control ++ RGB/BGR: ++ 1. Mode selection pin SRGB ++ RGB H/W pin for color filter setting: 0=RGB, 1=BGR ++ 2. MADCTL RGB bit ++ RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, MX | MY | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, MY | MV | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, MX | MV | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = 128, ++ .height = 160, ++ .init_sequence = default_init_sequence, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d02a1", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:s6d02a1"); ++MODULE_ALIAS("platform:s6d02a1"); ++ ++MODULE_DESCRIPTION("FB driver for the S6D02A1 LCD Controller"); ++MODULE_AUTHOR("WOLFGANG BUENING"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_s6d1121.c b/drivers/video/fbtft/fb_s6d1121.c +new file mode 100644 +index 0000000..1ef8c1a +--- /dev/null ++++ b/drivers/video/fbtft/fb_s6d1121.c +@@ -0,0 +1,208 @@ ++/* ++ * FB driver for the S6D1121 LCD Controller ++ * ++ * Copyright (C) 2013 Roman Rolinsky ++ * ++ * Based on fb_ili9325.c by Noralf Tronnes ++ * Based on ili9325.c by Jeroen Domburg ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_s6d1121" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++#define FPS 20 ++#define DEFAULT_GAMMA "26 09 24 2C 1F 23 24 25 22 26 25 23 0D 00\n" \ ++ "1C 1A 13 1D 0B 11 12 10 13 15 36 19 00 0D" ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ /* Initialization sequence from Lib_UTFT */ ++ ++ write_reg(par, 0x0011, 0x2004); ++ write_reg(par, 0x0013, 0xCC00); ++ write_reg(par, 0x0015, 0x2600); ++ write_reg(par, 0x0014, 0x252A); ++ write_reg(par, 0x0012, 0x0033); ++ write_reg(par, 0x0013, 0xCC04); ++ write_reg(par, 0x0013, 0xCC06); ++ write_reg(par, 0x0013, 0xCC4F); ++ write_reg(par, 0x0013, 0x674F); ++ write_reg(par, 0x0011, 0x2003); ++ write_reg(par, 0x0016, 0x0007); ++ write_reg(par, 0x0002, 0x0013); ++ write_reg(par, 0x0003, 0x0003); ++ write_reg(par, 0x0001, 0x0127); ++ write_reg(par, 0x0008, 0x0303); ++ write_reg(par, 0x000A, 0x000B); ++ write_reg(par, 0x000B, 0x0003); ++ write_reg(par, 0x000C, 0x0000); ++ write_reg(par, 0x0041, 0x0000); ++ write_reg(par, 0x0050, 0x0000); ++ write_reg(par, 0x0060, 0x0005); ++ write_reg(par, 0x0070, 0x000B); ++ write_reg(par, 0x0071, 0x0000); ++ write_reg(par, 0x0078, 0x0000); ++ write_reg(par, 0x007A, 0x0000); ++ write_reg(par, 0x0079, 0x0007); ++ write_reg(par, 0x0007, 0x0051); ++ write_reg(par, 0x0007, 0x0053); ++ write_reg(par, 0x0079, 0x0000); ++ ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, WIDTH - 1 - xs); ++ write_reg(par, 0x0021, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, WIDTH - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x03, 0x0003 | (par->bgr << 12)); ++ break; ++ case 180: ++ write_reg(par, 0x03, 0x0000 | (par->bgr << 12)); ++ break; ++ case 270: ++ write_reg(par, 0x03, 0x000A | (par->bgr << 12)); ++ break; ++ case 90: ++ write_reg(par, 0x03, 0x0009 | (par->bgr << 12)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 PKP6 PKP7 PKP8 PKP9 PKP10 PKP11 VRP0 VRP1 ++ PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b11111, 0b11111, ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b11111, 0b11111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 14; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ write_reg(par, 0x0031, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0032, CURVE(0, 5) << 8 | CURVE(0, 3)); ++ write_reg(par, 0x0033, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0034, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0035, CURVE(0, 11) << 8 | CURVE(0, 10)); ++ ++ write_reg(par, 0x0036, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x0038, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0039, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x003A, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x003B, CURVE(1, 11) << 8 | CURVE(1, 10)); ++ ++ write_reg(par, 0x003C, CURVE(0, 13) << 8 | CURVE(0, 12)); ++ write_reg(par, 0x003D, CURVE(1, 13) << 8 | CURVE(1, 12)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .bpp = BPP, ++ .fps = FPS, ++ .gamma_num = 2, ++ .gamma_len = 14, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:s6d1121"); ++MODULE_ALIAS("platform:s6d1121"); ++ ++MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller"); ++MODULE_AUTHOR("Roman Rolinsky"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ssd1289.c b/drivers/video/fbtft/fb_ssd1289.c +new file mode 100644 +index 0000000..ef46fbc +--- /dev/null ++++ b/drivers/video/fbtft/fb_ssd1289.c +@@ -0,0 +1,206 @@ ++/* ++ * FB driver for the SSD1289 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * Init sequence taken from ITDB02_Graph16.cpp - (C)2010-2011 Henning Karlsen ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1289" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define DEFAULT_GAMMA "02 03 2 5 7 7 4 2 4 2\n" \ ++ "02 03 2 5 7 5 4 2 4 2" ++ ++static unsigned reg11 = 0x6040; ++module_param(reg11, uint, 0); ++MODULE_PARM_DESC(reg11, "Register 11h value"); ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ write_reg(par, 0x00, 0x0001); ++ write_reg(par, 0x03, 0xA8A4); ++ write_reg(par, 0x0C, 0x0000); ++ write_reg(par, 0x0D, 0x080C); ++ write_reg(par, 0x0E, 0x2B00); ++ write_reg(par, 0x1E, 0x00B7); ++ write_reg(par, 0x01, ++ (1 << 13) | (par->bgr << 11) | (1 << 9) | (HEIGHT - 1)); ++ write_reg(par, 0x02, 0x0600); ++ write_reg(par, 0x10, 0x0000); ++ write_reg(par, 0x05, 0x0000); ++ write_reg(par, 0x06, 0x0000); ++ write_reg(par, 0x16, 0xEF1C); ++ write_reg(par, 0x17, 0x0003); ++ write_reg(par, 0x07, 0x0233); ++ write_reg(par, 0x0B, 0x0000); ++ write_reg(par, 0x0F, 0x0000); ++ write_reg(par, 0x41, 0x0000); ++ write_reg(par, 0x42, 0x0000); ++ write_reg(par, 0x48, 0x0000); ++ write_reg(par, 0x49, 0x013F); ++ write_reg(par, 0x4A, 0x0000); ++ write_reg(par, 0x4B, 0x0000); ++ write_reg(par, 0x44, 0xEF00); ++ write_reg(par, 0x45, 0x0000); ++ write_reg(par, 0x46, 0x013F); ++ write_reg(par, 0x23, 0x0000); ++ write_reg(par, 0x24, 0x0000); ++ write_reg(par, 0x25, 0x8000); ++ write_reg(par, 0x4f, 0x0000); ++ write_reg(par, 0x4e, 0x0000); ++ write_reg(par, 0x22); ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ switch (par->info->var.rotate) { ++ /* R4Eh - Set GDDRAM X address counter */ ++ /* R4Fh - Set GDDRAM Y address counter */ ++ case 0: ++ write_reg(par, 0x4e, xs); ++ write_reg(par, 0x4f, ys); ++ break; ++ case 180: ++ write_reg(par, 0x4e, par->info->var.xres - 1 - xs); ++ write_reg(par, 0x4f, par->info->var.yres - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x4e, par->info->var.yres - 1 - ys); ++ write_reg(par, 0x4f, xs); ++ break; ++ case 90: ++ write_reg(par, 0x4e, ys); ++ write_reg(par, 0x4f, par->info->var.xres - 1 - xs); ++ break; ++ } ++ ++ /* R22h - RAM data write */ ++ write_reg(par, 0x22); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->fbtftops.init_display != init_display) { ++ /* don't risk messing up register 11h */ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "%s: skipping since custom init_display() is used\n", ++ __func__); ++ return 0; ++ } ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x11, reg11 | 0b110000); ++ break; ++ case 270: ++ write_reg(par, 0x11, reg11 | 0b101000); ++ break; ++ case 180: ++ write_reg(par, 0x11, reg11 | 0b000000); ++ break; ++ case 90: ++ write_reg(par, 0x11, reg11 | 0b011000); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 ++ VRN0 VRN1 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 10; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); ++ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0033, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0034, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0035, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x0036, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x003A, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ write_reg(par, 0x003B, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 2, ++ .gamma_len = 10, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1289", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1289"); ++MODULE_ALIAS("platform:ssd1289"); ++ ++MODULE_DESCRIPTION("FB driver for the SSD1289 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ssd1306.c b/drivers/video/fbtft/fb_ssd1306.c +new file mode 100644 +index 0000000..5ea195b +--- /dev/null ++++ b/drivers/video/fbtft/fb_ssd1306.c +@@ -0,0 +1,229 @@ ++/* ++ * FB driver for the SSD1306 OLED Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1306" ++#define WIDTH 128 ++#define HEIGHT 64 ++ ++ ++/* ++ write_reg() caveat: ++ ++ This doesn't work because D/C has to be LOW for both values: ++ write_reg(par, val1, val2); ++ ++ Do it like this: ++ write_reg(par, val1); ++ write_reg(par, val2); ++*/ ++ ++/* Init sequence taken from the Adafruit SSD1306 Arduino library */ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gamma.curves[0] == 0) { ++ mutex_lock(&par->gamma.lock); ++ if (par->info->var.yres == 64) ++ par->gamma.curves[0] = 0xCF; ++ else ++ par->gamma.curves[0] = 0x8F; ++ mutex_unlock(&par->gamma.lock); ++ } ++ ++ /* Set Display OFF */ ++ write_reg(par, 0xAE); ++ ++ /* Set Display Clock Divide Ratio/ Oscillator Frequency */ ++ write_reg(par, 0xD5); ++ write_reg(par, 0x80); ++ ++ /* Set Multiplex Ratio */ ++ write_reg(par, 0xA8); ++ if (par->info->var.yres == 64) ++ write_reg(par, 0x3F); ++ else ++ write_reg(par, 0x1F); ++ ++ /* Set Display Offset */ ++ write_reg(par, 0xD3); ++ write_reg(par, 0x0); ++ ++ /* Set Display Start Line */ ++ write_reg(par, 0x40 | 0x0); ++ ++ /* Charge Pump Setting */ ++ write_reg(par, 0x8D); ++ /* A[2] = 1b, Enable charge pump during display on */ ++ write_reg(par, 0x14); ++ ++ /* Set Memory Addressing Mode */ ++ write_reg(par, 0x20); ++ /* Vertical addressing mode */ ++ write_reg(par, 0x01); ++ ++ /*Set Segment Re-map */ ++ /* column address 127 is mapped to SEG0 */ ++ write_reg(par, 0xA0 | 0x1); ++ ++ /* Set COM Output Scan Direction */ ++ /* remapped mode. Scan from COM[N-1] to COM0 */ ++ write_reg(par, 0xC8); ++ ++ /* Set COM Pins Hardware Configuration */ ++ write_reg(par, 0xDA); ++ if (par->info->var.yres == 64) ++ /* A[4]=1b, Alternative COM pin configuration */ ++ write_reg(par, 0x12); ++ else ++ /* A[4]=0b, Sequential COM pin configuration */ ++ write_reg(par, 0x02); ++ ++ /* Set Pre-charge Period */ ++ write_reg(par, 0xD9); ++ write_reg(par, 0xF1); ++ ++ /* Set VCOMH Deselect Level */ ++ write_reg(par, 0xDB); ++ /* according to the datasheet, this value is out of bounds */ ++ write_reg(par, 0x40); ++ ++ /* Entire Display ON */ ++ /* Resume to RAM content display. Output follows RAM content */ ++ write_reg(par, 0xA4); ++ ++ /* Set Normal Display ++ 0 in RAM: OFF in display panel ++ 1 in RAM: ON in display panel */ ++ write_reg(par, 0xA6); ++ ++ /* Set Display ON */ ++ write_reg(par, 0xAF); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Set Lower Column Start Address for Page Addressing Mode */ ++ write_reg(par, 0x00 | 0x0); ++ /* Set Higher Column Start Address for Page Addressing Mode */ ++ write_reg(par, 0x10 | 0x0); ++ /* Set Display Start Line */ ++ write_reg(par, 0x40 | 0x0); ++} ++ ++static int blank(struct fbtft_par *par, bool on) ++{ ++ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", ++ __func__, on ? "true" : "false"); ++ ++ if (on) ++ write_reg(par, 0xAE); ++ else ++ write_reg(par, 0xAF); ++ return 0; ++} ++ ++/* Gamma is used to control Contrast */ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ curves[0] &= 0xFF; ++ ++ /* Set Contrast Control for BANK0 */ ++ write_reg(par, 0x81); ++ write_reg(par, curves[0]); ++ ++ return 0; ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (x = 0; x < par->info->var.xres; x++) { ++ for (y = 0; y < par->info->var.yres/8; y++) { ++ *buf = 0x00; ++ for (i = 0; i < 8; i++) ++ *buf |= (vmem16[(y*8+i)*par->info->var.xres+x] ? 1 : 0) << i; ++ buf++; ++ } ++ } ++ ++ /* Write data */ ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, ++ par->info->var.xres*par->info->var.yres/8); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 1, ++ .gamma_len = 1, ++ .gamma = "00", ++ .fbtftops = { ++ .write_vmem = write_vmem, ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .blank = blank, ++ .set_gamma = set_gamma, ++ }, ++}; ++ ++ ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1306", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1306"); ++MODULE_ALIAS("platform:ssd1306"); ++ ++MODULE_DESCRIPTION("SSD1306 OLED Driver"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ssd1331.c b/drivers/video/fbtft/fb_ssd1331.c +new file mode 100644 +index 0000000..da7464f +--- /dev/null ++++ b/drivers/video/fbtft/fb_ssd1331.c +@@ -0,0 +1,205 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1331" ++#define WIDTH 96 ++#define HEIGHT 64 ++#define GAMMA_NUM 1 ++#define GAMMA_LEN 63 ++#define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2" \ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xae); /* Display Off */ ++ write_reg(par, 0xa0, 0x70 | (par->bgr << 2)); /* Set Colour Depth */ ++ write_reg(par, 0x72); // RGB colour ++ write_reg(par, 0xa1, 0x00); /* Set Display Start Line */ ++ write_reg(par, 0xa2, 0x00); /* Set Display Offset */ ++ write_reg(par, 0xa4); /* NORMALDISPLAY */ ++ write_reg(par, 0xa8, 0x3f); // Set multiplex ++ write_reg(par, 0xad, 0x8e); // Set master ++ // write_reg(par, 0xb0, 0x0b); // Set power mode ++ write_reg(par, 0xb1, 0x31); // Precharge ++ write_reg(par, 0xb3, 0xf0); // Clock div ++ write_reg(par, 0x8a, 0x64); // Precharge A ++ write_reg(par, 0x8b, 0x78); // Precharge B ++ write_reg(par, 0x8c, 0x64); // Precharge C ++ write_reg(par, 0xbb, 0x3a); // Precharge level ++ write_reg(par, 0xbe, 0x3e); // vcomh ++ write_reg(par, 0x87, 0x06); // Master current ++ write_reg(par, 0x81, 0x91); // Contrast A ++ write_reg(par, 0x82, 0x50); // Contrast B ++ write_reg(par, 0x83, 0x7d); // Contrast C ++ write_reg(par, 0xaf); /* Set Sleep Mode Display On */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x15, xs, xe); ++ write_reg(par, 0x75, ys, ye); ++} ++ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = (u8 *)par->buf; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) { ++ buf[i] = (u8)va_arg(args, unsigned int); ++ } ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, u8, buf, len, "%s: ", __func__); ++ } ++ ++ va_start(args, len); ++ ++ *buf = (u8)va_arg(args, unsigned int); ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 0); ++ ret = par->fbtftops.write(par, par->buf, sizeof(u8)); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++ len--; ++ ++ if (len) { ++ i = len; ++ while (i--) { ++ *buf++ = (u8)va_arg(args, unsigned int); ++ } ++ ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8))); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++ } ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 1); ++ va_end(args); ++} ++ ++/* ++ Grayscale Lookup Table ++ GS1 - GS63 ++ The driver Gamma curve contains the relative values between the entries ++ in the Lookup table. ++ ++ From datasheet: ++ 8.8 Gray Scale Decoder ++ ++ there are total 180 Gamma Settings (Setting 0 to Setting 180) ++ available for the Gray Scale table. ++ ++ The gray scale is defined in incremental way, with reference ++ to the length of previous table entry: ++ Setting of GS1 has to be >= 0 ++ Setting of GS2 has to be > Setting of GS1 +1 ++ Setting of GS3 has to be > Setting of GS2 +1 ++ : ++ Setting of GS63 has to be > Setting of GS62 +1 ++ ++ ++*/ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long tmp[GAMMA_NUM * GAMMA_LEN]; ++ int i, acc = 0; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ for (i = 0; i < 63; i++) { ++ if (i > 0 && curves[i] < 2) { ++ dev_err(par->info->device, ++ "Illegal value in Grayscale Lookup Table at index %d. " \ ++ "Must be greater than 1\n", i); ++ return -EINVAL; ++ } ++ acc += curves[i]; ++ tmp[i] = acc; ++ if (acc > 180) { ++ dev_err(par->info->device, ++ "Illegal value(s) in Grayscale Lookup Table. " \ ++ "At index=%d, the accumulated value has exceeded 180\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ write_reg(par, 0xB8, ++ tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], ++ tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15], ++ tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23], ++ tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31], ++ tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], ++ tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], ++ tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55], ++ tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]); ++ ++ return 0; ++} ++ ++static int blank(struct fbtft_par *par, bool on) ++{ ++ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", ++ __func__, on ? "true" : "false"); ++ if (on) ++ write_reg(par, 0xAE); ++ else ++ write_reg(par, 0xAF); ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = GAMMA_NUM, ++ .gamma_len = GAMMA_LEN, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .write_register = write_reg8_bus8, ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_gamma = set_gamma, ++ .blank = blank, ++ }, ++}; ++ ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1331", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1331"); ++MODULE_ALIAS("platform:ssd1331"); ++ ++MODULE_DESCRIPTION("SSD1331 OLED Driver"); ++MODULE_AUTHOR("Alec Smecher (adapted from SSD1351 by James Davies)"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_ssd1351.c b/drivers/video/fbtft/fb_ssd1351.c +new file mode 100644 +index 0000000..062d986 +--- /dev/null ++++ b/drivers/video/fbtft/fb_ssd1351.c +@@ -0,0 +1,258 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1351" ++#define WIDTH 128 ++#define HEIGHT 128 ++#define GAMMA_NUM 1 ++#define GAMMA_LEN 63 ++#define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2" \ ++ ++static void register_onboard_backlight(struct fbtft_par *par); ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->pdata ++ && par->pdata->display.backlight == FBTFT_ONBOARD_BACKLIGHT) { ++ /* module uses onboard GPIO for panel power */ ++ par->fbtftops.register_backlight = register_onboard_backlight; ++ } ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xfd, 0x12); /* Command Lock */ ++ write_reg(par, 0xfd, 0xb1); /* Command Lock */ ++ write_reg(par, 0xae); /* Display Off */ ++ write_reg(par, 0xb3, 0xf1); /* Front Clock Div */ ++ write_reg(par, 0xca, 0x7f); /* Set Mux Ratio */ ++ write_reg(par, 0x15, 0x00, 0x7f); /* Set Column Address */ ++ write_reg(par, 0x75, 0x00, 0x7f); /* Set Row Address */ ++ write_reg(par, 0xa1, 0x00); /* Set Display Start Line */ ++ write_reg(par, 0xa2, 0x00); /* Set Display Offset */ ++ write_reg(par, 0xb5, 0x00); /* Set GPIO */ ++ write_reg(par, 0xab, 0x01); /* Set Function Selection */ ++ write_reg(par, 0xb1, 0x32); /* Set Phase Length */ ++ write_reg(par, 0xb4, 0xa0, 0xb5, 0x55); /* Set Segment Low Voltage */ ++ write_reg(par, 0xbb, 0x17); /* Set Precharge Voltage */ ++ write_reg(par, 0xbe, 0x05); /* Set VComH Voltage */ ++ write_reg(par, 0xc1, 0xc8, 0x80, 0xc8); /* Set Contrast */ ++ write_reg(par, 0xc7, 0x0f); /* Set Master Contrast */ ++ write_reg(par, 0xb6, 0x01); /* Set Second Precharge Period */ ++ write_reg(par, 0xa6); /* Set Display Mode Reset */ ++ write_reg(par, 0xaf); /* Set Sleep Mode Display On */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x15, xs, xe); ++ write_reg(par, 0x75, ys, ye); ++ write_reg(par, 0x5c); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ unsigned remap; ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->fbtftops.init_display != init_display) { ++ /* don't risk messing up register A0h */ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "%s: skipping since custom init_display() is used\n", ++ __func__); ++ return 0; ++ } ++ ++ remap = 0x60 | (par->bgr << 2); /* Set Colour Depth */ ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0xA0, remap | 0b00 | 1<<4); ++ break; ++ case 270: ++ write_reg(par, 0xA0, remap | 0b11 | 1<<4); ++ break; ++ case 180: ++ write_reg(par, 0xA0, remap | 0b10); ++ break; ++ case 90: ++ write_reg(par, 0xA0, remap | 0b01); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Grayscale Lookup Table ++ GS1 - GS63 ++ The driver Gamma curve contains the relative values between the entries ++ in the Lookup table. ++ ++ From datasheet: ++ 8.8 Gray Scale Decoder ++ ++ there are total 180 Gamma Settings (Setting 0 to Setting 180) ++ available for the Gray Scale table. ++ ++ The gray scale is defined in incremental way, with reference ++ to the length of previous table entry: ++ Setting of GS1 has to be >= 0 ++ Setting of GS2 has to be > Setting of GS1 +1 ++ Setting of GS3 has to be > Setting of GS2 +1 ++ : ++ Setting of GS63 has to be > Setting of GS62 +1 ++ ++ ++*/ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long tmp[GAMMA_NUM * GAMMA_LEN]; ++ int i, acc = 0; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ for (i = 0; i < 63; i++) { ++ if (i > 0 && curves[i] < 2) { ++ dev_err(par->info->device, ++ "Illegal value in Grayscale Lookup Table at index %d. " \ ++ "Must be greater than 1\n", i); ++ return -EINVAL; ++ } ++ acc += curves[i]; ++ tmp[i] = acc; ++ if (acc > 180) { ++ dev_err(par->info->device, ++ "Illegal value(s) in Grayscale Lookup Table. " \ ++ "At index=%d, the accumulated value has exceeded 180\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ write_reg(par, 0xB8, ++ tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], ++ tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15], ++ tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23], ++ tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31], ++ tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], ++ tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], ++ tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55], ++ tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]); ++ ++ return 0; ++} ++ ++static int blank(struct fbtft_par *par, bool on) ++{ ++ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", ++ __func__, on ? "true" : "false"); ++ if (on) ++ write_reg(par, 0xAE); ++ else ++ write_reg(par, 0xAF); ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = GAMMA_NUM, ++ .gamma_len = GAMMA_LEN, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ .blank = blank, ++ }, ++}; ++ ++#ifdef CONFIG_FB_BACKLIGHT ++static int update_onboard_backlight(struct backlight_device *bd) ++{ ++ struct fbtft_par *par = bl_get_data(bd); ++ bool on; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s: power=%d, fb_blank=%d\n", ++ __func__, bd->props.power, bd->props.fb_blank); ++ ++ on = (bd->props.power == FB_BLANK_UNBLANK) ++ && (bd->props.fb_blank == FB_BLANK_UNBLANK); ++ /* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */ ++ write_reg(par, 0xB5, on ? 0x03 : 0x02); ++ ++ return 0; ++} ++ ++static void register_onboard_backlight(struct fbtft_par *par) ++{ ++ struct backlight_device *bd; ++ struct backlight_properties bl_props = { 0, }; ++ struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), ++ GFP_KERNEL); ++ if (!bl_ops) { ++ dev_err(par->info->device, ++ "%s: could not allocate memory for backlight operations.\n", ++ __func__); ++ return; ++ } ++ ++ bl_ops->update_status = update_onboard_backlight; ++ bl_props.type = BACKLIGHT_RAW; ++ bl_props.power = FB_BLANK_POWERDOWN; ++ ++ bd = backlight_device_register(dev_driver_string(par->info->device), ++ par->info->device, par, bl_ops, &bl_props); ++ if (IS_ERR(bd)) { ++ dev_err(par->info->device, ++ "cannot register backlight device (%ld)\n", ++ PTR_ERR(bd)); ++ return; ++ } ++ par->info->bl_dev = bd; ++ ++ if (!par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight = fbtft_unregister_backlight; ++} ++#else ++static void register_onboard_backlight(struct fbtft_par *par) { }; ++#endif ++ ++ ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1351", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1351"); ++MODULE_ALIAS("platform:ssd1351"); ++ ++MODULE_DESCRIPTION("SSD1351 OLED Driver"); ++MODULE_AUTHOR("James Davies"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_st7735r.c b/drivers/video/fbtft/fb_st7735r.c +new file mode 100644 +index 0000000..b63aa38 +--- /dev/null ++++ b/drivers/video/fbtft/fb_st7735r.c +@@ -0,0 +1,195 @@ ++/* ++ * FB driver for the ST7735R LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_st7735r" ++#define DEFAULT_GAMMA "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \ ++ "0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10" ++ ++ ++static int default_init_sequence[] = { ++ /* SWRESET - Software reset */ ++ -1, 0x01, ++ -2, 150, /* delay */ ++ ++ /* SLPOUT - Sleep out & booster on */ ++ -1, 0x11, ++ -2, 500, /* delay */ ++ ++ /* FRMCTR1 - frame rate control: normal mode ++ frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */ ++ -1, 0xB1, 0x01, 0x2C, 0x2D, ++ ++ /* FRMCTR2 - frame rate control: idle mode ++ frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */ ++ -1, 0xB2, 0x01, 0x2C, 0x2D, ++ ++ /* FRMCTR3 - frame rate control - partial mode ++ dot inversion mode, line inversion mode */ ++ -1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, ++ ++ /* INVCTR - display inversion control ++ no inversion */ ++ -1, 0xB4, 0x07, ++ ++ /* PWCTR1 - Power Control ++ -4.6V, AUTO mode */ ++ -1, 0xC0, 0xA2, 0x02, 0x84, ++ ++ /* PWCTR2 - Power Control ++ VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD */ ++ -1, 0xC1, 0xC5, ++ ++ /* PWCTR3 - Power Control ++ Opamp current small, Boost frequency */ ++ -1, 0xC2, 0x0A, 0x00, ++ ++ /* PWCTR4 - Power Control ++ BCLK/2, Opamp current small & Medium low */ ++ -1, 0xC3,0x8A,0x2A, ++ ++ /* PWCTR5 - Power Control */ ++ -1, 0xC4, 0x8A, 0xEE, ++ ++ /* VMCTR1 - Power Control */ ++ -1, 0xC5, 0x0E, ++ ++ /* INVOFF - Display inversion off */ ++ -1, 0x20, ++ ++ /* COLMOD - Interface pixel format */ ++ -1, 0x3A, 0x05, ++ ++ /* DISPON - Display On */ ++ -1, 0x29, ++ -2, 100, /* delay */ ++ ++ /* NORON - Partial off (Normal) */ ++ -1, 0x13, ++ -2, 10, /* delay */ ++ ++ /* end marker */ ++ -3 ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define MY (1 << 7) ++#define MX (1 << 6) ++#define MV (1 << 5) ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* MADCTL - Memory data access control ++ RGB/BGR: ++ 1. Mode selection pin SRGB ++ RGB H/W pin for color filter setting: 0=RGB, 1=BGR ++ 2. MADCTL RGB bit ++ RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, MX | MY | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, MY | MV | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, MX | MV | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRF0P VOS0P PK0P PK1P PK2P PK3P PK4P PK5P PK6P PK7P PK8P PK9P SELV0P SELV1P SELV62P SELV63P ++ VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ int i,j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ for (j = 0; j < par->gamma.num_values; j++) ++ CURVE(i,j) &= 0b111111; ++ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ write_reg(par, 0xE0 + i, ++ CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), CURVE(i, 3), ++ CURVE(i, 4), CURVE(i, 5), CURVE(i, 6), CURVE(i, 7), ++ CURVE(i, 8), CURVE(i, 9), CURVE(i, 10), CURVE(i, 11), ++ CURVE(i, 12), CURVE(i, 13), CURVE(i, 14), CURVE(i,15)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = 128, ++ .height = 160, ++ .init_sequence = default_init_sequence, ++ .gamma_num = 2, ++ .gamma_len = 16, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:st7735r"); ++MODULE_ALIAS("platform:st7735r"); ++ ++MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_tinylcd.c b/drivers/video/fbtft/fb_tinylcd.c +new file mode 100644 +index 0000000..ca98bfb +--- /dev/null ++++ b/drivers/video/fbtft/fb_tinylcd.c +@@ -0,0 +1,124 @@ ++/* ++ * Custom FB driver for tinylcd.com display ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_tinylcd" ++#define WIDTH 320 ++#define HEIGHT 480 ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xB0, 0x80); ++ write_reg(par, 0xC0, 0x0A, 0x0A); ++ write_reg(par, 0xC1, 0x45, 0x07); ++ write_reg(par, 0xC2, 0x33); ++ write_reg(par, 0xC5, 0x00, 0x42, 0x80); ++ write_reg(par, 0xB1, 0xD0, 0x11); ++ write_reg(par, 0xB4, 0x02); ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0xB7, 0x07); ++ write_reg(par, 0x36, 0x58); ++ write_reg(par, 0xF0, 0x36, 0xA5, 0xD3); ++ write_reg(par, 0xE5, 0x80); ++ write_reg(par, 0xE5, 0x01); ++ write_reg(par, 0xB3, 0x00); ++ write_reg(par, 0xE5, 0x00); ++ write_reg(par, 0xF0, 0x36, 0xA5, 0x53); ++ write_reg(par, 0xE0, 0x00, 0x35, 0x33, 0x00, 0x00, 0x00, ++ 0x00, 0x35, 0x33, 0x00, 0x00, 0x00); ++ write_reg(par, 0x3A, 0x55); ++ write_reg(par, 0x11); ++ udelay(250); ++ write_reg(par, 0x29); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 270: ++ write_reg(par, 0xB6, 0x00, 0x02, 0x3B); ++ write_reg(par, 0x36, 0x28); ++ break; ++ case 180: ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0x36, 0x58); ++ break; ++ case 90: ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0x36, 0x38); ++ break; ++ default: ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0x36, 0x08); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "neosec,tinylcd", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:tinylcd"); ++ ++MODULE_DESCRIPTION("Custom FB driver for tinylcd.com display"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_tls8204.c b/drivers/video/fbtft/fb_tls8204.c +new file mode 100644 +index 0000000..8738c7a +--- /dev/null ++++ b/drivers/video/fbtft/fb_tls8204.c +@@ -0,0 +1,176 @@ ++/* ++ * FB driver for the TLS8204 LCD Controller ++ * ++ * The display is monochrome and the video memory is RGB565. ++ * Any pixel value except 0 turns the pixel on. ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * Copyright (C) 2014 Michael Hope (adapted for the TLS8204) ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_tls8204" ++#define WIDTH 84 ++#define HEIGHT 48 ++#define TXBUFLEN WIDTH ++#define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ ++ ++static unsigned bs = 4; ++module_param(bs, uint, 0); ++MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* Enter extended command mode */ ++ write_reg(par, 0x21); /* 5:1 1 ++ 2:0 PD - Powerdown control: chip is active ++ 1:0 V - Entry mode: horizontal addressing ++ 0:1 H - Extended instruction set control: extended ++ */ ++ ++ /* H=1 Bias system */ ++ write_reg(par, 0x10 | (bs & 0x7)); /* ++ 4:1 1 ++ 3:0 0 ++ 2:x BS2 - Bias System ++ 1:x BS1 ++ 0:x BS0 ++ */ ++ ++ /* Set the address of the first display line. */ ++ write_reg(par, 0x04 | (64 >> 6)); ++ write_reg(par, 0x40 | (64 & 0x3F)); ++ ++ /* Enter H=0 standard command mode */ ++ write_reg(par, 0x20); ++ ++ /* H=0 Display control */ ++ write_reg(par, 0x08 | 4); /* ++ 3:1 1 ++ 2:1 D - DE: 10=normal mode ++ 1:0 0 ++ 0:0 E ++ */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* H=0 Set X address of RAM */ ++ write_reg(par, 0x80); /* 7:1 1 ++ 6-0: X[6:0] - 0x00 ++ */ ++ ++ /* H=0 Set Y address of RAM */ ++ write_reg(par, 0x40); /* 7:0 0 ++ 6:1 1 ++ 2-0: Y[2:0] - 0x0 ++ */ ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (y = 0; y < HEIGHT/8; y++) { ++ u8 *buf = par->txbuf.buf; ++ /* The display is 102x68 but the LCD is 84x48. Set ++ the write pointer at the start of each row. */ ++ gpio_set_value(par->gpio.dc, 0); ++ write_reg(par, 0x80 | 0); ++ write_reg(par, 0x40 | y); ++ ++ for (x = 0; x < WIDTH; x++) { ++ u8 ch = 0; ++ for (i = 0; i < 8*WIDTH; i += WIDTH) { ++ ch >>= 1; ++ if (vmem16[(y*8*WIDTH)+i+x]) ++ ch |= 0x80; ++ } ++ *buf++ = ch; ++ } ++ /* Write the row */ ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", __func__, ret); ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ curves[0] &= 0x7F; ++ ++ write_reg(par, 0x21); /* turn on extended instruction set */ ++ write_reg(par, 0x80 | curves[0]); ++ write_reg(par, 0x20); /* turn off extended instruction set */ ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 1, ++ .gamma_len = 1, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_vmem = write_vmem, ++ .set_gamma = set_gamma, ++ }, ++ .backlight = 1, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "teralane,tls8204", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:tls8204"); ++ ++MODULE_DESCRIPTION("FB driver for the TLS8204 LCD Controller"); ++MODULE_AUTHOR("Michael Hope"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_uc1701.c b/drivers/video/fbtft/fb_uc1701.c +new file mode 100644 +index 0000000..d70ac52 +--- /dev/null ++++ b/drivers/video/fbtft/fb_uc1701.c +@@ -0,0 +1,210 @@ ++/* ++ * FB driver for the UC1701 LCD Controller ++ * ++ * The display is monochrome and the video memory is RGB565. ++ * Any pixel value except 0 turns the pixel on. ++ * ++ * Copyright (C) 2014 Juergen Holzmann ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_uc1701" ++#define WIDTH 102 ++#define HEIGHT 64 ++#define PAGES (HEIGHT/8) ++ ++/* 1: Display on/off */ ++#define LCD_DISPLAY_ENABLE 0xAE ++/* 2: display start line set */ ++#define LCD_START_LINE 0x40 ++/* 3: Page address set (lower 4 bits select one of the pages) */ ++#define LCD_PAGE_ADDRESS 0xB0 ++/* 4: column address */ ++#define LCD_COL_ADDRESS 0x10 ++/* 8: select orientation */ ++#define LCD_BOTTOMVIEW 0xA0 ++/* 9: inverted display */ ++#define LCD_DISPLAY_INVERT 0xA6 ++/* 10: show memory content or switch all pixels on */ ++#define LCD_ALL_PIXEL 0xA4 ++/* 11: lcd bias set */ ++#define LCD_BIAS 0xA2 ++/* 14: Reset Controller */ ++#define LCD_RESET_CMD 0xE2 ++/* 15: output mode select (turns display upside-down) */ ++#define LCD_SCAN_DIR 0xC0 ++/* 16: power control set */ ++#define LCD_POWER_CONTROL 0x28 ++/* 17: voltage regulator resistor ratio set */ ++#define LCD_VOLTAGE 0x20 ++/* 18: Volume mode set */ ++#define LCD_VOLUME_MODE 0x81 ++/* 22: NOP command */ ++#define LCD_NO_OP 0xE3 ++/* 25: advanced program control */ ++#define LCD_ADV_PROG_CTRL 0xFA ++/* 25: advanced program control2 */ ++#define LCD_ADV_PROG_CTRL2 0x10 ++#define LCD_TEMPCOMP_HIGH 0x80 ++/* column offset for normal orientation */ ++#define SHIFT_ADDR_NORMAL 0 ++/* column offset for bottom view orientation */ ++#define SHIFT_ADDR_TOPVIEW 30 ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* softreset of LCD */ ++ write_reg(par, LCD_RESET_CMD); ++ mdelay(10); ++ ++ /* set startpoint */ ++ /* LCD_START_LINE | (pos & 0x3F) */ ++ write_reg(par, LCD_START_LINE); ++ ++ /* select orientation BOTTOMVIEW */ ++ write_reg(par, LCD_BOTTOMVIEW | 1); ++ /* output mode select (turns display upside-down) */ ++ write_reg(par, LCD_SCAN_DIR | 0x00); ++ ++ /* Normal Pixel mode */ ++ write_reg(par, LCD_ALL_PIXEL | 0); ++ ++ /* positive display */ ++ write_reg(par, LCD_DISPLAY_INVERT | 0); ++ ++ /* bias 1/9 */ ++ write_reg(par, LCD_BIAS | 0); ++ ++ /* power control mode: all features on */ ++ /* LCD_POWER_CONTROL | (val&0x07) */ ++ write_reg(par, LCD_POWER_CONTROL | 0x07); ++ ++ /* set voltage regulator R/R */ ++ /* LCD_VOLTAGE | (val&0x07) */ ++ write_reg(par, LCD_VOLTAGE | 0x07); ++ ++ /* volume mode set */ ++ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ ++ write_reg(par, LCD_VOLUME_MODE); ++ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ ++ write_reg(par, 0x09); ++ /* ???? */ ++ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ ++ write_reg(par, LCD_NO_OP); ++ ++ /* advanced program control */ ++ write_reg(par, LCD_ADV_PROG_CTRL); ++ write_reg(par, LCD_ADV_PROG_CTRL2|LCD_TEMPCOMP_HIGH); ++ ++ /* enable display */ ++ write_reg(par, LCD_DISPLAY_ENABLE | 1); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* goto address */ ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_PAGE_ADDRESS); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, 0x00); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_COL_ADDRESS); ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (y = 0; y < PAGES; y++) { ++ buf = par->txbuf.buf; ++ for (x = 0; x < WIDTH; x++) { ++ *buf = 0x00; ++ for (i = 0; i < 8; i++) ++ *buf |= (vmem16[((y*8*WIDTH)+(i*WIDTH))+x] ? 1 : 0) << i; ++ buf++; ++ } ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_PAGE_ADDRESS|(u8)y); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, 0x00); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_COL_ADDRESS); ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); ++ gpio_set_value(par->gpio.dc, 0); ++ } ++ ++ if (ret < 0) ++ dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_vmem = write_vmem, ++ }, ++ .backlight = 1, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:uc1701"); ++ ++MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller"); ++MODULE_AUTHOR("Juergen Holzmann"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_upd161704.c b/drivers/video/fbtft/fb_upd161704.c +new file mode 100644 +index 0000000..fff57b3 +--- /dev/null ++++ b/drivers/video/fbtft/fb_upd161704.c +@@ -0,0 +1,206 @@ ++/* ++ * FB driver for the uPD161704 LCD Controller ++ * ++ * Copyright (C) 2014 Seong-Woo Kim ++ * ++ * Based on fb_ili9325.c by Noralf Tronnes ++ * Based on ili9325.c by Jeroen Domburg ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_upd161704" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ /* Initialization sequence from Lib_UTFT */ ++ ++ /* register reset */ ++ write_reg(par, 0x0003,0x0001); /* Soft reset */ ++ ++ /* oscillator start */ ++ write_reg(par, 0x003A,0x0001); /*Oscillator 0: stop, 1: operation */ ++ udelay(100); ++ ++ /* y-setting */ ++ write_reg(par, 0x0024,0x007B); /* amplitude setting */ ++ udelay(10); ++ write_reg(par, 0x0025,0x003B); /* amplitude setting */ ++ write_reg(par, 0x0026,0x0034); /* amplitude setting */ ++ udelay(10); ++ write_reg(par, 0x0027,0x0004); /* amplitude setting */ ++ write_reg(par, 0x0052,0x0025); /* circuit setting 1 */ ++ udelay(10); ++ write_reg(par, 0x0053,0x0033); /* circuit setting 2 */ ++ write_reg(par, 0x0061,0x001C); /* adjustment V10 positive polarity */ ++ udelay(10); ++ write_reg(par, 0x0062,0x002C); /* adjustment V9 negative polarity */ ++ write_reg(par, 0x0063,0x0022); /* adjustment V34 positive polarity */ ++ udelay(10); ++ write_reg(par, 0x0064,0x0027); /* adjustment V31 negative polarity */ ++ udelay(10); ++ write_reg(par, 0x0065,0x0014); /* adjustment V61 negative polarity */ ++ udelay(10); ++ write_reg(par, 0x0066,0x0010); /* adjustment V61 negative polarity */ ++ ++ /* Basical clock for 1 line (BASECOUNT[7:0]) number specified */ ++ write_reg(par, 0x002E,0x002D); ++ ++ /* Power supply setting */ ++ write_reg(par, 0x0019,0x0000); /* DC/DC output setting */ ++ udelay(200); ++ write_reg(par, 0x001A,0x1000); /* DC/DC frequency setting */ ++ write_reg(par, 0x001B,0x0023); /* DC/DC rising setting */ ++ write_reg(par, 0x001C,0x0C01); /* Regulator voltage setting */ ++ write_reg(par, 0x001D,0x0000); /* Regulator current setting */ ++ write_reg(par, 0x001E,0x0009); /* VCOM output setting */ ++ write_reg(par, 0x001F,0x0035); /* VCOM amplitude setting */ ++ write_reg(par, 0x0020,0x0015); /* VCOMM cencter setting */ ++ write_reg(par, 0x0018,0x1E7B); /* DC/DC operation setting */ ++ ++ /* windows setting */ ++ write_reg(par, 0x0008,0x0000); /* Minimum X address */ ++ write_reg(par, 0x0009,0x00EF); /* Maximum X address */ ++ write_reg(par, 0x000a,0x0000); /* Minimum Y address */ ++ write_reg(par, 0x000b,0x013F); /* Maximum Y address */ ++ ++ /* LCD display area setting */ ++ write_reg(par, 0x0029,0x0000); /* [LCDSIZE] X MIN. size set */ ++ write_reg(par, 0x002A,0x0000); /* [LCDSIZE] Y MIN. size set */ ++ write_reg(par, 0x002B,0x00EF); /* [LCDSIZE] X MAX. size set */ ++ write_reg(par, 0x002C,0x013F); /* [LCDSIZE] Y MAX. size set */ ++ ++ /* Gate scan setting */ ++ write_reg(par, 0x0032,0x0002); ++ ++ /* n line inversion line number */ ++ write_reg(par, 0x0033,0x0000); ++ ++ /* Line inversion/frame inversion/interlace setting */ ++ write_reg(par, 0x0037,0x0000); ++ ++ /* Gate scan operation setting register */ ++ write_reg(par, 0x003B,0x0001); ++ ++ /* Color mode */ ++ /*GS = 0: 260-k color (64 gray scale), GS = 1: 8 color (2 gray scale) */ ++ write_reg(par, 0x0004,0x0000); ++ ++ /* RAM control register */ ++ write_reg(par, 0x0005,0x0000); /*Window access 00:Normal, 10:Window */ ++ ++ /* Display setting register 2 */ ++ write_reg(par, 0x0001,0x0000); ++ ++ /* display setting */ ++ write_reg(par, 0x0000,0x0000); /* display on */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0006, xs); ++ write_reg(par, 0x0007, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0006, WIDTH - 1 - xs); ++ write_reg(par, 0x0007, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0006, WIDTH - 1 - ys); ++ write_reg(par, 0x0007, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0006, ys); ++ write_reg(par, 0x0007, HEIGHT - 1 - xs); ++ break; ++ } ++ ++ write_reg(par, 0x0e); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x01, 0x0000); ++ write_reg(par, 0x05, 0x0000); ++ break; ++ case 180: ++ write_reg(par, 0x01, 0x00C0); ++ write_reg(par, 0x05, 0x0000); ++ break; ++ case 270: ++ write_reg(par, 0x01, 0x0080); ++ write_reg(par, 0x05, 0x0001); ++ break; ++ case 90: ++ write_reg(par, 0x01, 0x0040); ++ write_reg(par, 0x05, 0x0001); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "nec,upd161704", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:upd161704"); ++MODULE_ALIAS("platform:upd161704"); ++ ++MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller"); ++MODULE_AUTHOR("Seong-Woo Kim"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fb_watterott.c b/drivers/video/fbtft/fb_watterott.c +new file mode 100644 +index 0000000..975b579 +--- /dev/null ++++ b/drivers/video/fbtft/fb_watterott.c +@@ -0,0 +1,324 @@ ++/* ++ * FB driver for the Watterott LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_watterott" ++#define WIDTH 320 ++#define HEIGHT 240 ++#define FPS 5 ++#define TXBUFLEN 1024 ++#define DEFAULT_BRIGHTNESS 50 ++ ++#define CMD_VERSION 0x01 ++#define CMD_LCD_LED 0x10 ++#define CMD_LCD_RESET 0x11 ++#define CMD_LCD_ORIENTATION 0x20 ++#define CMD_LCD_DRAWIMAGE 0x27 ++#define COLOR_RGB323 8 ++#define COLOR_RGB332 9 ++#define COLOR_RGB233 10 ++#define COLOR_RGB565 16 ++ ++ ++static short mode = 565; ++module_param(mode, short, 0); ++MODULE_PARM_DESC(mode, "RGB color transfer mode: 332, 565 (default)"); ++ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = par->buf; ++ ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ *buf++ = (u8)va_arg(args, unsigned int); ++ va_end(args); ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, ++ par->info->device, u8, par->buf, len, "%s: ", __func__); ++ ++ ret = par->fbtftops.write(par, par->buf, len); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ unsigned start_line, end_line; ++ u16 *vmem16 = (u16 *)(par->info->screen_base + offset); ++ u16 *pos = par->txbuf.buf + 1; ++ u16 *buf16 = par->txbuf.buf + 10; ++ int i, j; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ start_line = offset / par->info->fix.line_length; ++ end_line = start_line + (len / par->info->fix.line_length) - 1; ++ ++ /* Set command header. pos: x, y, w, h */ ++ ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE; ++ pos[0] = 0; ++ pos[2] = cpu_to_be16(par->info->var.xres); ++ pos[3] = cpu_to_be16(1); ++ ((u8 *)par->txbuf.buf)[9] = COLOR_RGB565; ++ ++ for (i = start_line; i <= end_line; i++) { ++ pos[1] = cpu_to_be16(i); ++ for (j = 0; j < par->info->var.xres; j++) ++ buf16[j] = cpu_to_be16(*vmem16++); ++ ret = par->fbtftops.write(par, ++ par->txbuf.buf, 10 + par->info->fix.line_length); ++ if (ret < 0) ++ return ret; ++ udelay(300); ++ } ++ ++ return 0; ++} ++ ++#define RGB565toRGB323(c) (((c&0xE000)>>8) | ((c&0600)>>6) | ((c&0x001C)>>2)) ++#define RGB565toRGB332(c) (((c&0xE000)>>8) | ((c&0700)>>6) | ((c&0x0018)>>3)) ++#define RGB565toRGB233(c) (((c&0xC000)>>8) | ((c&0700)>>5) | ((c&0x001C)>>2)) ++ ++static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ unsigned start_line, end_line; ++ u16 *vmem16 = (u16 *)(par->info->screen_base + offset); ++ u16 *pos = par->txbuf.buf + 1; ++ u8 *buf8 = par->txbuf.buf + 10; ++ int i, j; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ start_line = offset / par->info->fix.line_length; ++ end_line = start_line + (len / par->info->fix.line_length) - 1; ++ ++ /* Set command header. pos: x, y, w, h */ ++ ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE; ++ pos[0] = 0; ++ pos[2] = cpu_to_be16(par->info->var.xres); ++ pos[3] = cpu_to_be16(1); ++ ((u8 *)par->txbuf.buf)[9] = COLOR_RGB332; ++ ++ for (i = start_line; i <= end_line; i++) { ++ pos[1] = cpu_to_be16(i); ++ for (j = 0; j < par->info->var.xres; j++) { ++ buf8[j] = RGB565toRGB332(*vmem16); ++ vmem16++; ++ } ++ ret = par->fbtftops.write(par, ++ par->txbuf.buf, 10 + par->info->var.xres); ++ if (ret < 0) ++ return ret; ++ udelay(700); ++ } ++ ++ return 0; ++} ++ ++static unsigned firmware_version(struct fbtft_par *par) ++{ ++ u8 rxbuf[4] = {0, }; ++ ++ write_reg(par, CMD_VERSION); ++ par->fbtftops.read(par, rxbuf, 4); ++ if (rxbuf[1] != '.') ++ return 0; ++ ++ return (rxbuf[0] - '0') << 8 | (rxbuf[2] - '0') << 4 | (rxbuf[3] - '0'); ++} ++ ++static int init_display(struct fbtft_par *par) ++{ ++ int ret; ++ unsigned version; ++ u8 save_mode; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* enable SPI interface by having CS and MOSI low during reset */ ++ save_mode = par->spi->mode; ++ par->spi->mode |= SPI_CS_HIGH; ++ ret = par->spi->master->setup(par->spi); /* set CS inactive low */ ++ if (ret) { ++ dev_err(par->info->device, "Could not set SPI_CS_HIGH\n"); ++ return ret; ++ } ++ write_reg(par, 0x00); /* make sure mode is set */ ++ ++ mdelay(50); ++ par->fbtftops.reset(par); ++ mdelay(1000); ++ par->spi->mode = save_mode; ++ ret = par->spi->master->setup(par->spi); ++ if (ret) { ++ dev_err(par->info->device, "Could not restore SPI mode\n"); ++ return ret; ++ } ++ write_reg(par, 0x00); ++ ++ version = firmware_version(par); ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Firmware version: %x.%02x\n", ++ version >> 8, version & 0xFF); ++ ++ if (mode == 332) ++ par->fbtftops.write_vmem = write_vmem_8bit; ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ /* not used on this controller */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ u8 rotate; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* this controller rotates clock wise */ ++ switch (par->info->var.rotate) { ++ case 90: ++ rotate = 27; ++ break; ++ case 180: ++ rotate = 18; ++ break; ++ case 270: ++ rotate = 9; ++ break; ++ default: ++ rotate = 0; ++ } ++ write_reg(par, CMD_LCD_ORIENTATION, rotate); ++ ++ return 0; ++} ++ ++static int verify_gpios(struct fbtft_par *par) ++{ ++ if (par->gpio.reset < 0) { ++ dev_err(par->info->device, "Missing 'reset' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_FB_BACKLIGHT ++static int backlight_chip_update_status(struct backlight_device *bd) ++{ ++ struct fbtft_par *par = bl_get_data(bd); ++ int brightness = bd->props.brightness; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s: brightness=%d, power=%d, fb_blank=%d\n", ++ __func__, bd->props.brightness, bd->props.power, ++ bd->props.fb_blank); ++ ++ if (bd->props.power != FB_BLANK_UNBLANK) ++ brightness = 0; ++ ++ if (bd->props.fb_blank != FB_BLANK_UNBLANK) ++ brightness = 0; ++ ++ write_reg(par, CMD_LCD_LED, brightness); ++ ++ return 0; ++} ++ ++static void register_chip_backlight(struct fbtft_par *par) ++{ ++ struct backlight_device *bd; ++ struct backlight_properties bl_props = { 0, }; ++ struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), ++ GFP_KERNEL); ++ if (!bl_ops) { ++ dev_err(par->info->device, ++ "%s: could not allocate memory for backlight operations.\n", ++ __func__); ++ return; ++ } ++ ++ bl_ops->update_status = backlight_chip_update_status; ++ bl_props.type = BACKLIGHT_RAW; ++ bl_props.power = FB_BLANK_POWERDOWN; ++ bl_props.max_brightness = 100; ++ bl_props.brightness = DEFAULT_BRIGHTNESS; ++ ++ bd = backlight_device_register(dev_driver_string(par->info->device), ++ par->info->device, par, bl_ops, &bl_props); ++ if (IS_ERR(bd)) { ++ dev_err(par->info->device, ++ "cannot register backlight device (%ld)\n", ++ PTR_ERR(bd)); ++ return; ++ } ++ par->info->bl_dev = bd; ++ ++ if (!par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight = fbtft_unregister_backlight; ++} ++#else ++#define register_chip_backlight NULL ++#endif ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .buswidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fps = FPS, ++ .txbuflen = TXBUFLEN, ++ .fbtftops = { ++ .write_register = write_reg8_bus8, ++ .write_vmem = write_vmem, ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .verify_gpios = verify_gpios, ++ .register_backlight = register_chip_backlight, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "watterott,openlcd", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++ ++MODULE_DESCRIPTION("FB driver for the Watterott LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fbtft-bus.c b/drivers/video/fbtft/fbtft-bus.c +new file mode 100644 +index 0000000..b3cddb0 +--- /dev/null ++++ b/drivers/video/fbtft/fbtft-bus.c +@@ -0,0 +1,256 @@ ++#include ++#include ++#include ++#include ++#include "fbtft.h" ++ ++ ++ ++ ++/***************************************************************************** ++ * ++ * void (*write_reg)(struct fbtft_par *par, int len, ...); ++ * ++ *****************************************************************************/ ++ ++#define define_fbtft_write_reg(func, type, modifier) \ ++void func(struct fbtft_par *par, int len, ...) \ ++{ \ ++ va_list args; \ ++ int i, ret; \ ++ int offset = 0; \ ++ type *buf = (type *)par->buf; \ ++ \ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { \ ++ va_start(args, len); \ ++ for (i = 0; i < len; i++) { \ ++ buf[i] = (type)va_arg(args, unsigned int); \ ++ } \ ++ va_end(args); \ ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, type, buf, len, "%s: ", __func__); \ ++ } \ ++ \ ++ va_start(args, len); \ ++ \ ++ if (par->startbyte) { \ ++ *(u8 *)par->buf = par->startbyte; \ ++ buf = (type *)(par->buf + 1); \ ++ offset = 1; \ ++ } \ ++ \ ++ *buf = modifier((type)va_arg(args, unsigned int)); \ ++ if (par->gpio.dc != -1) \ ++ gpio_set_value(par->gpio.dc, 0); \ ++ ret = par->fbtftops.write(par, par->buf, sizeof(type)+offset); \ ++ if (ret < 0) { \ ++ va_end(args); \ ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \ ++ return; \ ++ } \ ++ len--; \ ++ \ ++ if (par->startbyte) \ ++ *(u8 *)par->buf = par->startbyte | 0x2; \ ++ \ ++ if (len) { \ ++ i = len; \ ++ while (i--) { \ ++ *buf++ = modifier((type)va_arg(args, unsigned int)); \ ++ } \ ++ if (par->gpio.dc != -1) \ ++ gpio_set_value(par->gpio.dc, 1); \ ++ ret = par->fbtftops.write(par, par->buf, len * (sizeof(type)+offset)); \ ++ if (ret < 0) { \ ++ va_end(args); \ ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \ ++ return; \ ++ } \ ++ } \ ++ va_end(args); \ ++} \ ++EXPORT_SYMBOL(func); ++ ++define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, ) ++define_fbtft_write_reg(fbtft_write_reg16_bus8, u16, cpu_to_be16) ++define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, ) ++ ++void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ int pad = 0; ++ u16 *buf = (u16 *)par->buf; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ *(((u8 *)buf) + i) = (u8)va_arg(args, unsigned int); ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, ++ par->info->device, u8, buf, len, "%s: ", __func__); ++ } ++ if (len <= 0) ++ return; ++ ++ if (par->spi && (par->spi->bits_per_word == 8)) { ++ /* we're emulating 9-bit, pad start of buffer with no-ops ++ (assuming here that zero is a no-op) */ ++ pad = (len % 4) ? 4 - (len % 4) : 0; ++ for (i = 0; i < pad; i++) ++ *buf++ = 0x000; ++ } ++ ++ va_start(args, len); ++ *buf++ = (u8)va_arg(args, unsigned int); ++ i = len - 1; ++ while (i--) { ++ *buf = (u8)va_arg(args, unsigned int); ++ *buf++ |= 0x100; /* dc=1 */ ++ } ++ va_end(args); ++ ret = par->fbtftops.write(par, par->buf, (len + pad) * sizeof(u16)); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++} ++EXPORT_SYMBOL(fbtft_write_reg8_bus9); ++ ++ ++ ++ ++/***************************************************************************** ++ * ++ * int (*write_vmem)(struct fbtft_par *par); ++ * ++ *****************************************************************************/ ++ ++/* 16 bit pixel over 8-bit databus */ ++int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16; ++ u16 *txbuf16 = (u16 *)par->txbuf.buf; ++ size_t remain; ++ size_t to_copy; ++ size_t tx_array_size; ++ int i; ++ int ret = 0; ++ size_t startbyte_size = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ remain = len / 2; ++ vmem16 = (u16 *)(par->info->screen_base + offset); ++ ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 1); ++ ++ /* non buffered write */ ++ if (!par->txbuf.buf) ++ return par->fbtftops.write(par, vmem16, len); ++ ++ /* buffered write */ ++ tx_array_size = par->txbuf.len / 2; ++ ++ if (par->startbyte) { ++ txbuf16 = (u16 *)(par->txbuf.buf + 1); ++ tx_array_size -= 2; ++ *(u8 *)(par->txbuf.buf) = par->startbyte | 0x2; ++ startbyte_size = 1; ++ } ++ ++ while (remain) { ++ to_copy = remain > tx_array_size ? tx_array_size : remain; ++ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", ++ to_copy, remain - to_copy); ++ ++ for (i = 0; i < to_copy; i++) ++ txbuf16[i] = cpu_to_be16(vmem16[i]); ++ ++ vmem16 = vmem16 + to_copy; ++ ret = par->fbtftops.write(par, par->txbuf.buf, ++ startbyte_size + to_copy * 2); ++ if (ret < 0) ++ return ret; ++ remain -= to_copy; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_write_vmem16_bus8); ++ ++/* 16 bit pixel over 9-bit SPI bus: dc + high byte, dc + low byte */ ++int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u8 *vmem8; ++ u16 *txbuf16 = par->txbuf.buf; ++ size_t remain; ++ size_t to_copy; ++ size_t tx_array_size; ++ int i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ if (!par->txbuf.buf) { ++ dev_err(par->info->device, "%s: txbuf.buf is NULL\n", __func__); ++ return -1; ++ } ++ ++ remain = len; ++ vmem8 = par->info->screen_base + offset; ++ ++ tx_array_size = par->txbuf.len / 2; ++ ++ while (remain) { ++ to_copy = remain > tx_array_size ? tx_array_size : remain; ++ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", ++ to_copy, remain - to_copy); ++ ++#ifdef __LITTLE_ENDIAN ++ for (i = 0; i < to_copy; i += 2) { ++ txbuf16[i] = 0x0100 | vmem8[i+1]; ++ txbuf16[i+1] = 0x0100 | vmem8[i]; ++ } ++#else ++ for (i = 0; i < to_copy; i++) ++ txbuf16[i] = 0x0100 | vmem8[i]; ++#endif ++ vmem8 = vmem8 + to_copy; ++ ret = par->fbtftops.write(par, par->txbuf.buf, to_copy*2); ++ if (ret < 0) ++ return ret; ++ remain -= to_copy; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_write_vmem16_bus9); ++ ++int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ dev_err(par->info->device, "%s: function not implemented\n", __func__); ++ return -1; ++} ++EXPORT_SYMBOL(fbtft_write_vmem8_bus8); ++ ++/* 16 bit pixel over 16-bit databus */ ++int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ vmem16 = (u16 *)(par->info->screen_base + offset); ++ ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 1); ++ ++ /* no need for buffered write with 16-bit bus */ ++ return par->fbtftops.write(par, vmem16, len); ++} ++EXPORT_SYMBOL(fbtft_write_vmem16_bus16); +diff --git a/drivers/video/fbtft/fbtft-core.c b/drivers/video/fbtft/fbtft-core.c +new file mode 100644 +index 0000000..873e2c7 +--- /dev/null ++++ b/drivers/video/fbtft/fbtft-core.c +@@ -0,0 +1,1516 @@ ++/* ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This driver is inspired by: ++ * st7735fb.c, Copyright (C) 2011, Matt Porter ++ * broadsheetfb.c, Copyright (C) 2008, Jaya Kumar ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++extern void fbtft_sysfs_init(struct fbtft_par *par); ++extern void fbtft_sysfs_exit(struct fbtft_par *par); ++extern void fbtft_expand_debug_value(unsigned long *debug); ++extern int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves, ++ const char *str, int size); ++ ++static unsigned long debug; ++module_param(debug, ulong , 0); ++MODULE_PARM_DESC(debug, "override device debug level"); ++ ++static bool dma = true; ++module_param(dma, bool, 0); ++MODULE_PARM_DESC(dma, "Use DMA buffer"); ++ ++ ++void fbtft_dbg_hex(const struct device *dev, int groupsize, ++ void *buf, size_t len, const char *fmt, ...) ++{ ++ va_list args; ++ static char textbuf[512]; ++ char *text = textbuf; ++ size_t text_len; ++ ++ va_start(args, fmt); ++ text_len = vscnprintf(text, sizeof(textbuf), fmt, args); ++ va_end(args); ++ ++ hex_dump_to_buffer(buf, len, 32, groupsize, text + text_len, ++ 512 - text_len, false); ++ ++ if (len > 32) ++ dev_info(dev, "%s ...\n", text); ++ else ++ dev_info(dev, "%s\n", text); ++} ++EXPORT_SYMBOL(fbtft_dbg_hex); ++ ++unsigned long fbtft_request_gpios_match(struct fbtft_par *par, ++ const struct fbtft_gpio *gpio) ++{ ++ int ret; ++ long val; ++ ++ fbtft_par_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, "%s('%s')\n", ++ __func__, gpio->name); ++ ++ if (strcasecmp(gpio->name, "reset") == 0) { ++ par->gpio.reset = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "dc") == 0) { ++ par->gpio.dc = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (strcasecmp(gpio->name, "cs") == 0) { ++ par->gpio.cs = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "wr") == 0) { ++ par->gpio.wr = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "rd") == 0) { ++ par->gpio.rd = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "latch") == 0) { ++ par->gpio.latch = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (gpio->name[0] == 'd' && gpio->name[1] == 'b') { ++ ret = kstrtol(&gpio->name[2], 10, &val); ++ if (ret == 0 && val < 16) { ++ par->gpio.db[val] = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } ++ } else if (strcasecmp(gpio->name, "led") == 0) { ++ par->gpio.led[0] = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (strcasecmp(gpio->name, "led_") == 0) { ++ par->gpio.led[0] = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } ++ ++ return FBTFT_GPIO_NO_MATCH; ++} ++ ++int fbtft_request_gpios(struct fbtft_par *par) ++{ ++ struct fbtft_platform_data *pdata = par->pdata; ++ const struct fbtft_gpio *gpio; ++ unsigned long flags; ++ int ret; ++ ++ if (pdata && pdata->gpios) { ++ gpio = pdata->gpios; ++ while (gpio->name[0]) { ++ flags = FBTFT_GPIO_NO_MATCH; ++ /* if driver provides match function, try it first, ++ if no match use our own */ ++ if (par->fbtftops.request_gpios_match) ++ flags = par->fbtftops.request_gpios_match(par, gpio); ++ if (flags == FBTFT_GPIO_NO_MATCH) ++ flags = fbtft_request_gpios_match(par, gpio); ++ if (flags != FBTFT_GPIO_NO_MATCH) { ++ ret = devm_gpio_request_one(par->info->device, ++ gpio->gpio, flags, ++ par->info->device->driver->name); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: gpio_request_one('%s'=%d) failed with %d\n", ++ __func__, gpio->name, ++ gpio->gpio, ret); ++ return ret; ++ } ++ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, ++ "%s: '%s' = GPIO%d\n", ++ __func__, gpio->name, gpio->gpio); ++ } ++ gpio++; ++ } ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static int fbtft_request_one_gpio(struct fbtft_par *par, ++ const char *name, int index, int *gpiop) ++{ ++ struct device *dev = par->info->device; ++ struct device_node *node = dev->of_node; ++ int gpio, flags, ret = 0; ++ enum of_gpio_flags of_flags; ++ ++ if (of_find_property(node, name, NULL)) { ++ gpio = of_get_named_gpio_flags(node, name, index, &of_flags); ++ if (gpio == -ENOENT) ++ return 0; ++ if (gpio == -EPROBE_DEFER) ++ return gpio; ++ if (gpio < 0) { ++ dev_err(dev, ++ "failed to get '%s' from DT\n", name); ++ return gpio; ++ } ++ ++ /* active low translates to initially low */ ++ flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW : ++ GPIOF_OUT_INIT_HIGH; ++ ret = devm_gpio_request_one(dev, gpio, flags, ++ dev->driver->name); ++ if (ret) { ++ dev_err(dev, ++ "gpio_request_one('%s'=%d) failed with %d\n", ++ name, gpio, ret); ++ return ret; ++ } ++ if (gpiop) ++ *gpiop = gpio; ++ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n", ++ __func__, name, gpio); ++ } ++ ++ return ret; ++} ++ ++static int fbtft_request_gpios_dt(struct fbtft_par *par) ++{ ++ int i; ++ int ret; ++ ++ if (!par->info->device->of_node) ++ return -EINVAL; ++ ++ ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch); ++ if (ret) ++ return ret; ++ for (i = 0; i < 16; i++) { ++ ret = fbtft_request_one_gpio(par, "db-gpios", i, ++ &par->gpio.db[i]); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "led-gpios", i, ++ &par->gpio.led[i]); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "aux-gpios", i, ++ &par->gpio.aux[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_FB_BACKLIGHT ++int fbtft_backlight_update_status(struct backlight_device *bd) ++{ ++ struct fbtft_par *par = bl_get_data(bd); ++ bool polarity = !!(bd->props.state & BL_CORE_DRIVER1); ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s: polarity=%d, power=%d, fb_blank=%d\n", ++ __func__, polarity, bd->props.power, bd->props.fb_blank); ++ ++ if ((bd->props.power == FB_BLANK_UNBLANK) && (bd->props.fb_blank == FB_BLANK_UNBLANK)) ++ gpio_set_value(par->gpio.led[0], polarity); ++ else ++ gpio_set_value(par->gpio.led[0], !polarity); ++ ++ return 0; ++} ++ ++int fbtft_backlight_get_brightness(struct backlight_device *bd) ++{ ++ return bd->props.brightness; ++} ++ ++void fbtft_unregister_backlight(struct fbtft_par *par) ++{ ++ const struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ if (par->info->bl_dev) { ++ par->info->bl_dev->props.power = FB_BLANK_POWERDOWN; ++ backlight_update_status(par->info->bl_dev); ++ bl_ops = par->info->bl_dev->ops; ++ backlight_device_unregister(par->info->bl_dev); ++ par->info->bl_dev = NULL; ++ } ++} ++ ++void fbtft_register_backlight(struct fbtft_par *par) ++{ ++ struct backlight_device *bd; ++ struct backlight_properties bl_props = { 0, }; ++ struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ if (par->gpio.led[0] == -1) { ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s(): led pin not set, exiting.\n", __func__); ++ return; ++ } ++ ++ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), ++ GFP_KERNEL); ++ if (!bl_ops) { ++ dev_err(par->info->device, ++ "%s: could not allocate memeory for backlight operations.\n", ++ __func__); ++ return; ++ } ++ ++ bl_ops->get_brightness = fbtft_backlight_get_brightness; ++ bl_ops->update_status = fbtft_backlight_update_status; ++ bl_props.type = BACKLIGHT_RAW; ++ /* Assume backlight is off, get polarity from current state of pin */ ++ bl_props.power = FB_BLANK_POWERDOWN; ++ if (!gpio_get_value(par->gpio.led[0])) ++ bl_props.state |= BL_CORE_DRIVER1; ++ ++ bd = backlight_device_register(dev_driver_string(par->info->device), ++ par->info->device, par, bl_ops, &bl_props); ++ if (IS_ERR(bd)) { ++ dev_err(par->info->device, ++ "cannot register backlight device (%ld)\n", ++ PTR_ERR(bd)); ++ return; ++ } ++ par->info->bl_dev = bd; ++ ++ if (!par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight = fbtft_unregister_backlight; ++} ++#else ++void fbtft_register_backlight(struct fbtft_par *par) { }; ++void fbtft_unregister_backlight(struct fbtft_par *par) { }; ++#endif ++EXPORT_SYMBOL(fbtft_register_backlight); ++EXPORT_SYMBOL(fbtft_unregister_backlight); ++ ++void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address set */ ++ write_reg(par, 0x2A, ++ (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF); ++ ++ /* Row adress set */ ++ write_reg(par, 0x2B, ++ (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++ ++void fbtft_reset(struct fbtft_par *par) ++{ ++ if (par->gpio.reset == -1) ++ return; ++ fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__); ++ gpio_set_value(par->gpio.reset, 0); ++ udelay(20); ++ gpio_set_value(par->gpio.reset, 1); ++ mdelay(120); ++} ++ ++ ++void fbtft_update_display(struct fbtft_par *par, unsigned start_line, unsigned end_line) ++{ ++ size_t offset, len; ++ struct timespec ts_start, ts_end, ts_fps, ts_duration; ++ long fps_ms, fps_us, duration_ms, duration_us; ++ long fps, throughput; ++ bool timeit = false; ++ int ret = 0; ++ ++ if (unlikely(par->debug & (DEBUG_TIME_FIRST_UPDATE | DEBUG_TIME_EACH_UPDATE))) { ++ if ((par->debug & DEBUG_TIME_EACH_UPDATE) || \ ++ ((par->debug & DEBUG_TIME_FIRST_UPDATE) && !par->first_update_done)) { ++ getnstimeofday(&ts_start); ++ timeit = true; ++ } ++ } ++ ++ /* Sanity checks */ ++ if (start_line > end_line) { ++ dev_warn(par->info->device, ++ "%s: start_line=%u is larger than end_line=%u. Shouldn't happen, will do full display update\n", ++ __func__, start_line, end_line); ++ start_line = 0; ++ end_line = par->info->var.yres - 1; ++ } ++ if (start_line > par->info->var.yres - 1 || end_line > par->info->var.yres - 1) { ++ dev_warn(par->info->device, ++ "%s: start_line=%u or end_line=%u is larger than max=%d. Shouldn't happen, will do full display update\n", ++ __func__, start_line, end_line, par->info->var.yres - 1); ++ start_line = 0; ++ end_line = par->info->var.yres - 1; ++ } ++ ++ fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n", ++ __func__, start_line, end_line); ++ ++ if (par->fbtftops.set_addr_win) ++ par->fbtftops.set_addr_win(par, 0, start_line, ++ par->info->var.xres-1, end_line); ++ ++ offset = start_line * par->info->fix.line_length; ++ len = (end_line - start_line + 1) * par->info->fix.line_length; ++ ret = par->fbtftops.write_vmem(par, offset, len); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write_vmem failed to update display buffer\n", ++ __func__); ++ ++ if (unlikely(timeit)) { ++ getnstimeofday(&ts_end); ++ if (par->update_time.tv_nsec == 0 && par->update_time.tv_sec == 0) { ++ par->update_time.tv_sec = ts_start.tv_sec; ++ par->update_time.tv_nsec = ts_start.tv_nsec; ++ } ++ ts_fps = timespec_sub(ts_start, par->update_time); ++ par->update_time.tv_sec = ts_start.tv_sec; ++ par->update_time.tv_nsec = ts_start.tv_nsec; ++ fps_ms = (ts_fps.tv_sec * 1000) + ((ts_fps.tv_nsec / 1000000) % 1000); ++ fps_us = (ts_fps.tv_nsec / 1000) % 1000; ++ fps = fps_ms * 1000 + fps_us; ++ fps = fps ? 1000000 / fps : 0; ++ ++ ts_duration = timespec_sub(ts_end, ts_start); ++ duration_ms = (ts_duration.tv_sec * 1000) + ((ts_duration.tv_nsec / 1000000) % 1000); ++ duration_us = (ts_duration.tv_nsec / 1000) % 1000; ++ throughput = duration_ms * 1000 + duration_us; ++ throughput = throughput ? (len * 1000) / throughput : 0; ++ throughput = throughput * 1000 / 1024; ++ ++ dev_info(par->info->device, ++ "Display update: %ld kB/s (%ld.%.3ld ms), fps=%ld (%ld.%.3ld ms)\n", ++ throughput, duration_ms, duration_us, ++ fps, fps_ms, fps_us); ++ par->first_update_done = true; ++ } ++} ++ ++ ++void fbtft_mkdirty(struct fb_info *info, int y, int height) ++{ ++ struct fbtft_par *par = info->par; ++ struct fb_deferred_io *fbdefio = info->fbdefio; ++ ++ /* special case, needed ? */ ++ if (y == -1) { ++ y = 0; ++ height = info->var.yres - 1; ++ } ++ ++ /* Mark display lines/area as dirty */ ++ spin_lock(&par->dirty_lock); ++ if (y < par->dirty_lines_start) ++ par->dirty_lines_start = y; ++ if (y + height - 1 > par->dirty_lines_end) ++ par->dirty_lines_end = y + height - 1; ++ spin_unlock(&par->dirty_lock); ++ ++ /* Schedule deferred_io to update display (no-op if already on queue)*/ ++ schedule_delayed_work(&info->deferred_work, fbdefio->delay); ++} ++ ++void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) ++{ ++ struct fbtft_par *par = info->par; ++ unsigned dirty_lines_start, dirty_lines_end; ++ struct page *page; ++ unsigned long index; ++ unsigned y_low = 0, y_high = 0; ++ int count = 0; ++ ++ spin_lock(&par->dirty_lock); ++ dirty_lines_start = par->dirty_lines_start; ++ dirty_lines_end = par->dirty_lines_end; ++ /* set display line markers as clean */ ++ par->dirty_lines_start = par->info->var.yres - 1; ++ par->dirty_lines_end = 0; ++ spin_unlock(&par->dirty_lock); ++ ++ /* Mark display lines as dirty */ ++ list_for_each_entry(page, pagelist, lru) { ++ count++; ++ index = page->index << PAGE_SHIFT; ++ y_low = index / info->fix.line_length; ++ y_high = (index + PAGE_SIZE - 1) / info->fix.line_length; ++ fbtft_dev_dbg(DEBUG_DEFERRED_IO, par, info->device, ++ "page->index=%lu y_low=%d y_high=%d\n", ++ page->index, y_low, y_high); ++ if (y_high > info->var.yres - 1) ++ y_high = info->var.yres - 1; ++ if (y_low < dirty_lines_start) ++ dirty_lines_start = y_low; ++ if (y_high > dirty_lines_end) ++ dirty_lines_end = y_high; ++ } ++ ++ par->fbtftops.update_display(info->par, ++ dirty_lines_start, dirty_lines_end); ++} ++ ++ ++void fbtft_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ struct fbtft_par *par = info->par; ++ ++ fbtft_dev_dbg(DEBUG_FB_FILLRECT, par, info->dev, ++ "%s: dx=%d, dy=%d, width=%d, height=%d\n", ++ __func__, rect->dx, rect->dy, rect->width, rect->height); ++ sys_fillrect(info, rect); ++ ++ par->fbtftops.mkdirty(info, rect->dy, rect->height); ++} ++ ++void fbtft_fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ++{ ++ struct fbtft_par *par = info->par; ++ ++ fbtft_dev_dbg(DEBUG_FB_COPYAREA, par, info->dev, ++ "%s: dx=%d, dy=%d, width=%d, height=%d\n", ++ __func__, area->dx, area->dy, area->width, area->height); ++ sys_copyarea(info, area); ++ ++ par->fbtftops.mkdirty(info, area->dy, area->height); ++} ++ ++void fbtft_fb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ struct fbtft_par *par = info->par; ++ ++ fbtft_dev_dbg(DEBUG_FB_IMAGEBLIT, par, info->dev, ++ "%s: dx=%d, dy=%d, width=%d, height=%d\n", ++ __func__, image->dx, image->dy, image->width, image->height); ++ sys_imageblit(info, image); ++ ++ par->fbtftops.mkdirty(info, image->dy, image->height); ++} ++ ++ssize_t fbtft_fb_write(struct fb_info *info, ++ const char __user *buf, size_t count, loff_t *ppos) ++{ ++ struct fbtft_par *par = info->par; ++ ssize_t res; ++ ++ fbtft_dev_dbg(DEBUG_FB_WRITE, par, info->dev, ++ "%s: count=%zd, ppos=%llu\n", __func__, count, *ppos); ++ res = fb_sys_write(info, buf, count, ppos); ++ ++ /* TODO: only mark changed area ++ update all for now */ ++ par->fbtftops.mkdirty(info, -1, 0); ++ ++ return res; ++} ++ ++/* from pxafb.c */ ++unsigned int chan_to_field(unsigned chan, struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++int fbtft_fb_setcolreg(unsigned regno, ++ unsigned red, unsigned green, unsigned blue, ++ unsigned transp, struct fb_info *info) ++{ ++ struct fbtft_par *par = info->par; ++ unsigned val; ++ int ret = 1; ++ ++ fbtft_dev_dbg(DEBUG_FB_SETCOLREG, par, info->dev, ++ "%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n", ++ __func__, regno, red, green, blue, transp); ++ ++ switch (info->fix.visual) { ++ case FB_VISUAL_TRUECOLOR: ++ if (regno < 16) { ++ u32 *pal = info->pseudo_palette; ++ ++ val = chan_to_field(red, &info->var.red); ++ val |= chan_to_field(green, &info->var.green); ++ val |= chan_to_field(blue, &info->var.blue); ++ ++ pal[regno] = val; ++ ret = 0; ++ } ++ break; ++ ++ } ++ return ret; ++} ++ ++int fbtft_fb_blank(int blank, struct fb_info *info) ++{ ++ struct fbtft_par *par = info->par; ++ int ret = -EINVAL; ++ ++ fbtft_dev_dbg(DEBUG_FB_BLANK, par, info->dev, "%s(blank=%d)\n", ++ __func__, blank); ++ ++ if (!par->fbtftops.blank) ++ return ret; ++ ++ switch (blank) { ++ case FB_BLANK_POWERDOWN: ++ case FB_BLANK_VSYNC_SUSPEND: ++ case FB_BLANK_HSYNC_SUSPEND: ++ case FB_BLANK_NORMAL: ++ ret = par->fbtftops.blank(par, true); ++ break; ++ case FB_BLANK_UNBLANK: ++ ret = par->fbtftops.blank(par, false); ++ break; ++ } ++ return ret; ++} ++ ++void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) ++{ ++ if (src->write) ++ dst->write = src->write; ++ if (src->read) ++ dst->read = src->read; ++ if (src->write_vmem) ++ dst->write_vmem = src->write_vmem; ++ if (src->write_register) ++ dst->write_register = src->write_register; ++ if (src->set_addr_win) ++ dst->set_addr_win = src->set_addr_win; ++ if (src->reset) ++ dst->reset = src->reset; ++ if (src->mkdirty) ++ dst->mkdirty = src->mkdirty; ++ if (src->update_display) ++ dst->update_display = src->update_display; ++ if (src->init_display) ++ dst->init_display = src->init_display; ++ if (src->blank) ++ dst->blank = src->blank; ++ if (src->request_gpios_match) ++ dst->request_gpios_match = src->request_gpios_match; ++ if (src->request_gpios) ++ dst->request_gpios = src->request_gpios; ++ if (src->verify_gpios) ++ dst->verify_gpios = src->verify_gpios; ++ if (src->register_backlight) ++ dst->register_backlight = src->register_backlight; ++ if (src->unregister_backlight) ++ dst->unregister_backlight = src->unregister_backlight; ++ if (src->set_var) ++ dst->set_var = src->set_var; ++ if (src->set_gamma) ++ dst->set_gamma = src->set_gamma; ++} ++ ++/** ++ * fbtft_framebuffer_alloc - creates a new frame buffer info structure ++ * ++ * @display: pointer to structure describing the display ++ * @dev: pointer to the device for this fb, this can be NULL ++ * ++ * Creates a new frame buffer info structure. ++ * ++ * Also creates and populates the following structures: ++ * info->fbops ++ * info->fbdefio ++ * info->pseudo_palette ++ * par->fbtftops ++ * par->txbuf ++ * ++ * Returns the new structure, or NULL if an error occurred. ++ * ++ */ ++struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, ++ struct device *dev) ++{ ++ struct fb_info *info; ++ struct fbtft_par *par; ++ struct fb_ops *fbops = NULL; ++ struct fb_deferred_io *fbdefio = NULL; ++ struct fbtft_platform_data *pdata = dev->platform_data; ++ u8 *vmem = NULL; ++ void *txbuf = NULL; ++ void *buf = NULL; ++ unsigned width; ++ unsigned height; ++ int txbuflen = display->txbuflen; ++ unsigned bpp = display->bpp; ++ unsigned fps = display->fps; ++ int vmem_size, i; ++ int *init_sequence = display->init_sequence; ++ char *gamma = display->gamma; ++ unsigned long *gamma_curves = NULL; ++ ++ /* sanity check */ ++ if (display->gamma_num * display->gamma_len > FBTFT_GAMMA_MAX_VALUES_TOTAL) { ++ dev_err(dev, ++ "%s: FBTFT_GAMMA_MAX_VALUES_TOTAL=%d is exceeded\n", ++ __func__, FBTFT_GAMMA_MAX_VALUES_TOTAL); ++ return NULL; ++ } ++ ++ /* defaults */ ++ if (!fps) ++ fps = 20; ++ if (!bpp) ++ bpp = 16; ++ ++ if (!pdata) { ++ dev_err(dev, "platform data is missing\n"); ++ return NULL; ++ } ++ ++ /* override driver values? */ ++ if (pdata->fps) ++ fps = pdata->fps; ++ if (pdata->txbuflen) ++ txbuflen = pdata->txbuflen; ++ if (pdata->display.init_sequence) ++ init_sequence = pdata->display.init_sequence; ++ if (pdata->gamma) ++ gamma = pdata->gamma; ++ if (pdata->display.debug) ++ display->debug = pdata->display.debug; ++ if (pdata->display.backlight) ++ display->backlight = pdata->display.backlight; ++ if (pdata->display.width) ++ display->width = pdata->display.width; ++ if (pdata->display.height) ++ display->height = pdata->display.height; ++ if (pdata->display.buswidth) ++ display->buswidth = pdata->display.buswidth; ++ if (pdata->display.regwidth) ++ display->regwidth = pdata->display.regwidth; ++ ++ display->debug |= debug; ++ fbtft_expand_debug_value(&display->debug); ++ ++ switch (pdata->rotate) { ++ case 90: ++ case 270: ++ width = display->height; ++ height = display->width; ++ break; ++ default: ++ width = display->width; ++ height = display->height; ++ } ++ ++ vmem_size = display->width * display->height * bpp / 8; ++ vmem = vzalloc(vmem_size); ++ if (!vmem) ++ goto alloc_fail; ++ ++ fbops = devm_kzalloc(dev, sizeof(struct fb_ops), GFP_KERNEL); ++ if (!fbops) ++ goto alloc_fail; ++ ++ fbdefio = devm_kzalloc(dev, sizeof(struct fb_deferred_io), GFP_KERNEL); ++ if (!fbdefio) ++ goto alloc_fail; ++ ++ buf = devm_kzalloc(dev, 128, GFP_KERNEL); ++ if (!buf) ++ goto alloc_fail; ++ ++ if (display->gamma_num && display->gamma_len) { ++ gamma_curves = devm_kzalloc(dev, display->gamma_num * display->gamma_len * sizeof(gamma_curves[0]), ++ GFP_KERNEL); ++ if (!gamma_curves) ++ goto alloc_fail; ++ } ++ ++ info = framebuffer_alloc(sizeof(struct fbtft_par), dev); ++ if (!info) ++ goto alloc_fail; ++ ++ info->screen_base = (u8 __force __iomem *)vmem; ++ info->fbops = fbops; ++ info->fbdefio = fbdefio; ++ ++ fbops->owner = dev->driver->owner; ++ fbops->fb_read = fb_sys_read; ++ fbops->fb_write = fbtft_fb_write; ++ fbops->fb_fillrect = fbtft_fb_fillrect; ++ fbops->fb_copyarea = fbtft_fb_copyarea; ++ fbops->fb_imageblit = fbtft_fb_imageblit; ++ fbops->fb_setcolreg = fbtft_fb_setcolreg; ++ fbops->fb_blank = fbtft_fb_blank; ++ ++ fbdefio->delay = HZ/fps; ++ fbdefio->deferred_io = fbtft_deferred_io; ++ fb_deferred_io_init(info); ++ ++ strncpy(info->fix.id, dev->driver->name, 16); ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ info->fix.xpanstep = 0; ++ info->fix.ypanstep = 0; ++ info->fix.ywrapstep = 0; ++ info->fix.line_length = width*bpp/8; ++ info->fix.accel = FB_ACCEL_NONE; ++ info->fix.smem_len = vmem_size; ++ ++ info->var.rotate = pdata->rotate; ++ info->var.xres = width; ++ info->var.yres = height; ++ info->var.xres_virtual = info->var.xres; ++ info->var.yres_virtual = info->var.yres; ++ info->var.bits_per_pixel = bpp; ++ info->var.nonstd = 1; ++ ++ /* RGB565 */ ++ info->var.red.offset = 11; ++ info->var.red.length = 5; ++ info->var.green.offset = 5; ++ info->var.green.length = 6; ++ info->var.blue.offset = 0; ++ info->var.blue.length = 5; ++ info->var.transp.offset = 0; ++ info->var.transp.length = 0; ++ ++ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; ++ ++ par = info->par; ++ par->info = info; ++ par->pdata = dev->platform_data; ++ par->debug = display->debug; ++ par->buf = buf; ++ spin_lock_init(&par->dirty_lock); ++ par->bgr = pdata->bgr; ++ par->startbyte = pdata->startbyte; ++ par->init_sequence = init_sequence; ++ par->gamma.curves = gamma_curves; ++ par->gamma.num_curves = display->gamma_num; ++ par->gamma.num_values = display->gamma_len; ++ mutex_init(&par->gamma.lock); ++ info->pseudo_palette = par->pseudo_palette; ++ ++ if (par->gamma.curves && gamma) { ++ if (fbtft_gamma_parse_str(par, ++ par->gamma.curves, gamma, strlen(gamma))) ++ goto alloc_fail; ++ } ++ ++ /* Transmit buffer */ ++ if (txbuflen == -1) ++ txbuflen = vmem_size + 2; /* add in case startbyte is used */ ++ ++#ifdef __LITTLE_ENDIAN ++ if ((!txbuflen) && (bpp > 8)) ++ txbuflen = PAGE_SIZE; /* need buffer for byteswapping */ ++#endif ++ ++ if (txbuflen > 0) { ++ if (dma) { ++ dev->coherent_dma_mask = ~0; ++ txbuf = dmam_alloc_coherent(dev, txbuflen, &par->txbuf.dma, GFP_DMA); ++ } else { ++ txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL); ++ } ++ if (!txbuf) ++ goto alloc_fail; ++ par->txbuf.buf = txbuf; ++ par->txbuf.len = txbuflen; ++ } ++ ++ /* Initialize gpios to disabled */ ++ par->gpio.reset = -1; ++ par->gpio.dc = -1; ++ par->gpio.rd = -1; ++ par->gpio.wr = -1; ++ par->gpio.cs = -1; ++ par->gpio.latch = -1; ++ for (i = 0; i < 16; i++) { ++ par->gpio.db[i] = -1; ++ par->gpio.led[i] = -1; ++ par->gpio.aux[i] = -1; ++ } ++ ++ /* default fbtft operations */ ++ par->fbtftops.write = fbtft_write_spi; ++ par->fbtftops.read = fbtft_read_spi; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ par->fbtftops.write_register = fbtft_write_reg8_bus8; ++ par->fbtftops.set_addr_win = fbtft_set_addr_win; ++ par->fbtftops.reset = fbtft_reset; ++ par->fbtftops.mkdirty = fbtft_mkdirty; ++ par->fbtftops.update_display = fbtft_update_display; ++ par->fbtftops.request_gpios = fbtft_request_gpios; ++ if (display->backlight) ++ par->fbtftops.register_backlight = fbtft_register_backlight; ++ ++ /* use driver provided functions */ ++ fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops); ++ ++ return info; ++ ++alloc_fail: ++ vfree(vmem); ++ ++ return NULL; ++} ++EXPORT_SYMBOL(fbtft_framebuffer_alloc); ++ ++/** ++ * fbtft_framebuffer_release - frees up all memory used by the framebuffer ++ * ++ * @info: frame buffer info structure ++ * ++ */ ++void fbtft_framebuffer_release(struct fb_info *info) ++{ ++ fb_deferred_io_cleanup(info); ++ vfree(info->screen_base); ++ framebuffer_release(info); ++} ++EXPORT_SYMBOL(fbtft_framebuffer_release); ++ ++/** ++ * fbtft_register_framebuffer - registers a tft frame buffer device ++ * @fb_info: frame buffer info structure ++ * ++ * Sets SPI driverdata if needed ++ * Requests needed gpios. ++ * Initializes display ++ * Updates display. ++ * Registers a frame buffer device @fb_info. ++ * ++ * Returns negative errno on error, or zero for success. ++ * ++ */ ++int fbtft_register_framebuffer(struct fb_info *fb_info) ++{ ++ int ret; ++ char text1[50] = ""; ++ char text2[50] = ""; ++ struct fbtft_par *par = fb_info->par; ++ struct spi_device *spi = par->spi; ++ ++ /* sanity checks */ ++ if (!par->fbtftops.init_display) { ++ dev_err(fb_info->device, "missing fbtftops.init_display()\n"); ++ return -EINVAL; ++ } ++ ++ if (spi) ++ spi_set_drvdata(spi, fb_info); ++ if (par->pdev) ++ platform_set_drvdata(par->pdev, fb_info); ++ ++ ret = par->fbtftops.request_gpios(par); ++ if (ret < 0) ++ goto reg_fail; ++ ++ if (par->fbtftops.verify_gpios) { ++ ret = par->fbtftops.verify_gpios(par); ++ if (ret < 0) ++ goto reg_fail; ++ } ++ ++ ret = par->fbtftops.init_display(par); ++ if (ret < 0) ++ goto reg_fail; ++ if (par->fbtftops.set_var) { ++ ret = par->fbtftops.set_var(par); ++ if (ret < 0) ++ goto reg_fail; ++ } ++ ++ /* update the entire display */ ++ par->fbtftops.update_display(par, 0, par->info->var.yres - 1); ++ ++ if (par->fbtftops.set_gamma && par->gamma.curves) { ++ ret = par->fbtftops.set_gamma(par, par->gamma.curves); ++ if (ret) ++ goto reg_fail; ++ } ++ ++ if (par->fbtftops.register_backlight) ++ par->fbtftops.register_backlight(par); ++ ++ ret = register_framebuffer(fb_info); ++ if (ret < 0) ++ goto reg_fail; ++ ++ fbtft_sysfs_init(par); ++ ++ if (par->txbuf.buf) ++ sprintf(text1, ", %d KiB %sbuffer memory", ++ par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : ""); ++ if (spi) ++ sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num, ++ spi->chip_select, spi->max_speed_hz/1000000); ++ dev_info(fb_info->dev, ++ "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n", ++ fb_info->fix.id, fb_info->var.xres, fb_info->var.yres, ++ fb_info->fix.smem_len >> 10, text1, ++ HZ/fb_info->fbdefio->delay, text2); ++ ++#ifdef CONFIG_FB_BACKLIGHT ++ /* Turn on backlight if available */ ++ if (fb_info->bl_dev) { ++ fb_info->bl_dev->props.power = FB_BLANK_UNBLANK; ++ fb_info->bl_dev->ops->update_status(fb_info->bl_dev); ++ } ++#endif ++ ++ return 0; ++ ++reg_fail: ++ if (par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight(par); ++ if (spi) ++ spi_set_drvdata(spi, NULL); ++ if (par->pdev) ++ platform_set_drvdata(par->pdev, NULL); ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_register_framebuffer); ++ ++/** ++ * fbtft_unregister_framebuffer - releases a tft frame buffer device ++ * @fb_info: frame buffer info structure ++ * ++ * Frees SPI driverdata if needed ++ * Frees gpios. ++ * Unregisters frame buffer device. ++ * ++ */ ++int fbtft_unregister_framebuffer(struct fb_info *fb_info) ++{ ++ struct fbtft_par *par = fb_info->par; ++ struct spi_device *spi = par->spi; ++ int ret; ++ ++ if (spi) ++ spi_set_drvdata(spi, NULL); ++ if (par->pdev) ++ platform_set_drvdata(par->pdev, NULL); ++ if (par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight(par); ++ fbtft_sysfs_exit(par); ++ ret = unregister_framebuffer(fb_info); ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_unregister_framebuffer); ++ ++#ifdef CONFIG_OF ++/** ++ * fbtft_init_display_dt() - Device Tree init_display() function ++ * @par: Driver data ++ * ++ * Return: 0 if successful, negative if error ++ */ ++static int fbtft_init_display_dt(struct fbtft_par *par) ++{ ++ struct device_node *node = par->info->device->of_node; ++ struct property *prop; ++ const __be32 *p; ++ u32 val; ++ int buf[64], i, j; ++ char msg[128]; ++ char str[16]; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (!node) ++ return -EINVAL; ++ ++ prop = of_find_property(node, "init", NULL); ++ p = of_prop_next_u32(prop, NULL, &val); ++ if (!p) ++ return -EINVAL; ++ while (p) { ++ if (val & FBTFT_OF_INIT_CMD) { ++ val &= 0xFFFF; ++ i = 0; ++ while (p && !(val & 0xFFFF0000)) { ++ if (i > 63) { ++ dev_err(par->info->device, ++ "%s: Maximum register values exceeded\n", ++ __func__); ++ return -EINVAL; ++ } ++ buf[i++] = val; ++ p = of_prop_next_u32(prop, p, &val); ++ } ++ /* make debug message */ ++ msg[0] = '\0'; ++ for (j = 0; j < i; j++) { ++ snprintf(str, 128, " %02X", buf[j]); ++ strcat(msg, str); ++ } ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: write_register:%s\n", msg); ++ ++ par->fbtftops.write_register(par, i, ++ buf[0], buf[1], buf[2], buf[3], ++ buf[4], buf[5], buf[6], buf[7], ++ buf[8], buf[9], buf[10], buf[11], ++ buf[12], buf[13], buf[14], buf[15], ++ buf[16], buf[17], buf[18], buf[19], ++ buf[20], buf[21], buf[22], buf[23], ++ buf[24], buf[25], buf[26], buf[27], ++ buf[28], buf[29], buf[30], buf[31], ++ buf[32], buf[33], buf[34], buf[35], ++ buf[36], buf[37], buf[38], buf[39], ++ buf[40], buf[41], buf[42], buf[43], ++ buf[44], buf[45], buf[46], buf[47], ++ buf[48], buf[49], buf[50], buf[51], ++ buf[52], buf[53], buf[54], buf[55], ++ buf[56], buf[57], buf[58], buf[59], ++ buf[60], buf[61], buf[62], buf[63]); ++ } else if (val & FBTFT_OF_INIT_DELAY) { ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: msleep(%u)\n", val & 0xFFFF); ++ msleep(val & 0xFFFF); ++ p = of_prop_next_u32(prop, p, &val); ++ } else { ++ dev_err(par->info->device, "illegal init value 0x%X\n", ++ val); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++/** ++ * fbtft_init_display() - Generic init_display() function ++ * @par: Driver data ++ * ++ * Uses par->init_sequence to do the initialization ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_init_display(struct fbtft_par *par) ++{ ++ int buf[64]; ++ char msg[128]; ++ char str[16]; ++ int i = 0; ++ int j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* sanity check */ ++ if (!par->init_sequence) { ++ dev_err(par->info->device, ++ "error: init_sequence is not set\n"); ++ return -EINVAL; ++ } ++ ++ /* make sure stop marker exists */ ++ for (i = 0; i < FBTFT_MAX_INIT_SEQUENCE; i++) ++ if (par->init_sequence[i] == -3) ++ break; ++ if (i == FBTFT_MAX_INIT_SEQUENCE) { ++ dev_err(par->info->device, ++ "missing stop marker at end of init sequence\n"); ++ return -EINVAL; ++ } ++ ++ par->fbtftops.reset(par); ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ i = 0; ++ while (i < FBTFT_MAX_INIT_SEQUENCE) { ++ if (par->init_sequence[i] == -3) { ++ /* done */ ++ return 0; ++ } ++ if (par->init_sequence[i] >= 0) { ++ dev_err(par->info->device, ++ "missing delimiter at position %d\n", i); ++ return -EINVAL; ++ } ++ if (par->init_sequence[i+1] < 0) { ++ dev_err(par->info->device, ++ "missing value after delimiter %d at position %d\n", ++ par->init_sequence[i], i); ++ return -EINVAL; ++ } ++ switch (par->init_sequence[i]) { ++ case -1: ++ i++; ++ /* make debug message */ ++ strcpy(msg, ""); ++ j = i + 1; ++ while (par->init_sequence[j] >= 0) { ++ sprintf(str, "0x%02X ", par->init_sequence[j]); ++ strcat(msg, str); ++ j++; ++ } ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: write(0x%02X) %s\n", ++ par->init_sequence[i], msg); ++ ++ /* Write */ ++ j = 0; ++ while (par->init_sequence[i] >= 0) { ++ if (j > 63) { ++ dev_err(par->info->device, ++ "%s: Maximum register values exceeded\n", ++ __func__); ++ return -EINVAL; ++ } ++ buf[j++] = par->init_sequence[i++]; ++ } ++ par->fbtftops.write_register(par, j, ++ buf[0], buf[1], buf[2], buf[3], ++ buf[4], buf[5], buf[6], buf[7], ++ buf[8], buf[9], buf[10], buf[11], ++ buf[12], buf[13], buf[14], buf[15], ++ buf[16], buf[17], buf[18], buf[19], ++ buf[20], buf[21], buf[22], buf[23], ++ buf[24], buf[25], buf[26], buf[27], ++ buf[28], buf[29], buf[30], buf[31], ++ buf[32], buf[33], buf[34], buf[35], ++ buf[36], buf[37], buf[38], buf[39], ++ buf[40], buf[41], buf[42], buf[43], ++ buf[44], buf[45], buf[46], buf[47], ++ buf[48], buf[49], buf[50], buf[51], ++ buf[52], buf[53], buf[54], buf[55], ++ buf[56], buf[57], buf[58], buf[59], ++ buf[60], buf[61], buf[62], buf[63]); ++ break; ++ case -2: ++ i++; ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: mdelay(%d)\n", par->init_sequence[i]); ++ mdelay(par->init_sequence[i++]); ++ break; ++ default: ++ dev_err(par->info->device, ++ "unknown delimiter %d at position %d\n", ++ par->init_sequence[i], i); ++ return -EINVAL; ++ } ++ } ++ ++ dev_err(par->info->device, ++ "%s: something is wrong. Shouldn't get here.\n", __func__); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(fbtft_init_display); ++ ++/** ++ * fbtft_verify_gpios() - Generic verify_gpios() function ++ * @par: Driver data ++ * ++ * Uses @spi, @pdev and @buswidth to determine which GPIOs is needed ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_verify_gpios(struct fbtft_par *par) ++{ ++ struct fbtft_platform_data *pdata; ++ int i; ++ ++ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); ++ ++ pdata = par->info->device->platform_data; ++ if (pdata->display.buswidth != 9 && par->startbyte == 0 && \ ++ par->gpio.dc < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'dc' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ ++ if (!par->pdev) ++ return 0; ++ ++ if (par->gpio.wr < 0) { ++ dev_err(par->info->device, "Missing 'wr' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ for (i = 0; i < pdata->display.buswidth; i++) { ++ if (par->gpio.db[i] < 0) { ++ dev_err(par->info->device, ++ "Missing 'db%02d' gpio. Aborting.\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++/* returns 0 if the property is not present */ ++static u32 fbtft_of_value(struct device_node *node, const char *propname) ++{ ++ int ret; ++ u32 val = 0; ++ ++ ret = of_property_read_u32(node, propname, &val); ++ if (ret == 0) ++ pr_info("%s: %s = %u\n", __func__, propname, val); ++ ++ return val; ++} ++ ++static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev) ++{ ++ struct device_node *node = dev->of_node; ++ struct fbtft_platform_data *pdata; ++ ++ if (!node) { ++ dev_err(dev, "Missing platform data or DT\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) ++ return ERR_PTR(-ENOMEM); ++ ++ pdata->display.width = fbtft_of_value(node, "width"); ++ pdata->display.height = fbtft_of_value(node, "height"); ++ pdata->display.regwidth = fbtft_of_value(node, "regwidth"); ++ pdata->display.buswidth = fbtft_of_value(node, "buswidth"); ++ pdata->display.backlight = fbtft_of_value(node, "backlight"); ++ pdata->display.bpp = fbtft_of_value(node, "bpp"); ++ pdata->display.debug = fbtft_of_value(node, "debug"); ++ pdata->rotate = fbtft_of_value(node, "rotate"); ++ pdata->bgr = of_property_read_bool(node, "bgr"); ++ pdata->fps = fbtft_of_value(node, "fps"); ++ pdata->txbuflen = fbtft_of_value(node, "txbuflen"); ++ pdata->startbyte = fbtft_of_value(node, "startbyte"); ++ of_property_read_string(node, "gamma", (const char **)&pdata->gamma); ++ ++ if (of_find_property(node, "led-gpios", NULL)) ++ pdata->display.backlight = 1; ++ if (of_find_property(node, "init", NULL)) ++ pdata->display.fbtftops.init_display = fbtft_init_display_dt; ++ pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt; ++ ++ return pdata; ++} ++#else ++static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev) ++{ ++ dev_err(dev, "Missing platform data\n"); ++ return ERR_PTR(-EINVAL); ++} ++#endif ++ ++/** ++ * fbtft_probe_common() - Generic device probe() helper function ++ * @display: Display properties ++ * @sdev: SPI device ++ * @pdev: Platform device ++ * ++ * Allocates, initializes and registers a framebuffer ++ * ++ * Either @sdev or @pdev should be NULL ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_probe_common(struct fbtft_display *display, ++ struct spi_device *sdev, struct platform_device *pdev) ++{ ++ struct device *dev; ++ struct fb_info *info; ++ struct fbtft_par *par; ++ struct fbtft_platform_data *pdata; ++ int ret; ++ ++ if (sdev) ++ dev = &sdev->dev; ++ else ++ dev = &pdev->dev; ++ ++ if (unlikely(display->debug & DEBUG_DRIVER_INIT_FUNCTIONS)) ++ dev_info(dev, "%s()\n", __func__); ++ ++ pdata = dev->platform_data; ++ if (!pdata) { ++ pdata = fbtft_probe_dt(dev); ++ if (IS_ERR(pdata)) ++ return PTR_ERR(pdata); ++ dev->platform_data = pdata; ++ } ++ ++ info = fbtft_framebuffer_alloc(display, dev); ++ if (!info) ++ return -ENOMEM; ++ ++ par = info->par; ++ par->spi = sdev; ++ par->pdev = pdev; ++ ++ if (display->buswidth == 0) { ++ dev_err(dev, "buswidth is not set\n"); ++ return -EINVAL; ++ } ++ ++ /* write register functions */ ++ if (display->regwidth == 8 && display->buswidth == 8) { ++ par->fbtftops.write_register = fbtft_write_reg8_bus8; ++ } else ++ if (display->regwidth == 8 && display->buswidth == 9 && par->spi) { ++ par->fbtftops.write_register = fbtft_write_reg8_bus9; ++ } else if (display->regwidth == 16 && display->buswidth == 8) { ++ par->fbtftops.write_register = fbtft_write_reg16_bus8; ++ } else if (display->regwidth == 16 && display->buswidth == 16) { ++ par->fbtftops.write_register = fbtft_write_reg16_bus16; ++ } else { ++ dev_warn(dev, ++ "no default functions for regwidth=%d and buswidth=%d\n", ++ display->regwidth, display->buswidth); ++ } ++ ++ /* write_vmem() functions */ ++ if (display->buswidth == 8) ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ else if (display->buswidth == 9) ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus9; ++ else if (display->buswidth == 16) ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus16; ++ ++ /* GPIO write() functions */ ++ if (par->pdev) { ++ if (display->buswidth == 8) ++ par->fbtftops.write = fbtft_write_gpio8_wr; ++ else if (display->buswidth == 16) ++ par->fbtftops.write = fbtft_write_gpio16_wr; ++ } ++ ++ /* 9-bit SPI setup */ ++ if (par->spi && display->buswidth == 9) { ++ par->spi->bits_per_word = 9; ++ ret = par->spi->master->setup(par->spi); ++ if (ret) { ++ dev_warn(&par->spi->dev, ++ "9-bit SPI not available, emulating using 8-bit.\n"); ++ par->spi->bits_per_word = 8; ++ ret = par->spi->master->setup(par->spi); ++ if (ret) ++ goto out_release; ++ /* allocate buffer with room for dc bits */ ++ par->extra = devm_kzalloc(par->info->device, ++ par->txbuf.len + (par->txbuf.len / 8) + 8, ++ GFP_KERNEL); ++ if (!par->extra) { ++ ret = -ENOMEM; ++ goto out_release; ++ } ++ par->fbtftops.write = fbtft_write_spi_emulate_9; ++ } ++ } ++ ++ if (!par->fbtftops.verify_gpios) ++ par->fbtftops.verify_gpios = fbtft_verify_gpios; ++ ++ /* make sure we still use the driver provided functions */ ++ fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops); ++ ++ /* use init_sequence if provided */ ++ if (par->init_sequence) ++ par->fbtftops.init_display = fbtft_init_display; ++ ++ /* use platform_data provided functions above all */ ++ fbtft_merge_fbtftops(&par->fbtftops, &pdata->display.fbtftops); ++ ++ ret = fbtft_register_framebuffer(info); ++ if (ret < 0) ++ goto out_release; ++ ++ return 0; ++ ++out_release: ++ fbtft_framebuffer_release(info); ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_probe_common); ++ ++/** ++ * fbtft_remove_common() - Generic device remove() helper function ++ * @dev: Device ++ * @info: Framebuffer ++ * ++ * Unregisters and releases the framebuffer ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_remove_common(struct device *dev, struct fb_info *info) ++{ ++ struct fbtft_par *par; ++ ++ if (!info) ++ return -EINVAL; ++ par = info->par; ++ if (par) ++ fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, ++ "%s()\n", __func__); ++ fbtft_unregister_framebuffer(info); ++ fbtft_framebuffer_release(info); ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_remove_common); ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/fbtft-io.c b/drivers/video/fbtft/fbtft-io.c +new file mode 100644 +index 0000000..dfa2c46 +--- /dev/null ++++ b/drivers/video/fbtft/fbtft-io.c +@@ -0,0 +1,409 @@ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_ARCH_BCM2708 ++#include ++#endif ++#include "fbtft.h" ++ ++int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len) ++{ ++ struct spi_transfer t = { ++ .tx_buf = buf, ++ .len = len, ++ }; ++ struct spi_message m; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ if (!par->spi) { ++ dev_err(par->info->device, ++ "%s: par->spi is unexpectedly NULL\n", __func__); ++ return -1; ++ } ++ ++ spi_message_init(&m); ++ if (par->txbuf.dma && buf == par->txbuf.buf) { ++ t.tx_dma = par->txbuf.dma; ++ m.is_dma_mapped = 1; ++ } ++ spi_message_add_tail(&t, &m); ++ return spi_sync(par->spi, &m); ++} ++EXPORT_SYMBOL(fbtft_write_spi); ++ ++/** ++ * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit ++ * @par: Driver data ++ * @buf: Buffer to write ++ * @len: Length of buffer (must be divisible by 8) ++ * ++ * When 9-bit SPI is not available, this function can be used to emulate that. ++ * par->extra must hold a transformation buffer used for transfer. ++ */ ++int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u16 *src = buf; ++ u8 *dst = par->extra; ++ size_t size = len / 2; ++ size_t added = 0; ++ int bits, i, j; ++ u64 val, dc, tmp; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ if (!par->extra) { ++ dev_err(par->info->device, "%s: error: par->extra is NULL\n", ++ __func__); ++ return -EINVAL; ++ } ++ if ((len % 8) != 0) { ++ dev_err(par->info->device, ++ "%s: error: len=%d must be divisible by 8\n", ++ __func__, len); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < size; i += 8) { ++ tmp = 0; ++ bits = 63; ++ for (j = 0; j < 7; j++) { ++ dc = (*src & 0x0100) ? 1 : 0; ++ val = *src & 0x00FF; ++ tmp |= dc << bits; ++ bits -= 8; ++ tmp |= val << bits--; ++ src++; ++ } ++ tmp |= ((*src & 0x0100) ? 1 : 0); ++ *(u64 *)dst = cpu_to_be64(tmp); ++ dst += 8; ++ *dst++ = (u8)(*src++ & 0x00FF); ++ added++; ++ } ++ ++ return spi_write(par->spi, par->extra, size + added); ++} ++EXPORT_SYMBOL(fbtft_write_spi_emulate_9); ++ ++int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len) ++{ ++ int ret; ++ u8 txbuf[32] = { 0, }; ++ struct spi_transfer t = { ++ .speed_hz = 2000000, ++ .rx_buf = buf, ++ .len = len, ++ }; ++ struct spi_message m; ++ ++ if (!par->spi) { ++ dev_err(par->info->device, ++ "%s: par->spi is unexpectedly NULL\n", __func__); ++ return -ENODEV; ++ } ++ ++ if (par->startbyte) { ++ if (len > 32) { ++ dev_err(par->info->device, ++ "%s: len=%d can't be larger than 32 when using 'startbyte'\n", ++ __func__, len); ++ return -EINVAL; ++ } ++ txbuf[0] = par->startbyte | 0x3; ++ t.tx_buf = txbuf; ++ fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, ++ txbuf, len, "%s(len=%d) txbuf => ", __func__, len); ++ } ++ ++ spi_message_init(&m); ++ spi_message_add_tail(&t, &m); ++ ret = spi_sync(par->spi, &m); ++ fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len, ++ "%s(len=%d) buf <= ", __func__, len); ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_read_spi); ++ ++ ++#ifdef CONFIG_ARCH_BCM2708 ++ ++/* ++ * Raspberry Pi ++ * - writing directly to the registers is 40-50% faster than ++ * optimized use of gpiolib ++ */ ++ ++#define GPIOSET(no, ishigh) \ ++do { \ ++ if (ishigh) \ ++ set |= (1 << (no)); \ ++ else \ ++ reset |= (1 << (no)); \ ++} while (0) ++ ++int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ unsigned int set = 0; ++ unsigned int reset = 0; ++ u8 data; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len--) { ++ data = *(u8 *) buf; ++ buf++; ++ ++ /* Set data */ ++ GPIOSET(par->gpio.db[0], (data&0x01)); ++ GPIOSET(par->gpio.db[1], (data&0x02)); ++ GPIOSET(par->gpio.db[2], (data&0x04)); ++ GPIOSET(par->gpio.db[3], (data&0x08)); ++ GPIOSET(par->gpio.db[4], (data&0x10)); ++ GPIOSET(par->gpio.db[5], (data&0x20)); ++ GPIOSET(par->gpio.db[6], (data&0x40)); ++ GPIOSET(par->gpio.db[7], (data&0x80)); ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pulse /WR low */ ++ writel((1<gpio.wr), __io_address(GPIO_BASE+0x28)); ++ writel(0, __io_address(GPIO_BASE+0x28)); /* used as a delay */ ++ writel((1<gpio.wr), __io_address(GPIO_BASE+0x1C)); ++ ++ set = 0; ++ reset = 0; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio8_wr); ++ ++int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ unsigned int set = 0; ++ unsigned int reset = 0; ++ u16 data; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ len -= 2; ++ data = *(u16 *) buf; ++ buf += 2; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++ GPIOSET(par->gpio.db[0], (data&0x0001)); ++ GPIOSET(par->gpio.db[1], (data&0x0002)); ++ GPIOSET(par->gpio.db[2], (data&0x0004)); ++ GPIOSET(par->gpio.db[3], (data&0x0008)); ++ GPIOSET(par->gpio.db[4], (data&0x0010)); ++ GPIOSET(par->gpio.db[5], (data&0x0020)); ++ GPIOSET(par->gpio.db[6], (data&0x0040)); ++ GPIOSET(par->gpio.db[7], (data&0x0080)); ++ ++ GPIOSET(par->gpio.db[8], (data&0x0100)); ++ GPIOSET(par->gpio.db[9], (data&0x0200)); ++ GPIOSET(par->gpio.db[10], (data&0x0400)); ++ GPIOSET(par->gpio.db[11], (data&0x0800)); ++ GPIOSET(par->gpio.db[12], (data&0x1000)); ++ GPIOSET(par->gpio.db[13], (data&0x2000)); ++ GPIOSET(par->gpio.db[14], (data&0x4000)); ++ GPIOSET(par->gpio.db[15], (data&0x8000)); ++ ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++ set = 0; ++ reset = 0; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr); ++ ++int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) ++{ ++ unsigned int set = 0; ++ unsigned int reset = 0; ++ u16 data; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ len -= 2; ++ data = *(u16 *) buf; ++ buf += 2; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Low byte */ ++ GPIOSET(par->gpio.db[0], (data&0x0001)); ++ GPIOSET(par->gpio.db[1], (data&0x0002)); ++ GPIOSET(par->gpio.db[2], (data&0x0004)); ++ GPIOSET(par->gpio.db[3], (data&0x0008)); ++ GPIOSET(par->gpio.db[4], (data&0x0010)); ++ GPIOSET(par->gpio.db[5], (data&0x0020)); ++ GPIOSET(par->gpio.db[6], (data&0x0040)); ++ GPIOSET(par->gpio.db[7], (data&0x0080)); ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pulse 'latch' high */ ++ gpio_set_value(par->gpio.latch, 1); ++ gpio_set_value(par->gpio.latch, 0); ++ ++ /* High byte */ ++ GPIOSET(par->gpio.db[0], (data&0x0100)); ++ GPIOSET(par->gpio.db[1], (data&0x0200)); ++ GPIOSET(par->gpio.db[2], (data&0x0400)); ++ GPIOSET(par->gpio.db[3], (data&0x0800)); ++ GPIOSET(par->gpio.db[4], (data&0x1000)); ++ GPIOSET(par->gpio.db[5], (data&0x2000)); ++ GPIOSET(par->gpio.db[6], (data&0x4000)); ++ GPIOSET(par->gpio.db[7], (data&0x8000)); ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++ set = 0; ++ reset = 0; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); ++ ++#undef GPIOSET ++ ++#else ++ ++/* ++ * Optimized use of gpiolib is twice as fast as no optimization ++ * only one driver can use the optimized version at a time ++ */ ++int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u8 data; ++ int i; ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ static u8 prev_data; ++#endif ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len--) { ++ data = *(u8 *) buf; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ if (data == prev_data) { ++ gpio_set_value(par->gpio.wr, 0); /* used as delay */ ++ } else { ++ for (i = 0; i < 8; i++) { ++ if ((data & 1) != (prev_data & 1)) ++ gpio_set_value(par->gpio.db[i], ++ (data & 1)); ++ data >>= 1; ++ prev_data >>= 1; ++ } ++ } ++#else ++ for (i = 0; i < 8; i++) { ++ gpio_set_value(par->gpio.db[i], (data & 1)); ++ data >>= 1; ++ } ++#endif ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ prev_data = *(u8 *) buf; ++#endif ++ buf++; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio8_wr); ++ ++int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u16 data; ++ int i; ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ static u16 prev_data; ++#endif ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ data = *(u16 *) buf; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ if (data == prev_data) { ++ gpio_set_value(par->gpio.wr, 0); /* used as delay */ ++ } else { ++ for (i = 0; i < 16; i++) { ++ if ((data & 1) != (prev_data & 1)) ++ gpio_set_value(par->gpio.db[i], ++ (data & 1)); ++ data >>= 1; ++ prev_data >>= 1; ++ } ++ } ++#else ++ for (i = 0; i < 16; i++) { ++ gpio_set_value(par->gpio.db[i], (data & 1)); ++ data >>= 1; ++ } ++#endif ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ prev_data = *(u16 *) buf; ++#endif ++ buf += 2; ++ len -= 2; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr); ++ ++int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) ++{ ++ dev_err(par->info->device, "%s: function not implemented\n", __func__); ++ return -1; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); ++ ++#endif /* CONFIG_ARCH_BCM2708 */ +diff --git a/drivers/video/fbtft/fbtft-sysfs.c b/drivers/video/fbtft/fbtft-sysfs.c +new file mode 100644 +index 0000000..45f8de3 +--- /dev/null ++++ b/drivers/video/fbtft/fbtft-sysfs.c +@@ -0,0 +1,222 @@ ++#include "fbtft.h" ++ ++ ++static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base) ++{ ++ char *p_val; ++ int ret; ++ ++ if (!str_p || !(*str_p)) ++ return -EINVAL; ++ ++ p_val = strsep(str_p, sep); ++ ++ if (!p_val) ++ return -EINVAL; ++ ++ ret = kstrtoul(p_val, base, val); ++ if (ret) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves, ++ const char *str, int size) ++{ ++ char *str_p, *curve_p = NULL; ++ char *tmp; ++ unsigned long val = 0; ++ int ret = 0; ++ int curve_counter, value_counter; ++ ++ fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__); ++ ++ if (!str || !curves) ++ return -EINVAL; ++ ++ fbtft_par_dbg(DEBUG_SYSFS, par, "%s\n", str); ++ ++ tmp = kmalloc(size+1, GFP_KERNEL); ++ if (!tmp) ++ return -ENOMEM; ++ memcpy(tmp, str, size+1); ++ ++ /* replace optional separators */ ++ str_p = tmp; ++ while (*str_p) { ++ if (*str_p == ',') ++ *str_p = ' '; ++ if (*str_p == ';') ++ *str_p = '\n'; ++ str_p++; ++ } ++ ++ str_p = strim(tmp); ++ ++ curve_counter = 0; ++ while (str_p) { ++ if (curve_counter == par->gamma.num_curves) { ++ dev_err(par->info->device, "Gamma: Too many curves\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ curve_p = strsep(&str_p, "\n"); ++ value_counter = 0; ++ while (curve_p) { ++ if (value_counter == par->gamma.num_values) { ++ dev_err(par->info->device, ++ "Gamma: Too many values\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ret = get_next_ulong(&curve_p, &val, " ", 16); ++ if (ret) ++ goto out; ++ curves[curve_counter * par->gamma.num_values + value_counter] = val; ++ value_counter++; ++ } ++ if (value_counter != par->gamma.num_values) { ++ dev_err(par->info->device, "Gamma: Too few values\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ curve_counter++; ++ } ++ if (curve_counter != par->gamma.num_curves) { ++ dev_err(par->info->device, "Gamma: Too few curves\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++out: ++ kfree(tmp); ++ return ret; ++} ++ ++static ssize_t ++sprintf_gamma(struct fbtft_par *par, unsigned long *curves, char *buf) ++{ ++ ssize_t len = 0; ++ unsigned int i, j; ++ ++ mutex_lock(&par->gamma.lock); ++ for (i = 0; i < par->gamma.num_curves; i++) { ++ for (j = 0; j < par->gamma.num_values; j++) ++ len += scnprintf(&buf[len], PAGE_SIZE, ++ "%04lx ", curves[i*par->gamma.num_values + j]); ++ buf[len-1] = '\n'; ++ } ++ mutex_unlock(&par->gamma.lock); ++ ++ return len; ++} ++ ++static ssize_t store_gamma_curve(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ unsigned long tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL]; ++ int ret; ++ ++ ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count); ++ if (ret) ++ return ret; ++ ++ ret = par->fbtftops.set_gamma(par, tmp_curves); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&par->gamma.lock); ++ memcpy(par->gamma.curves, tmp_curves, ++ par->gamma.num_curves * par->gamma.num_values * sizeof(tmp_curves[0])); ++ mutex_unlock(&par->gamma.lock); ++ ++ return count; ++} ++ ++static ssize_t show_gamma_curve(struct device *device, ++ struct device_attribute *attr, char *buf) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ ++ return sprintf_gamma(par, par->gamma.curves, buf); ++} ++ ++static struct device_attribute gamma_device_attrs[] = { ++ __ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve), ++}; ++ ++ ++void fbtft_expand_debug_value(unsigned long *debug) ++{ ++ switch (*debug & 0b111) { ++ case 1: ++ *debug |= DEBUG_LEVEL_1; ++ break; ++ case 2: ++ *debug |= DEBUG_LEVEL_2; ++ break; ++ case 3: ++ *debug |= DEBUG_LEVEL_3; ++ break; ++ case 4: ++ *debug |= DEBUG_LEVEL_4; ++ break; ++ case 5: ++ *debug |= DEBUG_LEVEL_5; ++ break; ++ case 6: ++ *debug |= DEBUG_LEVEL_6; ++ break; ++ case 7: ++ *debug = 0xFFFFFFFF; ++ break; ++ } ++} ++ ++static ssize_t store_debug(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ int ret; ++ ++ ret = kstrtoul(buf, 10, &par->debug); ++ if (ret) ++ return ret; ++ fbtft_expand_debug_value(&par->debug); ++ ++ return count; ++} ++ ++static ssize_t show_debug(struct device *device, ++ struct device_attribute *attr, char *buf) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ ++ return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug); ++} ++ ++static struct device_attribute debug_device_attr = \ ++ __ATTR(debug, 0660, show_debug, store_debug); ++ ++ ++void fbtft_sysfs_init(struct fbtft_par *par) ++{ ++ device_create_file(par->info->dev, &debug_device_attr); ++ if (par->gamma.curves && par->fbtftops.set_gamma) ++ device_create_file(par->info->dev, &gamma_device_attrs[0]); ++} ++ ++void fbtft_sysfs_exit(struct fbtft_par *par) ++{ ++ device_remove_file(par->info->dev, &debug_device_attr); ++ if (par->gamma.curves && par->fbtftops.set_gamma) ++ device_remove_file(par->info->dev, &gamma_device_attrs[0]); ++} +diff --git a/drivers/video/fbtft/fbtft.h b/drivers/video/fbtft/fbtft.h +new file mode 100644 +index 0000000..0dbf3f9 +--- /dev/null ++++ b/drivers/video/fbtft/fbtft.h +@@ -0,0 +1,447 @@ ++/* ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef __LINUX_FBTFT_H ++#define __LINUX_FBTFT_H ++ ++#include ++#include ++#include ++#include ++ ++ ++#define FBTFT_NOP 0x00 ++#define FBTFT_SWRESET 0x01 ++#define FBTFT_RDDID 0x04 ++#define FBTFT_RDDST 0x09 ++#define FBTFT_CASET 0x2A ++#define FBTFT_RASET 0x2B ++#define FBTFT_RAMWR 0x2C ++ ++#define FBTFT_ONBOARD_BACKLIGHT 2 ++ ++#define FBTFT_GPIO_NO_MATCH 0xFFFF ++#define FBTFT_GPIO_NAME_SIZE 32 ++#define FBTFT_MAX_INIT_SEQUENCE 512 ++#define FBTFT_GAMMA_MAX_VALUES_TOTAL 128 ++ ++#define FBTFT_OF_INIT_CMD BIT(24) ++#define FBTFT_OF_INIT_DELAY BIT(25) ++ ++/** ++ * struct fbtft_gpio - Structure that holds one pinname to gpio mapping ++ * @name: pinname (reset, dc, etc.) ++ * @gpio: GPIO number ++ * ++ */ ++struct fbtft_gpio { ++ char name[FBTFT_GPIO_NAME_SIZE]; ++ unsigned gpio; ++}; ++ ++struct fbtft_par; ++ ++/** ++ * struct fbtft_ops - FBTFT operations structure ++ * @write: Writes to interface bus ++ * @read: Reads from interface bus ++ * @write_vmem: Writes video memory to display ++ * @write_reg: Writes to controller register ++ * @set_addr_win: Set the GRAM update window ++ * @reset: Reset the LCD controller ++ * @mkdirty: Marks display lines for update ++ * @update_display: Updates the display ++ * @init_display: Initializes the display ++ * @blank: Blank the display (optional) ++ * @request_gpios_match: Do pinname to gpio matching ++ * @request_gpios: Request gpios from the kernel ++ * @free_gpios: Free previously requested gpios ++ * @verify_gpios: Verify that necessary gpios is present (optional) ++ * @register_backlight: Used to register backlight device (optional) ++ * @unregister_backlight: Unregister backlight device (optional) ++ * @set_var: Configure LCD with values from variables like @rotate and @bgr ++ * (optional) ++ * @set_gamma: Set Gamma curve (optional) ++ * ++ * Most of these operations have default functions assigned to them in ++ * fbtft_framebuffer_alloc() ++ */ ++struct fbtft_ops { ++ int (*write)(struct fbtft_par *par, void *buf, size_t len); ++ int (*read)(struct fbtft_par *par, void *buf, size_t len); ++ int (*write_vmem)(struct fbtft_par *par, size_t offset, size_t len); ++ void (*write_register)(struct fbtft_par *par, int len, ...); ++ ++ void (*set_addr_win)(struct fbtft_par *par, ++ int xs, int ys, int xe, int ye); ++ void (*reset)(struct fbtft_par *par); ++ void (*mkdirty)(struct fb_info *info, int from, int to); ++ void (*update_display)(struct fbtft_par *par, ++ unsigned start_line, unsigned end_line); ++ int (*init_display)(struct fbtft_par *par); ++ int (*blank)(struct fbtft_par *par, bool on); ++ ++ unsigned long (*request_gpios_match)(struct fbtft_par *par, ++ const struct fbtft_gpio *gpio); ++ int (*request_gpios)(struct fbtft_par *par); ++ int (*verify_gpios)(struct fbtft_par *par); ++ ++ void (*register_backlight)(struct fbtft_par *par); ++ void (*unregister_backlight)(struct fbtft_par *par); ++ ++ int (*set_var)(struct fbtft_par *par); ++ int (*set_gamma)(struct fbtft_par *par, unsigned long *curves); ++}; ++ ++/** ++ * struct fbtft_display - Describes the display properties ++ * @width: Width of display in pixels ++ * @height: Height of display in pixels ++ * @regwidth: LCD Controller Register width in bits ++ * @buswidth: Display interface bus width in bits ++ * @backlight: Backlight type. ++ * @fbtftops: FBTFT operations provided by driver or device (platform_data) ++ * @bpp: Bits per pixel ++ * @fps: Frames per second ++ * @txbuflen: Size of transmit buffer ++ * @init_sequence: Pointer to LCD initialization array ++ * @gamma: String representation of Gamma curve(s) ++ * @gamma_num: Number of Gamma curves ++ * @gamma_len: Number of values per Gamma curve ++ * @debug: Initial debug value ++ * ++ * This structure is not stored by FBTFT except for init_sequence. ++ */ ++struct fbtft_display { ++ unsigned width; ++ unsigned height; ++ unsigned regwidth; ++ unsigned buswidth; ++ unsigned backlight; ++ struct fbtft_ops fbtftops; ++ unsigned bpp; ++ unsigned fps; ++ int txbuflen; ++ int *init_sequence; ++ char *gamma; ++ int gamma_num; ++ int gamma_len; ++ unsigned long debug; ++}; ++ ++/** ++ * struct fbtft_platform_data - Passes display specific data to the driver ++ * @display: Display properties ++ * @gpios: Pointer to an array of piname to gpio mappings ++ * @rotate: Display rotation angle ++ * @bgr: LCD Controller BGR bit ++ * @fps: Frames per second (this will go away, use @fps in @fbtft_display) ++ * @txbuflen: Size of transmit buffer ++ * @startbyte: When set, enables use of Startbyte in transfers ++ * @gamma: String representation of Gamma curve(s) ++ * @extra: A way to pass extra info ++ */ ++struct fbtft_platform_data { ++ struct fbtft_display display; ++ const struct fbtft_gpio *gpios; ++ unsigned rotate; ++ bool bgr; ++ unsigned fps; ++ int txbuflen; ++ u8 startbyte; ++ char *gamma; ++ void *extra; ++}; ++ ++/** ++ * struct fbtft_par - Main FBTFT data structure ++ * ++ * This structure holds all relevant data to operate the display ++ * ++ * See sourcefile for documentation since nested structs is not ++ * supported by kernel-doc. ++ * ++ */ ++/* @spi: Set if it is a SPI device ++ * @pdev: Set if it is a platform device ++ * @info: Pointer to framebuffer fb_info structure ++ * @pdata: Pointer to platform data ++ * @ssbuf: Not used ++ * @pseudo_palette: Used by fb_set_colreg() ++ * @txbuf.buf: Transmit buffer ++ * @txbuf.len: Transmit buffer length ++ * @buf: Small buffer used when writing init data over SPI ++ * @startbyte: Used by some controllers when in SPI mode. ++ * Format: 6 bit Device id + RS bit + RW bit ++ * @fbtftops: FBTFT operations provided by driver or device (platform_data) ++ * @dirty_lock: Protects dirty_lines_start and dirty_lines_end ++ * @dirty_lines_start: Where to begin updating display ++ * @dirty_lines_end: Where to end updating display ++ * @gpio.reset: GPIO used to reset display ++ * @gpio.dc: Data/Command signal, also known as RS ++ * @gpio.rd: Read latching signal ++ * @gpio.wr: Write latching signal ++ * @gpio.latch: Bus latch signal, eg. 16->8 bit bus latch ++ * @gpio.cs: LCD Chip Select with parallel interface bus ++ * @gpio.db[16]: Parallel databus ++ * @gpio.led[16]: Led control signals ++ * @gpio.aux[16]: Auxillary signals, not used by core ++ * @init_sequence: Pointer to LCD initialization array ++ * @gamma.lock: Mutex for Gamma curve locking ++ * @gamma.curves: Pointer to Gamma curve array ++ * @gamma.num_values: Number of values per Gamma curve ++ * @gamma.num_curves: Number of Gamma curves ++ * @debug: Pointer to debug value ++ * @current_debug: ++ * @first_update_done: Used to only time the first display update ++ * @update_time: Used to calculate 'fps' in debug output ++ * @bgr: BGR mode/\n ++ * @extra: Extra info needed by driver ++ */ ++struct fbtft_par { ++ struct spi_device *spi; ++ struct platform_device *pdev; ++ struct fb_info *info; ++ struct fbtft_platform_data *pdata; ++ u16 *ssbuf; ++ u32 pseudo_palette[16]; ++ struct { ++ void *buf; ++ dma_addr_t dma; ++ size_t len; ++ } txbuf; ++ u8 *buf; ++ u8 startbyte; ++ struct fbtft_ops fbtftops; ++ spinlock_t dirty_lock; ++ unsigned dirty_lines_start; ++ unsigned dirty_lines_end; ++ struct { ++ int reset; ++ int dc; ++ int rd; ++ int wr; ++ int latch; ++ int cs; ++ int db[16]; ++ int led[16]; ++ int aux[16]; ++ } gpio; ++ int *init_sequence; ++ struct { ++ struct mutex lock; ++ unsigned long *curves; ++ int num_values; ++ int num_curves; ++ } gamma; ++ unsigned long debug; ++ bool first_update_done; ++ struct timespec update_time; ++ bool bgr; ++ void *extra; ++}; ++ ++#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) ++ ++#define write_reg(par, ...) \ ++do { \ ++ par->fbtftops.write_register(par, NUMARGS(__VA_ARGS__), __VA_ARGS__); \ ++} while (0) ++ ++/* fbtft-core.c */ ++extern void fbtft_dbg_hex(const struct device *dev, ++ int groupsize, void *buf, size_t len, const char *fmt, ...); ++extern struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, ++ struct device *dev); ++extern void fbtft_framebuffer_release(struct fb_info *info); ++extern int fbtft_register_framebuffer(struct fb_info *fb_info); ++extern int fbtft_unregister_framebuffer(struct fb_info *fb_info); ++extern void fbtft_register_backlight(struct fbtft_par *par); ++extern void fbtft_unregister_backlight(struct fbtft_par *par); ++extern int fbtft_init_display(struct fbtft_par *par); ++extern int fbtft_probe_common(struct fbtft_display *display, ++ struct spi_device *sdev, struct platform_device *pdev); ++extern int fbtft_remove_common(struct device *dev, struct fb_info *info); ++ ++/* fbtft-io.c */ ++extern int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_spi_emulate_9(struct fbtft_par *par, ++ void *buf, size_t len); ++extern int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, ++ void *buf, size_t len); ++ ++/* fbtft-bus.c */ ++extern int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len); ++extern int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len); ++extern int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len); ++extern int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len); ++extern void fbtft_write_reg8_bus8(struct fbtft_par *par, int len, ...); ++extern void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); ++extern void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...); ++extern void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...); ++ ++ ++#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ ++ \ ++static int fbtft_driver_probe_spi(struct spi_device *spi) \ ++{ \ ++ return fbtft_probe_common(_display, spi, NULL); \ ++} \ ++ \ ++static int fbtft_driver_remove_spi(struct spi_device *spi) \ ++{ \ ++ struct fb_info *info = spi_get_drvdata(spi); \ ++ \ ++ return fbtft_remove_common(&spi->dev, info); \ ++} \ ++ \ ++static int fbtft_driver_probe_pdev(struct platform_device *pdev) \ ++{ \ ++ return fbtft_probe_common(_display, NULL, pdev); \ ++} \ ++ \ ++static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ ++{ \ ++ struct fb_info *info = platform_get_drvdata(pdev); \ ++ \ ++ return fbtft_remove_common(&pdev->dev, info); \ ++} \ ++ \ ++static const struct of_device_id dt_ids[] = { \ ++ { .compatible = _compatible }, \ ++ {}, \ ++}; \ ++ \ ++MODULE_DEVICE_TABLE(of, dt_ids); \ ++ \ ++ \ ++static struct spi_driver fbtft_driver_spi_driver = { \ ++ .driver = { \ ++ .name = _name, \ ++ .owner = THIS_MODULE, \ ++ .of_match_table = of_match_ptr(dt_ids), \ ++ }, \ ++ .probe = fbtft_driver_probe_spi, \ ++ .remove = fbtft_driver_remove_spi, \ ++}; \ ++ \ ++static struct platform_driver fbtft_driver_platform_driver = { \ ++ .driver = { \ ++ .name = _name, \ ++ .owner = THIS_MODULE, \ ++ .of_match_table = of_match_ptr(dt_ids), \ ++ }, \ ++ .probe = fbtft_driver_probe_pdev, \ ++ .remove = fbtft_driver_remove_pdev, \ ++}; \ ++ \ ++static int __init fbtft_driver_module_init(void) \ ++{ \ ++ int ret; \ ++ \ ++ ret = spi_register_driver(&fbtft_driver_spi_driver); \ ++ if (ret < 0) \ ++ return ret; \ ++ return platform_driver_register(&fbtft_driver_platform_driver); \ ++} \ ++ \ ++static void __exit fbtft_driver_module_exit(void) \ ++{ \ ++ spi_unregister_driver(&fbtft_driver_spi_driver); \ ++ platform_driver_unregister(&fbtft_driver_platform_driver); \ ++} \ ++ \ ++module_init(fbtft_driver_module_init); \ ++module_exit(fbtft_driver_module_exit); ++ ++ ++/* Debug macros */ ++ ++/* shorthand debug levels */ ++#define DEBUG_LEVEL_1 DEBUG_REQUEST_GPIOS ++#define DEBUG_LEVEL_2 (DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS | DEBUG_TIME_FIRST_UPDATE) ++#define DEBUG_LEVEL_3 (DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY | DEBUG_BLANK | DEBUG_REQUEST_GPIOS | DEBUG_FREE_GPIOS | DEBUG_VERIFY_GPIOS | DEBUG_BACKLIGHT | DEBUG_SYSFS) ++#define DEBUG_LEVEL_4 (DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE | DEBUG_FB_FILLRECT | DEBUG_FB_COPYAREA | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK) ++#define DEBUG_LEVEL_5 (DEBUG_LEVEL_3 | DEBUG_UPDATE_DISPLAY) ++#define DEBUG_LEVEL_6 (DEBUG_LEVEL_4 | DEBUG_LEVEL_5) ++#define DEBUG_LEVEL_7 0xFFFFFFFF ++ ++#define DEBUG_DRIVER_INIT_FUNCTIONS (1<<3) ++#define DEBUG_TIME_FIRST_UPDATE (1<<4) ++#define DEBUG_TIME_EACH_UPDATE (1<<5) ++#define DEBUG_DEFERRED_IO (1<<6) ++#define DEBUG_FBTFT_INIT_FUNCTIONS (1<<7) ++ ++/* fbops */ ++#define DEBUG_FB_READ (1<<8) ++#define DEBUG_FB_WRITE (1<<9) ++#define DEBUG_FB_FILLRECT (1<<10) ++#define DEBUG_FB_COPYAREA (1<<11) ++#define DEBUG_FB_IMAGEBLIT (1<<12) ++#define DEBUG_FB_SETCOLREG (1<<13) ++#define DEBUG_FB_BLANK (1<<14) ++ ++#define DEBUG_SYSFS (1<<16) ++ ++/* fbtftops */ ++#define DEBUG_BACKLIGHT (1<<17) ++#define DEBUG_READ (1<<18) ++#define DEBUG_WRITE (1<<19) ++#define DEBUG_WRITE_VMEM (1<<20) ++#define DEBUG_WRITE_REGISTER (1<<21) ++#define DEBUG_SET_ADDR_WIN (1<<22) ++#define DEBUG_RESET (1<<23) ++#define DEBUG_MKDIRTY (1<<24) ++#define DEBUG_UPDATE_DISPLAY (1<<25) ++#define DEBUG_INIT_DISPLAY (1<<26) ++#define DEBUG_BLANK (1<<27) ++#define DEBUG_REQUEST_GPIOS (1<<28) ++#define DEBUG_FREE_GPIOS (1<<29) ++#define DEBUG_REQUEST_GPIOS_MATCH (1<<30) ++#define DEBUG_VERIFY_GPIOS (1<<31) ++ ++ ++#define fbtft_init_dbg(dev, format, arg...) \ ++do { \ ++ if (unlikely((dev)->platform_data && \ ++ (((struct fbtft_platform_data *)(dev)->platform_data)->display.debug & DEBUG_DRIVER_INIT_FUNCTIONS))) \ ++ dev_info(dev, format, ##arg); \ ++} while (0) ++ ++#define fbtft_par_dbg(level, par, format, arg...) \ ++do { \ ++ if (unlikely(par->debug & level)) \ ++ dev_info(par->info->device, format, ##arg); \ ++} while (0) ++ ++#define fbtft_dev_dbg(level, par, dev, format, arg...) \ ++do { \ ++ if (unlikely(par->debug & level)) \ ++ dev_info(dev, format, ##arg); \ ++} while (0) ++ ++#define fbtft_par_dbg_hex(level, par, dev, type, buf, num, format, arg...) \ ++do { \ ++ if (unlikely(par->debug & level)) \ ++ fbtft_dbg_hex(dev, sizeof(type), buf, num * sizeof(type), format, ##arg); \ ++} while (0) ++ ++#endif /* __LINUX_FBTFT_H */ +diff --git a/drivers/video/fbtft/fbtft_device.c b/drivers/video/fbtft/fbtft_device.c +new file mode 100644 +index 0000000..b9f4c30 +--- /dev/null ++++ b/drivers/video/fbtft/fbtft_device.c +@@ -0,0 +1,1444 @@ ++/* ++ * ++ * Copyright (C) 2013, Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fbtft_device" ++ ++#define MAX_GPIOS 32 ++ ++struct spi_device *spi_device; ++struct platform_device *p_device; ++ ++static char *name; ++module_param(name, charp, 0); ++MODULE_PARM_DESC(name, "Devicename (required). " \ ++"name=list => list all supported devices."); ++ ++static unsigned rotate; ++module_param(rotate, uint, 0); ++MODULE_PARM_DESC(rotate, ++"Angle to rotate display counter clockwise: 0, 90, 180, 270"); ++ ++static unsigned busnum; ++module_param(busnum, uint, 0); ++MODULE_PARM_DESC(busnum, "SPI bus number (default=0)"); ++ ++static unsigned cs; ++module_param(cs, uint, 0); ++MODULE_PARM_DESC(cs, "SPI chip select (default=0)"); ++ ++static unsigned speed; ++module_param(speed, uint, 0); ++MODULE_PARM_DESC(speed, "SPI speed (override device default)"); ++ ++static int mode = -1; ++module_param(mode, int, 0); ++MODULE_PARM_DESC(mode, "SPI mode (override device default)"); ++ ++static char *gpios; ++module_param(gpios, charp, 0); ++MODULE_PARM_DESC(gpios, ++"List of gpios. Comma separated with the form: reset:23,dc:24 " \ ++"(when overriding the default, all gpios must be specified)"); ++ ++static unsigned fps; ++module_param(fps, uint, 0); ++MODULE_PARM_DESC(fps, "Frames per second (override driver default)"); ++ ++static char *gamma; ++module_param(gamma, charp, 0); ++MODULE_PARM_DESC(gamma, ++"String representation of Gamma Curve(s). Driver specific."); ++ ++static int txbuflen; ++module_param(txbuflen, int, 0); ++MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)"); ++ ++static int bgr = -1; ++module_param(bgr, int, 0); ++MODULE_PARM_DESC(bgr, ++"BGR bit (supported by some drivers)."); ++ ++static unsigned startbyte; ++module_param(startbyte, uint, 0); ++MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays."); ++ ++static bool custom; ++module_param(custom, bool, 0); ++MODULE_PARM_DESC(custom, "Add a custom display device. " \ ++"Use speed= argument to make it a SPI device, else platform_device"); ++ ++static unsigned width; ++module_param(width, uint, 0); ++MODULE_PARM_DESC(width, "Display width, used with the custom argument"); ++ ++static unsigned height; ++module_param(height, uint, 0); ++MODULE_PARM_DESC(height, "Display height, used with the custom argument"); ++ ++static unsigned buswidth = 8; ++module_param(buswidth, uint, 0); ++MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument"); ++ ++static int init[FBTFT_MAX_INIT_SEQUENCE]; ++static int init_num; ++module_param_array(init, int, &init_num, 0); ++MODULE_PARM_DESC(init, "Init sequence, used with the custom argument"); ++ ++static unsigned long debug; ++module_param(debug, ulong , 0); ++MODULE_PARM_DESC(debug, ++"level: 0-7 (the remaining 29 bits is for advanced usage)"); ++ ++static unsigned verbose = 3; ++module_param(verbose, uint, 0); ++MODULE_PARM_DESC(verbose, ++"0 silent, >0 show gpios, >1 show devices, >2 show devices before (default=3)"); ++ ++ ++struct fbtft_device_display { ++ char *name; ++ struct spi_board_info *spi; ++ struct platform_device *pdev; ++}; ++ ++static void fbtft_device_pdev_release(struct device *dev); ++ ++static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len); ++static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par, ++ int xs, int ys, int xe, int ye); ++ ++#define ADAFRUIT18_GAMMA \ ++ "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \ ++ "03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10" ++ ++static int hy28b_init_sequence[] = { ++ -1,0x00e7,0x0010,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700, ++ -1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0207,-1,0x0009,0x0000, ++ -1,0x000a,0x0000,-1,0x000c,0x0001,-1,0x000d,0x0000,-1,0x000f,0x0000, ++ -1,0x0010,0x0000,-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000, ++ -2,50,-1,0x0010,0x1590,-1,0x0011,0x0227,-2,50,-1,0x0012,0x009c,-2,50, ++ -1,0x0013,0x1900,-1,0x0029,0x0023,-1,0x002b,0x000e,-2,50, ++ -1,0x0020,0x0000,-1,0x0021,0x0000,-2,50,-1,0x0050,0x0000, ++ -1,0x0051,0x00ef,-1,0x0052,0x0000,-1,0x0053,0x013f,-1,0x0060,0xa700, ++ -1,0x0061,0x0001,-1,0x006a,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000, ++ -1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000, ++ -1,0x0090,0x0010,-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110, ++ -1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0133,-1,0x0020,0x0000, ++ -1,0x0021,0x0000,-2,100,-3 }; ++ ++#define HY28B_GAMMA \ ++ "04 1F 4 7 7 0 7 7 6 0\n" \ ++ "0F 00 1 7 4 0 0 0 6 7" ++ ++static int pitft_init_sequence[] = { ++ -1,0x01,-2,5,-1,0x28,-1,0xEF,0x03,0x80,0x02,-1,0xCF,0x00,0xC1,0x30, ++ -1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x00,0x78, ++ -1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00, ++ -1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86,-1,0x3A,0x55, ++ -1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27,-1,0xF2,0x00,-1,0x26,0x01, ++ -1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03, ++ 0x0E,0x09,0x00,-1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48, ++ 0x08,0x0F,0x0C,0x31,0x36,0x0F,-1,0x11,-2,100,-1,0x29,-2,20,-3 }; ++ ++static int waveshare32b_init_sequence[] = { ++ -1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xCF,0x00,0xC1,0x30, ++ -1,0xE8,0x85,0x00,0x78,-1,0xEA,0x00,0x00,-1,0xED,0x64,0x03,0x12,0x81, ++ -1,0xF7,0x20,-1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86, ++ -1,0x36,0x28,-1,0x3A,0x55,-1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27, ++ -1,0xF2,0x00,-1,0x26,0x01, ++ -1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,0x0E,0x09,0x00, ++ -1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0F,0x0C,0x31,0x36,0x0F, ++ -1,0x11,-2,120,-1,0x29,-1,0x2c,-3 }; ++ ++/* Supported displays in alphabetical order */ ++static struct fbtft_device_display displays[] = { ++ { ++ .name = "adafruit18", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_st7735r", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ .gamma = ADAFRUIT18_GAMMA, ++ } ++ } ++ }, { ++ .name = "adafruit18_green", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_st7735r", ++ .max_speed_hz = 4000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .fbtftops.set_addr_win = \ ++ adafruit18_green_tab_set_addr_win, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ .gamma = ADAFRUIT18_GAMMA, ++ } ++ } ++ }, { ++ .name = "adafruit22", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_hx8340bn", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 9, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "adafruit22a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9340", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "adafruit28", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "adafruit13m", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1306", ++ .max_speed_hz = 16000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "agm1264k-fl", ++ .pdev = &(struct platform_device) { ++ .name = "fb_agm1264k-fl", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = FBTFT_ONBOARD_BACKLIGHT, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "dogs102", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_uc1701", ++ .max_speed_hz = 8000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 13 }, ++ { "dc", 6 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "er_tftm050_2", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ra8875", ++ .max_speed_hz = 5000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .width = 480, ++ .height = 272, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "er_tftm070_5", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ra8875", ++ .max_speed_hz = 5000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .width = 800, ++ .height = 480, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "flexfb", ++ .spi = &(struct spi_board_info) { ++ .modalias = "flexfb", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "flexpfb", ++ .pdev = &(struct platform_device) { ++ .name = "flexpfb", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 17 }, ++ { "dc", 1 }, ++ { "wr", 0 }, ++ { "cs", 21 }, ++ { "db00", 9 }, ++ { "db01", 11 }, ++ { "db02", 18 }, ++ { "db03", 23 }, ++ { "db04", 24 }, ++ { "db05", 25 }, ++ { "db06", 8 }, ++ { "db07", 7 }, ++ { "led", 4 }, ++ {}, ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "freetronicsoled128", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1351", ++ .max_speed_hz = 20000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = FBTFT_ONBOARD_BACKLIGHT, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "hx8353d", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_hx8353d", ++ .max_speed_hz = 16000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "hy28a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9320", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .startbyte = 0b01110000, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "hy28b", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9325", ++ .max_speed_hz = 48000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .init_sequence = hy28b_init_sequence, ++ }, ++ .startbyte = 0b01110000, ++ .bgr = true, ++ .fps= 50, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 18 }, ++ {}, ++ }, ++ .gamma = HY28B_GAMMA, ++ } ++ } ++ }, { ++ .name = "ili9481", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9481", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .regwidth = 16, ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 22 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "itdb24", ++ .pdev = &(struct platform_device) { ++ .name = "fb_s6d1121", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = false, ++ .gpios = (const struct fbtft_gpio []) { ++ /* Wiring for LCD adapter kit */ ++ { "reset", 7 }, ++ { "dc", 0 }, /* rev 2: 2 */ ++ { "wr", 1 }, /* rev 2: 3 */ ++ { "cs", 8 }, ++ { "db00", 17 }, ++ { "db01", 18 }, ++ { "db02", 21 }, /* rev 2: 27 */ ++ { "db03", 22 }, ++ { "db04", 23 }, ++ { "db05", 24 }, ++ { "db06", 25 }, ++ { "db07", 4 }, ++ {} ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "itdb28", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ili9325", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "itdb28_spi", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9325", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "mi0283qt-2", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_hx8347d", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .startbyte = 0b01110000, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "mi0283qt-9a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 9, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "mi0283qt-v2", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_watterott", ++ .max_speed_hz = 4000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "nokia3310", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_pcd8544", ++ .max_speed_hz = 400000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "nokia3310a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_tls8204", ++ .max_speed_hz = 1000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "piscreen", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9486", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .regwidth = 16, ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 22 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "pitft", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9340", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .chip_select = 0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .init_sequence = pitft_init_sequence, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "pioled", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1351", ++ .max_speed_hz = 20000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ .gamma = "0 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 3 " \ ++ "3 3 3 3 3 3 3 3 " \ ++ "3 3 3 3 3 3 3 3 " \ ++ "3 3 3 4 4 4 4 4 " \ ++ "4 4 4 4 4 4 4" ++ } ++ } ++ }, { ++ .name = "rpi-display", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 23 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "s6d02a1", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_s6d02a1", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "sainsmart18", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_st7735r", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "sainsmart32", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ssd1289", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 16, ++ .txbuflen = -2, /* disable buffer */ ++ .backlight = 1, ++ .fbtftops.write = write_gpio16_wr_slow, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ } ++ }, { ++ .name = "sainsmart32_fast", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ssd1289", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 16, ++ .txbuflen = -2, /* disable buffer */ ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ } ++ }, { ++ .name = "sainsmart32_latched", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ssd1289", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 16, ++ .txbuflen = -2, /* disable buffer */ ++ .backlight = 1, ++ .fbtftops.write = \ ++ fbtft_write_gpio16_wr_latched, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ } ++ }, { ++ .name = "sainsmart32_spi", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1289", ++ .max_speed_hz = 16000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "spidev", ++ .spi = &(struct spi_board_info) { ++ .modalias = "spidev", ++ .max_speed_hz = 500000, ++ .bus_num = 0, ++ .chip_select = 0, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "ssd1331", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1331", ++ .max_speed_hz = 20000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tinylcd35", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_tinylcd", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tm022hdh26", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tontec35_9481", /* boards before 02 July 2014 */ ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9481", ++ .max_speed_hz = 128000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 15 }, ++ { "dc", 25 }, ++ { "led_", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tontec35_9486", /* boards after 02 July 2014 */ ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9486", ++ .max_speed_hz = 128000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 15 }, ++ { "dc", 25 }, ++ { "led_", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "upd161704", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_upd161704", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "waveshare32b", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9340", ++ .max_speed_hz = 48000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .init_sequence = waveshare32b_init_sequence, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 27 }, ++ { "dc", 22 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "waveshare22", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_bd663474", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ /* This should be the last item. ++ Used with the custom argument */ ++ .name = "", ++ .spi = &(struct spi_board_info) { ++ .modalias = "", ++ .max_speed_hz = 0, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ } ++ }, ++ .pdev = &(struct platform_device) { ++ .name = "", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ }, ++ } ++}; ++ ++static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u16 data; ++ int i; ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ static u16 prev_data; ++#endif ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ data = *(u16 *) buf; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ if (data == prev_data) { ++ gpio_set_value(par->gpio.wr, 0); /* used as delay */ ++ } else { ++ for (i = 0; i < 16; i++) { ++ if ((data & 1) != (prev_data & 1)) ++ gpio_set_value(par->gpio.db[i], ++ (data & 1)); ++ data >>= 1; ++ prev_data >>= 1; ++ } ++ } ++#else ++ for (i = 0; i < 16; i++) { ++ gpio_set_value(par->gpio.db[i], (data & 1)); ++ data >>= 1; ++ } ++#endif ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ prev_data = *(u16 *) buf; ++#endif ++ buf += 2; ++ len -= 2; ++ } ++ ++ return 0; ++} ++ ++static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par, ++ int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2); ++ write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1); ++ write_reg(par, 0x2C); ++} ++ ++/* used if gpios parameter is present */ ++static struct fbtft_gpio fbtft_device_param_gpios[MAX_GPIOS+1] = { }; ++ ++static void fbtft_device_pdev_release(struct device *dev) ++{ ++/* Needed to silence this message: ++Device 'xxx' does not have a release() function, it is broken and must be fixed ++*/ ++} ++ ++static int spi_device_found(struct device *dev, void *data) ++{ ++ struct spi_device *spi = container_of(dev, struct spi_device, dev); ++ ++ pr_info(DRVNAME": %s %s %dkHz %d bits mode=0x%02X\n", ++ spi->modalias, dev_name(dev), spi->max_speed_hz/1000, ++ spi->bits_per_word, spi->mode); ++ ++ return 0; ++} ++ ++static void pr_spi_devices(void) ++{ ++ pr_info(DRVNAME": SPI devices registered:\n"); ++ bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found); ++} ++ ++static int p_device_found(struct device *dev, void *data) ++{ ++ struct platform_device ++ *pdev = container_of(dev, struct platform_device, dev); ++ ++ if (strstr(pdev->name, "fb")) ++ pr_info(DRVNAME": %s id=%d pdata? %s\n", ++ pdev->name, pdev->id, ++ pdev->dev.platform_data ? "yes" : "no"); ++ ++ return 0; ++} ++ ++static void pr_p_devices(void) ++{ ++ pr_info(DRVNAME": 'fb' Platform devices registered:\n"); ++ bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found); ++} ++ ++#ifdef MODULE ++static void fbtft_device_spi_delete(struct spi_master *master, unsigned cs) ++{ ++ struct device *dev; ++ char str[32]; ++ ++ snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs); ++ ++ dev = bus_find_device_by_name(&spi_bus_type, NULL, str); ++ if (dev) { ++ if (verbose) ++ pr_info(DRVNAME": Deleting %s\n", str); ++ device_del(dev); ++ } ++} ++ ++static int fbtft_device_spi_device_register(struct spi_board_info *spi) ++{ ++ struct spi_master *master; ++ ++ master = spi_busnum_to_master(spi->bus_num); ++ if (!master) { ++ pr_err(DRVNAME ": spi_busnum_to_master(%d) returned NULL\n", ++ spi->bus_num); ++ return -EINVAL; ++ } ++ /* make sure it's available */ ++ fbtft_device_spi_delete(master, spi->chip_select); ++ spi_device = spi_new_device(master, spi); ++ put_device(&master->dev); ++ if (!spi_device) { ++ pr_err(DRVNAME ": spi_new_device() returned NULL\n"); ++ return -EPERM; ++ } ++ return 0; ++} ++#else ++static int fbtft_device_spi_device_register(struct spi_board_info *spi) ++{ ++ return spi_register_board_info(spi, 1); ++} ++#endif ++ ++static int __init fbtft_device_init(void) ++{ ++ struct spi_board_info *spi = NULL; ++ struct fbtft_platform_data *pdata; ++ const struct fbtft_gpio *gpio = NULL; ++ char *p_gpio, *p_name, *p_num; ++ bool found = false; ++ int i = 0; ++ long val; ++ int ret = 0; ++ ++ pr_debug("\n\n"DRVNAME": init\n"); ++ ++ if (name == NULL) { ++#ifdef MODULE ++ pr_err(DRVNAME": missing module parameter: 'name'\n"); ++ return -EINVAL; ++#else ++ return 0; ++#endif ++ } ++ ++ if (init_num > FBTFT_MAX_INIT_SEQUENCE) { ++ pr_err(DRVNAME \ ++ ": init parameter: exceeded max array size: %d\n", ++ FBTFT_MAX_INIT_SEQUENCE); ++ return -EINVAL; ++ } ++ ++ /* parse module parameter: gpios */ ++ while ((p_gpio = strsep(&gpios, ","))) { ++ if (strchr(p_gpio, ':') == NULL) { ++ pr_err(DRVNAME \ ++ ": error: missing ':' in gpios parameter: %s\n", ++ p_gpio); ++ return -EINVAL; ++ } ++ p_num = p_gpio; ++ p_name = strsep(&p_num, ":"); ++ if (p_name == NULL || p_num == NULL) { ++ pr_err(DRVNAME \ ++ ": something bad happened parsing gpios parameter: %s\n", ++ p_gpio); ++ return -EINVAL; ++ } ++ ret = kstrtol(p_num, 10, &val); ++ if (ret) { ++ pr_err(DRVNAME \ ++ ": could not parse number in gpios parameter: %s:%s\n", ++ p_name, p_num); ++ return -EINVAL; ++ } ++ strcpy(fbtft_device_param_gpios[i].name, p_name); ++ fbtft_device_param_gpios[i++].gpio = (int) val; ++ if (i == MAX_GPIOS) { ++ pr_err(DRVNAME \ ++ ": gpios parameter: exceeded max array size: %d\n", ++ MAX_GPIOS); ++ return -EINVAL; ++ } ++ } ++ if (fbtft_device_param_gpios[0].name[0]) ++ gpio = fbtft_device_param_gpios; ++ ++ if (verbose > 2) ++ pr_spi_devices(); /* print list of registered SPI devices */ ++ ++ if (verbose > 2) ++ pr_p_devices(); /* print list of 'fb' platform devices */ ++ ++ pr_debug(DRVNAME": name='%s', busnum=%d, cs=%d\n", name, busnum, cs); ++ ++ if (rotate > 0 && rotate < 4) { ++ rotate = (4 - rotate) * 90; ++ pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n", ++ rotate); ++ } ++ if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) { ++ pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n", ++ rotate); ++ rotate = 0; ++ } ++ ++ /* name=list lists all supported displays */ ++ if (strncmp(name, "list", 32) == 0) { ++ pr_info(DRVNAME": Supported displays:\n"); ++ ++ for (i = 0; i < ARRAY_SIZE(displays); i++) ++ pr_info(DRVNAME": %s\n", displays[i].name); ++ return -ECANCELED; ++ } ++ ++ if (custom) { ++ i = ARRAY_SIZE(displays) - 1; ++ displays[i].name = name; ++ if (speed == 0) { ++ displays[i].pdev->name = name; ++ displays[i].spi = NULL; ++ } else { ++ strncpy(displays[i].spi->modalias, name, SPI_NAME_SIZE); ++ displays[i].pdev = NULL; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(displays); i++) { ++ if (strncmp(name, displays[i].name, 32) == 0) { ++ if (displays[i].spi) { ++ spi = displays[i].spi; ++ spi->chip_select = cs; ++ spi->bus_num = busnum; ++ if (speed) ++ spi->max_speed_hz = speed; ++ if (mode != -1) ++ spi->mode = mode; ++ pdata = (void *)spi->platform_data; ++ } else if (displays[i].pdev) { ++ p_device = displays[i].pdev; ++ pdata = p_device->dev.platform_data; ++ } else { ++ pr_err(DRVNAME": broken displays array\n"); ++ return -EINVAL; ++ } ++ ++ pdata->rotate = rotate; ++ if (bgr == 0) ++ pdata->bgr = false; ++ else if (bgr == 1) ++ pdata->bgr = true; ++ if (startbyte) ++ pdata->startbyte = startbyte; ++ if (gamma) ++ pdata->gamma = gamma; ++ pdata->display.debug = debug; ++ if (fps) ++ pdata->fps = fps; ++ if (txbuflen) ++ pdata->txbuflen = txbuflen; ++ if (init_num) ++ pdata->display.init_sequence = init; ++ if (gpio) ++ pdata->gpios = gpio; ++ if (custom) { ++ pdata->display.width = width; ++ pdata->display.height = height; ++ pdata->display.buswidth = buswidth; ++ pdata->display.backlight = 1; ++ } ++ ++ if (displays[i].spi) { ++ ret = fbtft_device_spi_device_register(spi); ++ if (ret) { ++ pr_err(DRVNAME \ ++ ": failed to register SPI device\n"); ++ return ret; ++ } ++ found = true; ++ break; ++ } else { ++ ret = platform_device_register(p_device); ++ if (ret < 0) { ++ pr_err(DRVNAME \ ++ ": platform_device_register() returned %d\n", ++ ret); ++ return ret; ++ } ++ found = true; ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ pr_err(DRVNAME": display not supported: '%s'\n", name); ++ return -EINVAL; ++ } ++ ++ if (verbose && pdata && pdata->gpios) { ++ gpio = pdata->gpios; ++ pr_info(DRVNAME": GPIOS used by '%s':\n", name); ++ found = false; ++ while (verbose && gpio->name[0]) { ++ pr_info(DRVNAME": '%s' = GPIO%d\n", ++ gpio->name, gpio->gpio); ++ gpio++; ++ found = true; ++ } ++ if (!found) ++ pr_info(DRVNAME": (none)\n"); ++ } ++ ++ if (spi_device && (verbose > 1)) ++ pr_spi_devices(); ++ if (p_device && (verbose > 1)) ++ pr_p_devices(); ++ ++ return 0; ++} ++ ++static void __exit fbtft_device_exit(void) ++{ ++ pr_debug(DRVNAME" - exit\n"); ++ ++ if (spi_device) { ++ device_del(&spi_device->dev); ++ kfree(spi_device); ++ } ++ ++ if (p_device) ++ platform_device_unregister(p_device); ++ ++} ++ ++arch_initcall(fbtft_device_init); ++module_exit(fbtft_device_exit); ++ ++MODULE_DESCRIPTION("Add a FBTFT device."); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/video/fbtft/flexfb.c b/drivers/video/fbtft/flexfb.c +new file mode 100644 +index 0000000..45574a0 +--- /dev/null ++++ b/drivers/video/fbtft/flexfb.c +@@ -0,0 +1,593 @@ ++/* ++ * Generic FB driver for TFT LCD displays ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "flexfb" ++ ++ ++static char *chip = NULL; ++module_param(chip, charp, 0); ++MODULE_PARM_DESC(chip, "LCD controller"); ++ ++static unsigned int width = 0; ++module_param(width, uint, 0); ++MODULE_PARM_DESC(width, "Display width"); ++ ++static unsigned int height = 0; ++module_param(height, uint, 0); ++MODULE_PARM_DESC(height, "Display height"); ++ ++static int init[512]; ++static int init_num = 0; ++module_param_array(init, int, &init_num, 0); ++MODULE_PARM_DESC(init, "Init sequence"); ++ ++static unsigned int setaddrwin = 0; ++module_param(setaddrwin, uint, 0); ++MODULE_PARM_DESC(setaddrwin, "Which set_addr_win() implementation to use"); ++ ++static unsigned int buswidth = 8; ++module_param(buswidth, uint, 0); ++MODULE_PARM_DESC(buswidth, "Width of databus (default: 8)"); ++ ++static unsigned int regwidth = 8; ++module_param(regwidth, uint, 0); ++MODULE_PARM_DESC(regwidth, "Width of controller register (default: 8)"); ++ ++static bool nobacklight = false; ++module_param(nobacklight, bool, 0); ++MODULE_PARM_DESC(nobacklight, "Turn off backlight functionality."); ++ ++static bool latched = false; ++module_param(latched, bool, 0); ++MODULE_PARM_DESC(latched, "Use with latched 16-bit databus"); ++ ++ ++static int *initp = NULL; ++static int initp_num = 0; ++ ++/* default init sequences */ ++static int st7735r_init[] = { \ ++-1,0x01,-2,150,-1,0x11,-2,500,-1,0xB1,0x01,0x2C,0x2D,-1,0xB2,0x01,0x2C,0x2D,-1,0xB3,0x01,0x2C,0x2D,0x01,0x2C,0x2D, \ ++-1,0xB4,0x07,-1,0xC0,0xA2,0x02,0x84,-1,0xC1,0xC5,-1,0xC2,0x0A,0x00,-1,0xC3,0x8A,0x2A,-1,0xC4,0x8A,0xEE,-1,0xC5,0x0E, \ ++-1,0x20,-1,0x36,0xC0,-1,0x3A,0x05,-1,0xE0,0x0f,0x1a,0x0f,0x18,0x2f,0x28,0x20,0x22,0x1f,0x1b,0x23,0x37,0x00,0x07,0x02,0x10, \ ++-1,0xE1,0x0f,0x1b,0x0f,0x17,0x33,0x2c,0x29,0x2e,0x30,0x30,0x39,0x3f,0x00,0x07,0x03,0x10,-1,0x29,-2,100,-1,0x13,-2,10,-3 }; ++ ++static int ssd1289_init[] = { \ ++-1,0x00,0x0001,-1,0x03,0xA8A4,-1,0x0C,0x0000,-1,0x0D,0x080C,-1,0x0E,0x2B00,-1,0x1E,0x00B7,-1,0x01,0x2B3F,-1,0x02,0x0600, \ ++-1,0x10,0x0000,-1,0x11,0x6070,-1,0x05,0x0000,-1,0x06,0x0000,-1,0x16,0xEF1C,-1,0x17,0x0003,-1,0x07,0x0233,-1,0x0B,0x0000, \ ++-1,0x0F,0x0000,-1,0x41,0x0000,-1,0x42,0x0000,-1,0x48,0x0000,-1,0x49,0x013F,-1,0x4A,0x0000,-1,0x4B,0x0000,-1,0x44,0xEF00, \ ++-1,0x45,0x0000,-1,0x46,0x013F,-1,0x30,0x0707,-1,0x31,0x0204,-1,0x32,0x0204,-1,0x33,0x0502,-1,0x34,0x0507,-1,0x35,0x0204, \ ++-1,0x36,0x0204,-1,0x37,0x0502,-1,0x3A,0x0302,-1,0x3B,0x0302,-1,0x23,0x0000,-1,0x24,0x0000,-1,0x25,0x8000,-1,0x4f,0x0000, \ ++-1,0x4e,0x0000,-1,0x22,-3 }; ++ ++static int hx8340bn_init[] = { \ ++-1,0xC1,0xFF,0x83,0x40,-1,0x11,-2,150,-1,0xCA,0x70,0x00,0xD9,-1,0xB0,0x01,0x11, \ ++-1,0xC9,0x90,0x49,0x10,0x28,0x28,0x10,0x00,0x06,-2,20,-1,0xC2,0x60,0x71,0x01,0x0E,0x05,0x02,0x09,0x31,0x0A, \ ++-1,0xC3,0x67,0x30,0x61,0x17,0x48,0x07,0x05,0x33,-2,10,-1,0xB5,0x35,0x20,0x45,-1,0xB4,0x33,0x25,0x4C,-2,10, \ ++-1,0x3A,0x05,-1,0x29,-2,10,-3 }; ++ ++static int ili9225_init[] = { \ ++-1,0x0001,0x011C,-1,0x0002,0x0100,-1,0x0003,0x1030,-1,0x0008,0x0808,-1,0x000C,0x0000,-1,0x000F,0x0A01,-1,0x0020,0x0000, \ ++-1,0x0021,0x0000,-2,50,-1,0x0010,0x0A00,-1,0x0011,0x1038,-2,50,-1,0x0012,0x1121,-1,0x0013,0x004E,-1,0x0014,0x676F, \ ++-1,0x0030,0x0000,-1,0x0031,0x00DB,-1,0x0032,0x0000,-1,0x0033,0x0000,-1,0x0034,0x00DB,-1,0x0035,0x0000,-1,0x0036,0x00AF, \ ++-1,0x0037,0x0000,-1,0x0038,0x00DB,-1,0x0039,0x0000,-1,0x0050,0x0000,-1,0x0051,0x060A,-1,0x0052,0x0D0A,-1,0x0053,0x0303, \ ++-1,0x0054,0x0A0D,-1,0x0055,0x0A06,-1,0x0056,0x0000,-1,0x0057,0x0303,-1,0x0058,0x0000,-1,0x0059,0x0000,-2,50, \ ++-1,0x0007,0x1017,-2,50,-3 }; ++ ++static int ili9320_init[] = { \ ++-1,0x00E5,0x8000,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0202, \ ++-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000,-1,0x0011,0x0007, \ ++-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x17B0,-1,0x0011,0x0031,-2,50,-1,0x0012,0x0138,-2,50,-1,0x0013,0x1800, \ ++-1,0x0029,0x0008,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000,-1,0x0031,0x0505,-1,0x0032,0x0004, \ ++-1,0x0035,0x0006,-1,0x0036,0x0707,-1,0x0037,0x0105,-1,0x0038,0x0002,-1,0x0039,0x0707,-1,0x003C,0x0704,-1,0x003D,0x0807, \ ++-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0x2700,-1,0x0061,0x0001,-1,0x006A,0x0000, \ ++-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000,-1,0x0090,0x0010, \ ++-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110,-1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0173,-3 }; ++ ++static int ili9325_init[] = { \ ++-1,0x00E3,0x3008,-1,0x00E7,0x0012,-1,0x00EF,0x1231,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000, \ ++-1,0x0008,0x0207,-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000, \ ++-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x1690,-1,0x0011,0x0223,-2,50,-1,0x0012,0x000D,-2,50, \ ++-1,0x0013,0x1200,-1,0x0029,0x000A,-1,0x002B,0x000C,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000, \ ++-1,0x0031,0x0506,-1,0x0032,0x0104,-1,0x0035,0x0207,-1,0x0036,0x000F,-1,0x0037,0x0306,-1,0x0038,0x0102,-1,0x0039,0x0707, \ ++-1,0x003C,0x0702,-1,0x003D,0x1604,-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0xA700, \ ++-1,0x0061,0x0001,-1,0x006A,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000, \ ++-1,0x0085,0x0000,-1,0x0090,0x0010,-1,0x0092,0x0600,-1,0x0007,0x0133,-3 }; ++ ++static int ili9341_init[] = { \ ++-1,0x28,-2,20,-1,0xCF,0x00,0x83,0x30,-1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x01,0x79, \ ++-1,0xCB,0x39,0x2c,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00,-1,0xC0,0x26,-1,0xC1,0x11, \ ++-1,0xC5,0x35,0x3E,-1,0xC7,0xBE,-1,0xB1,0x00,0x1B,-1,0xB6,0x0a,0x82,0x27,0x00,-1,0xB7,0x07, \ ++-1,0x3A,0x55,-1,0x36,0x48,-1,0x11,-2,120,-1,0x29,-2,20,-3 }; ++ ++static int ssd1351_init[] = { -1,0xfd,0x12,-1,0xfd,0xb1,-1,0xae,-1,0xb3,0xf1,-1,0xca,0x7f,-1,0xa0,0x74, \ ++ -1,0x15,0x00,0x7f,-1,0x75,0x00,0x7f,-1,0xa1,0x00,-1,0xa2,0x00,-1,0xb5,0x00, \ ++ -1,0xab,0x01,-1,0xb1,0x32,-1,0xb4,0xa0,0xb5,0x55,-1,0xbb,0x17,-1,0xbe,0x05, \ ++ -1,0xc1,0xc8,0x80,0xc8,-1,0xc7,0x0f,-1,0xb6,0x01,-1,0xa6,-1,0xaf,-3 }; ++ ++ ++/* ili9320, ili9325 */ ++static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, width - 1 - xs); ++ write_reg(par, 0x0021, height - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, width - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, height - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++/* ssd1289 */ ++static void flexfb_set_addr_win_2(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ switch (par->info->var.rotate) { ++ /* R4Eh - Set GDDRAM X address counter */ ++ /* R4Fh - Set GDDRAM Y address counter */ ++ case 0: ++ write_reg(par, 0x4e, xs); ++ write_reg(par, 0x4f, ys); ++ break; ++ case 180: ++ write_reg(par, 0x4e, par->info->var.xres - 1 - xs); ++ write_reg(par, 0x4f, par->info->var.yres - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x4e, par->info->var.yres - 1 - ys); ++ write_reg(par, 0x4f, xs); ++ break; ++ case 90: ++ write_reg(par, 0x4e, ys); ++ write_reg(par, 0x4f, par->info->var.xres - 1 - xs); ++ break; ++ } ++ ++ /* R22h - RAM data write */ ++ write_reg(par, 0x22, 0); ++} ++ ++/* ssd1351 */ ++static void set_addr_win_3(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x15, xs, xe); ++ write_reg(par, 0x75, ys, ye); ++ write_reg(par, 0x5C); ++} ++ ++static int flexfb_verify_gpios_dc(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); ++ ++ if (par->gpio.dc < 0) { ++ dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int flexfb_verify_gpios_db(struct fbtft_par *par) ++{ ++ int i; ++ int num_db = buswidth; ++ ++ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); ++ ++ if (par->gpio.dc < 0) { ++ dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (par->gpio.wr < 0) { ++ dev_err(par->info->device, "Missing info about 'wr' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (latched && (par->gpio.latch < 0)) { ++ dev_err(par->info->device, "Missing info about 'latch' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (latched) ++ num_db=buswidth/2; ++ for (i=0;i < num_db;i++) { ++ if (par->gpio.db[i] < 0) { ++ dev_err(par->info->device, "Missing info about 'db%02d' gpio. Aborting.\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display flex_display = { }; ++ ++static int flexfb_probe_common(struct spi_device *sdev, struct platform_device *pdev) ++{ ++ struct device *dev; ++ struct fb_info *info; ++ struct fbtft_par *par; ++ int ret; ++ ++ initp = init; ++ initp_num = init_num; ++ ++ if (sdev) ++ dev = &sdev->dev; ++ else ++ dev = &pdev->dev; ++ ++ fbtft_init_dbg(dev, "%s(%s)\n", __func__, sdev ? "'SPI device'" : "'Platform device'"); ++ ++ if (chip) { ++ ++ if (!strcmp(chip, "st7735r")) { ++ if (!width) ++ width = 128; ++ if (!height) ++ height = 160; ++ if (init_num == 0) { ++ initp = st7735r_init; ++ initp_num = ARRAY_SIZE(st7735r_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "hx8340bn")) { ++ if (!width) ++ width = 176; ++ if (!height) ++ height = 220; ++ setaddrwin = 0; ++ if (init_num == 0) { ++ initp = hx8340bn_init; ++ initp_num = ARRAY_SIZE(hx8340bn_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "ili9225")) { ++ if (!width) ++ width = 176; ++ if (!height) ++ height = 220; ++ setaddrwin = 0; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ili9225_init; ++ initp_num = ARRAY_SIZE(ili9225_init); ++ } ++ ++ ++ ++ } else if (!strcmp(chip, "ili9320")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 1; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ili9320_init; ++ initp_num = ARRAY_SIZE(ili9320_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "ili9325")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 1; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ili9325_init; ++ initp_num = ARRAY_SIZE(ili9325_init); ++ } ++ ++ } else if (!strcmp(chip, "ili9341")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 0; ++ regwidth = 8; ++ if (init_num == 0) { ++ initp = ili9341_init; ++ initp_num = ARRAY_SIZE(ili9341_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "ssd1289")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 2; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ssd1289_init; ++ initp_num = ARRAY_SIZE(ssd1289_init); ++ } ++ ++ ++ ++ } else if (!strcmp(chip, "ssd1351")) { ++ if (!width) ++ width = 128; ++ if (!height) ++ height = 128; ++ setaddrwin = 3; ++ if (init_num == 0) { ++ initp = ssd1351_init; ++ initp_num = ARRAY_SIZE(ssd1351_init); ++ } ++ } else { ++ dev_err(dev, "chip=%s is not supported\n", chip); ++ return -EINVAL; ++ } ++ } ++ ++ if (width == 0 || height == 0) { ++ dev_err(dev, "argument(s) missing: width and height has to be set.\n"); ++ return -EINVAL; ++ } ++ flex_display.width = width; ++ flex_display.height = height; ++ fbtft_init_dbg(dev, "Display resolution: %dx%d\n", width, height); ++ fbtft_init_dbg(dev, "chip = %s\n", chip ? chip : "not set"); ++ fbtft_init_dbg(dev, "setaddrwin = %d\n", setaddrwin); ++ fbtft_init_dbg(dev, "regwidth = %d\n", regwidth); ++ fbtft_init_dbg(dev, "buswidth = %d\n", buswidth); ++ ++ info = fbtft_framebuffer_alloc(&flex_display, dev); ++ if (!info) ++ return -ENOMEM; ++ ++ par = info->par; ++ if (sdev) ++ par->spi = sdev; ++ else ++ par->pdev = pdev; ++ if (!par->init_sequence) ++ par->init_sequence = initp; ++ par->fbtftops.init_display = fbtft_init_display; ++ ++ /* registerwrite functions */ ++ switch (regwidth) { ++ case 8: ++ par->fbtftops.write_register = fbtft_write_reg8_bus8; ++ break; ++ case 16: ++ par->fbtftops.write_register = fbtft_write_reg16_bus8; ++ break; ++ default: ++ dev_err(dev, "argument 'regwidth': %d is not supported.\n", regwidth); ++ return -EINVAL; ++ } ++ ++ /* bus functions */ ++ if (sdev) { ++ par->fbtftops.write = fbtft_write_spi; ++ switch (buswidth) { ++ case 8: ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ if (!par->startbyte) ++ par->fbtftops.verify_gpios = flexfb_verify_gpios_dc; ++ break; ++ case 9: ++ if (regwidth == 16) { ++ dev_err(dev, "argument 'regwidth': %d is not supported with buswidth=%d and SPI.\n", regwidth, buswidth); ++ return -EINVAL; ++ } ++ par->fbtftops.write_register = fbtft_write_reg8_bus9; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus9; ++ sdev->bits_per_word=9; ++ ret = sdev->master->setup(sdev); ++ if (ret) { ++ dev_warn(dev, ++ "9-bit SPI not available, emulating using 8-bit.\n"); ++ sdev->bits_per_word = 8; ++ ret = sdev->master->setup(sdev); ++ if (ret) ++ goto out_release; ++ /* allocate buffer with room for dc bits */ ++ par->extra = devm_kzalloc(par->info->device, ++ par->txbuf.len + (par->txbuf.len / 8) + 8, ++ GFP_KERNEL); ++ if (!par->extra) { ++ ret = -ENOMEM; ++ goto out_release; ++ } ++ par->fbtftops.write = fbtft_write_spi_emulate_9; ++ } ++ break; ++ default: ++ dev_err(dev, "argument 'buswidth': %d is not supported with SPI.\n", buswidth); ++ return -EINVAL; ++ } ++ } else { ++ par->fbtftops.verify_gpios = flexfb_verify_gpios_db; ++ switch (buswidth) { ++ case 8: ++ par->fbtftops.write = fbtft_write_gpio8_wr; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ break; ++ case 16: ++ par->fbtftops.write_register = fbtft_write_reg16_bus16; ++ if (latched) ++ par->fbtftops.write = fbtft_write_gpio16_wr_latched; ++ else ++ par->fbtftops.write = fbtft_write_gpio16_wr; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus16; ++ break; ++ default: ++ dev_err(dev, "argument 'buswidth': %d is not supported with parallel.\n", buswidth); ++ return -EINVAL; ++ } ++ } ++ ++ /* set_addr_win function */ ++ switch (setaddrwin) { ++ case 0: ++ /* use default */ ++ break; ++ case 1: ++ par->fbtftops.set_addr_win = flexfb_set_addr_win_1; ++ break; ++ case 2: ++ par->fbtftops.set_addr_win = flexfb_set_addr_win_2; ++ break; ++ case 3: ++ par->fbtftops.set_addr_win = set_addr_win_3; ++ break; ++ default: ++ dev_err(dev, "argument 'setaddrwin': unknown value %d.\n", setaddrwin); ++ return -EINVAL; ++ } ++ ++ if (!nobacklight) ++ par->fbtftops.register_backlight = fbtft_register_backlight; ++ ++ ret = fbtft_register_framebuffer(info); ++ if (ret < 0) ++ goto out_release; ++ ++ return 0; ++ ++out_release: ++ fbtft_framebuffer_release(info); ++ ++ return ret; ++} ++ ++static int flexfb_remove_common(struct device *dev, struct fb_info *info) ++{ ++ struct fbtft_par *par; ++ ++ if (!info) ++ return -EINVAL; ++ par = info->par; ++ if (par) ++ fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, ++ "%s()\n", __func__); ++ fbtft_unregister_framebuffer(info); ++ fbtft_framebuffer_release(info); ++ ++ return 0; ++} ++ ++static int flexfb_probe_spi(struct spi_device *spi) ++{ ++ return flexfb_probe_common(spi, NULL); ++} ++ ++static int flexfb_remove_spi(struct spi_device *spi) ++{ ++ struct fb_info *info = spi_get_drvdata(spi); ++ ++ return flexfb_remove_common(&spi->dev, info); ++} ++ ++static int flexfb_probe_pdev(struct platform_device *pdev) ++{ ++ return flexfb_probe_common(NULL, pdev); ++} ++ ++static int flexfb_remove_pdev(struct platform_device *pdev) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ ++ return flexfb_remove_common(&pdev->dev, info); ++} ++ ++static struct spi_driver flexfb_spi_driver = { ++ .driver = { ++ .name = DRVNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = flexfb_probe_spi, ++ .remove = flexfb_remove_spi, ++}; ++ ++static const struct platform_device_id flexfb_platform_ids[] = { ++ { "flexpfb", 0 }, ++ { }, ++}; ++ ++static struct platform_driver flexfb_platform_driver = { ++ .driver = { ++ .name = DRVNAME, ++ .owner = THIS_MODULE, ++ }, ++ .id_table = flexfb_platform_ids, ++ .probe = flexfb_probe_pdev, ++ .remove = flexfb_remove_pdev, ++}; ++ ++static int __init flexfb_init(void) ++{ ++ int ret, ret2; ++ ++ ret = spi_register_driver(&flexfb_spi_driver); ++ ret2 = platform_driver_register(&flexfb_platform_driver); ++ if (ret < 0) ++ return ret; ++ return ret2; ++} ++ ++static void __exit flexfb_exit(void) ++{ ++ spi_unregister_driver(&flexfb_spi_driver); ++ platform_driver_unregister(&flexfb_platform_driver); ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++module_init(flexfb_init); ++module_exit(flexfb_exit); ++ ++MODULE_DESCRIPTION("Generic FB driver for TFT LCD displays"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); diff --git a/patch/kernel/odroidc1-default/packagin-guitar.patch b/patch/kernel/odroidc1-default/packagin-guitar.patch new file mode 100644 index 0000000000..be8b2462ae --- /dev/null +++ b/patch/kernel/odroidc1-default/packagin-guitar.patch @@ -0,0 +1,311 @@ +diff --git a/scripts/package/builddeb b/scripts/package/builddeb +old mode 100644 +new mode 100755 +index 3001ec5..d6b844d +--- a/scripts/package/builddeb ++++ b/scripts/package/builddeb +@@ -35,15 +35,17 @@ create_package() { + sparc*) + debarch=sparc ;; + s390*) +- debarch=s390 ;; ++ debarch=s390$(grep -q CONFIG_64BIT=y $KCONFIG_CONFIG && echo x || true) ;; + ppc*) +- debarch=powerpc ;; ++ debarch=$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo ppc64el || echo powerpc) ;; + parisc*) + debarch=hppa ;; + mips*) +- debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y .config && echo el) ;; ++ debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el || true) ;; ++ arm64) ++ debarch=arm64 ;; + arm*) +- debarch=arm$(grep -q CONFIG_AEABI=y .config && echo el) ;; ++ debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;; + *) + echo "" >&2 + echo "** ** ** WARNING ** ** **" >&2 +@@ -62,7 +64,7 @@ create_package() { + fi + + # Create the package +- dpkg-gencontrol -isp $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir" ++ dpkg-gencontrol $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir" + dpkg --build "$pdir" .. + } + +@@ -78,49 +80,76 @@ tmpdir="$objtree/debian/tmp" + fwdir="$objtree/debian/fwtmp" + kernel_headers_dir="$objtree/debian/hdrtmp" + libc_headers_dir="$objtree/debian/headertmp" +-packagename=linux-image-$version +-fwpackagename=linux-firmware-image +-kernel_headers_packagename=linux-headers-$version +-libc_headers_packagename=linux-libc-dev ++dtb_dir="$objtree/debian/dtbtmp" ++dbg_dir="$objtree/debian/dbgtmp" ++packagename=linux-image"$LOCALVERSION" ++fwpackagename=linux-firmware-image"$LOCALVERSION" ++kernel_headers_packagename=linux-headers"$LOCALVERSION" ++dtb_packagename=linux-dtb"$LOCALVERSION" ++libc_headers_packagename=linux-libc-dev"$LOCALVERSION" ++dbg_packagename=$packagename-dbg + + if [ "$ARCH" = "um" ] ; then + packagename=user-mode-linux-$version + fi + ++# Not all arches have the same installed path in debian ++# XXX: have each arch Makefile export a variable of the canonical image install ++# path instead ++case $ARCH in ++um) ++ installed_image_path="usr/bin/linux-$version" ++ ;; ++parisc|mips|powerpc) ++ installed_image_path="boot/vmlinux-$version" ++ ;; ++*) ++ installed_image_path="boot/vmlinuz-$version" ++esac ++ ++BUILD_DEBUG="$(grep -s '^CONFIG_DEBUG_INFO=y' $KCONFIG_CONFIG || true)" ++ + # Setup the directory structure +-rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" ++rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" "$dbg_dir" "$dtb_dir" + mkdir -m 755 -p "$tmpdir/DEBIAN" + mkdir -p "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" + mkdir -m 755 -p "$fwdir/DEBIAN" + mkdir -p "$fwdir/lib/firmware/$version/" "$fwdir/usr/share/doc/$fwpackagename" + mkdir -m 755 -p "$libc_headers_dir/DEBIAN" + mkdir -p "$libc_headers_dir/usr/share/doc/$libc_headers_packagename" ++ ++mkdir -m 755 -p "$dtb_dir/DEBIAN" ++mkdir -p "$dtb_dir/boot/dtb" "$dtb_dir/usr/share/doc/$dtb_packagename" ++ + mkdir -m 755 -p "$kernel_headers_dir/DEBIAN" + mkdir -p "$kernel_headers_dir/usr/share/doc/$kernel_headers_packagename" + mkdir -p "$kernel_headers_dir/lib/modules/$version/" + if [ "$ARCH" = "um" ] ; then + mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin" + fi ++if [ -n "$BUILD_DEBUG" ] ; then ++ mkdir -p "$dbg_dir/usr/share/doc/$dbg_packagename" ++ mkdir -m 755 -p "$dbg_dir/DEBIAN" ++fi + + # Build and install the kernel + if [ "$ARCH" = "um" ] ; then + $MAKE linux + cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map" +- cp .config "$tmpdir/usr/share/doc/$packagename/config" ++ cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config" + gzip "$tmpdir/usr/share/doc/$packagename/config" +- cp $KBUILD_IMAGE "$tmpdir/usr/bin/linux-$version" +-else ++else + cp System.map "$tmpdir/boot/System.map-$version" +- cp .config "$tmpdir/boot/config-$version" +- # Not all arches include the boot path in KBUILD_IMAGE +- if [ -e $KBUILD_IMAGE ]; then +- cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version" +- else +- cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version" +- fi ++ cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version" ++fi ++# Not all arches include the boot path in KBUILD_IMAGE ++if [ -e $KBUILD_IMAGE ]; then ++ cp $KBUILD_IMAGE "$tmpdir/$installed_image_path" ++else ++ cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/$installed_image_path" + fi + +-if grep -q '^CONFIG_MODULES=y' .config ; then ++if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then + INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_install + rm -f "$tmpdir/lib/modules/$version/build" + rm -f "$tmpdir/lib/modules/$version/source" +@@ -128,6 +157,24 @@ if grep -q '^CONFIG_MODULES=y' .config ; then + mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/" + rmdir "$tmpdir/lib/modules/$version" + fi ++ if [ -n "$BUILD_DEBUG" ] ; then ++ for module in $(find $tmpdir/lib/modules/ -name *.ko -printf '%P\n'); do ++ module=lib/modules/$module ++ mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module) ++ # only keep debug symbols in the debug file ++ $OBJCOPY --only-keep-debug $tmpdir/$module $dbg_dir/usr/lib/debug/$module ++ # strip original module from debug symbols ++ $OBJCOPY --strip-debug $tmpdir/$module ++ # then add a link to those ++ $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $tmpdir/$module ++ done ++ fi ++fi ++ ++if grep -q '^CONFIG_OF=y' $KCONFIG_CONFIG ; then ++ mkdir -p "$tmpdir/boot/dtb" ++ cp $objtree/arch/arm/boot/dts/*.dtb $dtb_dir/boot/dtb ++ #INSTALL_DTBS_PATH="$dtb_dir/boot/dtb" $MAKE KBUILD_SRC= dtbs_install + fi + + if [ "$ARCH" != "um" ]; then +@@ -137,8 +184,15 @@ fi + + # Install the maintainer scripts + # Note: hook scripts under /etc/kernel are also executed by official Debian +-# kernel packages, as well as kernel packages built using make-kpkg ++# kernel packages, as well as kernel packages built using make-kpkg. ++# make-kpkg sets $INITRD to indicate whether an initramfs is wanted, and ++# so do we; recent versions of dracut and initramfs-tools will obey this. + debhookdir=${KDEB_HOOKDIR:-/etc/kernel} ++if grep -q '^CONFIG_BLK_DEV_INITRD=y' $KCONFIG_CONFIG; then ++ want_initrd=Yes ++else ++ want_initrd=No ++fi + for script in postinst postrm preinst prerm ; do + mkdir -p "$tmpdir$debhookdir/$script.d" + cat < "$tmpdir/DEBIAN/$script" +@@ -147,14 +201,43 @@ for script in postinst postrm preinst prerm ; do + set -e + + # Pass maintainer script parameters to hook scripts ++ + export DEB_MAINT_PARAMS="\$*" + +-test -d $debhookdir/$script.d && run-parts --arg="$version" $debhookdir/$script.d ++# Tell initramfs builder whether it's wanted ++ ++export INITRD=$want_initrd ++ ++test -d $debhookdir/$script.d && run-parts --arg="$version" --arg="/$installed_image_path" $debhookdir/$script.d + exit 0 + EOF + chmod 755 "$tmpdir/DEBIAN/$script" + done + ++## ++## Create sym link to kernel image ++## ++sed -e "s/exit 0//g" -i $tmpdir/DEBIAN/postinst ++cat >> $tmpdir/DEBIAN/postinst < /dev/null 2>&1 ++rm -f /$installed_image_path /boot/zImage ++else ++ln -sf $(basename $installed_image_path) /boot/zImage > /dev/null 2>&1 || mv /$installed_image_path /boot/zImage ++fi ++rm -f /boot/.next ++exit 0 ++EOT ++## ++## FAT install workaround ++## ++sed -e "s/exit 0//g" -i $tmpdir/DEBIAN/preinst ++cat >> $tmpdir/DEBIAN/preinst <> $tmpdir/DEBIAN/preinst ++ ++ + # Try to determine maintainer and email values + if [ -n "$DEBEMAIL" ]; then + email=$DEBEMAIL +@@ -242,21 +325,30 @@ EOF + + fi + +-# Build header package +-(cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles") +-(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles") +-(cd $objtree; find arch/$SRCARCH/include .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") ++# Build kernel header package ++(cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles" ++(cd $srctree; find arch/$SRCARCH/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles" ++(cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles" ++(cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles" ++(cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles" + destdir=$kernel_headers_dir/usr/src/linux-headers-$version + mkdir -p "$destdir" +-(cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -) +-(cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -) ++######################## headers patch ++ZACNI=$(pwd) ++cd $destdir ++patch -p1 < /tmp/headers-debian-byteshift.patch ++cd $ZACNI ++######################## headers patch ++(cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -) ++(cd $objtree; tar -c -f - -T -) < "$objtree/debian/hdrobjfiles" | (cd $destdir; tar -xf -) ++(cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be + ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build" + rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles" + + cat <> debian/control + + Package: $kernel_headers_packagename +-Provides: linux-headers, linux-headers-2.6 ++Provides: linux-headers + Architecture: any + Description: Linux kernel headers for $KERNELRELEASE on \${kernel:debarch} + This package provides kernel header files for $KERNELRELEASE on \${kernel:debarch} +@@ -282,6 +374,16 @@ fi + + cat <> debian/control + ++Package: $dtb_packagename ++Architecture: any ++Description: Linux DTB, version $version ++ This package contains device blobs from the Linux kernel, version $version. ++EOF ++ ++create_package "$dtb_packagename" "$dtb_dir" ++ ++cat <> debian/control ++ + Package: $libc_headers_packagename + Section: devel + Provides: linux-kernel-headers +@@ -293,9 +395,35 @@ EOF + + if [ "$ARCH" != "um" ]; then + create_package "$kernel_headers_packagename" "$kernel_headers_dir" +- create_package "$libc_headers_packagename" "$libc_headers_dir" ++# create_package "$libc_headers_packagename" "$libc_headers_dir" + fi + + create_package "$packagename" "$tmpdir" + +-exit 0 ++if [ -n "$BUILD_DEBUG" ] ; then ++ # Build debug package ++ # Different tools want the image in different locations ++ # perf ++ mkdir -p $dbg_dir/usr/lib/debug/lib/modules/$version/ ++ cp vmlinux $dbg_dir/usr/lib/debug/lib/modules/$version/ ++ # systemtap ++ mkdir -p $dbg_dir/usr/lib/debug/boot/ ++ ln -s ../lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/boot/vmlinux-$version ++ # kdump-tools ++ ln -s lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/vmlinux-$version ++ ++ cat <> debian/control ++ ++Package: $dbg_packagename ++Section: debug ++Provides: linux-debug, linux-debug-$version ++Architecture: any ++Description: Linux kernel debugging symbols for $version ++ This package will come in handy if you need to debug the kernel. It provides ++ all the necessary debug symbols for the kernel and its modules. ++EOF ++ ++ create_package "$dbg_packagename" "$dbg_dir" ++fi ++ ++exit 0 +\ No newline at end of file diff --git a/patch/kernel/odroidc1-default/patch-3.10.96-97.patch b/patch/kernel/odroidc1-default/patch-3.10.96-97.patch new file mode 100644 index 0000000000..487d76eb1e --- /dev/null +++ b/patch/kernel/odroidc1-default/patch-3.10.96-97.patch @@ -0,0 +1,2341 @@ +diff --git a/Makefile b/Makefile +index c88ea5d8d19c..f26470169c70 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 96 ++SUBLEVEL = 97 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h +index 294d251ca7b2..2ae13ce592e8 100644 +--- a/arch/parisc/include/uapi/asm/mman.h ++++ b/arch/parisc/include/uapi/asm/mman.h +@@ -46,16 +46,6 @@ + #define MADV_DONTFORK 10 /* don't inherit across fork */ + #define MADV_DOFORK 11 /* do inherit across fork */ + +-/* The range 12-64 is reserved for page size specification. */ +-#define MADV_4K_PAGES 12 /* Use 4K pages */ +-#define MADV_16K_PAGES 14 /* Use 16K pages */ +-#define MADV_64K_PAGES 16 /* Use 64K pages */ +-#define MADV_256K_PAGES 18 /* Use 256K pages */ +-#define MADV_1M_PAGES 20 /* Use 1 Megabyte pages */ +-#define MADV_4M_PAGES 22 /* Use 4 Megabyte pages */ +-#define MADV_16M_PAGES 24 /* Use 16 Megabyte pages */ +-#define MADV_64M_PAGES 26 /* Use 64 Megabyte pages */ +- + #define MADV_MERGEABLE 65 /* KSM may merge identical pages */ + #define MADV_UNMERGEABLE 66 /* KSM may not merge identical pages */ + +diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h +index d7034728f377..1c75565d984b 100644 +--- a/arch/parisc/include/uapi/asm/siginfo.h ++++ b/arch/parisc/include/uapi/asm/siginfo.h +@@ -1,6 +1,10 @@ + #ifndef _PARISC_SIGINFO_H + #define _PARISC_SIGINFO_H + ++#if defined(__LP64__) ++#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) ++#endif ++ + #include + + #undef NSIGTRAP +diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c +index 940188d1942c..ae9aa83854c0 100644 +--- a/arch/parisc/kernel/signal.c ++++ b/arch/parisc/kernel/signal.c +@@ -449,6 +449,55 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, + regs->gr[28]); + } + ++/* ++ * Check how the syscall number gets loaded into %r20 within ++ * the delay branch in userspace and adjust as needed. ++ */ ++ ++static void check_syscallno_in_delay_branch(struct pt_regs *regs) ++{ ++ u32 opcode, source_reg; ++ u32 __user *uaddr; ++ int err; ++ ++ /* Usually we don't have to restore %r20 (the system call number) ++ * because it gets loaded in the delay slot of the branch external ++ * instruction via the ldi instruction. ++ * In some cases a register-to-register copy instruction might have ++ * been used instead, in which case we need to copy the syscall ++ * number into the source register before returning to userspace. ++ */ ++ ++ /* A syscall is just a branch, so all we have to do is fiddle the ++ * return pointer so that the ble instruction gets executed again. ++ */ ++ regs->gr[31] -= 8; /* delayed branching */ ++ ++ /* Get assembler opcode of code in delay branch */ ++ uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4); ++ err = get_user(opcode, uaddr); ++ if (err) ++ return; ++ ++ /* Check if delay branch uses "ldi int,%r20" */ ++ if ((opcode & 0xffff0000) == 0x34140000) ++ return; /* everything ok, just return */ ++ ++ /* Check if delay branch uses "nop" */ ++ if (opcode == INSN_NOP) ++ return; ++ ++ /* Check if delay branch uses "copy %rX,%r20" */ ++ if ((opcode & 0xffe0ffff) == 0x08000254) { ++ source_reg = (opcode >> 16) & 31; ++ regs->gr[source_reg] = regs->gr[20]; ++ return; ++ } ++ ++ pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n", ++ current->comm, task_pid_nr(current), opcode); ++} ++ + static inline void + syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) + { +@@ -471,10 +520,7 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) + } + /* fallthrough */ + case -ERESTARTNOINTR: +- /* A syscall is just a branch, so all +- * we have to do is fiddle the return pointer. +- */ +- regs->gr[31] -= 8; /* delayed branching */ ++ check_syscallno_in_delay_branch(regs); + break; + } + } +@@ -523,15 +569,9 @@ insert_restart_trampoline(struct pt_regs *regs) + } + case -ERESTARTNOHAND: + case -ERESTARTSYS: +- case -ERESTARTNOINTR: { +- /* Hooray for delayed branching. We don't +- * have to restore %r20 (the system call +- * number) because it gets loaded in the delay +- * slot of the branch external instruction. +- */ +- regs->gr[31] -= 8; ++ case -ERESTARTNOINTR: ++ check_syscallno_in_delay_branch(regs); + return; +- } + default: + break; + } +diff --git a/arch/sh/include/uapi/asm/unistd_64.h b/arch/sh/include/uapi/asm/unistd_64.h +index e6820c86e8c7..47ebd5b5ed55 100644 +--- a/arch/sh/include/uapi/asm/unistd_64.h ++++ b/arch/sh/include/uapi/asm/unistd_64.h +@@ -278,7 +278,7 @@ + #define __NR_fsetxattr 256 + #define __NR_getxattr 257 + #define __NR_lgetxattr 258 +-#define __NR_fgetxattr 269 ++#define __NR_fgetxattr 259 + #define __NR_listxattr 260 + #define __NR_llistxattr 261 + #define __NR_flistxattr 262 +diff --git a/crypto/af_alg.c b/crypto/af_alg.c +index 6ef6e2ad344e..0ca108f3c840 100644 +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -125,6 +125,23 @@ int af_alg_release(struct socket *sock) + } + EXPORT_SYMBOL_GPL(af_alg_release); + ++void af_alg_release_parent(struct sock *sk) ++{ ++ struct alg_sock *ask = alg_sk(sk); ++ bool last; ++ ++ sk = ask->parent; ++ ask = alg_sk(sk); ++ ++ lock_sock(sk); ++ last = !--ask->refcnt; ++ release_sock(sk); ++ ++ if (last) ++ sock_put(sk); ++} ++EXPORT_SYMBOL_GPL(af_alg_release_parent); ++ + static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + { + struct sock *sk = sock->sk; +@@ -132,6 +149,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + struct sockaddr_alg *sa = (void *)uaddr; + const struct af_alg_type *type; + void *private; ++ int err; + + if (sock->state == SS_CONNECTED) + return -EINVAL; +@@ -157,16 +175,22 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + return PTR_ERR(private); + } + ++ err = -EBUSY; + lock_sock(sk); ++ if (ask->refcnt) ++ goto unlock; + + swap(ask->type, type); + swap(ask->private, private); + ++ err = 0; ++ ++unlock: + release_sock(sk); + + alg_do_release(type, private); + +- return 0; ++ return err; + } + + static int alg_setkey(struct sock *sk, char __user *ukey, +@@ -199,11 +223,15 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + const struct af_alg_type *type; +- int err = -ENOPROTOOPT; ++ int err = -EBUSY; + + lock_sock(sk); ++ if (ask->refcnt) ++ goto unlock; ++ + type = ask->type; + ++ err = -ENOPROTOOPT; + if (level != SOL_ALG || !type) + goto unlock; + +@@ -247,14 +275,13 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) + security_sk_clone(sk, sk2); + + err = type->accept(ask->private, sk2); +- if (err) { +- sk_free(sk2); ++ if (err) + goto unlock; +- } + + sk2->sk_family = PF_ALG; + +- sock_hold(sk); ++ if (!ask->refcnt++) ++ sock_hold(sk); + alg_sk(sk2)->parent = sk; + alg_sk(sk2)->type = type; + +diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c +index 850246206b12..c542c0d88afd 100644 +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -51,7 +51,8 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, + + lock_sock(sk); + if (!ctx->more) { +- err = crypto_ahash_init(&ctx->req); ++ err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req), ++ &ctx->completion); + if (err) + goto unlock; + } +@@ -131,6 +132,7 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page, + } else { + if (!ctx->more) { + err = crypto_ahash_init(&ctx->req); ++ err = af_alg_wait_for_completion(err, &ctx->completion); + if (err) + goto unlock; + } +@@ -192,9 +194,14 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags) + struct sock *sk2; + struct alg_sock *ask2; + struct hash_ctx *ctx2; ++ bool more; + int err; + +- err = crypto_ahash_export(req, state); ++ lock_sock(sk); ++ more = ctx->more; ++ err = more ? crypto_ahash_export(req, state) : 0; ++ release_sock(sk); ++ + if (err) + return err; + +@@ -205,7 +212,10 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags) + sk2 = newsock->sk; + ask2 = alg_sk(sk2); + ctx2 = ask2->private; +- ctx2->more = 1; ++ ctx2->more = more; ++ ++ if (!more) ++ return err; + + err = crypto_ahash_import(&ctx2->req, state); + if (err) { +diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c +index c7666f401381..a3dfc0d83107 100644 +--- a/crypto/crypto_user.c ++++ b/crypto/crypto_user.c +@@ -477,6 +477,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + if (link->dump == NULL) + return -EINVAL; + ++ down_read(&crypto_alg_sem); + list_for_each_entry(alg, &crypto_alg_list, cra_list) + dump_alloc += CRYPTO_REPORT_MAXSIZE; + +@@ -486,8 +487,11 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + .done = link->done, + .min_dump_alloc = dump_alloc, + }; +- return netlink_dump_start(crypto_nlsk, skb, nlh, &c); ++ err = netlink_dump_start(crypto_nlsk, skb, nlh, &c); + } ++ up_read(&crypto_alg_sem); ++ ++ return err; + } + + err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX, +diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c +index 9064a2f2760c..cb106934bf1c 100644 +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -247,6 +247,26 @@ static const struct pci_device_id ahci_pci_tbl[] = { + { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ + { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */ ++ { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ + { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */ + { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ +diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c +index cf5f35877559..d04f5c8dbbdc 100644 +--- a/drivers/ata/libahci.c ++++ b/drivers/ata/libahci.c +@@ -486,8 +486,8 @@ void ahci_save_initial_config(struct device *dev, + } + } + +- /* fabricate port_map from cap.nr_ports */ +- if (!port_map) { ++ /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */ ++ if (!port_map && vers < 0x10300) { + port_map = (1 << ahci_nr_ports(cap)) - 1; + dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map); + +@@ -1244,6 +1244,15 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, + ata_tf_to_fis(tf, pmp, is_cmd, fis); + ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12)); + ++ /* set port value for softreset of Port Multiplier */ ++ if (pp->fbs_enabled && pp->fbs_last_dev != pmp) { ++ tmp = readl(port_mmio + PORT_FBS); ++ tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC); ++ tmp |= pmp << PORT_FBS_DEV_OFFSET; ++ writel(tmp, port_mmio + PORT_FBS); ++ pp->fbs_last_dev = pmp; ++ } ++ + /* issue & wait */ + writel(1, port_mmio + PORT_CMD_ISSUE); + +diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c +index a6524c3efdf7..ce854bbd33ef 100644 +--- a/drivers/char/tpm/tpm_ibmvtpm.c ++++ b/drivers/char/tpm/tpm_ibmvtpm.c +@@ -529,7 +529,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, + } + ibmvtpm->rtce_size = be16_to_cpu(crq->len); + ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size, +- GFP_KERNEL); ++ GFP_ATOMIC); + if (!ibmvtpm->rtce_buf) { + dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n"); + return; +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index de904e6a4ab7..5da58e3899eb 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -490,8 +490,6 @@ static void hid_ctrl(struct urb *urb) + struct usbhid_device *usbhid = hid->driver_data; + int unplug = 0, status = urb->status; + +- spin_lock(&usbhid->lock); +- + switch (status) { + case 0: /* success */ + if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) +@@ -511,6 +509,8 @@ static void hid_ctrl(struct urb *urb) + hid_warn(urb->dev, "ctrl urb status %d received\n", status); + } + ++ spin_lock(&usbhid->lock); ++ + if (unplug) { + usbhid->ctrltail = usbhid->ctrlhead; + } else { +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index 0ba21b0f3972..eb7ddb20fd48 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -1608,11 +1608,8 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, + /* + * Only pass ioctls through if the device sizes match exactly. + */ +- if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) { +- int err = scsi_verify_blk_ioctl(NULL, cmd); +- if (err) +- r = err; +- } ++ if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) ++ r = scsi_verify_blk_ioctl(NULL, cmd); + + if (r == -ENOTCONN && !fatal_signal_pending(current)) + queue_work(kmultipathd, &m->process_queued_ios); +diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c +index b53669404cb5..6d7f4d950b8f 100644 +--- a/drivers/md/persistent-data/dm-btree.c ++++ b/drivers/md/persistent-data/dm-btree.c +@@ -455,8 +455,10 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root, + + r = insert_at(sizeof(__le64), pn, parent_index + 1, + le64_to_cpu(rn->keys[0]), &location); +- if (r) ++ if (r) { ++ unlock_block(s->info, right); + return r; ++ } + + if (key < le64_to_cpu(rn->keys[0])) { + unlock_block(s->info, right); +diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c +index dbcdfbf8aed0..11b0ef3a2858 100644 +--- a/drivers/media/pci/saa7134/saa7134-alsa.c ++++ b/drivers/media/pci/saa7134/saa7134-alsa.c +@@ -1145,6 +1145,8 @@ static int alsa_device_init(struct saa7134_dev *dev) + + static int alsa_device_exit(struct saa7134_dev *dev) + { ++ if (!snd_saa7134_cards[dev->nr]) ++ return 1; + + snd_card_free(snd_saa7134_cards[dev->nr]); + snd_saa7134_cards[dev->nr] = NULL; +@@ -1194,7 +1196,8 @@ static void saa7134_alsa_exit(void) + int idx; + + for (idx = 0; idx < SNDRV_CARDS; idx++) { +- snd_card_free(snd_saa7134_cards[idx]); ++ if (snd_saa7134_cards[idx]) ++ snd_card_free(snd_saa7134_cards[idx]); + } + + saa7134_dmasound_init = NULL; +diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +index e2b0a0969ebb..35fb8f0cb539 100644 +--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c ++++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +@@ -264,7 +264,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_ + + struct v4l2_standard32 { + __u32 index; +- __u32 id[2]; /* __u64 would get the alignment wrong */ ++ compat_u64 id; + __u8 name[24]; + struct v4l2_fract frameperiod; /* Frames, not fields */ + __u32 framelines; +@@ -284,7 +284,7 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 + { + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) || + put_user(kp->index, &up->index) || +- copy_to_user(up->id, &kp->id, sizeof(__u64)) || ++ put_user(kp->id, &up->id) || + copy_to_user(up->name, kp->name, 24) || + copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) || + put_user(kp->framelines, &up->framelines) || +@@ -576,10 +576,10 @@ struct v4l2_input32 { + __u32 type; /* Type of input */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 tuner; /* Associated tuner */ +- v4l2_std_id std; ++ compat_u64 std; + __u32 status; + __u32 reserved[4]; +-} __attribute__ ((packed)); ++}; + + /* The 64-bit v4l2_input struct has extra padding at the end of the struct. + Otherwise it is identical to the 32-bit version. */ +@@ -719,6 +719,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext + struct v4l2_event32 { + __u32 type; + union { ++ compat_s64 value64; + __u8 data[64]; + } u; + __u32 pending; +diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c +index fd56f2563201..297fbc59a800 100644 +--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c ++++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c +@@ -117,7 +117,8 @@ static void vb2_dc_prepare(void *buf_priv) + if (!sgt || buf->db_attach) + return; + +- dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); ++ dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, ++ buf->dma_dir); + } + + static void vb2_dc_finish(void *buf_priv) +@@ -129,7 +130,7 @@ static void vb2_dc_finish(void *buf_priv) + if (!sgt || buf->db_attach) + return; + +- dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); ++ dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); + } + + /*********************************************/ +diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c +index 301493382cd0..f8013c1d8cd5 100644 +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -634,8 +634,10 @@ int add_mtd_partitions(struct mtd_info *master, + + for (i = 0; i < nbparts; i++) { + slave = allocate_partition(master, parts + i, i, cur_offset); +- if (IS_ERR(slave)) ++ if (IS_ERR(slave)) { ++ del_mtd_partitions(master); + return PTR_ERR(slave); ++ } + + mutex_lock(&mtd_partitions_mutex); + list_add(&slave->list, &mtd_partitions); +diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h +index af7d9f9b3b4d..beed58b0c795 100644 +--- a/drivers/net/wireless/ti/wlcore/io.h ++++ b/drivers/net/wireless/ti/wlcore/io.h +@@ -203,19 +203,23 @@ static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg, + + static inline void wl1271_power_off(struct wl1271 *wl) + { +- int ret; ++ int ret = 0; + + if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags)) + return; + +- ret = wl->if_ops->power(wl->dev, false); ++ if (wl->if_ops->power) ++ ret = wl->if_ops->power(wl->dev, false); + if (!ret) + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + } + + static inline int wl1271_power_on(struct wl1271 *wl) + { +- int ret = wl->if_ops->power(wl->dev, true); ++ int ret = 0; ++ ++ if (wl->if_ops->power) ++ ret = wl->if_ops->power(wl->dev, true); + if (ret == 0) + set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + +diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c +index e26447832683..bfb57e671034 100644 +--- a/drivers/net/wireless/ti/wlcore/spi.c ++++ b/drivers/net/wireless/ti/wlcore/spi.c +@@ -72,7 +72,10 @@ + */ + #define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) + +-#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) ++/* Maximum number of SPI write chunks */ ++#define WSPI_MAX_NUM_OF_CHUNKS \ ++ ((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1) ++ + + struct wl12xx_spi_glue { + struct device *dev; +@@ -270,9 +273,10 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, + void *buf, size_t len, bool fixed) + { + struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); +- struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)]; ++ /* SPI write buffers - 2 for each chunk */ ++ struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; + struct spi_message m; +- u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; ++ u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */ + u32 *cmd; + u32 chunk_len; + int i; +diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c +index 157a57309601..4ef0dbdcace1 100644 +--- a/drivers/remoteproc/remoteproc_debugfs.c ++++ b/drivers/remoteproc/remoteproc_debugfs.c +@@ -156,7 +156,7 @@ rproc_recovery_write(struct file *filp, const char __user *user_buf, + char buf[10]; + int ret; + +- if (count > sizeof(buf)) ++ if (count < 1 || count > sizeof(buf)) + return count; + + ret = copy_from_user(buf, user_buf, count); +diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c +index 380387a47b1d..462af46ceee7 100644 +--- a/drivers/spi/spi-atmel.c ++++ b/drivers/spi/spi-atmel.c +@@ -594,7 +594,8 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, + + *plen = len; + +- if (atmel_spi_dma_slave_config(as, &slave_config, 8)) ++ if (atmel_spi_dma_slave_config(as, &slave_config, ++ xfer->bits_per_word)) + goto err_exit; + + /* Send both scatterlists */ +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index 7c159634aaae..cc80ab14aa32 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -1047,7 +1047,7 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) + master->bus_num = -1; + master->num_chipselect = 1; + master->dev.class = &spi_master_class; +- master->dev.parent = get_device(dev); ++ master->dev.parent = dev; + spi_master_set_devdata(master, &master[1]); + + return master; +diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c +index 2967b6eb4c70..8977eaf24d9f 100644 +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -2576,6 +2576,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) + } + + /** ++ * tiocgetd - get line discipline ++ * @tty: tty device ++ * @p: pointer to user data ++ * ++ * Retrieves the line discipline id directly from the ldisc. ++ * ++ * Locking: waits for ldisc reference (in case the line discipline ++ * is changing or the tty is being hungup) ++ */ ++ ++static int tiocgetd(struct tty_struct *tty, int __user *p) ++{ ++ struct tty_ldisc *ld; ++ int ret; ++ ++ ld = tty_ldisc_ref_wait(tty); ++ ret = put_user(ld->ops->num, p); ++ tty_ldisc_deref(ld); ++ return ret; ++} ++ ++/** + * send_break - performed time break + * @tty: device to break on + * @duration: timeout in mS +@@ -2789,7 +2811,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + case TIOCGSID: + return tiocgsid(tty, real_tty, p); + case TIOCGETD: +- return put_user(tty->ldisc->ops->num, (int __user *)p); ++ return tiocgetd(tty, p); + case TIOCSETD: + return tiocsetd(tty, p); + case TIOCVHANGUP: +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 4dc18615cd0f..9dd6fa3a1260 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -4788,6 +4788,9 @@ static int __init xhci_hcd_init(void) + { + int retval; + ++ if (usb_disabled()) ++ return -ENODEV; ++ + retval = xhci_register_pci(); + if (retval < 0) { + printk(KERN_DEBUG "Problem registering PCI driver."); +@@ -4816,9 +4819,6 @@ static int __init xhci_hcd_init(void) + /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ + BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); + +- if (usb_disabled()) +- return -ENODEV; +- + return 0; + unreg_pci: + xhci_unregister_pci(); +diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c +index 72c14d7d604f..89ba7cfba5bc 100644 +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -98,6 +98,7 @@ static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ + { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ + { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ ++ { USB_DEVICE(0x10C4, 0x81D7) }, /* IAI Corp. RCB-CV-USB USB to RS485 Adaptor */ + { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ + { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ +diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c +index 514f3117ee2b..4e865664699b 100644 +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -840,6 +840,7 @@ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, ++ { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) }, + { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, + + /* Papouch devices based on FTDI chip */ +diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h +index bfb0ecd98808..3eff1d6a2b17 100644 +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -615,6 +615,7 @@ + */ + #define RATOC_VENDOR_ID 0x0584 + #define RATOC_PRODUCT_ID_USB60F 0xb020 ++#define RATOC_PRODUCT_ID_SCU18 0xb03a + + /* + * Infineon Technologies +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index bdbe642e6569..81f6a572f016 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -269,6 +269,8 @@ static void option_instat_callback(struct urb *urb); + #define TELIT_PRODUCT_CC864_SINGLE 0x1006 + #define TELIT_PRODUCT_DE910_DUAL 0x1010 + #define TELIT_PRODUCT_UE910_V2 0x1012 ++#define TELIT_PRODUCT_LE922_USBCFG0 0x1042 ++#define TELIT_PRODUCT_LE922_USBCFG3 0x1043 + #define TELIT_PRODUCT_LE920 0x1200 + #define TELIT_PRODUCT_LE910 0x1201 + +@@ -623,6 +625,16 @@ static const struct option_blacklist_info telit_le920_blacklist = { + .reserved = BIT(1) | BIT(5), + }; + ++static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = { ++ .sendsetup = BIT(2), ++ .reserved = BIT(0) | BIT(1) | BIT(3), ++}; ++ ++static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = { ++ .sendsetup = BIT(0), ++ .reserved = BIT(1) | BIT(2) | BIT(3), ++}; ++ + static const struct usb_device_id option_ids[] = { + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, +@@ -1168,6 +1180,10 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, ++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), ++ .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, ++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3), ++ .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), + .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), +@@ -1679,7 +1695,7 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +- { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, ++ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, +diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c +index 4cc84c0c990d..0a7c68fa5e5e 100644 +--- a/drivers/usb/serial/ti_usb_3410_5052.c ++++ b/drivers/usb/serial/ti_usb_3410_5052.c +@@ -158,7 +158,7 @@ static unsigned int product_5052_count; + /* the array dimension is the number of default entries plus */ + /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ + /* null entry */ +-static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { ++static struct usb_device_id ti_id_table_3410[16+TI_EXTRA_VID_PID_COUNT+1] = { + { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, +@@ -184,7 +184,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { + { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, + }; + +-static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { ++static struct usb_device_id ti_id_table_combined[20+2*TI_EXTRA_VID_PID_COUNT+1] = { + { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, +diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c +index 727905de0ba4..605068e6acf2 100644 +--- a/drivers/usb/serial/visor.c ++++ b/drivers/usb/serial/visor.c +@@ -551,6 +551,11 @@ static int treo_attach(struct usb_serial *serial) + (serial->num_interrupt_in == 0)) + return 0; + ++ if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) { ++ dev_err(&serial->interface->dev, "missing endpoints\n"); ++ return -ENODEV; ++ } ++ + /* + * It appears that Treos and Kyoceras want to use the + * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, +@@ -604,8 +609,10 @@ static int clie_5_attach(struct usb_serial *serial) + */ + + /* some sanity check */ +- if (serial->num_ports < 2) +- return -1; ++ if (serial->num_bulk_out < 2) { ++ dev_err(&serial->interface->dev, "missing bulk out endpoints\n"); ++ return -ENODEV; ++ } + + /* port 0 now uses the modified endpoint Address */ + port = serial->port[0]; +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index 618bcc84a09e..948e6f21b594 100644 +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -682,16 +682,16 @@ static int load_elf_binary(struct linux_binprm *bprm) + */ + would_dump(bprm, interpreter); + +- retval = kernel_read(interpreter, 0, bprm->buf, +- BINPRM_BUF_SIZE); +- if (retval != BINPRM_BUF_SIZE) { ++ /* Get the exec headers */ ++ retval = kernel_read(interpreter, 0, ++ (void *)&loc->interp_elf_ex, ++ sizeof(loc->interp_elf_ex)); ++ if (retval != sizeof(loc->interp_elf_ex)) { + if (retval >= 0) + retval = -EIO; + goto out_free_dentry; + } + +- /* Get the exec headers */ +- loc->interp_elf_ex = *((struct elfhdr *)bprm->buf); + break; + } + elf_ppnt++; +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 2a71466b0115..6f74b8919237 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -728,19 +729,55 @@ struct move_extent { + <= (EXT4_GOOD_OLD_INODE_SIZE + \ + (einode)->i_extra_isize)) \ + ++/* ++ * We use an encoding that preserves the times for extra epoch "00": ++ * ++ * extra msb of adjust for signed ++ * epoch 32-bit 32-bit tv_sec to ++ * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range ++ * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31 ++ * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19 ++ * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07 ++ * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25 ++ * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16 ++ * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04 ++ * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22 ++ * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10 ++ * ++ * Note that previous versions of the kernel on 64-bit systems would ++ * incorrectly use extra epoch bits 1,1 for dates between 1901 and ++ * 1970. e2fsck will correct this, assuming that it is run on the ++ * affected filesystem before 2242. ++ */ ++ + static inline __le32 ext4_encode_extra_time(struct timespec *time) + { +- return cpu_to_le32((sizeof(time->tv_sec) > 4 ? +- (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) | +- ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK)); ++ u32 extra = sizeof(time->tv_sec) > 4 ? ++ ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0; ++ return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS)); + } + + static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra) + { +- if (sizeof(time->tv_sec) > 4) +- time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) +- << 32; +- time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; ++ if (unlikely(sizeof(time->tv_sec) > 4 && ++ (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0) ++ /* Handle legacy encoding of pre-1970 dates with epoch ++ * bits 1,1. We assume that by kernel version 4.20, ++ * everyone will have run fsck over the affected ++ * filesystems to correct the problem. (This ++ * backwards compatibility may be removed before this ++ * time, at the discretion of the ext4 developers.) ++ */ ++ u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK; ++ if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0) ++ extra_bits = 0; ++ time->tv_sec += extra_bits << 32; ++#else ++ time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32; ++#endif ++ } ++ time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; + } + + #define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \ +diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c +index a69bd74ed390..fa7d2e668c3a 100644 +--- a/fs/ext4/resize.c ++++ b/fs/ext4/resize.c +@@ -1025,7 +1025,7 @@ exit_free: + * do not copy the full number of backups at this time. The resize + * which changed s_groups_count will backup again. + */ +-static void update_backups(struct super_block *sb, int blk_off, char *data, ++static void update_backups(struct super_block *sb, sector_t blk_off, char *data, + int size, int meta_bg) + { + struct ext4_sb_info *sbi = EXT4_SB(sb); +@@ -1050,7 +1050,7 @@ static void update_backups(struct super_block *sb, int blk_off, char *data, + group = ext4_list_backups(sb, &three, &five, &seven); + last = sbi->s_groups_count; + } else { +- group = ext4_meta_bg_first_group(sb, group) + 1; ++ group = ext4_get_group_number(sb, blk_off) + 1; + last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2); + } + +diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c +index e028b8eb1c40..0912b90e05bc 100644 +--- a/fs/fscache/netfs.c ++++ b/fs/fscache/netfs.c +@@ -45,9 +45,6 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) + netfs->primary_index->parent = &fscache_fsdef_index; + netfs->primary_index->netfs_data = netfs; + +- atomic_inc(&netfs->primary_index->parent->usage); +- atomic_inc(&netfs->primary_index->parent->n_children); +- + spin_lock_init(&netfs->primary_index->lock); + INIT_HLIST_HEAD(&netfs->primary_index->backing_objects); + +@@ -60,6 +57,9 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) + goto already_registered; + } + ++ atomic_inc(&netfs->primary_index->parent->usage); ++ atomic_inc(&netfs->primary_index->parent->n_children); ++ + list_add(&netfs->link, &fscache_netfs_list); + ret = 0; + +@@ -70,8 +70,7 @@ already_registered: + up_write(&fscache_addremove_sem); + + if (ret < 0) { +- netfs->primary_index->parent = NULL; +- __fscache_cookie_put(netfs->primary_index); ++ kmem_cache_free(fscache_cookie_jar, netfs->primary_index); + netfs->primary_index = NULL; + } + +diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c +index ec34e11d6854..21b828c713cc 100644 +--- a/fs/jbd2/transaction.c ++++ b/fs/jbd2/transaction.c +@@ -1936,6 +1936,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, + + if (!buffer_dirty(bh)) { + /* bdflush has written it. We can drop it now */ ++ __jbd2_journal_remove_checkpoint(jh); + goto zap_buffer; + } + +@@ -1965,6 +1966,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, + /* The orphan record's transaction has + * committed. We can cleanse this buffer */ + clear_buffer_jbddirty(bh); ++ __jbd2_journal_remove_checkpoint(jh); + goto zap_buffer; + } + } +diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c +index 2c119d5d04c9..d084200dbc4e 100644 +--- a/fs/ocfs2/dlm/dlmmaster.c ++++ b/fs/ocfs2/dlm/dlmmaster.c +@@ -2456,6 +2456,11 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, + spin_lock(&dlm->master_lock); + ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name, + namelen, target, dlm->node_num); ++ /* get an extra reference on the mle. ++ * otherwise the assert_master from the new ++ * master will destroy this. ++ */ ++ dlm_get_mle_inuse(mle); + spin_unlock(&dlm->master_lock); + spin_unlock(&dlm->spinlock); + +@@ -2491,6 +2496,7 @@ fail: + if (mle_added) { + dlm_mle_detach_hb_events(dlm, mle); + dlm_put_mle(mle); ++ dlm_put_mle_inuse(mle); + } else if (mle) { + kmem_cache_free(dlm_mle_cache, mle); + mle = NULL; +@@ -2508,17 +2514,6 @@ fail: + * ensure that all assert_master work is flushed. */ + flush_workqueue(dlm->dlm_worker); + +- /* get an extra reference on the mle. +- * otherwise the assert_master from the new +- * master will destroy this. +- * also, make sure that all callers of dlm_get_mle +- * take both dlm->spinlock and dlm->master_lock */ +- spin_lock(&dlm->spinlock); +- spin_lock(&dlm->master_lock); +- dlm_get_mle_inuse(mle); +- spin_unlock(&dlm->master_lock); +- spin_unlock(&dlm->spinlock); +- + /* notify new node and send all lock state */ + /* call send_one_lockres with migration flag. + * this serves as notice to the target node that a +@@ -3246,6 +3241,15 @@ top: + mle->new_master != dead_node) + continue; + ++ if (mle->new_master == dead_node && mle->inuse) { ++ mlog(ML_NOTICE, "%s: target %u died during " ++ "migration from %u, the MLE is " ++ "still keep used, ignore it!\n", ++ dlm->name, dead_node, ++ mle->master); ++ continue; ++ } ++ + /* If we have reached this point, this mle needs to be + * removed from the list and freed. */ + dlm_clean_migration_mle(dlm, mle); +diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c +index 9bd981cd3142..01c69f24e416 100644 +--- a/fs/ocfs2/dlm/dlmrecovery.c ++++ b/fs/ocfs2/dlm/dlmrecovery.c +@@ -2326,6 +2326,8 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) + break; + } + } ++ dlm_lockres_clear_refmap_bit(dlm, res, ++ dead_node); + spin_unlock(&res->spinlock); + continue; + } +diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c +index c327d4ee1235..7b3792e5844a 100644 +--- a/fs/sysv/inode.c ++++ b/fs/sysv/inode.c +@@ -161,14 +161,8 @@ void sysv_set_inode(struct inode *inode, dev_t rdev) + inode->i_fop = &sysv_dir_operations; + inode->i_mapping->a_ops = &sysv_aops; + } else if (S_ISLNK(inode->i_mode)) { +- if (inode->i_blocks) { +- inode->i_op = &sysv_symlink_inode_operations; +- inode->i_mapping->a_ops = &sysv_aops; +- } else { +- inode->i_op = &sysv_fast_symlink_inode_operations; +- nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size, +- sizeof(SYSV_I(inode)->i_data) - 1); +- } ++ inode->i_op = &sysv_symlink_inode_operations; ++ inode->i_mapping->a_ops = &sysv_aops; + } else + init_special_inode(inode, inode->i_mode, rdev); + } +diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h +index d61c11170213..2f38daaab3d7 100644 +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -30,6 +30,8 @@ struct alg_sock { + + struct sock *parent; + ++ unsigned int refcnt; ++ + const struct af_alg_type *type; + void *private; + }; +@@ -64,6 +66,7 @@ int af_alg_register_type(const struct af_alg_type *type); + int af_alg_unregister_type(const struct af_alg_type *type); + + int af_alg_release(struct socket *sock); ++void af_alg_release_parent(struct sock *sk); + int af_alg_accept(struct sock *sk, struct socket *newsock); + + int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, +@@ -80,11 +83,6 @@ static inline struct alg_sock *alg_sk(struct sock *sk) + return (struct alg_sock *)sk; + } + +-static inline void af_alg_release_parent(struct sock *sk) +-{ +- sock_put(alg_sk(sk)->parent); +-} +- + static inline void af_alg_init_completion(struct af_alg_completion *completion) + { + init_completion(&completion->completion); +diff --git a/include/linux/signal.h b/include/linux/signal.h +index 2ac423bdb676..53944e50e421 100644 +--- a/include/linux/signal.h ++++ b/include/linux/signal.h +@@ -247,7 +247,6 @@ extern int sigprocmask(int, sigset_t *, sigset_t *); + extern void set_current_blocked(sigset_t *); + extern void __set_current_blocked(const sigset_t *); + extern int show_unhandled_signals; +-extern int sigsuspend(sigset_t *); + + struct sigaction { + #ifndef __ARCH_HAS_IRIX_SIGACTION +diff --git a/kernel/signal.c b/kernel/signal.c +index 2e51bcbea1e3..4d1f7fa3138d 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -3551,7 +3551,7 @@ SYSCALL_DEFINE0(pause) + + #endif + +-int sigsuspend(sigset_t *set) ++static int sigsuspend(sigset_t *set) + { + current->saved_sigmask = current->blocked; + set_current_blocked(set); +diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h +index 49b582a225b0..b9897e2be404 100644 +--- a/scripts/recordmcount.h ++++ b/scripts/recordmcount.h +@@ -377,7 +377,7 @@ static void nop_mcount(Elf_Shdr const *const relhdr, + + if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { + if (make_nop) +- ret = make_nop((void *)ehdr, shdr->sh_offset + relp->r_offset); ++ ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset)); + if (warn_on_notrace_sect && !once) { + printf("Section %s has mcount callers being ignored\n", + txtname); +diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c +index 3fdf998ad057..572f95175e97 100644 +--- a/sound/core/compress_offload.c ++++ b/sound/core/compress_offload.c +@@ -44,6 +44,13 @@ + #include + #include + ++/* struct snd_compr_codec_caps overflows the ioctl bit size for some ++ * architectures, so we need to disable the relevant ioctls. ++ */ ++#if _IOC_SIZEBITS < 14 ++#define COMPR_CODEC_CAPS_OVERFLOW ++#endif ++ + /* TODO: + * - add substream support for multiple devices in case of + * SND_DYNAMIC_MINORS is not used +@@ -427,6 +434,7 @@ out: + return retval; + } + ++#ifndef COMPR_CODEC_CAPS_OVERFLOW + static int + snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) + { +@@ -450,6 +458,7 @@ out: + kfree(caps); + return retval; + } ++#endif /* !COMPR_CODEC_CAPS_OVERFLOW */ + + /* revisit this with snd_pcm_preallocate_xxx */ + static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, +@@ -791,9 +800,11 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) + case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): + retval = snd_compr_get_caps(stream, arg); + break; ++#ifndef COMPR_CODEC_CAPS_OVERFLOW + case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): + retval = snd_compr_get_codec_caps(stream, arg); + break; ++#endif + case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS): + retval = snd_compr_set_params(stream, arg); + break; +diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c +index 4c1cc51772e6..7417f96cea6e 100644 +--- a/sound/core/oss/pcm_oss.c ++++ b/sound/core/oss/pcm_oss.c +@@ -834,7 +834,8 @@ static int choose_rate(struct snd_pcm_substream *substream, + return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); + } + +-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) ++static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, ++ bool trylock) + { + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hw_params *params, *sparams; +@@ -848,7 +849,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) + struct snd_mask sformat_mask; + struct snd_mask mask; + +- if (mutex_lock_interruptible(&runtime->oss.params_lock)) ++ if (trylock) { ++ if (!(mutex_trylock(&runtime->oss.params_lock))) ++ return -EAGAIN; ++ } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -EINTR; + sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); + params = kmalloc(sizeof(*params), GFP_KERNEL); +@@ -1091,7 +1095,7 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil + if (asubstream == NULL) + asubstream = substream; + if (substream->runtime->oss.params) { +- err = snd_pcm_oss_change_params(substream); ++ err = snd_pcm_oss_change_params(substream, false); + if (err < 0) + return err; + } +@@ -1130,7 +1134,7 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream) + return 0; + runtime = substream->runtime; + if (runtime->oss.params) { +- err = snd_pcm_oss_change_params(substream); ++ err = snd_pcm_oss_change_params(substream, false); + if (err < 0) + return err; + } +@@ -2168,7 +2172,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre + runtime = substream->runtime; + + if (runtime->oss.params && +- (err = snd_pcm_oss_change_params(substream)) < 0) ++ (err = snd_pcm_oss_change_params(substream, false)) < 0) + return err; + + info.fragsize = runtime->oss.period_bytes; +@@ -2804,7 +2808,12 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area) + return -EIO; + + if (runtime->oss.params) { +- if ((err = snd_pcm_oss_change_params(substream)) < 0) ++ /* use mutex_trylock() for params_lock for avoiding a deadlock ++ * between mmap_sem and params_lock taken by ++ * copy_from/to_user() in snd_pcm_oss_write/read() ++ */ ++ err = snd_pcm_oss_change_params(substream, true); ++ if (err < 0) + return err; + } + #ifdef CONFIG_SND_PCM_OSS_PLUGINS +diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c +index 7b596b5751db..500765f20843 100644 +--- a/sound/core/rawmidi.c ++++ b/sound/core/rawmidi.c +@@ -934,31 +934,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, + unsigned long flags; + long result = 0, count1; + struct snd_rawmidi_runtime *runtime = substream->runtime; ++ unsigned long appl_ptr; + ++ spin_lock_irqsave(&runtime->lock, flags); + while (count > 0 && runtime->avail) { + count1 = runtime->buffer_size - runtime->appl_ptr; + if (count1 > count) + count1 = count; +- spin_lock_irqsave(&runtime->lock, flags); + if (count1 > (int)runtime->avail) + count1 = runtime->avail; ++ ++ /* update runtime->appl_ptr before unlocking for userbuf */ ++ appl_ptr = runtime->appl_ptr; ++ runtime->appl_ptr += count1; ++ runtime->appl_ptr %= runtime->buffer_size; ++ runtime->avail -= count1; ++ + if (kernelbuf) +- memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); ++ memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); + if (userbuf) { + spin_unlock_irqrestore(&runtime->lock, flags); + if (copy_to_user(userbuf + result, +- runtime->buffer + runtime->appl_ptr, count1)) { ++ runtime->buffer + appl_ptr, count1)) { + return result > 0 ? result : -EFAULT; + } + spin_lock_irqsave(&runtime->lock, flags); + } +- runtime->appl_ptr += count1; +- runtime->appl_ptr %= runtime->buffer_size; +- runtime->avail -= count1; +- spin_unlock_irqrestore(&runtime->lock, flags); + result += count1; + count -= count1; + } ++ spin_unlock_irqrestore(&runtime->lock, flags); + return result; + } + +@@ -1161,8 +1166,9 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, + unsigned long flags; + long count1, result; + struct snd_rawmidi_runtime *runtime = substream->runtime; ++ unsigned long appl_ptr; + +- if (snd_BUG_ON(!kernelbuf && !userbuf)) ++ if (!kernelbuf && !userbuf) + return -EINVAL; + if (snd_BUG_ON(!runtime->buffer)) + return -EINVAL; +@@ -1181,12 +1187,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, + count1 = count; + if (count1 > (long)runtime->avail) + count1 = runtime->avail; ++ ++ /* update runtime->appl_ptr before unlocking for userbuf */ ++ appl_ptr = runtime->appl_ptr; ++ runtime->appl_ptr += count1; ++ runtime->appl_ptr %= runtime->buffer_size; ++ runtime->avail -= count1; ++ + if (kernelbuf) +- memcpy(runtime->buffer + runtime->appl_ptr, ++ memcpy(runtime->buffer + appl_ptr, + kernelbuf + result, count1); + else if (userbuf) { + spin_unlock_irqrestore(&runtime->lock, flags); +- if (copy_from_user(runtime->buffer + runtime->appl_ptr, ++ if (copy_from_user(runtime->buffer + appl_ptr, + userbuf + result, count1)) { + spin_lock_irqsave(&runtime->lock, flags); + result = result > 0 ? result : -EFAULT; +@@ -1194,9 +1207,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, + } + spin_lock_irqsave(&runtime->lock, flags); + } +- runtime->appl_ptr += count1; +- runtime->appl_ptr %= runtime->buffer_size; +- runtime->avail -= count1; + result += count1; + count -= count1; + } +diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c +index c5b773a1eea9..4a09c3085ca4 100644 +--- a/sound/core/seq/oss/seq_oss_synth.c ++++ b/sound/core/seq/oss/seq_oss_synth.c +@@ -310,7 +310,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) + struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; + +- if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) ++ if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) + return; + for (i = 0; i < dp->max_synthdev; i++) { + info = &dp->synths[i]; +diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c +index ecfbf5f39d38..08865dcbf5f1 100644 +--- a/sound/core/seq/seq_clientmgr.c ++++ b/sound/core/seq/seq_clientmgr.c +@@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client *client, + else + down_read(&grp->list_mutex); + list_for_each_entry(subs, &grp->list_head, src_list) { ++ /* both ports ready? */ ++ if (atomic_read(&subs->ref_count) != 2) ++ continue; + event->dest = subs->info.dest; + if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) + /* convert time according to flag with subscription */ +diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c +index 9516e5ce3aad..67c91d226552 100644 +--- a/sound/core/seq/seq_ports.c ++++ b/sound/core/seq/seq_ports.c +@@ -175,10 +175,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, + } + + /* */ +-enum group_type { +- SRC_LIST, DEST_LIST +-}; +- + static int subscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_port_subs_info *grp, +@@ -205,6 +201,20 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, + return NULL; + } + ++static void delete_and_unsubscribe_port(struct snd_seq_client *client, ++ struct snd_seq_client_port *port, ++ struct snd_seq_subscribers *subs, ++ bool is_src, bool ack); ++ ++static inline struct snd_seq_subscribers * ++get_subscriber(struct list_head *p, bool is_src) ++{ ++ if (is_src) ++ return list_entry(p, struct snd_seq_subscribers, src_list); ++ else ++ return list_entry(p, struct snd_seq_subscribers, dest_list); ++} ++ + /* + * remove all subscribers on the list + * this is called from port_delete, for each src and dest list. +@@ -212,7 +222,7 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, + static void clear_subscriber_list(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_port_subs_info *grp, +- int grptype) ++ int is_src) + { + struct list_head *p, *n; + +@@ -221,15 +231,13 @@ static void clear_subscriber_list(struct snd_seq_client *client, + struct snd_seq_client *c; + struct snd_seq_client_port *aport; + +- if (grptype == SRC_LIST) { +- subs = list_entry(p, struct snd_seq_subscribers, src_list); ++ subs = get_subscriber(p, is_src); ++ if (is_src) + aport = get_client_port(&subs->info.dest, &c); +- } else { +- subs = list_entry(p, struct snd_seq_subscribers, dest_list); ++ else + aport = get_client_port(&subs->info.sender, &c); +- } +- list_del(p); +- unsubscribe_port(client, port, grp, &subs->info, 0); ++ delete_and_unsubscribe_port(client, port, subs, is_src, false); ++ + if (!aport) { + /* looks like the connected port is being deleted. + * we decrease the counter, and when both ports are deleted +@@ -237,21 +245,14 @@ static void clear_subscriber_list(struct snd_seq_client *client, + */ + if (atomic_dec_and_test(&subs->ref_count)) + kfree(subs); +- } else { +- /* ok we got the connected port */ +- struct snd_seq_port_subs_info *agrp; +- agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src; +- down_write(&agrp->list_mutex); +- if (grptype == SRC_LIST) +- list_del(&subs->dest_list); +- else +- list_del(&subs->src_list); +- up_write(&agrp->list_mutex); +- unsubscribe_port(c, aport, agrp, &subs->info, 1); +- kfree(subs); +- snd_seq_port_unlock(aport); +- snd_seq_client_unlock(c); ++ continue; + } ++ ++ /* ok we got the connected port */ ++ delete_and_unsubscribe_port(c, aport, subs, !is_src, true); ++ kfree(subs); ++ snd_seq_port_unlock(aport); ++ snd_seq_client_unlock(c); + } + } + +@@ -264,8 +265,8 @@ static int port_delete(struct snd_seq_client *client, + snd_use_lock_sync(&port->use_lock); + + /* clear subscribers info */ +- clear_subscriber_list(client, port, &port->c_src, SRC_LIST); +- clear_subscriber_list(client, port, &port->c_dest, DEST_LIST); ++ clear_subscriber_list(client, port, &port->c_src, true); ++ clear_subscriber_list(client, port, &port->c_dest, false); + + if (port->private_free) + port->private_free(port->private_data); +@@ -484,85 +485,120 @@ static int match_subs_info(struct snd_seq_port_subscribe *r, + return 0; + } + +- +-/* connect two ports */ +-int snd_seq_port_connect(struct snd_seq_client *connector, +- struct snd_seq_client *src_client, +- struct snd_seq_client_port *src_port, +- struct snd_seq_client *dest_client, +- struct snd_seq_client_port *dest_port, +- struct snd_seq_port_subscribe *info) ++static int check_and_subscribe_port(struct snd_seq_client *client, ++ struct snd_seq_client_port *port, ++ struct snd_seq_subscribers *subs, ++ bool is_src, bool exclusive, bool ack) + { +- struct snd_seq_port_subs_info *src = &src_port->c_src; +- struct snd_seq_port_subs_info *dest = &dest_port->c_dest; +- struct snd_seq_subscribers *subs, *s; +- int err, src_called = 0; +- unsigned long flags; +- int exclusive; ++ struct snd_seq_port_subs_info *grp; ++ struct list_head *p; ++ struct snd_seq_subscribers *s; ++ int err; + +- subs = kzalloc(sizeof(*subs), GFP_KERNEL); +- if (! subs) +- return -ENOMEM; +- +- subs->info = *info; +- atomic_set(&subs->ref_count, 2); +- +- down_write(&src->list_mutex); +- down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); +- +- exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0; ++ grp = is_src ? &port->c_src : &port->c_dest; + err = -EBUSY; ++ down_write(&grp->list_mutex); + if (exclusive) { +- if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head)) ++ if (!list_empty(&grp->list_head)) + goto __error; + } else { +- if (src->exclusive || dest->exclusive) ++ if (grp->exclusive) + goto __error; + /* check whether already exists */ +- list_for_each_entry(s, &src->list_head, src_list) { +- if (match_subs_info(info, &s->info)) +- goto __error; +- } +- list_for_each_entry(s, &dest->list_head, dest_list) { +- if (match_subs_info(info, &s->info)) ++ list_for_each(p, &grp->list_head) { ++ s = get_subscriber(p, is_src); ++ if (match_subs_info(&subs->info, &s->info)) + goto __error; + } + } + +- if ((err = subscribe_port(src_client, src_port, src, info, +- connector->number != src_client->number)) < 0) +- goto __error; +- src_called = 1; +- +- if ((err = subscribe_port(dest_client, dest_port, dest, info, +- connector->number != dest_client->number)) < 0) ++ err = subscribe_port(client, port, grp, &subs->info, ack); ++ if (err < 0) { ++ grp->exclusive = 0; + goto __error; ++ } + + /* add to list */ +- write_lock_irqsave(&src->list_lock, flags); +- // write_lock(&dest->list_lock); // no other lock yet +- list_add_tail(&subs->src_list, &src->list_head); +- list_add_tail(&subs->dest_list, &dest->list_head); +- // write_unlock(&dest->list_lock); // no other lock yet +- write_unlock_irqrestore(&src->list_lock, flags); ++ write_lock_irq(&grp->list_lock); ++ if (is_src) ++ list_add_tail(&subs->src_list, &grp->list_head); ++ else ++ list_add_tail(&subs->dest_list, &grp->list_head); ++ grp->exclusive = exclusive; ++ atomic_inc(&subs->ref_count); ++ write_unlock_irq(&grp->list_lock); ++ err = 0; ++ ++ __error: ++ up_write(&grp->list_mutex); ++ return err; ++} + +- src->exclusive = dest->exclusive = exclusive; ++static void delete_and_unsubscribe_port(struct snd_seq_client *client, ++ struct snd_seq_client_port *port, ++ struct snd_seq_subscribers *subs, ++ bool is_src, bool ack) ++{ ++ struct snd_seq_port_subs_info *grp; ++ ++ grp = is_src ? &port->c_src : &port->c_dest; ++ down_write(&grp->list_mutex); ++ write_lock_irq(&grp->list_lock); ++ if (is_src) ++ list_del(&subs->src_list); ++ else ++ list_del(&subs->dest_list); ++ grp->exclusive = 0; ++ write_unlock_irq(&grp->list_lock); ++ up_write(&grp->list_mutex); ++ ++ unsubscribe_port(client, port, grp, &subs->info, ack); ++} ++ ++/* connect two ports */ ++int snd_seq_port_connect(struct snd_seq_client *connector, ++ struct snd_seq_client *src_client, ++ struct snd_seq_client_port *src_port, ++ struct snd_seq_client *dest_client, ++ struct snd_seq_client_port *dest_port, ++ struct snd_seq_port_subscribe *info) ++{ ++ struct snd_seq_subscribers *subs; ++ bool exclusive; ++ int err; ++ ++ subs = kzalloc(sizeof(*subs), GFP_KERNEL); ++ if (!subs) ++ return -ENOMEM; ++ ++ subs->info = *info; ++ atomic_set(&subs->ref_count, 0); ++ INIT_LIST_HEAD(&subs->src_list); ++ INIT_LIST_HEAD(&subs->dest_list); ++ ++ exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE); ++ ++ err = check_and_subscribe_port(src_client, src_port, subs, true, ++ exclusive, ++ connector->number != src_client->number); ++ if (err < 0) ++ goto error; ++ err = check_and_subscribe_port(dest_client, dest_port, subs, false, ++ exclusive, ++ connector->number != dest_client->number); ++ if (err < 0) ++ goto error_dest; + +- up_write(&dest->list_mutex); +- up_write(&src->list_mutex); + return 0; + +- __error: +- if (src_called) +- unsubscribe_port(src_client, src_port, src, info, +- connector->number != src_client->number); ++ error_dest: ++ delete_and_unsubscribe_port(src_client, src_port, subs, true, ++ connector->number != src_client->number); ++ error: + kfree(subs); +- up_write(&dest->list_mutex); +- up_write(&src->list_mutex); + return err; + } + +- + /* remove the connection */ + int snd_seq_port_disconnect(struct snd_seq_client *connector, + struct snd_seq_client *src_client, +@@ -572,37 +608,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, + struct snd_seq_port_subscribe *info) + { + struct snd_seq_port_subs_info *src = &src_port->c_src; +- struct snd_seq_port_subs_info *dest = &dest_port->c_dest; + struct snd_seq_subscribers *subs; + int err = -ENOENT; +- unsigned long flags; + + down_write(&src->list_mutex); +- down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); +- + /* look for the connection */ + list_for_each_entry(subs, &src->list_head, src_list) { + if (match_subs_info(info, &subs->info)) { +- write_lock_irqsave(&src->list_lock, flags); +- // write_lock(&dest->list_lock); // no lock yet +- list_del(&subs->src_list); +- list_del(&subs->dest_list); +- // write_unlock(&dest->list_lock); +- write_unlock_irqrestore(&src->list_lock, flags); +- src->exclusive = dest->exclusive = 0; +- unsubscribe_port(src_client, src_port, src, info, +- connector->number != src_client->number); +- unsubscribe_port(dest_client, dest_port, dest, info, +- connector->number != dest_client->number); +- kfree(subs); ++ atomic_dec(&subs->ref_count); /* mark as not ready */ + err = 0; + break; + } + } +- +- up_write(&dest->list_mutex); + up_write(&src->list_mutex); +- return err; ++ if (err < 0) ++ return err; ++ ++ delete_and_unsubscribe_port(src_client, src_port, subs, true, ++ connector->number != src_client->number); ++ delete_and_unsubscribe_port(dest_client, dest_port, subs, false, ++ connector->number != dest_client->number); ++ kfree(subs); ++ return 0; + } + + +diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c +index 24d44b2f61ac..6ec30a98a92a 100644 +--- a/sound/core/seq/seq_timer.c ++++ b/sound/core/seq/seq_timer.c +@@ -92,6 +92,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr) + + void snd_seq_timer_defaults(struct snd_seq_timer * tmr) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tmr->lock, flags); + /* setup defaults */ + tmr->ppq = 96; /* 96 PPQ */ + tmr->tempo = 500000; /* 120 BPM */ +@@ -107,21 +110,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) + tmr->preferred_resolution = seq_default_timer_resolution; + + tmr->skew = tmr->skew_base = SKEW_BASE; ++ spin_unlock_irqrestore(&tmr->lock, flags); + } + +-void snd_seq_timer_reset(struct snd_seq_timer * tmr) ++static void seq_timer_reset(struct snd_seq_timer *tmr) + { +- unsigned long flags; +- +- spin_lock_irqsave(&tmr->lock, flags); +- + /* reset time & songposition */ + tmr->cur_time.tv_sec = 0; + tmr->cur_time.tv_nsec = 0; + + tmr->tick.cur_tick = 0; + tmr->tick.fraction = 0; ++} ++ ++void snd_seq_timer_reset(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; + ++ spin_lock_irqsave(&tmr->lock, flags); ++ seq_timer_reset(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + } + +@@ -140,8 +147,11 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, + tmr = q->timer; + if (tmr == NULL) + return; +- if (!tmr->running) ++ spin_lock_irqsave(&tmr->lock, flags); ++ if (!tmr->running) { ++ spin_unlock_irqrestore(&tmr->lock, flags); + return; ++ } + + resolution *= ticks; + if (tmr->skew != tmr->skew_base) { +@@ -150,8 +160,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, + (((resolution & 0xffff) * tmr->skew) >> 16); + } + +- spin_lock_irqsave(&tmr->lock, flags); +- + /* update timer */ + snd_seq_inc_time_nsec(&tmr->cur_time, resolution); + +@@ -298,26 +306,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q) + t->callback = snd_seq_timer_interrupt; + t->callback_data = q; + t->flags |= SNDRV_TIMER_IFLG_AUTO; ++ spin_lock_irq(&tmr->lock); + tmr->timeri = t; ++ spin_unlock_irq(&tmr->lock); + return 0; + } + + int snd_seq_timer_close(struct snd_seq_queue *q) + { + struct snd_seq_timer *tmr; ++ struct snd_timer_instance *t; + + tmr = q->timer; + if (snd_BUG_ON(!tmr)) + return -EINVAL; +- if (tmr->timeri) { +- snd_timer_stop(tmr->timeri); +- snd_timer_close(tmr->timeri); +- tmr->timeri = NULL; +- } ++ spin_lock_irq(&tmr->lock); ++ t = tmr->timeri; ++ tmr->timeri = NULL; ++ spin_unlock_irq(&tmr->lock); ++ if (t) ++ snd_timer_close(t); + return 0; + } + +-int snd_seq_timer_stop(struct snd_seq_timer * tmr) ++static int seq_timer_stop(struct snd_seq_timer *tmr) + { + if (! tmr->timeri) + return -EINVAL; +@@ -328,6 +340,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr) + return 0; + } + ++int snd_seq_timer_stop(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&tmr->lock, flags); ++ err = seq_timer_stop(tmr); ++ spin_unlock_irqrestore(&tmr->lock, flags); ++ return err; ++} ++ + static int initialize_timer(struct snd_seq_timer *tmr) + { + struct snd_timer *t; +@@ -360,13 +383,13 @@ static int initialize_timer(struct snd_seq_timer *tmr) + return 0; + } + +-int snd_seq_timer_start(struct snd_seq_timer * tmr) ++static int seq_timer_start(struct snd_seq_timer *tmr) + { + if (! tmr->timeri) + return -EINVAL; + if (tmr->running) +- snd_seq_timer_stop(tmr); +- snd_seq_timer_reset(tmr); ++ seq_timer_stop(tmr); ++ seq_timer_reset(tmr); + if (initialize_timer(tmr) < 0) + return -EINVAL; + snd_timer_start(tmr->timeri, tmr->ticks); +@@ -375,14 +398,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr) + return 0; + } + +-int snd_seq_timer_continue(struct snd_seq_timer * tmr) ++int snd_seq_timer_start(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&tmr->lock, flags); ++ err = seq_timer_start(tmr); ++ spin_unlock_irqrestore(&tmr->lock, flags); ++ return err; ++} ++ ++static int seq_timer_continue(struct snd_seq_timer *tmr) + { + if (! tmr->timeri) + return -EINVAL; + if (tmr->running) + return -EBUSY; + if (! tmr->initialized) { +- snd_seq_timer_reset(tmr); ++ seq_timer_reset(tmr); + if (initialize_timer(tmr) < 0) + return -EINVAL; + } +@@ -392,11 +426,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr) + return 0; + } + ++int snd_seq_timer_continue(struct snd_seq_timer *tmr) ++{ ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&tmr->lock, flags); ++ err = seq_timer_continue(tmr); ++ spin_unlock_irqrestore(&tmr->lock, flags); ++ return err; ++} ++ + /* return current 'real' time. use timeofday() to get better granularity. */ + snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) + { + snd_seq_real_time_t cur_time; ++ unsigned long flags; + ++ spin_lock_irqsave(&tmr->lock, flags); + cur_time = tmr->cur_time; + if (tmr->running) { + struct timeval tm; +@@ -412,7 +459,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) + } + snd_seq_sanity_real_time(&cur_time); + } +- ++ spin_unlock_irqrestore(&tmr->lock, flags); + return cur_time; + } + +diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c +index 4b50e604276d..0fa691e01384 100644 +--- a/sound/core/seq/seq_virmidi.c ++++ b/sound/core/seq/seq_virmidi.c +@@ -254,9 +254,13 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) + */ + static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) + { ++ struct snd_virmidi_dev *rdev = substream->rmidi->private_data; + struct snd_virmidi *vmidi = substream->runtime->private_data; +- snd_midi_event_free(vmidi->parser); ++ ++ write_lock_irq(&rdev->filelist_lock); + list_del(&vmidi->list); ++ write_unlock_irq(&rdev->filelist_lock); ++ snd_midi_event_free(vmidi->parser); + substream->runtime->private_data = NULL; + kfree(vmidi); + return 0; +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 4e436fe53afa..d90d8f4b85fe 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -300,8 +300,7 @@ int snd_timer_open(struct snd_timer_instance **ti, + return 0; + } + +-static int _snd_timer_stop(struct snd_timer_instance *timeri, +- int keep_flag, int event); ++static int _snd_timer_stop(struct snd_timer_instance *timeri, int event); + + /* + * close a timer instance +@@ -343,7 +342,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) + spin_unlock_irq(&timer->lock); + mutex_lock(®ister_mutex); + list_del(&timeri->open_list); +- if (timer && list_empty(&timer->open_list_head) && ++ if (list_empty(&timer->open_list_head) && + timer->hw.close) + timer->hw.close(timer); + /* remove slave links */ +@@ -415,7 +414,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) + spin_lock_irqsave(&timer->lock, flags); + list_for_each_entry(ts, &ti->slave_active_head, active_list) + if (ts->ccallback) +- ts->ccallback(ti, event + 100, &tstamp, resolution); ++ ts->ccallback(ts, event + 100, &tstamp, resolution); + spin_unlock_irqrestore(&timer->lock, flags); + } + +@@ -444,6 +443,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) + unsigned long flags; + + spin_lock_irqsave(&slave_active_lock, flags); ++ if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { ++ spin_unlock_irqrestore(&slave_active_lock, flags); ++ return -EBUSY; ++ } + timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; + if (timeri->master && timeri->timer) { + spin_lock(&timeri->timer->lock); +@@ -468,23 +471,30 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) + return -EINVAL; + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + result = snd_timer_start_slave(timeri); +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); ++ if (result >= 0) ++ snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + return result; + } + timer = timeri->timer; + if (timer == NULL) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); ++ if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | ++ SNDRV_TIMER_IFLG_START)) { ++ result = -EBUSY; ++ goto unlock; ++ } + timeri->ticks = timeri->cticks = ticks; + timeri->pticks = 0; + result = snd_timer_start1(timer, timeri, ticks); ++ unlock: + spin_unlock_irqrestore(&timer->lock, flags); +- snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); ++ if (result >= 0) ++ snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + return result; + } + +-static int _snd_timer_stop(struct snd_timer_instance * timeri, +- int keep_flag, int event) ++static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) + { + struct snd_timer *timer; + unsigned long flags; +@@ -493,19 +503,30 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, + return -ENXIO; + + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { +- if (!keep_flag) { +- spin_lock_irqsave(&slave_active_lock, flags); +- timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; +- list_del_init(&timeri->ack_list); +- list_del_init(&timeri->active_list); ++ spin_lock_irqsave(&slave_active_lock, flags); ++ if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { + spin_unlock_irqrestore(&slave_active_lock, flags); ++ return -EBUSY; + } ++ if (timeri->timer) ++ spin_lock(&timeri->timer->lock); ++ timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; ++ list_del_init(&timeri->ack_list); ++ list_del_init(&timeri->active_list); ++ if (timeri->timer) ++ spin_unlock(&timeri->timer->lock); ++ spin_unlock_irqrestore(&slave_active_lock, flags); + goto __end; + } + timer = timeri->timer; + if (!timer) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); ++ if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | ++ SNDRV_TIMER_IFLG_START))) { ++ spin_unlock_irqrestore(&timer->lock, flags); ++ return -EBUSY; ++ } + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && +@@ -520,9 +541,7 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, + } + } + } +- if (!keep_flag) +- timeri->flags &= +- ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); ++ timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + spin_unlock_irqrestore(&timer->lock, flags); + __end: + if (event != SNDRV_TIMER_EVENT_RESOLUTION) +@@ -541,7 +560,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) + unsigned long flags; + int err; + +- err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); ++ err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP); + if (err < 0) + return err; + timer = timeri->timer; +@@ -571,10 +590,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri) + if (! timer) + return -EINVAL; + spin_lock_irqsave(&timer->lock, flags); ++ if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { ++ result = -EBUSY; ++ goto unlock; ++ } + if (!timeri->cticks) + timeri->cticks = 1; + timeri->pticks = 0; + result = snd_timer_start1(timer, timeri, timer->sticks); ++ unlock: + spin_unlock_irqrestore(&timer->lock, flags); + snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); + return result; +@@ -585,7 +609,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) + */ + int snd_timer_pause(struct snd_timer_instance * timeri) + { +- return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); ++ return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE); + } + + /* +@@ -702,8 +726,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) + ti->cticks = ti->ticks; + } else { + ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; +- if (--timer->running) +- list_del_init(&ti->active_list); ++ --timer->running; ++ list_del_init(&ti->active_list); + } + if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || + (ti->flags & SNDRV_TIMER_IFLG_FAST)) +diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c +index fd798f753609..982a2c2faf24 100644 +--- a/sound/drivers/dummy.c ++++ b/sound/drivers/dummy.c +@@ -109,6 +109,9 @@ struct dummy_timer_ops { + snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); + }; + ++#define get_dummy_ops(substream) \ ++ (*(const struct dummy_timer_ops **)(substream)->runtime->private_data) ++ + struct dummy_model { + const char *name; + int (*playback_constraints)(struct snd_pcm_runtime *runtime); +@@ -137,7 +140,6 @@ struct snd_dummy { + int iobox; + struct snd_kcontrol *cd_volume_ctl; + struct snd_kcontrol *cd_switch_ctl; +- const struct dummy_timer_ops *timer_ops; + }; + + /* +@@ -231,6 +233,8 @@ struct dummy_model *dummy_models[] = { + */ + + struct dummy_systimer_pcm { ++ /* ops must be the first item */ ++ const struct dummy_timer_ops *timer_ops; + spinlock_t lock; + struct timer_list timer; + unsigned long base_time; +@@ -368,6 +372,8 @@ static struct dummy_timer_ops dummy_systimer_ops = { + */ + + struct dummy_hrtimer_pcm { ++ /* ops must be the first item */ ++ const struct dummy_timer_ops *timer_ops; + ktime_t base_time; + ktime_t period_time; + atomic_t running; +@@ -494,31 +500,25 @@ static struct dummy_timer_ops dummy_hrtimer_ops = { + + static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: +- return dummy->timer_ops->start(substream); ++ return get_dummy_ops(substream)->start(substream); + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: +- return dummy->timer_ops->stop(substream); ++ return get_dummy_ops(substream)->stop(substream); + } + return -EINVAL; + } + + static int dummy_pcm_prepare(struct snd_pcm_substream *substream) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- +- return dummy->timer_ops->prepare(substream); ++ return get_dummy_ops(substream)->prepare(substream); + } + + static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- +- return dummy->timer_ops->pointer(substream); ++ return get_dummy_ops(substream)->pointer(substream); + } + + static struct snd_pcm_hardware dummy_pcm_hardware = { +@@ -564,17 +564,19 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) + struct snd_dummy *dummy = snd_pcm_substream_chip(substream); + struct dummy_model *model = dummy->model; + struct snd_pcm_runtime *runtime = substream->runtime; ++ const struct dummy_timer_ops *ops; + int err; + +- dummy->timer_ops = &dummy_systimer_ops; ++ ops = &dummy_systimer_ops; + #ifdef CONFIG_HIGH_RES_TIMERS + if (hrtimer) +- dummy->timer_ops = &dummy_hrtimer_ops; ++ ops = &dummy_hrtimer_ops; + #endif + +- err = dummy->timer_ops->create(substream); ++ err = ops->create(substream); + if (err < 0) + return err; ++ get_dummy_ops(substream) = ops; + + runtime->hw = dummy->pcm_hw; + if (substream->pcm->device & 1) { +@@ -596,7 +598,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) + err = model->capture_constraints(substream->runtime); + } + if (err < 0) { +- dummy->timer_ops->free(substream); ++ get_dummy_ops(substream)->free(substream); + return err; + } + return 0; +@@ -604,8 +606,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) + + static int dummy_pcm_close(struct snd_pcm_substream *substream) + { +- struct snd_dummy *dummy = snd_pcm_substream_chip(substream); +- dummy->timer_ops->free(substream); ++ get_dummy_ops(substream)->free(substream); + return 0; + } + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 69a2aafb0b0f..babbf238a648 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -2188,6 +2188,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { + SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), + SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), ++ SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), + + /* All Apple entries are in codec SSIDs */ + SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 02d26915b61d..c6d408c819b1 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1248,7 +1248,8 @@ static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) && +- (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) ++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && ++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) + continue; + + dev_dbg(be->dev, "ASoC: hw_free BE %s\n", +diff --git a/sound/usb/midi.c b/sound/usb/midi.c +index dabbe05d17f5..37ecba340876 100644 +--- a/sound/usb/midi.c ++++ b/sound/usb/midi.c +@@ -2291,7 +2291,6 @@ int snd_usbmidi_create(struct snd_card *card, + else + err = snd_usbmidi_create_endpoints(umidi, endpoints); + if (err < 0) { +- snd_usbmidi_free(umidi); + return err; + } + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 94cd28c2bd8d..44550a4cf893 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -900,8 +900,12 @@ void snd_usb_set_interface_quirk(struct usb_device *dev) + * "Playback Design" products need a 50ms delay after setting the + * USB interface. + */ +- if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) ++ switch (le16_to_cpu(dev->descriptor.idVendor)) { ++ case 0x23ba: /* Playback Design */ ++ case 0x0644: /* TEAC Corp. */ + mdelay(50); ++ break; ++ } + } + + void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, +@@ -916,6 +920,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, + (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) + mdelay(20); + ++ /* ++ * "TEAC Corp." products need a 20ms delay after each ++ * class compliant request ++ */ ++ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x0644) && ++ (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) ++ mdelay(20); ++ + /* Marantz/Denon devices with USB DAC functionality need a delay + * after each class compliant request + */ diff --git a/patch/kernel/odroidc1-default/patch-3.10.97-98.patch b/patch/kernel/odroidc1-default/patch-3.10.97-98.patch new file mode 100644 index 0000000000..332f8fede4 --- /dev/null +++ b/patch/kernel/odroidc1-default/patch-3.10.97-98.patch @@ -0,0 +1,1792 @@ +diff --git a/Makefile b/Makefile +index f26470169c70..dadd1edc6f84 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 97 ++SUBLEVEL = 98 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/arm/common/icst.c b/arch/arm/common/icst.c +index 2dc6da70ae59..d7ed252708c5 100644 +--- a/arch/arm/common/icst.c ++++ b/arch/arm/common/icst.c +@@ -16,7 +16,7 @@ + */ + #include + #include +- ++#include + #include + + /* +@@ -29,7 +29,11 @@ EXPORT_SYMBOL(icst525_s2div); + + unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco) + { +- return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]); ++ u64 dividend = p->ref * 2 * (u64)(vco.v + 8); ++ u32 divisor = (vco.r + 2) * p->s2div[vco.s]; ++ ++ do_div(dividend, divisor); ++ return (unsigned long)dividend; + } + + EXPORT_SYMBOL(icst_hz); +@@ -58,6 +62,7 @@ icst_hz_to_vco(const struct icst_params *p, unsigned long freq) + + if (f > p->vco_min && f <= p->vco_max) + break; ++ i++; + } while (i < 8); + + if (i >= 8) +diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c +index 0392112a5d70..a5ecef7188ba 100644 +--- a/arch/m32r/kernel/setup.c ++++ b/arch/m32r/kernel/setup.c +@@ -81,7 +81,10 @@ static struct resource code_resource = { + }; + + unsigned long memory_start; ++EXPORT_SYMBOL(memory_start); ++ + unsigned long memory_end; ++EXPORT_SYMBOL(memory_end); + + void __init setup_arch(char **); + int get_cpuinfo(char *); +diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h +index c48a95035a77..4dde707a6ff7 100644 +--- a/arch/x86/include/asm/segment.h ++++ b/arch/x86/include/asm/segment.h +@@ -212,8 +212,19 @@ + #define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8) + + #ifdef __KERNEL__ ++ ++/* ++ * early_idt_handler_array is an array of entry points referenced in the ++ * early IDT. For simplicity, it's a real array with one entry point ++ * every nine bytes. That leaves room for an optional 'push $0' if the ++ * vector has no error code (two bytes), a 'push $vector_number' (two ++ * bytes), and a jump to the common entry code (up to five bytes). ++ */ ++#define EARLY_IDT_HANDLER_SIZE 9 ++ + #ifndef __ASSEMBLY__ +-extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5]; ++ ++extern const char early_idt_handler_array[NUM_EXCEPTION_VECTORS][EARLY_IDT_HANDLER_SIZE]; + + /* + * Load a segment. Fall back on loading the zero +diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c +index 55b67614ed94..3b861b7661ee 100644 +--- a/arch/x86/kernel/head64.c ++++ b/arch/x86/kernel/head64.c +@@ -162,7 +162,7 @@ void __init x86_64_start_kernel(char * real_mode_data) + clear_bss(); + + for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) +- set_intr_gate(i, &early_idt_handlers[i]); ++ set_intr_gate(i, &early_idt_handler_array[i]); + load_idt((const struct desc_ptr *)&idt_descr); + + copy_bootdata(__va(real_mode_data)); +diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S +index df63cae573e0..8060c8b95b3a 100644 +--- a/arch/x86/kernel/head_32.S ++++ b/arch/x86/kernel/head_32.S +@@ -499,21 +499,22 @@ check_x87: + __INIT + setup_once: + /* +- * Set up a idt with 256 entries pointing to ignore_int, +- * interrupt gates. It doesn't actually load idt - that needs +- * to be done on each CPU. Interrupts are enabled elsewhere, +- * when we can be relatively sure everything is ok. ++ * Set up a idt with 256 interrupt gates that push zero if there ++ * is no error code and then jump to early_idt_handler_common. ++ * It doesn't actually load the idt - that needs to be done on ++ * each CPU. Interrupts are enabled elsewhere, when we can be ++ * relatively sure everything is ok. + */ + + movl $idt_table,%edi +- movl $early_idt_handlers,%eax ++ movl $early_idt_handler_array,%eax + movl $NUM_EXCEPTION_VECTORS,%ecx + 1: + movl %eax,(%edi) + movl %eax,4(%edi) + /* interrupt gate, dpl=0, present */ + movl $(0x8E000000 + __KERNEL_CS),2(%edi) +- addl $9,%eax ++ addl $EARLY_IDT_HANDLER_SIZE,%eax + addl $8,%edi + loop 1b + +@@ -545,26 +546,28 @@ setup_once: + andl $0,setup_once_ref /* Once is enough, thanks */ + ret + +-ENTRY(early_idt_handlers) ++ENTRY(early_idt_handler_array) + # 36(%esp) %eflags + # 32(%esp) %cs + # 28(%esp) %eip + # 24(%rsp) error code + i = 0 + .rept NUM_EXCEPTION_VECTORS +- .if (EXCEPTION_ERRCODE_MASK >> i) & 1 +- ASM_NOP2 +- .else ++ .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1 + pushl $0 # Dummy error code, to make stack frame uniform + .endif + pushl $i # 20(%esp) Vector number +- jmp early_idt_handler ++ jmp early_idt_handler_common + i = i + 1 ++ .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc + .endr +-ENDPROC(early_idt_handlers) ++ENDPROC(early_idt_handler_array) + +- /* This is global to keep gas from relaxing the jumps */ +-ENTRY(early_idt_handler) ++early_idt_handler_common: ++ /* ++ * The stack is the hardware frame, an error code or zero, and the ++ * vector number. ++ */ + cld + + cmpl $2,(%esp) # X86_TRAP_NMI +@@ -624,7 +627,7 @@ ex_entry: + is_nmi: + addl $8,%esp /* drop vector number and error code */ + iret +-ENDPROC(early_idt_handler) ++ENDPROC(early_idt_handler_common) + + /* This is the default interrupt "handler" :-) */ + ALIGN +diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S +index 3280489905a8..54bf9c2d0d13 100644 +--- a/arch/x86/kernel/head_64.S ++++ b/arch/x86/kernel/head_64.S +@@ -329,26 +329,28 @@ bad_address: + jmp bad_address + + __INIT +- .globl early_idt_handlers +-early_idt_handlers: ++ENTRY(early_idt_handler_array) + # 104(%rsp) %rflags + # 96(%rsp) %cs + # 88(%rsp) %rip + # 80(%rsp) error code + i = 0 + .rept NUM_EXCEPTION_VECTORS +- .if (EXCEPTION_ERRCODE_MASK >> i) & 1 +- ASM_NOP2 +- .else ++ .ifeq (EXCEPTION_ERRCODE_MASK >> i) & 1 + pushq $0 # Dummy error code, to make stack frame uniform + .endif + pushq $i # 72(%rsp) Vector number +- jmp early_idt_handler ++ jmp early_idt_handler_common + i = i + 1 ++ .fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc + .endr ++ENDPROC(early_idt_handler_array) + +-/* This is global to keep gas from relaxing the jumps */ +-ENTRY(early_idt_handler) ++early_idt_handler_common: ++ /* ++ * The stack is the hardware frame, an error code or zero, and the ++ * vector number. ++ */ + cld + + cmpl $2,(%rsp) # X86_TRAP_NMI +@@ -420,7 +422,7 @@ ENTRY(early_idt_handler) + is_nmi: + addq $16,%rsp # drop vector number and error code + INTERRUPT_RETURN +-ENDPROC(early_idt_handler) ++ENDPROC(early_idt_handler_common) + + __INITDATA + +diff --git a/block/blk-core.c b/block/blk-core.c +index 5a750b18172e..9ae84ae05e6a 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -3097,6 +3097,9 @@ int blk_pre_runtime_suspend(struct request_queue *q) + { + int ret = 0; + ++ if (!q->dev) ++ return ret; ++ + spin_lock_irq(q->queue_lock); + if (q->nr_pending) { + ret = -EBUSY; +@@ -3124,6 +3127,9 @@ EXPORT_SYMBOL(blk_pre_runtime_suspend); + */ + void blk_post_runtime_suspend(struct request_queue *q, int err) + { ++ if (!q->dev) ++ return; ++ + spin_lock_irq(q->queue_lock); + if (!err) { + q->rpm_status = RPM_SUSPENDED; +@@ -3148,6 +3154,9 @@ EXPORT_SYMBOL(blk_post_runtime_suspend); + */ + void blk_pre_runtime_resume(struct request_queue *q) + { ++ if (!q->dev) ++ return; ++ + spin_lock_irq(q->queue_lock); + q->rpm_status = RPM_RESUMING; + spin_unlock_irq(q->queue_lock); +@@ -3170,6 +3179,9 @@ EXPORT_SYMBOL(blk_pre_runtime_resume); + */ + void blk_post_runtime_resume(struct request_queue *q, int err) + { ++ if (!q->dev) ++ return; ++ + spin_lock_irq(q->queue_lock); + if (!err) { + q->rpm_status = RPM_ACTIVE; +diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c +index 334e31ff7a4e..6bd0c1ade9f2 100644 +--- a/drivers/iio/adc/ad7793.c ++++ b/drivers/iio/adc/ad7793.c +@@ -101,7 +101,7 @@ + #define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */ + + /* ID Register Bit Designations (AD7793_REG_ID) */ +-#define AD7785_ID 0xB ++#define AD7785_ID 0x3 + #define AD7792_ID 0xA + #define AD7793_ID 0xB + #define AD7794_ID 0xF +diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c +index aa26d50ab638..4eda4ea037b7 100644 +--- a/drivers/iio/dac/ad5064.c ++++ b/drivers/iio/dac/ad5064.c +@@ -602,10 +602,16 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd, + unsigned int addr, unsigned int val) + { + struct i2c_client *i2c = to_i2c_client(st->dev); ++ int ret; + + st->data.i2c[0] = (cmd << 4) | addr; + put_unaligned_be16(val, &st->data.i2c[1]); +- return i2c_master_send(i2c, st->data.i2c, 3); ++ ++ ret = i2c_master_send(i2c, st->data.i2c, 3); ++ if (ret < 0) ++ return ret; ++ ++ return 0; + } + + static int ad5064_i2c_probe(struct i2c_client *i2c, +diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c +index a612ec766d96..029207bbf03d 100644 +--- a/drivers/iio/dac/mcp4725.c ++++ b/drivers/iio/dac/mcp4725.c +@@ -166,6 +166,7 @@ static int mcp4725_probe(struct i2c_client *client, + data->client = client; + + indio_dev->dev.parent = &client->dev; ++ indio_dev->name = id->name; + indio_dev->info = &mcp4725_info; + indio_dev->channels = &mcp4725_channel; + indio_dev->num_channels = 1; +diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c +index 99d8e0b0dd34..d0538bcdc1b8 100644 +--- a/drivers/iio/imu/adis_buffer.c ++++ b/drivers/iio/imu/adis_buffer.c +@@ -43,7 +43,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, + return -ENOMEM; + + rx = adis->buffer; +- tx = rx + indio_dev->scan_bytes; ++ tx = rx + scan_count; + + spi_message_init(&adis->msg); + +diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c +index 02099afb6c79..77f06d001a66 100644 +--- a/drivers/input/mouse/elantech.c ++++ b/drivers/input/mouse/elantech.c +@@ -1081,7 +1081,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) + input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, + ETP_WMAX_V2, 0, 0); + } +- input_mt_init_slots(dev, 2, 0); ++ input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT); + input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); + break; +@@ -1357,6 +1357,13 @@ static const struct dmi_system_id no_hw_res_dmi_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "U2442"), + }, + }, ++ { ++ /* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), ++ }, ++ }, + #endif + { } + }; +diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h +index 4de2571938b8..5102b4f68f18 100644 +--- a/drivers/input/serio/i8042-x86ia64io.h ++++ b/drivers/input/serio/i8042-x86ia64io.h +@@ -258,6 +258,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { + }, + }, + { ++ /* Fujitsu Lifebook U745 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), ++ }, ++ }, ++ { + /* Fujitsu T70H */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), +diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c +index a7967ceb79e6..3d4622cae2cf 100644 +--- a/drivers/iommu/dmar.c ++++ b/drivers/iommu/dmar.c +@@ -968,7 +968,7 @@ void dmar_disable_qi(struct intel_iommu *iommu) + + raw_spin_lock_irqsave(&iommu->register_lock, flags); + +- sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); ++ sts = readl(iommu->reg + DMAR_GSTS_REG); + if (!(sts & DMA_GSTS_QIES)) + goto end; + +diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c +index 45011f63ad16..990cc298824a 100644 +--- a/drivers/iommu/intel_irq_remapping.c ++++ b/drivers/iommu/intel_irq_remapping.c +@@ -495,7 +495,7 @@ static void iommu_disable_irq_remapping(struct intel_iommu *iommu) + + raw_spin_lock_irqsave(&iommu->register_lock, flags); + +- sts = dmar_readq(iommu->reg + DMAR_GSTS_REG); ++ sts = readl(iommu->reg + DMAR_GSTS_REG); + if (!(sts & DMA_GSTS_IRES)) + goto end; + +diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c +index 5895f1978691..e98de425f8e0 100644 +--- a/drivers/net/wan/x25_asy.c ++++ b/drivers/net/wan/x25_asy.c +@@ -545,16 +545,12 @@ static void x25_asy_receive_buf(struct tty_struct *tty, + + static int x25_asy_open_tty(struct tty_struct *tty) + { +- struct x25_asy *sl = tty->disc_data; ++ struct x25_asy *sl; + int err; + + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + +- /* First make sure we're not already connected. */ +- if (sl && sl->magic == X25_ASY_MAGIC) +- return -EEXIST; +- + /* OK. Find a free X.25 channel to use. */ + sl = x25_asy_alloc(); + if (sl == NULL) +diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c +index 02bc5a6343c3..aa454241489c 100644 +--- a/drivers/platform/x86/intel_scu_ipcutil.c ++++ b/drivers/platform/x86/intel_scu_ipcutil.c +@@ -49,7 +49,7 @@ struct scu_ipc_data { + + static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) + { +- int count = data->count; ++ unsigned int count = data->count; + + if (count == 0 || count == 3 || count > 4) + return -EINVAL; +diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c +index 69c915aa77c2..d661fcda1932 100644 +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -569,7 +569,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev, + /* + * Command Lock contention + */ +- err = SCSI_DH_RETRY; ++ err = SCSI_DH_IMM_RETRY; + break; + default: + break; +@@ -619,6 +619,8 @@ retry: + err = mode_select_handle_sense(sdev, h->sense); + if (err == SCSI_DH_RETRY && retry_cnt--) + goto retry; ++ if (err == SCSI_DH_IMM_RETRY) ++ goto retry; + } + if (err == SCSI_DH_OK) { + h->state = RDAC_STATE_ACTIVE; +diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c +index 3cafe0d784b8..3020f1ff4abb 100644 +--- a/drivers/scsi/hosts.c ++++ b/drivers/scsi/hosts.c +@@ -305,6 +305,17 @@ static void scsi_host_dev_release(struct device *dev) + kfree(queuedata); + } + ++ if (shost->shost_state == SHOST_CREATED) { ++ /* ++ * Free the shost_dev device name here if scsi_host_alloc() ++ * and scsi_host_put() have been called but neither ++ * scsi_host_add() nor scsi_host_remove() has been called. ++ * This avoids that the memory allocated for the shost_dev ++ * name is leaked. ++ */ ++ kfree(dev_name(&shost->shost_dev)); ++ } ++ + scsi_destroy_command_freelist(shost); + if (shost->bqt) + blk_free_tags(shost->bqt); +diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c +index 9e2dd478dd15..135d7b56fbe6 100644 +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -789,7 +789,7 @@ sdev_store_queue_ramp_up_period(struct device *dev, + return -EINVAL; + + sdev->queue_ramp_up_period = msecs_to_jiffies(period); +- return period; ++ return count; + } + + static struct device_attribute sdev_attr_queue_ramp_up_period = +@@ -1030,31 +1030,25 @@ static void __scsi_remove_target(struct scsi_target *starget) + void scsi_remove_target(struct device *dev) + { + struct Scsi_Host *shost = dev_to_shost(dev->parent); +- struct scsi_target *starget, *last = NULL; ++ struct scsi_target *starget, *last_target = NULL; + unsigned long flags; + +- /* remove targets being careful to lookup next entry before +- * deleting the last +- */ ++restart: + spin_lock_irqsave(shost->host_lock, flags); + list_for_each_entry(starget, &shost->__targets, siblings) { +- if (starget->state == STARGET_DEL) ++ if (starget->state == STARGET_DEL || ++ starget == last_target) + continue; + if (starget->dev.parent == dev || &starget->dev == dev) { +- /* assuming new targets arrive at the end */ + kref_get(&starget->reap_ref); ++ last_target = starget; + spin_unlock_irqrestore(shost->host_lock, flags); +- if (last) +- scsi_target_reap(last); +- last = starget; + __scsi_remove_target(starget); +- spin_lock_irqsave(shost->host_lock, flags); ++ scsi_target_reap(starget); ++ goto restart; + } + } + spin_unlock_irqrestore(shost->host_lock, flags); +- +- if (last) +- scsi_target_reap(last); + } + EXPORT_SYMBOL(scsi_remove_target); + +diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c +index 26b543bc4f53..4afce0e838a2 100644 +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -3090,8 +3090,8 @@ static int sd_suspend(struct device *dev) + struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + int ret = 0; + +- if (!sdkp) +- return 0; /* this can happen */ ++ if (!sdkp) /* E.g.: runtime suspend following sd_remove() */ ++ return 0; + + if (sdkp->WCE) { + sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); +@@ -3115,6 +3115,9 @@ static int sd_resume(struct device *dev) + struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + int ret = 0; + ++ if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */ ++ return 0; ++ + if (!sdkp->device->manage_start_stop) + goto done; + +diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c +index 721d839d6c54..0be16bf5f0cd 100644 +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1258,7 +1258,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma) + } + + sfp->mmap_called = 1; +- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; ++ vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_private_data = sfp; + vma->vm_ops = &sg_mmap_vm_ops; + return 0; +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index 119d67f9c47e..1ac9943cbb93 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -142,6 +142,9 @@ static int sr_runtime_suspend(struct device *dev) + { + struct scsi_cd *cd = dev_get_drvdata(dev); + ++ if (!cd) /* E.g.: runtime suspend following sr_remove() */ ++ return 0; ++ + if (cd->media_present) + return -EBUSY; + else +@@ -1006,6 +1009,7 @@ static int sr_remove(struct device *dev) + + blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn); + del_gendisk(cd->disk); ++ dev_set_drvdata(dev, NULL); + + mutex_lock(&sr_ref_mutex); + kref_put(&cd->kref, sr_kref_release); +diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c +index 2f2f7fdd0691..9cbe2dd70499 100644 +--- a/drivers/staging/iio/adc/lpc32xx_adc.c ++++ b/drivers/staging/iio/adc/lpc32xx_adc.c +@@ -76,7 +76,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, + + if (mask == IIO_CHAN_INFO_RAW) { + mutex_lock(&indio_dev->mlock); +- clk_enable(info->clk); ++ clk_prepare_enable(info->clk); + /* Measurement setup */ + __raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm, + LPC32XX_ADC_SELECT(info->adc_base)); +@@ -84,7 +84,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, + __raw_writel(AD_PDN_CTRL | AD_STROBE, + LPC32XX_ADC_CTRL(info->adc_base)); + wait_for_completion(&info->completion); /* set by ISR */ +- clk_disable(info->clk); ++ clk_disable_unprepare(info->clk); + *val = info->value; + mutex_unlock(&indio_dev->mlock); + +diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c +index b9359753784e..364978e63d8d 100644 +--- a/drivers/staging/speakup/selection.c ++++ b/drivers/staging/speakup/selection.c +@@ -139,7 +139,9 @@ static void __speakup_paste_selection(struct work_struct *work) + struct tty_ldisc *ld; + DECLARE_WAITQUEUE(wait, current); + +- ld = tty_ldisc_ref_wait(tty); ++ ld = tty_ldisc_ref(tty); ++ if (!ld) ++ goto tty_unref; + + /* FIXME: this is completely unsafe */ + add_wait_queue(&vc->paste_wait, &wait); +@@ -158,6 +160,7 @@ static void __speakup_paste_selection(struct work_struct *work) + current->state = TASK_RUNNING; + + tty_ldisc_deref(ld); ++tty_unref: + tty_kref_put(tty); + } + +diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c +index 06cd916f91fe..d74da9598d58 100644 +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -3960,6 +3960,17 @@ reject: + return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf); + } + ++static bool iscsi_target_check_conn_state(struct iscsi_conn *conn) ++{ ++ bool ret; ++ ++ spin_lock_bh(&conn->state_lock); ++ ret = (conn->conn_state != TARG_CONN_STATE_LOGGED_IN); ++ spin_unlock_bh(&conn->state_lock); ++ ++ return ret; ++} ++ + int iscsi_target_rx_thread(void *arg) + { + int ret, rc; +@@ -3977,7 +3988,7 @@ int iscsi_target_rx_thread(void *arg) + * incoming iscsi/tcp socket I/O, and/or failing the connection. + */ + rc = wait_for_completion_interruptible(&conn->rx_login_comp); +- if (rc < 0) ++ if (rc < 0 || iscsi_target_check_conn_state(conn)) + return 0; + + if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { +diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c +index c45b3365d63d..200d779d0c03 100644 +--- a/drivers/target/iscsi/iscsi_target_configfs.c ++++ b/drivers/target/iscsi/iscsi_target_configfs.c +@@ -1730,7 +1730,8 @@ static void lio_tpg_release_fabric_acl( + } + + /* +- * Called with spin_lock_bh(struct se_portal_group->session_lock) held.. ++ * Called with spin_lock_irq(struct se_portal_group->session_lock) held ++ * or not held. + * + * Also, this function calls iscsit_inc_session_usage_count() on the + * struct iscsi_session in question. +@@ -1738,19 +1739,32 @@ static void lio_tpg_release_fabric_acl( + static int lio_tpg_shutdown_session(struct se_session *se_sess) + { + struct iscsi_session *sess = se_sess->fabric_sess_ptr; ++ struct se_portal_group *se_tpg = se_sess->se_tpg; ++ bool local_lock = false; ++ ++ if (!spin_is_locked(&se_tpg->session_lock)) { ++ spin_lock_irq(&se_tpg->session_lock); ++ local_lock = true; ++ } + + spin_lock(&sess->conn_lock); + if (atomic_read(&sess->session_fall_back_to_erl0) || + atomic_read(&sess->session_logout) || + (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { + spin_unlock(&sess->conn_lock); ++ if (local_lock) ++ spin_unlock_irq(&sess->conn_lock); + return 0; + } + atomic_set(&sess->session_reinstatement, 1); + spin_unlock(&sess->conn_lock); + + iscsit_stop_time2retain_timer(sess); ++ spin_unlock_irq(&se_tpg->session_lock); ++ + iscsit_stop_session(sess, 1, 1); ++ if (!local_lock) ++ spin_lock_irq(&se_tpg->session_lock); + + return 1; + } +diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c +index 77c276acccb6..2a61a01142e9 100644 +--- a/drivers/target/iscsi/iscsi_target_nego.c ++++ b/drivers/target/iscsi/iscsi_target_nego.c +@@ -384,6 +384,7 @@ err: + if (login->login_complete) { + if (conn->rx_thread && conn->rx_thread_active) { + send_sig(SIGINT, conn->rx_thread, 1); ++ complete(&conn->rx_login_comp); + kthread_stop(conn->rx_thread); + } + if (conn->tx_thread && conn->tx_thread_active) { +diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c +index 7cb36813aac2..deee2b81afff 100644 +--- a/drivers/tty/pty.c ++++ b/drivers/tty/pty.c +@@ -623,7 +623,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) + /* this is called once with whichever end is closed last */ + static void pty_unix98_shutdown(struct tty_struct *tty) + { +- devpts_kill_index(tty->driver_data, tty->index); ++ struct inode *ptmx_inode; ++ ++ if (tty->driver->subtype == PTY_TYPE_MASTER) ++ ptmx_inode = tty->driver_data; ++ else ++ ptmx_inode = tty->link->driver_data; ++ devpts_kill_index(ptmx_inode, tty->index); ++ devpts_del_ref(ptmx_inode); + } + + static const struct tty_operations ptm_unix98_ops = { +@@ -714,6 +721,18 @@ static int ptmx_open(struct inode *inode, struct file *filp) + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + tty->driver_data = inode; + ++ /* ++ * In the case where all references to ptmx inode are dropped and we ++ * still have /dev/tty opened pointing to the master/slave pair (ptmx ++ * is closed/released before /dev/tty), we must make sure that the inode ++ * is still valid when we call the final pty_unix98_shutdown, thus we ++ * hold an additional reference to the ptmx inode. For the same /dev/tty ++ * last close case, we also need to make sure the super_block isn't ++ * destroyed (devpts instance unmounted), before /dev/tty is closed and ++ * on its release devpts_kill_index is called. ++ */ ++ devpts_add_ref(inode); ++ + tty_add_file(tty, filp); + + slave_inode = devpts_pty_new(inode, +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 9dd6fa3a1260..507677b9bdc7 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -1502,7 +1502,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) + if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) { + xhci_dbg(xhci, "HW died, freeing TD.\n"); + urb_priv = urb->hcpriv; +- for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { ++ for (i = urb_priv->td_cnt; ++ i < urb_priv->length && xhci->devs[urb->dev->slot_id]; ++ i++) { + td = urb_priv->td[i]; + if (!list_empty(&td->td_list)) + list_del_init(&td->td_list); +diff --git a/fs/aio.c b/fs/aio.c +index ded94c4fa30d..9798d4edfd8f 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -977,12 +977,17 @@ static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat) + + static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb) + { +- if (unlikely(!access_ok(!rw, kiocb->ki_buf, kiocb->ki_nbytes))) +- return -EFAULT; ++ size_t len = kiocb->ki_nbytes; ++ ++ if (len > MAX_RW_COUNT) ++ len = MAX_RW_COUNT; ++ ++ if (unlikely(!access_ok(!rw, kiocb->ki_buf, len))) ++ return -EFAULT; + + kiocb->ki_iovec = &kiocb->ki_inline_vec; + kiocb->ki_iovec->iov_base = kiocb->ki_buf; +- kiocb->ki_iovec->iov_len = kiocb->ki_nbytes; ++ kiocb->ki_iovec->iov_len = len; + kiocb->ki_nr_segs = 1; + return 0; + } +diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c +index d85f90c92bb4..bca854b44056 100644 +--- a/fs/btrfs/backref.c ++++ b/fs/btrfs/backref.c +@@ -1228,7 +1228,8 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, + read_extent_buffer(eb, dest + bytes_left, + name_off, name_len); + if (eb != eb_in) { +- btrfs_tree_read_unlock_blocking(eb); ++ if (!path->skip_locking) ++ btrfs_tree_read_unlock_blocking(eb); + free_extent_buffer(eb); + } + ret = inode_ref_info(parent, 0, fs_root, path, &found_key); +@@ -1247,9 +1248,10 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, + eb = path->nodes[0]; + /* make sure we can use eb after releasing the path */ + if (eb != eb_in) { +- atomic_inc(&eb->refs); +- btrfs_tree_read_lock(eb); +- btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); ++ if (!path->skip_locking) ++ btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); ++ path->nodes[0] = NULL; ++ path->locks[0] = 0; + } + btrfs_release_path(path); + iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); +diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c +index 5c807b23ca67..182e82f22b3a 100644 +--- a/fs/cifs/cifsencrypt.c ++++ b/fs/cifs/cifsencrypt.c +@@ -591,7 +591,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) + + ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); + if (!ses->auth_key.response) { +- rc = ENOMEM; ++ rc = -ENOMEM; + ses->auth_key.len = 0; + goto setup_ntlmv2_rsp_ret; + } +diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c +index a726b9f29cb7..61af24e379ad 100644 +--- a/fs/devpts/inode.c ++++ b/fs/devpts/inode.c +@@ -564,6 +564,26 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx) + mutex_unlock(&allocated_ptys_lock); + } + ++/* ++ * pty code needs to hold extra references in case of last /dev/tty close ++ */ ++ ++void devpts_add_ref(struct inode *ptmx_inode) ++{ ++ struct super_block *sb = pts_sb_from_inode(ptmx_inode); ++ ++ atomic_inc(&sb->s_active); ++ ihold(ptmx_inode); ++} ++ ++void devpts_del_ref(struct inode *ptmx_inode) ++{ ++ struct super_block *sb = pts_sb_from_inode(ptmx_inode); ++ ++ iput(ptmx_inode); ++ deactivate_super(sb); ++} ++ + /** + * devpts_pty_new -- create a new inode in /dev/pts/ + * @ptmx_inode: inode of the master +diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c +index fa7d2e668c3a..cf0a70486618 100644 +--- a/fs/ext4/resize.c ++++ b/fs/ext4/resize.c +@@ -181,7 +181,7 @@ static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned long flexbg_size) + if (flex_gd == NULL) + goto out3; + +- if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_flex_group_data)) ++ if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_group_data)) + goto out2; + flex_gd->count = flexbg_size; + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 4fafb8484bbc..35f604b5f408 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -993,6 +993,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, + + mark_page_accessed(page); + ++ iov_iter_advance(ii, tmp); + if (!tmp) { + unlock_page(page); + page_cache_release(page); +@@ -1005,7 +1006,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, + req->page_descs[req->num_pages].length = tmp; + req->num_pages++; + +- iov_iter_advance(ii, tmp); + count += tmp; + pos += tmp; + offset += tmp; +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 78679b489484..d8ac734a1e44 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -1005,6 +1005,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s + * Protect the call to nfs4_state_set_mode_locked and + * serialise the stateid update + */ ++ spin_lock(&state->owner->so_lock); + write_seqlock(&state->seqlock); + if (deleg_stateid != NULL) { + nfs4_stateid_copy(&state->stateid, deleg_stateid); +@@ -1013,7 +1014,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s + if (open_stateid != NULL) + nfs_set_open_stateid_locked(state, open_stateid, fmode); + write_sequnlock(&state->seqlock); +- spin_lock(&state->owner->so_lock); + update_open_stateflags(state, fmode); + spin_unlock(&state->owner->so_lock); + } +diff --git a/fs/proc/array.c b/fs/proc/array.c +index 09f0d9c374a3..5c45eb5e4e0d 100644 +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -398,7 +398,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, + + state = *get_task_state(task); + vsize = eip = esp = 0; +- permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT); ++ permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT); + mm = get_task_mm(task); + if (mm) { + vsize = task_vsize(mm); +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 8fc784aef0b8..7b5d453ebf53 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -239,7 +239,7 @@ out: + + static int proc_pid_auxv(struct task_struct *task, char *buffer) + { +- struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ); ++ struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); + int res = PTR_ERR(mm); + if (mm && !IS_ERR(mm)) { + unsigned int nwords = 0; +@@ -269,7 +269,7 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer) + wchan = get_wchan(task); + + if (lookup_symbol_name(wchan, symname) < 0) +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) + return 0; + else + return sprintf(buffer, "%lu", wchan); +@@ -283,7 +283,7 @@ static int lock_trace(struct task_struct *task) + int err = mutex_lock_killable(&task->signal->cred_guard_mutex); + if (err) + return err; +- if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) { ++ if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { + mutex_unlock(&task->signal->cred_guard_mutex); + return -EPERM; + } +@@ -557,7 +557,7 @@ static int proc_fd_access_allowed(struct inode *inode) + */ + task = get_proc_task(inode); + if (task) { +- allowed = ptrace_may_access(task, PTRACE_MODE_READ); ++ allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); + put_task_struct(task); + } + return allowed; +@@ -592,7 +592,7 @@ static bool has_pid_permissions(struct pid_namespace *pid, + return true; + if (in_group_p(pid->pid_gid)) + return true; +- return ptrace_may_access(task, PTRACE_MODE_READ); ++ return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); + } + + +@@ -707,7 +707,7 @@ static int __mem_open(struct inode *inode, struct file *file, unsigned int mode) + if (!task) + return -ESRCH; + +- mm = mm_access(task, mode); ++ mm = mm_access(task, mode | PTRACE_MODE_FSCREDS); + put_task_struct(task); + + if (IS_ERR(mm)) +@@ -1761,7 +1761,7 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) + if (!task) + goto out_notask; + +- mm = mm_access(task, PTRACE_MODE_READ); ++ mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); + if (IS_ERR_OR_NULL(mm)) + goto out; + +@@ -1896,7 +1896,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir, + goto out; + + result = ERR_PTR(-EACCES); +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) + goto out_put_task; + + result = ERR_PTR(-ENOENT); +@@ -1952,7 +1952,7 @@ proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir) + goto out; + + ret = -EACCES; +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) + goto out_put_task; + + ret = 0; +@@ -2488,7 +2488,7 @@ static int do_io_accounting(struct task_struct *task, char *buffer, int whole) + if (result) + return result; + +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) { ++ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { + result = -EACCES; + goto out_unlock; + } +diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c +index 54bdc6701e9f..ac49a8d4aaf8 100644 +--- a/fs/proc/namespaces.c ++++ b/fs/proc/namespaces.c +@@ -125,7 +125,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) + if (!task) + goto out; + +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) + goto out_put_task; + + ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns.ns_ops); +@@ -158,7 +158,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl + if (!task) + goto out; + +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) + goto out_put_task; + + len = -ENOENT; +diff --git a/fs/udf/inode.c b/fs/udf/inode.c +index 789814f27438..5c1120a5fa42 100644 +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -2055,14 +2055,29 @@ void udf_write_aext(struct inode *inode, struct extent_position *epos, + epos->offset += adsize; + } + ++/* ++ * Only 1 indirect extent in a row really makes sense but allow upto 16 in case ++ * someone does some weird stuff. ++ */ ++#define UDF_MAX_INDIR_EXTS 16 ++ + int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, + struct kernel_lb_addr *eloc, uint32_t *elen, int inc) + { + int8_t etype; ++ unsigned int indirections = 0; + + while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == + (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { + int block; ++ ++ if (++indirections > UDF_MAX_INDIR_EXTS) { ++ udf_err(inode->i_sb, ++ "too many indirect extents in inode %lu\n", ++ inode->i_ino); ++ return -1; ++ } ++ + epos->block = *eloc; + epos->offset = sizeof(struct allocExtDesc); + brelse(epos->bh); +diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c +index 44b815e57f94..685fbd8a2937 100644 +--- a/fs/udf/unicode.c ++++ b/fs/udf/unicode.c +@@ -132,11 +132,15 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) + if (c < 0x80U) + utf_o->u_name[utf_o->u_len++] = (uint8_t)c; + else if (c < 0x800U) { ++ if (utf_o->u_len > (UDF_NAME_LEN - 4)) ++ break; + utf_o->u_name[utf_o->u_len++] = + (uint8_t)(0xc0 | (c >> 6)); + utf_o->u_name[utf_o->u_len++] = + (uint8_t)(0x80 | (c & 0x3f)); + } else { ++ if (utf_o->u_len > (UDF_NAME_LEN - 5)) ++ break; + utf_o->u_name[utf_o->u_len++] = + (uint8_t)(0xe0 | (c >> 12)); + utf_o->u_name[utf_o->u_len++] = +@@ -177,17 +181,22 @@ int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) + static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) + { + unsigned c, i, max_val, utf_char; +- int utf_cnt, u_len; ++ int utf_cnt, u_len, u_ch; + + memset(ocu, 0, sizeof(dstring) * length); + ocu[0] = 8; + max_val = 0xffU; ++ u_ch = 1; + + try_again: + u_len = 0U; + utf_char = 0U; + utf_cnt = 0U; + for (i = 0U; i < utf->u_len; i++) { ++ /* Name didn't fit? */ ++ if (u_len + 1 + u_ch >= length) ++ return 0; ++ + c = (uint8_t)utf->u_name[i]; + + /* Complete a multi-byte UTF-8 character */ +@@ -229,6 +238,7 @@ try_again: + if (max_val == 0xffU) { + max_val = 0xffffU; + ocu[0] = (uint8_t)0x10U; ++ u_ch = 2; + goto try_again; + } + goto error_out; +@@ -281,7 +291,7 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, + c = (c << 8) | ocu[i++]; + + len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len], +- UDF_NAME_LEN - utf_o->u_len); ++ UDF_NAME_LEN - 2 - utf_o->u_len); + /* Valid character? */ + if (len >= 0) + utf_o->u_len += len; +@@ -299,15 +309,19 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, + int len; + unsigned i, max_val; + uint16_t uni_char; +- int u_len; ++ int u_len, u_ch; + + memset(ocu, 0, sizeof(dstring) * length); + ocu[0] = 8; + max_val = 0xffU; ++ u_ch = 1; + + try_again: + u_len = 0U; + for (i = 0U; i < uni->u_len; i++) { ++ /* Name didn't fit? */ ++ if (u_len + 1 + u_ch >= length) ++ return 0; + len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); + if (!len) + continue; +@@ -320,6 +334,7 @@ try_again: + if (uni_char > max_val) { + max_val = 0xffffU; + ocu[0] = (uint8_t)0x10U; ++ u_ch = 2; + goto try_again; + } + +diff --git a/include/linux/compiler.h b/include/linux/compiler.h +index a2329c5e6206..a2ce6f8871c4 100644 +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -131,7 +131,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); + */ + #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) ) + #define __trace_if(cond) \ +- if (__builtin_constant_p((cond)) ? !!(cond) : \ ++ if (__builtin_constant_p(!!(cond)) ? !!(cond) : \ + ({ \ + int ______r; \ + static struct ftrace_branch_data \ +diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h +index 251a2090a554..e0ee0b3000b2 100644 +--- a/include/linux/devpts_fs.h ++++ b/include/linux/devpts_fs.h +@@ -19,6 +19,8 @@ + + int devpts_new_index(struct inode *ptmx_inode); + void devpts_kill_index(struct inode *ptmx_inode, int idx); ++void devpts_add_ref(struct inode *ptmx_inode); ++void devpts_del_ref(struct inode *ptmx_inode); + /* mknod in devpts */ + struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, + void *priv); +@@ -32,6 +34,8 @@ void devpts_pty_kill(struct inode *inode); + /* Dummy stubs in the no-pty case */ + static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; } + static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { } ++static inline void devpts_add_ref(struct inode *ptmx_inode) { } ++static inline void devpts_del_ref(struct inode *ptmx_inode) { } + static inline struct inode *devpts_pty_new(struct inode *ptmx_inode, + dev_t device, int index, void *priv) + { +diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h +index bb980ae6d9d3..6af8988f5ddd 100644 +--- a/include/linux/ptrace.h ++++ b/include/linux/ptrace.h +@@ -56,7 +56,29 @@ extern void exit_ptrace(struct task_struct *tracer); + #define PTRACE_MODE_READ 0x01 + #define PTRACE_MODE_ATTACH 0x02 + #define PTRACE_MODE_NOAUDIT 0x04 +-/* Returns true on success, false on denial. */ ++#define PTRACE_MODE_FSCREDS 0x08 ++#define PTRACE_MODE_REALCREDS 0x10 ++ ++/* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */ ++#define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS) ++#define PTRACE_MODE_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS) ++#define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS) ++#define PTRACE_MODE_ATTACH_REALCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS) ++ ++/** ++ * ptrace_may_access - check whether the caller is permitted to access ++ * a target task. ++ * @task: target task ++ * @mode: selects type of access and caller credentials ++ * ++ * Returns true on success, false on denial. ++ * ++ * One of the flags PTRACE_MODE_FSCREDS and PTRACE_MODE_REALCREDS must ++ * be set in @mode to specify whether the access was requested through ++ * a filesystem syscall (should use effective capabilities and fsuid ++ * of the caller) or through an explicit syscall such as ++ * process_vm_writev or ptrace (and should use the real credentials). ++ */ + extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); + + static inline int ptrace_reparented(struct task_struct *child) +diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h +index ffc444c38b0a..e02e09f85fad 100644 +--- a/include/linux/radix-tree.h ++++ b/include/linux/radix-tree.h +@@ -322,12 +322,28 @@ void **radix_tree_next_chunk(struct radix_tree_root *root, + struct radix_tree_iter *iter, unsigned flags); + + /** ++ * radix_tree_iter_retry - retry this chunk of the iteration ++ * @iter: iterator state ++ * ++ * If we iterate over a tree protected only by the RCU lock, a race ++ * against deletion or creation may result in seeing a slot for which ++ * radix_tree_deref_retry() returns true. If so, call this function ++ * and continue the iteration. ++ */ ++static inline __must_check ++void **radix_tree_iter_retry(struct radix_tree_iter *iter) ++{ ++ iter->next_index = iter->index; ++ return NULL; ++} ++ ++/** + * radix_tree_chunk_size - get current chunk size + * + * @iter: pointer to radix tree iterator + * Returns: current chunk size + */ +-static __always_inline unsigned ++static __always_inline long + radix_tree_chunk_size(struct radix_tree_iter *iter) + { + return iter->next_index - iter->index; +@@ -361,9 +377,9 @@ radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags) + return slot + offset + 1; + } + } else { +- unsigned size = radix_tree_chunk_size(iter) - 1; ++ long size = radix_tree_chunk_size(iter); + +- while (size--) { ++ while (--size > 0) { + slot++; + iter->index++; + if (likely(*slot)) +diff --git a/kernel/events/core.c b/kernel/events/core.c +index d9b0aad17dbf..0f5207839673 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -2938,7 +2938,7 @@ find_lively_task_by_vpid(pid_t vpid) + + /* Reuse ptrace permission checks for now. */ + err = -EACCES; +- if (!ptrace_may_access(task, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) + goto errout; + + return task; +@@ -5639,6 +5639,10 @@ static int perf_tp_filter_match(struct perf_event *event, + { + void *record = data->raw->data; + ++ /* only top level events have filters set */ ++ if (event->parent) ++ event = event->parent; ++ + if (likely(!event->filter) || filter_match_preds(event->filter, record)) + return 1; + return 0; +diff --git a/kernel/futex.c b/kernel/futex.c +index 625a4e659e7a..edc4beae4df1 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -2494,6 +2494,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, + if (q.pi_state && (q.pi_state->owner != current)) { + spin_lock(q.lock_ptr); + ret = fixup_pi_state_owner(uaddr2, &q, current); ++ /* ++ * Drop the reference to the pi state which ++ * the requeue_pi() code acquired for us. ++ */ ++ free_pi_state(q.pi_state); + spin_unlock(q.lock_ptr); + } + } else { +@@ -2620,7 +2625,7 @@ SYSCALL_DEFINE3(get_robust_list, int, pid, + } + + ret = -EPERM; +- if (!ptrace_may_access(p, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS)) + goto err_unlock; + + head = p->robust_list; +diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c +index f9f44fd4d34d..3888617a1f9e 100644 +--- a/kernel/futex_compat.c ++++ b/kernel/futex_compat.c +@@ -155,7 +155,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid, + } + + ret = -EPERM; +- if (!ptrace_may_access(p, PTRACE_MODE_READ)) ++ if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS)) + goto err_unlock; + + head = p->compat_robust_list; +diff --git a/kernel/kcmp.c b/kernel/kcmp.c +index 0aa69ea1d8fd..3a47fa998fe0 100644 +--- a/kernel/kcmp.c ++++ b/kernel/kcmp.c +@@ -122,8 +122,8 @@ SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type, + &task2->signal->cred_guard_mutex); + if (ret) + goto err; +- if (!ptrace_may_access(task1, PTRACE_MODE_READ) || +- !ptrace_may_access(task2, PTRACE_MODE_READ)) { ++ if (!ptrace_may_access(task1, PTRACE_MODE_READ_REALCREDS) || ++ !ptrace_may_access(task2, PTRACE_MODE_READ_REALCREDS)) { + ret = -EPERM; + goto err_unlock; + } +diff --git a/kernel/module.c b/kernel/module.c +index fd2afdf48a89..70a4754c001f 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -3398,6 +3398,11 @@ static inline int is_arm_mapping_symbol(const char *str) + && (str[2] == '\0' || str[2] == '.'); + } + ++static const char *symname(struct module *mod, unsigned int symnum) ++{ ++ return mod->strtab + mod->symtab[symnum].st_name; ++} ++ + static const char *get_ksymbol(struct module *mod, + unsigned long addr, + unsigned long *size, +@@ -3420,15 +3425,15 @@ static const char *get_ksymbol(struct module *mod, + + /* We ignore unnamed symbols: they're uninformative + * and inserted at a whim. */ ++ if (*symname(mod, i) == '\0' ++ || is_arm_mapping_symbol(symname(mod, i))) ++ continue; ++ + if (mod->symtab[i].st_value <= addr +- && mod->symtab[i].st_value > mod->symtab[best].st_value +- && *(mod->strtab + mod->symtab[i].st_name) != '\0' +- && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name)) ++ && mod->symtab[i].st_value > mod->symtab[best].st_value) + best = i; + if (mod->symtab[i].st_value > addr +- && mod->symtab[i].st_value < nextval +- && *(mod->strtab + mod->symtab[i].st_name) != '\0' +- && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name)) ++ && mod->symtab[i].st_value < nextval) + nextval = mod->symtab[i].st_value; + } + +@@ -3439,7 +3444,7 @@ static const char *get_ksymbol(struct module *mod, + *size = nextval - mod->symtab[best].st_value; + if (offset) + *offset = addr - mod->symtab[best].st_value; +- return mod->strtab + mod->symtab[best].st_name; ++ return symname(mod, best); + } + + /* For kallsyms to ask for address resolution. NULL means not found. Careful +@@ -3540,8 +3545,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + if (symnum < mod->num_symtab) { + *value = mod->symtab[symnum].st_value; + *type = mod->symtab[symnum].st_info; +- strlcpy(name, mod->strtab + mod->symtab[symnum].st_name, +- KSYM_NAME_LEN); ++ strlcpy(name, symname(mod, symnum), KSYM_NAME_LEN); + strlcpy(module_name, mod->name, MODULE_NAME_LEN); + *exported = is_exported(name, *value, mod); + preempt_enable(); +@@ -3558,7 +3562,7 @@ static unsigned long mod_find_symname(struct module *mod, const char *name) + unsigned int i; + + for (i = 0; i < mod->num_symtab; i++) +- if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 && ++ if (strcmp(name, symname(mod, i)) == 0 && + mod->symtab[i].st_info != 'U') + return mod->symtab[i].st_value; + return 0; +@@ -3602,7 +3606,7 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, + if (mod->state == MODULE_STATE_UNFORMED) + continue; + for (i = 0; i < mod->num_symtab; i++) { +- ret = fn(data, mod->strtab + mod->symtab[i].st_name, ++ ret = fn(data, symname(mod, i), + mod, mod->symtab[i].st_value); + if (ret != 0) + return ret; +diff --git a/kernel/ptrace.c b/kernel/ptrace.c +index 30ab20623bca..72b0b3e0e065 100644 +--- a/kernel/ptrace.c ++++ b/kernel/ptrace.c +@@ -225,6 +225,14 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) + static int __ptrace_may_access(struct task_struct *task, unsigned int mode) + { + const struct cred *cred = current_cred(), *tcred; ++ int dumpable = 0; ++ kuid_t caller_uid; ++ kgid_t caller_gid; ++ ++ if (!(mode & PTRACE_MODE_FSCREDS) == !(mode & PTRACE_MODE_REALCREDS)) { ++ WARN(1, "denying ptrace access check without PTRACE_MODE_*CREDS\n"); ++ return -EPERM; ++ } + + /* May we inspect the given task? + * This check is used both for attaching with ptrace +@@ -234,18 +242,33 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) + * because setting up the necessary parent/child relationship + * or halting the specified task is impossible. + */ +- int dumpable = 0; ++ + /* Don't let security modules deny introspection */ + if (same_thread_group(task, current)) + return 0; + rcu_read_lock(); ++ if (mode & PTRACE_MODE_FSCREDS) { ++ caller_uid = cred->fsuid; ++ caller_gid = cred->fsgid; ++ } else { ++ /* ++ * Using the euid would make more sense here, but something ++ * in userland might rely on the old behavior, and this ++ * shouldn't be a security problem since ++ * PTRACE_MODE_REALCREDS implies that the caller explicitly ++ * used a syscall that requests access to another process ++ * (and not a filesystem syscall to procfs). ++ */ ++ caller_uid = cred->uid; ++ caller_gid = cred->gid; ++ } + tcred = __task_cred(task); +- if (uid_eq(cred->uid, tcred->euid) && +- uid_eq(cred->uid, tcred->suid) && +- uid_eq(cred->uid, tcred->uid) && +- gid_eq(cred->gid, tcred->egid) && +- gid_eq(cred->gid, tcred->sgid) && +- gid_eq(cred->gid, tcred->gid)) ++ if (uid_eq(caller_uid, tcred->euid) && ++ uid_eq(caller_uid, tcred->suid) && ++ uid_eq(caller_uid, tcred->uid) && ++ gid_eq(caller_gid, tcred->egid) && ++ gid_eq(caller_gid, tcred->sgid) && ++ gid_eq(caller_gid, tcred->gid)) + goto ok; + if (ptrace_has_cap(tcred->user_ns, mode)) + goto ok; +@@ -312,7 +335,7 @@ static int ptrace_attach(struct task_struct *task, long request, + goto out; + + task_lock(task); +- retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); ++ retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS); + task_unlock(task); + if (retval) + goto unlock_creds; +diff --git a/lib/dma-debug.c b/lib/dma-debug.c +index d87a17a819d0..eb43517bf261 100644 +--- a/lib/dma-debug.c ++++ b/lib/dma-debug.c +@@ -962,7 +962,7 @@ static inline bool overlap(void *addr, unsigned long len, void *start, void *end + + static void check_for_illegal_area(struct device *dev, void *addr, unsigned long len) + { +- if (overlap(addr, len, _text, _etext) || ++ if (overlap(addr, len, _stext, _etext) || + overlap(addr, len, __start_rodata, __end_rodata)) + err_printk(dev, NULL, "DMA-API: device driver maps memory from kernel text or rodata [addr=%p] [len=%lu]\n", addr, len); + } +diff --git a/lib/klist.c b/lib/klist.c +index 358a368a2947..2e59aecbec0d 100644 +--- a/lib/klist.c ++++ b/lib/klist.c +@@ -282,9 +282,9 @@ void klist_iter_init_node(struct klist *k, struct klist_iter *i, + struct klist_node *n) + { + i->i_klist = k; +- i->i_cur = n; +- if (n) +- kref_get(&n->n_ref); ++ i->i_cur = NULL; ++ if (n && kref_get_unless_zero(&n->n_ref)) ++ i->i_cur = n; + } + EXPORT_SYMBOL_GPL(klist_iter_init_node); + +diff --git a/lib/radix-tree.c b/lib/radix-tree.c +index e7964296fd50..936a02c1c77b 100644 +--- a/lib/radix-tree.c ++++ b/lib/radix-tree.c +@@ -1015,9 +1015,13 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results, + return 0; + + radix_tree_for_each_slot(slot, root, &iter, first_index) { +- results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot)); ++ results[ret] = rcu_dereference_raw(*slot); + if (!results[ret]) + continue; ++ if (radix_tree_is_indirect_ptr(results[ret])) { ++ slot = radix_tree_iter_retry(&iter); ++ continue; ++ } + if (++ret == max_items) + break; + } +@@ -1094,9 +1098,13 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, + return 0; + + radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) { +- results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot)); ++ results[ret] = rcu_dereference_raw(*slot); + if (!results[ret]) + continue; ++ if (radix_tree_is_indirect_ptr(results[ret])) { ++ slot = radix_tree_iter_retry(&iter); ++ continue; ++ } + if (++ret == max_items) + break; + } +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index eaa3accb01e7..437ae2cbe102 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -5790,16 +5790,17 @@ static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp, + swap_buffers: + /* Swap primary and spare array */ + thresholds->spare = thresholds->primary; +- /* If all events are unregistered, free the spare array */ +- if (!new) { +- kfree(thresholds->spare); +- thresholds->spare = NULL; +- } + + rcu_assign_pointer(thresholds->primary, new); + + /* To be sure that nobody uses thresholds */ + synchronize_rcu(); ++ ++ /* If all events are unregistered, free the spare array */ ++ if (!new) { ++ kfree(thresholds->spare); ++ thresholds->spare = NULL; ++ } + unlock: + mutex_unlock(&memcg->thresholds_lock); + } +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index f97d709594e6..37df20faddd5 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1472,7 +1472,7 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags) + * Did it turn free? + */ + ret = __get_any_page(page, pfn, 0); +- if (!PageLRU(page)) { ++ if (ret == 1 && !PageLRU(page)) { + /* Drop page reference which is from __get_any_page() */ + put_page(page); + pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n", +diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c +index d85d3a0e06ce..7f1bf93fa87f 100644 +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -1209,23 +1209,30 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) + */ + static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) + { +- unsigned long pfn; ++ unsigned long pfn, sec_end_pfn; + struct zone *zone = NULL; + struct page *page; + int i; +- for (pfn = start_pfn; ++ for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn); + pfn < end_pfn; +- pfn += MAX_ORDER_NR_PAGES) { +- i = 0; +- /* This is just a CONFIG_HOLES_IN_ZONE check.*/ +- while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i)) +- i++; +- if (i == MAX_ORDER_NR_PAGES) ++ pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) { ++ /* Make sure the memory section is present first */ ++ if (!present_section_nr(pfn_to_section_nr(pfn))) + continue; +- page = pfn_to_page(pfn + i); +- if (zone && page_zone(page) != zone) +- return 0; +- zone = page_zone(page); ++ for (; pfn < sec_end_pfn && pfn < end_pfn; ++ pfn += MAX_ORDER_NR_PAGES) { ++ i = 0; ++ /* This is just a CONFIG_HOLES_IN_ZONE check.*/ ++ while ((i < MAX_ORDER_NR_PAGES) && ++ !pfn_valid_within(pfn + i)) ++ i++; ++ if (i == MAX_ORDER_NR_PAGES) ++ continue; ++ page = pfn_to_page(pfn + i); ++ if (zone && page_zone(page) != zone) ++ return 0; ++ zone = page_zone(page); ++ } + } + return 1; + } +diff --git a/mm/process_vm_access.c b/mm/process_vm_access.c +index fd26d0433509..e739825be8b3 100644 +--- a/mm/process_vm_access.c ++++ b/mm/process_vm_access.c +@@ -298,7 +298,7 @@ static ssize_t process_vm_rw_core(pid_t pid, const struct iovec *lvec, + goto free_proc_pages; + } + +- mm = mm_access(task, PTRACE_MODE_ATTACH); ++ mm = mm_access(task, PTRACE_MODE_ATTACH_REALCREDS); + if (!mm || IS_ERR(mm)) { + rc = IS_ERR(mm) ? PTR_ERR(mm) : -ESRCH; + /* +diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c +index 9ec416552cc5..8d69df16f6a8 100644 +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -336,7 +336,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id) + + static void ip6mr_free_table(struct mr6_table *mrt) + { +- del_timer(&mrt->ipmr_expire_timer); ++ del_timer_sync(&mrt->ipmr_expire_timer); + mroute_clean_tables(mrt, true); + kfree(mrt); + } +diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter +index 6129020c41a9..81228a443122 100755 +--- a/scripts/bloat-o-meter ++++ b/scripts/bloat-o-meter +@@ -55,8 +55,8 @@ for name in common: + delta.sort() + delta.reverse() + +-print "add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ +- (add, remove, grow, shrink, up, -down, up-down) +-print "%-40s %7s %7s %+7s" % ("function", "old", "new", "delta") ++print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \ ++ (add, remove, grow, shrink, up, -down, up-down)) ++print("%-40s %7s %7s %+7s" % ("function", "old", "new", "delta")) + for d, n in delta: +- if d: print "%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d) ++ if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d)) +diff --git a/security/commoncap.c b/security/commoncap.c +index c9219a66b7c6..4fd7bf2b19e1 100644 +--- a/security/commoncap.c ++++ b/security/commoncap.c +@@ -142,12 +142,17 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) + { + int ret = 0; + const struct cred *cred, *child_cred; ++ const kernel_cap_t *caller_caps; + + rcu_read_lock(); + cred = current_cred(); + child_cred = __task_cred(child); ++ if (mode & PTRACE_MODE_FSCREDS) ++ caller_caps = &cred->cap_effective; ++ else ++ caller_caps = &cred->cap_permitted; + if (cred->user_ns == child_cred->user_ns && +- cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) ++ cap_issubset(child_cred->cap_permitted, *caller_caps)) + goto out; + if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE)) + goto out; +diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c +index 67c91d226552..ee0522a8f730 100644 +--- a/sound/core/seq/seq_ports.c ++++ b/sound/core/seq/seq_ports.c +@@ -540,19 +540,22 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, + bool is_src, bool ack) + { + struct snd_seq_port_subs_info *grp; ++ struct list_head *list; ++ bool empty; + + grp = is_src ? &port->c_src : &port->c_dest; ++ list = is_src ? &subs->src_list : &subs->dest_list; + down_write(&grp->list_mutex); + write_lock_irq(&grp->list_lock); +- if (is_src) +- list_del(&subs->src_list); +- else +- list_del(&subs->dest_list); ++ empty = list_empty(list); ++ if (!empty) ++ list_del_init(list); + grp->exclusive = 0; + write_unlock_irq(&grp->list_lock); + up_write(&grp->list_mutex); + +- unsubscribe_port(client, port, grp, &subs->info, ack); ++ if (!empty) ++ unsubscribe_port(client, port, grp, &subs->info, ack); + } + + /* connect two ports */ +diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c +index 82b0606dcb8a..c3efcf2f816b 100644 +--- a/tools/lib/traceevent/event-parse.c ++++ b/tools/lib/traceevent/event-parse.c +@@ -4190,13 +4190,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event + sizeof(long) != 8) { + char *p; + +- ls = 2; + /* make %l into %ll */ +- p = strchr(format, 'l'); +- if (p) ++ if (ls == 1 && (p = strchr(format, 'l'))) + memmove(p+1, p, strlen(p)+1); + else if (strcmp(format, "%p") == 0) + strcpy(format, "0x%llx"); ++ ls = 2; + } + switch (ls) { + case -2: diff --git a/patch/kernel/odroidc1-default/patch-3.10.98-99.patch b/patch/kernel/odroidc1-default/patch-3.10.98-99.patch new file mode 100644 index 0000000000..e405e5ac5a --- /dev/null +++ b/patch/kernel/odroidc1-default/patch-3.10.98-99.patch @@ -0,0 +1,2573 @@ +diff --git a/Makefile b/Makefile +index dadd1edc6f84..f1e6491fd7d8 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 98 ++SUBLEVEL = 99 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c +index a8d02223da44..14558a9fa3b3 100644 +--- a/arch/arc/kernel/unwind.c ++++ b/arch/arc/kernel/unwind.c +@@ -984,42 +984,13 @@ int arc_unwind(struct unwind_frame_info *frame) + (const u8 *)(fde + + 1) + + *fde, ptrType); +- if (pc >= endLoc) ++ if (pc >= endLoc) { + fde = NULL; +- } else +- fde = NULL; +- } +- if (fde == NULL) { +- for (fde = table->address, tableSize = table->size; +- cie = NULL, tableSize > sizeof(*fde) +- && tableSize - sizeof(*fde) >= *fde; +- tableSize -= sizeof(*fde) + *fde, +- fde += 1 + *fde / sizeof(*fde)) { +- cie = cie_for_fde(fde, table); +- if (cie == &bad_cie) { + cie = NULL; +- break; + } +- if (cie == NULL +- || cie == ¬_fde +- || (ptrType = fde_pointer_type(cie)) < 0) +- continue; +- ptr = (const u8 *)(fde + 2); +- startLoc = read_pointer(&ptr, +- (const u8 *)(fde + 1) + +- *fde, ptrType); +- if (!startLoc) +- continue; +- if (!(ptrType & DW_EH_PE_indirect)) +- ptrType &= +- DW_EH_PE_FORM | DW_EH_PE_signed; +- endLoc = +- startLoc + read_pointer(&ptr, +- (const u8 *)(fde + +- 1) + +- *fde, ptrType); +- if (pc >= startLoc && pc < endLoc) +- break; ++ } else { ++ fde = NULL; ++ cie = NULL; + } + } + } +diff --git a/arch/mips/kvm/kvm_locore.S b/arch/mips/kvm/kvm_locore.S +index 920b63210806..34c35f0e3290 100644 +--- a/arch/mips/kvm/kvm_locore.S ++++ b/arch/mips/kvm/kvm_locore.S +@@ -156,9 +156,11 @@ FEXPORT(__kvm_mips_vcpu_run) + + FEXPORT(__kvm_mips_load_asid) + /* Set the ASID for the Guest Kernel */ +- sll t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */ +- /* addresses shift to 0x80000000 */ +- bltz t0, 1f /* If kernel */ ++ PTR_L t0, VCPU_COP0(k1) ++ LONG_L t0, COP0_STATUS(t0) ++ andi t0, KSU_USER | ST0_ERL | ST0_EXL ++ xori t0, KSU_USER ++ bnez t0, 1f /* If kernel */ + addiu t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */ + addiu t1, k1, VCPU_GUEST_USER_ASID /* else user */ + 1: +@@ -442,9 +444,11 @@ __kvm_mips_return_to_guest: + mtc0 t0, CP0_EPC + + /* Set the ASID for the Guest Kernel */ +- sll t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */ +- /* addresses shift to 0x80000000 */ +- bltz t0, 1f /* If kernel */ ++ PTR_L t0, VCPU_COP0(k1) ++ LONG_L t0, COP0_STATUS(t0) ++ andi t0, KSU_USER | ST0_ERL | ST0_EXL ++ xori t0, KSU_USER ++ bnez t0, 1f /* If kernel */ + addiu t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */ + addiu t1, k1, VCPU_GUEST_USER_ASID /* else user */ + 1: +diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c +index 843ec38fec7b..8aa5f30d8579 100644 +--- a/arch/mips/kvm/kvm_mips.c ++++ b/arch/mips/kvm/kvm_mips.c +@@ -308,7 +308,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) + + if (!gebase) { + err = -ENOMEM; +- goto out_free_cpu; ++ goto out_uninit_cpu; + } + kvm_info("Allocated %d bytes for KVM Exception Handlers @ %p\n", + ALIGN(size, PAGE_SIZE), gebase); +@@ -368,6 +368,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) + out_free_gebase: + kfree(gebase); + ++out_uninit_cpu: ++ kvm_vcpu_uninit(vcpu); ++ + out_free_cpu: + kfree(vcpu); + +diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c +index c76f297b7149..33085819cd89 100644 +--- a/arch/mips/kvm/kvm_mips_emul.c ++++ b/arch/mips/kvm/kvm_mips_emul.c +@@ -935,7 +935,7 @@ kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc, uint32_t cause, + + base = (inst >> 21) & 0x1f; + op_inst = (inst >> 16) & 0x1f; +- offset = inst & 0xffff; ++ offset = (int16_t)inst; + cache = (inst >> 16) & 0x3; + op = (inst >> 18) & 0x7; + +diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c +index 4d1ee88864e8..18c8b819b0aa 100644 +--- a/arch/s390/mm/extable.c ++++ b/arch/s390/mm/extable.c +@@ -52,12 +52,16 @@ void sort_extable(struct exception_table_entry *start, + int i; + + /* Normalize entries to being relative to the start of the section */ +- for (p = start, i = 0; p < finish; p++, i += 8) ++ for (p = start, i = 0; p < finish; p++, i += 8) { + p->insn += i; ++ p->fixup += i + 4; ++ } + sort(start, finish - start, sizeof(*start), cmp_ex, NULL); + /* Denormalize all entries */ +- for (p = start, i = 0; p < finish; p++, i += 8) ++ for (p = start, i = 0; p < finish; p++, i += 8) { + p->insn -= i; ++ p->fixup -= i + 4; ++ } + } + + #ifdef CONFIG_MODULES +diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c +index be8db9bb7878..666510b39870 100644 +--- a/arch/sparc/kernel/sys_sparc_64.c ++++ b/arch/sparc/kernel/sys_sparc_64.c +@@ -416,7 +416,7 @@ out: + + SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality) + { +- int ret; ++ long ret; + + if (personality(current->personality) == PER_LINUX32 && + personality(personality) == PER_LINUX) +diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c +index 337518c5042a..b412c62486f0 100644 +--- a/arch/um/os-Linux/start_up.c ++++ b/arch/um/os-Linux/start_up.c +@@ -95,6 +95,8 @@ static int start_ptraced_child(void) + { + int pid, n, status; + ++ fflush(stdout); ++ + pid = fork(); + if (pid == 0) + ptrace_child(); +diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c +index 6033be9ff81a..3c8bffdc71c8 100644 +--- a/arch/x86/platform/efi/efi.c ++++ b/arch/x86/platform/efi/efi.c +@@ -250,12 +250,19 @@ static efi_status_t __init phys_efi_set_virtual_address_map( + efi_memory_desc_t *virtual_map) + { + efi_status_t status; ++ unsigned long flags; + + efi_call_phys_prelog(); ++ ++ /* Disable interrupts around EFI calls: */ ++ local_irq_save(flags); + status = efi_call_phys4(efi_phys.set_virtual_address_map, + memory_map_size, descriptor_size, + descriptor_version, virtual_map); ++ local_irq_restore(flags); ++ + efi_call_phys_epilog(); ++ + return status; + } + +diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c +index 40e446941dd7..bebbee05e331 100644 +--- a/arch/x86/platform/efi/efi_32.c ++++ b/arch/x86/platform/efi/efi_32.c +@@ -33,19 +33,16 @@ + + /* + * To make EFI call EFI runtime service in physical addressing mode we need +- * prelog/epilog before/after the invocation to disable interrupt, to +- * claim EFI runtime service handler exclusively and to duplicate a memory in +- * low memory space say 0 - 3G. ++ * prolog/epilog before/after the invocation to claim the EFI runtime service ++ * handler exclusively and to duplicate a memory mapping in low memory space, ++ * say 0 - 3G. + */ + +-static unsigned long efi_rt_eflags; + + void efi_call_phys_prelog(void) + { + struct desc_ptr gdt_descr; + +- local_irq_save(efi_rt_eflags); +- + load_cr3(initial_page_table); + __flush_tlb_all(); + +@@ -64,6 +61,4 @@ void efi_call_phys_epilog(void) + + load_cr3(swapper_pg_dir); + __flush_tlb_all(); +- +- local_irq_restore(efi_rt_eflags); + } +diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c +index 39a0e7f1f0a3..2f6c1a9734c8 100644 +--- a/arch/x86/platform/efi/efi_64.c ++++ b/arch/x86/platform/efi/efi_64.c +@@ -40,7 +40,6 @@ + #include + + static pgd_t *save_pgd __initdata; +-static unsigned long efi_flags __initdata; + + static void __init early_code_mapping_set_exec(int executable) + { +@@ -66,7 +65,6 @@ void __init efi_call_phys_prelog(void) + int n_pgds; + + early_code_mapping_set_exec(1); +- local_irq_save(efi_flags); + + n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE); + save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL); +@@ -90,7 +88,6 @@ void __init efi_call_phys_epilog(void) + set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]); + kfree(save_pgd); + __flush_tlb_all(); +- local_irq_restore(efi_flags); + early_code_mapping_set_exec(0); + } + +diff --git a/block/partitions/mac.c b/block/partitions/mac.c +index 76d8ba6379a9..bd5b91465230 100644 +--- a/block/partitions/mac.c ++++ b/block/partitions/mac.c +@@ -32,7 +32,7 @@ int mac_partition(struct parsed_partitions *state) + Sector sect; + unsigned char *data; + int slot, blocks_in_map; +- unsigned secsize; ++ unsigned secsize, datasize, partoffset; + #ifdef CONFIG_PPC_PMAC + int found_root = 0; + int found_root_goodness = 0; +@@ -50,10 +50,14 @@ int mac_partition(struct parsed_partitions *state) + } + secsize = be16_to_cpu(md->block_size); + put_dev_sector(sect); +- data = read_part_sector(state, secsize/512, §); ++ datasize = round_down(secsize, 512); ++ data = read_part_sector(state, datasize / 512, §); + if (!data) + return -1; +- part = (struct mac_partition *) (data + secsize%512); ++ partoffset = secsize % 512; ++ if (partoffset + sizeof(*part) > datasize) ++ return -1; ++ part = (struct mac_partition *) (data + partoffset); + if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) { + put_dev_sector(sect); + return 0; /* not a MacOS disk */ +diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c +index 136803c47cdb..96e5ed188636 100644 +--- a/drivers/ata/libata-sff.c ++++ b/drivers/ata/libata-sff.c +@@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, + static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) + { + struct ata_port *ap = qc->ap; +- unsigned long flags; + + if (ap->ops->error_handler) { + if (in_wq) { +- spin_lock_irqsave(ap->lock, flags); +- + /* EH might have kicked in while host lock is + * released. + */ +@@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) + } else + ata_port_freeze(ap); + } +- +- spin_unlock_irqrestore(ap->lock, flags); + } else { + if (likely(!(qc->err_mask & AC_ERR_HSM))) + ata_qc_complete(qc); +@@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) + } + } else { + if (in_wq) { +- spin_lock_irqsave(ap->lock, flags); + ata_sff_irq_on(ap); + ata_qc_complete(qc); +- spin_unlock_irqrestore(ap->lock, flags); + } else + ata_qc_complete(qc); + } +@@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + { + struct ata_link *link = qc->dev->link; + struct ata_eh_info *ehi = &link->eh_info; +- unsigned long flags = 0; + int poll_next; + ++ lockdep_assert_held(ap->lock); ++ + WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); + + /* Make sure ata_sff_qc_issue() does not throw things +@@ -1112,14 +1106,6 @@ fsm_start: + } + } + +- /* Send the CDB (atapi) or the first data block (ata pio out). +- * During the state transition, interrupt handler shouldn't +- * be invoked before the data transfer is complete and +- * hsm_task_state is changed. Hence, the following locking. +- */ +- if (in_wq) +- spin_lock_irqsave(ap->lock, flags); +- + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. +@@ -1135,9 +1121,6 @@ fsm_start: + /* send CDB */ + atapi_send_cdb(ap, qc); + +- if (in_wq) +- spin_unlock_irqrestore(ap->lock, flags); +- + /* if polling, ata_sff_pio_task() handles the rest. + * otherwise, interrupt handler takes over from here. + */ +@@ -1361,12 +1344,14 @@ static void ata_sff_pio_task(struct work_struct *work) + u8 status; + int poll_next; + ++ spin_lock_irq(ap->lock); ++ + BUG_ON(ap->sff_pio_task_link == NULL); + /* qc can be NULL if timeout occurred */ + qc = ata_qc_from_tag(ap, link->active_tag); + if (!qc) { + ap->sff_pio_task_link = NULL; +- return; ++ goto out_unlock; + } + + fsm_start: +@@ -1381,11 +1366,14 @@ fsm_start: + */ + status = ata_sff_busy_wait(ap, ATA_BUSY, 5); + if (status & ATA_BUSY) { ++ spin_unlock_irq(ap->lock); + ata_msleep(ap, 2); ++ spin_lock_irq(ap->lock); ++ + status = ata_sff_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); +- return; ++ goto out_unlock; + } + } + +@@ -1402,6 +1390,8 @@ fsm_start: + */ + if (poll_next) + goto fsm_start; ++out_unlock: ++ spin_unlock_irq(ap->lock); + } + + /** +diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c +index dd1faa564eb2..cdfb98e70cfd 100644 +--- a/drivers/ata/sata_sil.c ++++ b/drivers/ata/sata_sil.c +@@ -631,6 +631,9 @@ static void sil_dev_config(struct ata_device *dev) + unsigned int n, quirks = 0; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + ++ /* This controller doesn't support trim */ ++ dev->horkage |= ATA_HORKAGE_NOTRIM; ++ + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + + for (n = 0; sil_blacklist[n].product; n++) +diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c +index 64f553f04fa4..5874ebf9dced 100644 +--- a/drivers/clocksource/vt8500_timer.c ++++ b/drivers/clocksource/vt8500_timer.c +@@ -50,6 +50,8 @@ + + #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) + ++#define MIN_OSCR_DELTA 16 ++ + static void __iomem *regbase; + + static cycle_t vt8500_timer_read(struct clocksource *cs) +@@ -80,7 +82,7 @@ static int vt8500_timer_set_next_event(unsigned long cycles, + cpu_relax(); + writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); + +- if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) ++ if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA) + return -ETIME; + + writel(1, regbase + TIMER_IER_VAL); +@@ -162,7 +164,7 @@ static void __init vt8500_timer_init(struct device_node *np) + pr_err("%s: setup_irq failed for %s\n", __func__, + clockevent.name); + clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, +- 4, 0xf0000000); ++ MIN_OSCR_DELTA * 2, 0xf0000000); + } + + CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); +diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h +index b6b7d70f2832..5cfc1765af74 100644 +--- a/drivers/gpu/drm/ast/ast_drv.h ++++ b/drivers/gpu/drm/ast/ast_drv.h +@@ -296,6 +296,7 @@ int ast_framebuffer_init(struct drm_device *dev, + int ast_fbdev_init(struct drm_device *dev); + void ast_fbdev_fini(struct drm_device *dev); + void ast_fbdev_set_suspend(struct drm_device *dev, int state); ++void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr); + + struct ast_bo { + struct ttm_buffer_object bo; +diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c +index fbc0823cfa18..a298d8f72225 100644 +--- a/drivers/gpu/drm/ast/ast_fb.c ++++ b/drivers/gpu/drm/ast/ast_fb.c +@@ -366,3 +366,10 @@ void ast_fbdev_set_suspend(struct drm_device *dev, int state) + + fb_set_suspend(ast->fbdev->helper.fbdev, state); + } ++ ++void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr) ++{ ++ ast->fbdev->helper.fbdev->fix.smem_start = ++ ast->fbdev->helper.fbdev->apertures->ranges[0].base + gpu_addr; ++ ast->fbdev->helper.fbdev->fix.smem_len = ast->vram_size - gpu_addr; ++} +diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c +index 96f874a508e2..313ccaf25f49 100644 +--- a/drivers/gpu/drm/ast/ast_main.c ++++ b/drivers/gpu/drm/ast/ast_main.c +@@ -359,6 +359,7 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) + dev->mode_config.min_height = 0; + dev->mode_config.preferred_depth = 24; + dev->mode_config.prefer_shadow = 1; ++ dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0); + + if (ast->chip == AST2100 || + ast->chip == AST2200 || +diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c +index e8f6418b6dec..f3a54ad77e3f 100644 +--- a/drivers/gpu/drm/ast/ast_mode.c ++++ b/drivers/gpu/drm/ast/ast_mode.c +@@ -509,6 +509,8 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc, + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); + if (ret) + DRM_ERROR("failed to kmap fbcon\n"); ++ else ++ ast_fbdev_set_base(ast, gpu_addr); + } + ast_bo_unreserve(bo); + +diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c +index ba2ab9a9b988..f3cce23f4a62 100644 +--- a/drivers/gpu/drm/radeon/radeon_atombios.c ++++ b/drivers/gpu/drm/radeon/radeon_atombios.c +@@ -452,7 +452,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, + } + + /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ +- if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) && ++ if (((dev->pdev->device == 0x9802) || ++ (dev->pdev->device == 0x9805) || ++ (dev->pdev->device == 0x9806)) && + (dev->pdev->subsystem_vendor == 0x1734) && + (dev->pdev->subsystem_device == 0x11bd)) { + if (*connector_type == DRM_MODE_CONNECTOR_VGA) { +@@ -463,14 +465,6 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, + } + } + +- /* Fujitsu D3003-S2 board lists DVI-I as DVI-I and VGA */ +- if ((dev->pdev->device == 0x9805) && +- (dev->pdev->subsystem_vendor == 0x1734) && +- (dev->pdev->subsystem_device == 0x11bd)) { +- if (*connector_type == DRM_MODE_CONNECTOR_VGA) +- return false; +- } +- + return true; + } + +diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c +index db83d075606e..6acd3646ac08 100644 +--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c ++++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c +@@ -73,6 +73,11 @@ static void radeon_hotplug_work_func(struct work_struct *work) + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + ++ /* we can race here at startup, some boards seem to trigger ++ * hotplug irqs when they shouldn't. */ ++ if (!rdev->mode_info.mode_config_initialized) ++ return; ++ + mutex_lock(&mode_config->mutex); + if (mode_config->num_connector) { + list_for_each_entry(connector, &mode_config->connector_list, head) +diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c +index f0bac68254b7..bb166849aa6e 100644 +--- a/drivers/gpu/drm/radeon/radeon_sa.c ++++ b/drivers/gpu/drm/radeon/radeon_sa.c +@@ -349,8 +349,13 @@ int radeon_sa_bo_new(struct radeon_device *rdev, + /* see if we can skip over some allocations */ + } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); + ++ for (i = 0; i < RADEON_NUM_RINGS; ++i) ++ radeon_fence_ref(fences[i]); ++ + spin_unlock(&sa_manager->wq.lock); + r = radeon_fence_wait_any(rdev, fences, false); ++ for (i = 0; i < RADEON_NUM_RINGS; ++i) ++ radeon_fence_unref(&fences[i]); + spin_lock(&sa_manager->wq.lock); + /* if we have nothing to wait for block */ + if (r == -ENOENT && block) { +diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c +index 4a14e113369d..f7015592544f 100644 +--- a/drivers/gpu/drm/radeon/radeon_ttm.c ++++ b/drivers/gpu/drm/radeon/radeon_ttm.c +@@ -619,7 +619,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) + 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(rdev->pdev, gtt->ttm.dma_address[i])) { +- while (--i) { ++ while (i--) { + pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i], + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + gtt->ttm.dma_address[i] = 0; +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +index 6c44c69a5ba4..94a0baac93dd 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +@@ -25,6 +25,7 @@ + * + **************************************************************************/ + #include ++#include + + #include + #include "vmwgfx_drv.h" +@@ -1192,6 +1193,12 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + static int __init vmwgfx_init(void) + { + int ret; ++ ++#ifdef CONFIG_VGA_CONSOLE ++ if (vgacon_text_force()) ++ return -EINVAL; ++#endif ++ + ret = drm_pci_init(&driver, &vmw_pci_driver); + if (ret) + DRM_ERROR("Failed initializing DRM.\n"); +diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c +index e893f6e1937d..3c84e96a485a 100644 +--- a/drivers/gpu/vga/vgaarb.c ++++ b/drivers/gpu/vga/vgaarb.c +@@ -392,8 +392,10 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) + set_current_state(interruptible ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); +- if (signal_pending(current)) { +- rc = -EINTR; ++ if (interruptible && signal_pending(current)) { ++ __set_current_state(TASK_RUNNING); ++ remove_wait_queue(&vga_wait_queue, &wait); ++ rc = -ERESTARTSYS; + break; + } + schedule(); +diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c +index 3e094cd6a0e3..a9194ef626cd 100644 +--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c ++++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c +@@ -149,7 +149,7 @@ static int iwch_l2t_send(struct t3cdev *tdev, struct sk_buff *skb, struct l2t_en + error = l2t_send(tdev, skb, l2e); + if (error < 0) + kfree_skb(skb); +- return error; ++ return error < 0 ? error : 0; + } + + int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) +@@ -165,7 +165,7 @@ int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) + error = cxgb3_ofld_send(tdev, skb); + if (error < 0) + kfree_skb(skb); +- return error; ++ return error < 0 ? error : 0; + } + + static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb) +diff --git a/drivers/infiniband/hw/qib/qib_verbs_mcast.c b/drivers/infiniband/hw/qib/qib_verbs_mcast.c +index dabb697b1c2a..48ba1c3e945a 100644 +--- a/drivers/infiniband/hw/qib/qib_verbs_mcast.c ++++ b/drivers/infiniband/hw/qib/qib_verbs_mcast.c +@@ -286,15 +286,13 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) + struct qib_ibdev *dev = to_idev(ibqp->device); + struct qib_ibport *ibp = to_iport(ibqp->device, qp->port_num); + struct qib_mcast *mcast = NULL; +- struct qib_mcast_qp *p, *tmp; ++ struct qib_mcast_qp *p, *tmp, *delp = NULL; + struct rb_node *n; + int last = 0; + int ret; + +- if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) { +- ret = -EINVAL; +- goto bail; +- } ++ if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) ++ return -EINVAL; + + spin_lock_irq(&ibp->lock); + +@@ -303,8 +301,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) + while (1) { + if (n == NULL) { + spin_unlock_irq(&ibp->lock); +- ret = -EINVAL; +- goto bail; ++ return -EINVAL; + } + + mcast = rb_entry(n, struct qib_mcast, rb_node); +@@ -328,6 +325,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) + */ + list_del_rcu(&p->list); + mcast->n_attached--; ++ delp = p; + + /* If this was the last attached QP, remove the GID too. */ + if (list_empty(&mcast->qp_list)) { +@@ -338,15 +336,16 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) + } + + spin_unlock_irq(&ibp->lock); ++ /* QP not attached */ ++ if (!delp) ++ return -EINVAL; ++ /* ++ * Wait for any list walkers to finish before freeing the ++ * list element. ++ */ ++ wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); ++ qib_mcast_qp_free(delp); + +- if (p) { +- /* +- * Wait for any list walkers to finish before freeing the +- * list element. +- */ +- wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); +- qib_mcast_qp_free(p); +- } + if (last) { + atomic_dec(&mcast->refcount); + wait_event(mcast->wait, !atomic_read(&mcast->refcount)); +@@ -355,11 +354,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) + dev->n_mcast_grps_allocated--; + spin_unlock_irq(&dev->n_mcast_grps_lock); + } +- +- ret = 0; +- +-bail: +- return ret; ++ return 0; + } + + int qib_mcast_tree_empty(struct qib_ibport *ibp) +diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c +index b4713cea1913..2d2915fdbf02 100644 +--- a/drivers/md/bcache/super.c ++++ b/drivers/md/bcache/super.c +@@ -1959,8 +1959,10 @@ static int __init bcache_init(void) + closure_debug_init(); + + bcache_major = register_blkdev(0, "bcache"); +- if (bcache_major < 0) ++ if (bcache_major < 0) { ++ unregister_reboot_notifier(&reboot); + return bcache_major; ++ } + + if (!(bcache_wq = create_workqueue("bcache")) || + !(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) || +diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h +index 0b2536247cf5..84e27708ad97 100644 +--- a/drivers/md/dm-exception-store.h ++++ b/drivers/md/dm-exception-store.h +@@ -70,7 +70,7 @@ struct dm_exception_store_type { + * Update the metadata with this exception. + */ + void (*commit_exception) (struct dm_exception_store *store, +- struct dm_exception *e, ++ struct dm_exception *e, int valid, + void (*callback) (void *, int success), + void *callback_context); + +diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c +index 2d2b1b7588d7..8f6d3ea55401 100644 +--- a/drivers/md/dm-snap-persistent.c ++++ b/drivers/md/dm-snap-persistent.c +@@ -646,7 +646,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store, + } + + static void persistent_commit_exception(struct dm_exception_store *store, +- struct dm_exception *e, ++ struct dm_exception *e, int valid, + void (*callback) (void *, int success), + void *callback_context) + { +@@ -655,6 +655,9 @@ static void persistent_commit_exception(struct dm_exception_store *store, + struct core_exception ce; + struct commit_callback *cb; + ++ if (!valid) ++ ps->valid = 0; ++ + ce.old_chunk = e->old_chunk; + ce.new_chunk = e->new_chunk; + write_exception(ps, ps->current_committed++, &ce); +diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c +index 1ce9a2586e41..31439d53cf7e 100644 +--- a/drivers/md/dm-snap-transient.c ++++ b/drivers/md/dm-snap-transient.c +@@ -52,12 +52,12 @@ static int transient_prepare_exception(struct dm_exception_store *store, + } + + static void transient_commit_exception(struct dm_exception_store *store, +- struct dm_exception *e, ++ struct dm_exception *e, int valid, + void (*callback) (void *, int success), + void *callback_context) + { + /* Just succeed */ +- callback(callback_context, 1); ++ callback(callback_context, valid); + } + + static void transient_usage(struct dm_exception_store *store, +diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c +index d892a05c84f4..dbd0f00f7395 100644 +--- a/drivers/md/dm-snap.c ++++ b/drivers/md/dm-snap.c +@@ -1388,8 +1388,9 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err) + dm_table_event(s->ti->table); + } + +-static void pending_complete(struct dm_snap_pending_exception *pe, int success) ++static void pending_complete(void *context, int success) + { ++ struct dm_snap_pending_exception *pe = context; + struct dm_exception *e; + struct dm_snapshot *s = pe->snap; + struct bio *origin_bios = NULL; +@@ -1459,24 +1460,13 @@ out: + free_pending_exception(pe); + } + +-static void commit_callback(void *context, int success) +-{ +- struct dm_snap_pending_exception *pe = context; +- +- pending_complete(pe, success); +-} +- + static void complete_exception(struct dm_snap_pending_exception *pe) + { + struct dm_snapshot *s = pe->snap; + +- if (unlikely(pe->copy_error)) +- pending_complete(pe, 0); +- +- else +- /* Update the metadata if we are persistent */ +- s->store->type->commit_exception(s->store, &pe->e, +- commit_callback, pe); ++ /* Update the metadata if we are persistent */ ++ s->store->type->commit_exception(s->store, &pe->e, !pe->copy_error, ++ pending_complete, pe); + } + + /* +diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c +index 43f6250baadd..4bf9211b2740 100644 +--- a/drivers/md/dm-thin-metadata.c ++++ b/drivers/md/dm-thin-metadata.c +@@ -1191,6 +1191,12 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd) + dm_block_t held_root; + + /* ++ * We commit to ensure the btree roots which we increment in a ++ * moment are up to date. ++ */ ++ __commit_transaction(pmd); ++ ++ /* + * Copy the superblock. + */ + dm_sm_inc_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION); +diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c +index ec56072c6326..295f74d4f0ab 100644 +--- a/drivers/md/dm-thin.c ++++ b/drivers/md/dm-thin.c +@@ -2281,7 +2281,7 @@ static void pool_postsuspend(struct dm_target *ti) + struct pool_c *pt = ti->private; + struct pool *pool = pt->pool; + +- cancel_delayed_work(&pool->waker); ++ cancel_delayed_work_sync(&pool->waker); + flush_workqueue(pool->wq); + (void) commit_or_fallback(pool); + } +diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c +index 6d7f4d950b8f..b07fcda9ca71 100644 +--- a/drivers/md/persistent-data/dm-btree.c ++++ b/drivers/md/persistent-data/dm-btree.c +@@ -235,6 +235,16 @@ static bool is_internal_level(struct dm_btree_info *info, struct frame *f) + return f->level < (info->levels - 1); + } + ++static void unlock_all_frames(struct del_stack *s) ++{ ++ struct frame *f; ++ ++ while (unprocessed_frames(s)) { ++ f = s->spine + s->top--; ++ dm_tm_unlock(s->tm, f->b); ++ } ++} ++ + int dm_btree_del(struct dm_btree_info *info, dm_block_t root) + { + int r; +@@ -290,9 +300,13 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root) + f->current_child = f->nr_children; + } + } +- + out: ++ if (r) { ++ /* cleanup all frames of del_stack */ ++ unlock_all_frames(s); ++ } + kfree(s); ++ + return r; + } + EXPORT_SYMBOL_GPL(dm_btree_del); +diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c +index 1f925e856974..46a984291b7d 100644 +--- a/drivers/media/dvb-core/dvb_frontend.c ++++ b/drivers/media/dvb-core/dvb_frontend.c +@@ -2195,9 +2195,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file, + dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", + __func__, c->delivery_system, fe->ops.info.type); + +- /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't +- * do it, it is done for it. */ +- info->caps |= FE_CAN_INVERSION_AUTO; ++ /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ ++ if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) ++ info->caps |= FE_CAN_INVERSION_AUTO; + err = 0; + break; + } +diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c +index a2631be7ffac..08e0f0dd8728 100644 +--- a/drivers/media/dvb-frontends/tda1004x.c ++++ b/drivers/media/dvb-frontends/tda1004x.c +@@ -903,9 +903,18 @@ static int tda1004x_get_fe(struct dvb_frontend *fe) + { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; + struct tda1004x_state* state = fe->demodulator_priv; ++ int status; + + dprintk("%s\n", __func__); + ++ status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); ++ if (status == -1) ++ return -EIO; ++ ++ /* Only update the properties cache if device is locked */ ++ if (!(status & 8)) ++ return 0; ++ + // inversion status + fe_params->inversion = INVERSION_OFF; + if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) +diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c +index 2e28c81a03ab..a5bee0d0d686 100644 +--- a/drivers/media/usb/gspca/ov534.c ++++ b/drivers/media/usb/gspca/ov534.c +@@ -1490,8 +1490,13 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_fract *tpf = &cp->timeperframe; + struct sd *sd = (struct sd *) gspca_dev; + +- /* Set requested framerate */ +- sd->frame_rate = tpf->denominator / tpf->numerator; ++ if (tpf->numerator == 0 || tpf->denominator == 0) ++ /* Set default framerate */ ++ sd->frame_rate = 30; ++ else ++ /* Set requested framerate */ ++ sd->frame_rate = tpf->denominator / tpf->numerator; ++ + if (gspca_dev->streaming) + set_frame_rate(gspca_dev); + +diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c +index 4cb511ccc5f6..22ea6aefd22f 100644 +--- a/drivers/media/usb/gspca/topro.c ++++ b/drivers/media/usb/gspca/topro.c +@@ -4791,7 +4791,11 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_fract *tpf = &cp->timeperframe; + int fr, i; + +- sd->framerate = tpf->denominator / tpf->numerator; ++ if (tpf->numerator == 0 || tpf->denominator == 0) ++ sd->framerate = 30; ++ else ++ sd->framerate = tpf->denominator / tpf->numerator; ++ + if (gspca_dev->streaming) + setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure)); + +diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c +index 885ba4a19a6c..ebb40a292d67 100644 +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -59,8 +59,7 @@ MODULE_ALIAS("mmc:block"); + #define INAND_CMD38_ARG_SECTRIM2 0x88 + #define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ + +-#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \ +- (req->cmd_flags & REQ_META)) && \ ++#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \ + (rq_data_dir(req) == WRITE)) + #define PACKED_CMD_VER 0x01 + #define PACKED_CMD_WR 0x02 +@@ -1300,13 +1299,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, + + /* + * Reliable writes are used to implement Forced Unit Access and +- * REQ_META accesses, and are supported only on MMCs. +- * +- * XXX: this really needs a good explanation of why REQ_META +- * is treated special. ++ * are supported only on MMCs. + */ +- bool do_rel_wr = ((req->cmd_flags & REQ_FUA) || +- (req->cmd_flags & REQ_META)) && ++ bool do_rel_wr = (req->cmd_flags & REQ_FUA) && + (rq_data_dir(req) == WRITE) && + (md->flags & MMC_BLK_REL_WR); + +diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c +index f4f3038c1df0..faeda85e78fa 100644 +--- a/drivers/mmc/host/mmci.c ++++ b/drivers/mmc/host/mmci.c +@@ -1740,7 +1740,7 @@ static struct amba_id mmci_ids[] = { + { + .id = 0x00280180, + .mask = 0x00ffffff, +- .data = &variant_u300, ++ .data = &variant_nomadik, + }, + { + .id = 0x00480180, +diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c +index c2d0559115d3..732a8ed571c2 100644 +--- a/drivers/net/can/sja1000/sja1000.c ++++ b/drivers/net/can/sja1000/sja1000.c +@@ -187,6 +187,9 @@ static void sja1000_start(struct net_device *dev) + /* clear interrupt flags */ + priv->read_reg(priv, SJA1000_IR); + ++ /* clear interrupt flags */ ++ priv->read_reg(priv, SJA1000_IR); ++ + /* leave reset mode */ + set_normal_mode(dev); + } +diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c +index 5f9a7ad9b964..d921416295ce 100644 +--- a/drivers/net/can/usb/ems_usb.c ++++ b/drivers/net/can/usb/ems_usb.c +@@ -118,6 +118,9 @@ MODULE_LICENSE("GPL v2"); + */ + #define EMS_USB_ARM7_CLOCK 8000000 + ++#define CPC_TX_QUEUE_TRIGGER_LOW 25 ++#define CPC_TX_QUEUE_TRIGGER_HIGH 35 ++ + /* + * CAN-Message representation in a CPC_MSG. Message object type is + * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or +@@ -279,6 +282,11 @@ static void ems_usb_read_interrupt_callback(struct urb *urb) + switch (urb->status) { + case 0: + dev->free_slots = dev->intr_in_buffer[1]; ++ if(dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH){ ++ if (netif_queue_stopped(netdev)){ ++ netif_wake_queue(netdev); ++ } ++ } + break; + + case -ECONNRESET: /* unlink */ +@@ -530,8 +538,6 @@ static void ems_usb_write_bulk_callback(struct urb *urb) + /* Release context */ + context->echo_index = MAX_TX_URBS; + +- if (netif_queue_stopped(netdev)) +- netif_wake_queue(netdev); + } + + /* +@@ -591,7 +597,7 @@ static int ems_usb_start(struct ems_usb *dev) + int err, i; + + dev->intr_in_buffer[0] = 0; +- dev->free_slots = 15; /* initial size */ ++ dev->free_slots = 50; /* initial size */ + + for (i = 0; i < MAX_RX_URBS; i++) { + struct urb *urb = NULL; +@@ -841,7 +847,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne + + /* Slow down tx path */ + if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS || +- dev->free_slots < 5) { ++ dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) { + netif_stop_queue(netdev); + } + } +diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c +index 76ef634caf6f..b84e713445d0 100644 +--- a/drivers/pci/pcie/aer/aerdrv.c ++++ b/drivers/pci/pcie/aer/aerdrv.c +@@ -262,7 +262,6 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) + rpc->rpd = dev; + INIT_WORK(&rpc->dpc_handler, aer_isr); + mutex_init(&rpc->rpc_mutex); +- init_waitqueue_head(&rpc->wait_release); + + /* Use PCIe bus function to store rpc into PCIe device */ + set_service_data(dev, rpc); +@@ -285,8 +284,7 @@ static void aer_remove(struct pcie_device *dev) + if (rpc->isr) + free_irq(dev->irq, dev); + +- wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); +- ++ flush_work(&rpc->dpc_handler); + aer_disable_rootport(rpc); + kfree(rpc); + set_service_data(dev, NULL); +diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h +index d12c77cd6991..3b8766e1e51b 100644 +--- a/drivers/pci/pcie/aer/aerdrv.h ++++ b/drivers/pci/pcie/aer/aerdrv.h +@@ -76,7 +76,6 @@ struct aer_rpc { + * recovery on the same + * root port hierarchy + */ +- wait_queue_head_t wait_release; + }; + + struct aer_broadcast_data { +diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c +index 0f4554e48cc5..a017aac0d7ed 100644 +--- a/drivers/pci/pcie/aer/aerdrv_core.c ++++ b/drivers/pci/pcie/aer/aerdrv_core.c +@@ -817,8 +817,6 @@ void aer_isr(struct work_struct *work) + while (get_e_source(rpc, &e_src)) + aer_isr_one_error(p_device, &e_src); + mutex_unlock(&rpc->rpc_mutex); +- +- wake_up(&rpc->wait_release); + } + + /** +diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c +index f7197a790341..eb402f4f0e2f 100644 +--- a/drivers/pci/xen-pcifront.c ++++ b/drivers/pci/xen-pcifront.c +@@ -51,7 +51,7 @@ struct pcifront_device { + }; + + struct pcifront_sd { +- int domain; ++ struct pci_sysdata sd; + struct pcifront_device *pdev; + }; + +@@ -65,7 +65,9 @@ static inline void pcifront_init_sd(struct pcifront_sd *sd, + unsigned int domain, unsigned int bus, + struct pcifront_device *pdev) + { +- sd->domain = domain; ++ /* Because we do not expose that information via XenBus. */ ++ sd->sd.node = first_online_node; ++ sd->sd.domain = domain; + sd->pdev = pdev; + } + +@@ -463,8 +465,8 @@ static int pcifront_scan_root(struct pcifront_device *pdev, + dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", + domain, bus); + +- bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); +- sd = kmalloc(sizeof(*sd), GFP_KERNEL); ++ bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL); ++ sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!bus_entry || !sd) { + err = -ENOMEM; + goto err_out; +diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c +index 3bed2f55cf7d..3ccadf631d45 100644 +--- a/drivers/power/wm831x_power.c ++++ b/drivers/power/wm831x_power.c +@@ -567,7 +567,7 @@ static int wm831x_power_probe(struct platform_device *pdev) + + irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "SYSLO")); + ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq, +- IRQF_TRIGGER_RISING, "System power low", ++ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "System power low", + power); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n", +@@ -577,7 +577,7 @@ static int wm831x_power_probe(struct platform_device *pdev) + + irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "PWR SRC")); + ret = request_threaded_irq(irq, NULL, wm831x_pwr_src_irq, +- IRQF_TRIGGER_RISING, "Power source", ++ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "Power source", + power); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request PWR SRC IRQ %d: %d\n", +@@ -590,7 +590,7 @@ static int wm831x_power_probe(struct platform_device *pdev) + platform_get_irq_byname(pdev, + wm831x_bat_irqs[i])); + ret = request_threaded_irq(irq, NULL, wm831x_bat_irq, +- IRQF_TRIGGER_RISING, ++ IRQF_TRIGGER_RISING | IRQF_ONESHOT, + wm831x_bat_irqs[i], + power); + if (ret != 0) { +diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c +index a2597e683e79..6a64e86e8ccd 100644 +--- a/drivers/s390/block/dasd_alias.c ++++ b/drivers/s390/block/dasd_alias.c +@@ -264,8 +264,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) + spin_unlock_irqrestore(&lcu->lock, flags); + cancel_work_sync(&lcu->suc_data.worker); + spin_lock_irqsave(&lcu->lock, flags); +- if (device == lcu->suc_data.device) ++ if (device == lcu->suc_data.device) { ++ dasd_put_device(device); + lcu->suc_data.device = NULL; ++ } + } + was_pending = 0; + if (device == lcu->ruac_data.device) { +@@ -273,8 +275,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) + was_pending = 1; + cancel_delayed_work_sync(&lcu->ruac_data.dwork); + spin_lock_irqsave(&lcu->lock, flags); +- if (device == lcu->ruac_data.device) ++ if (device == lcu->ruac_data.device) { ++ dasd_put_device(device); + lcu->ruac_data.device = NULL; ++ } + } + private->lcu = NULL; + spin_unlock_irqrestore(&lcu->lock, flags); +@@ -549,8 +553,10 @@ static void lcu_update_work(struct work_struct *work) + if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) { + DBF_DEV_EVENT(DBF_WARNING, device, "could not update" + " alias data in lcu (rc = %d), retry later", rc); +- schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); ++ if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ)) ++ dasd_put_device(device); + } else { ++ dasd_put_device(device); + lcu->ruac_data.device = NULL; + lcu->flags &= ~UPDATE_PENDING; + } +@@ -593,8 +599,10 @@ static int _schedule_lcu_update(struct alias_lcu *lcu, + */ + if (!usedev) + return -EINVAL; ++ dasd_get_device(usedev); + lcu->ruac_data.device = usedev; +- schedule_delayed_work(&lcu->ruac_data.dwork, 0); ++ if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0)) ++ dasd_put_device(usedev); + return 0; + } + +@@ -722,7 +730,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu, + ASCEBC((char *) &cqr->magic, 4); + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_RSCK; +- ccw->flags = 0 ; ++ ccw->flags = CCW_FLAG_SLI; + ccw->count = 16; + ccw->cda = (__u32)(addr_t) cqr->data; + ((char *)cqr->data)[0] = reason; +@@ -926,6 +934,7 @@ static void summary_unit_check_handling_work(struct work_struct *work) + /* 3. read new alias configuration */ + _schedule_lcu_update(lcu, device); + lcu->suc_data.device = NULL; ++ dasd_put_device(device); + spin_unlock_irqrestore(&lcu->lock, flags); + } + +@@ -985,6 +994,8 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, + } + lcu->suc_data.reason = reason; + lcu->suc_data.device = device; ++ dasd_get_device(device); + spin_unlock(&lcu->lock); +- schedule_work(&lcu->suc_data.worker); ++ if (!schedule_work(&lcu->suc_data.worker)) ++ dasd_put_device(device); + }; +diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h +index b52121358385..280e769a1686 100644 +--- a/drivers/scsi/megaraid/megaraid_sas.h ++++ b/drivers/scsi/megaraid/megaraid_sas.h +@@ -300,6 +300,8 @@ enum MR_EVT_ARGS { + MR_EVT_ARGS_GENERIC, + }; + ++ ++#define SGE_BUFFER_SIZE 4096 + /* + * define constants for device list query options + */ +diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c +index 78b4fe845245..e6dfa8108301 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_base.c ++++ b/drivers/scsi/megaraid/megaraid_sas_base.c +@@ -3602,7 +3602,7 @@ static int megasas_init_fw(struct megasas_instance *instance) + } + + instance->max_sectors_per_req = instance->max_num_sge * +- PAGE_SIZE / 512; ++ SGE_BUFFER_SIZE / 512; + if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) + instance->max_sectors_per_req = tmp_sectors; + +@@ -5051,6 +5051,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) + int i; + int error = 0; + compat_uptr_t ptr; ++ unsigned long local_raw_ptr; ++ u32 local_sense_off; ++ u32 local_sense_len; + + if (clear_user(ioc, sizeof(*ioc))) + return -EFAULT; +@@ -5068,9 +5071,15 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) + * sense_len is not null, so prepare the 64bit value under + * the same condition. + */ +- if (ioc->sense_len) { ++ if (get_user(local_raw_ptr, ioc->frame.raw) || ++ get_user(local_sense_off, &ioc->sense_off) || ++ get_user(local_sense_len, &ioc->sense_len)) ++ return -EFAULT; ++ ++ ++ if (local_sense_len) { + void __user **sense_ioc_ptr = +- (void __user **)(ioc->frame.raw + ioc->sense_off); ++ (void __user **)((u8*)local_raw_ptr + local_sense_off); + compat_uptr_t *sense_cioc_ptr = + (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off); + if (get_user(ptr, sense_cioc_ptr) || +diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c +index eba183c428cf..3643bbf5456d 100644 +--- a/drivers/scsi/ses.c ++++ b/drivers/scsi/ses.c +@@ -70,6 +70,7 @@ static int ses_probe(struct device *dev) + static int ses_recv_diag(struct scsi_device *sdev, int page_code, + void *buf, int bufflen) + { ++ int ret; + unsigned char cmd[] = { + RECEIVE_DIAGNOSTIC, + 1, /* Set PCV bit */ +@@ -78,9 +79,26 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code, + bufflen & 0xff, + 0 + }; ++ unsigned char recv_page_code; + +- return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, ++ ret = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, + NULL, SES_TIMEOUT, SES_RETRIES, NULL); ++ if (unlikely(!ret)) ++ return ret; ++ ++ recv_page_code = ((unsigned char *)buf)[0]; ++ ++ if (likely(recv_page_code == page_code)) ++ return ret; ++ ++ /* successful diagnostic but wrong page code. This happens to some ++ * USB devices, just print a message and pretend there was an error */ ++ ++ sdev_printk(KERN_ERR, sdev, ++ "Wrong diagnostic page; asked for %d got %u\n", ++ page_code, recv_page_code); ++ ++ return -EINVAL; + } + + static int ses_send_diag(struct scsi_device *sdev, int page_code, +@@ -436,7 +454,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, + if (desc_ptr) + desc_ptr += len; + +- if (addl_desc_ptr) ++ if (addl_desc_ptr && ++ /* only find additional descriptions for specific devices */ ++ (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || ++ type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE || ++ type_ptr[0] == ENCLOSURE_COMPONENT_SAS_EXPANDER || ++ /* these elements are optional */ ++ type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT || ++ type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT || ++ type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS)) + addl_desc_ptr += addl_desc_ptr[1] + 2; + + } +diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c +index d2ea64de92df..d6dab8adf60e 100644 +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1726,6 +1726,11 @@ static const struct usb_device_id acm_ids[] = { + }, + #endif + ++ /*Samsung phone in firmware update mode */ ++ { USB_DEVICE(0x04e8, 0x685d), ++ .driver_info = IGNORE_DEVICE, ++ }, ++ + /* Exclude Infineon Flash Loader utility */ + { USB_DEVICE(0x058b, 0x0041), + .driver_info = IGNORE_DEVICE, +diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c +index 89ba7cfba5bc..303f3b3fb65f 100644 +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -162,6 +162,8 @@ static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ + { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */ ++ { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ ++ { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ + { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ + { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ + { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index 81f6a572f016..9bab34cf01d4 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -315,6 +315,7 @@ static void option_instat_callback(struct urb *urb); + #define TOSHIBA_PRODUCT_G450 0x0d45 + + #define ALINK_VENDOR_ID 0x1e0e ++#define SIMCOM_PRODUCT_SIM7100E 0x9001 /* Yes, ALINK_VENDOR_ID */ + #define ALINK_PRODUCT_PH300 0x9100 + #define ALINK_PRODUCT_3GU 0x9200 + +@@ -615,6 +616,10 @@ static const struct option_blacklist_info zte_1255_blacklist = { + .reserved = BIT(3) | BIT(4), + }; + ++static const struct option_blacklist_info simcom_sim7100e_blacklist = { ++ .reserved = BIT(5) | BIT(6), ++}; ++ + static const struct option_blacklist_info telit_le910_blacklist = { + .sendsetup = BIT(0), + .reserved = BIT(1) | BIT(2), +@@ -1130,6 +1135,8 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, + { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, 0x6001, 0xff, 0xff, 0xff), /* 4G LTE usb-modem U901 */ ++ .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ +@@ -1645,6 +1652,8 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, + { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) }, + { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, ++ { USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E), ++ .driver_info = (kernel_ulong_t)&simcom_sim7100e_blacklist }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), + .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist + }, +diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c +index ee59b74768d9..beaa7cc4e857 100644 +--- a/drivers/virtio/virtio.c ++++ b/drivers/virtio/virtio.c +@@ -238,6 +238,7 @@ static int virtio_init(void) + static void __exit virtio_exit(void) + { + bus_unregister(&virtio_bus); ++ ida_destroy(&virtio_index_ida); + } + core_initcall(virtio_init); + module_exit(virtio_exit); +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 7360f03ddbe1..9612a01198df 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -2437,6 +2437,7 @@ int open_ctree(struct super_block *sb, + "unsupported option features (%Lx).\n", + (unsigned long long)features); + err = -EINVAL; ++ brelse(bh); + goto fail_alloc; + } + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index ae29b403a7e2..b5d13c4eea00 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -7477,15 +7477,28 @@ int btrfs_readpage(struct file *file, struct page *page) + static int btrfs_writepage(struct page *page, struct writeback_control *wbc) + { + struct extent_io_tree *tree; +- ++ struct inode *inode = page->mapping->host; ++ int ret; + + if (current->flags & PF_MEMALLOC) { + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return 0; + } ++ ++ /* ++ * If we are under memory pressure we will call this directly from the ++ * VM, we need to make sure we have the inode referenced for the ordered ++ * extent. If not just return like we didn't do anything. ++ */ ++ if (!igrab(inode)) { ++ redirty_page_for_writepage(wbc, page); ++ return AOP_WRITEPAGE_ACTIVATE; ++ } + tree = &BTRFS_I(page->mapping->host)->io_tree; +- return extent_write_full_page(tree, page, btrfs_get_extent, wbc); ++ ret = extent_write_full_page(tree, page, btrfs_get_extent, wbc); ++ btrfs_add_delayed_iput(inode); ++ return ret; + } + + static int btrfs_writepages(struct address_space *mapping, +@@ -8474,9 +8487,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, + /* + * 2 items for inode item and ref + * 2 items for dir items ++ * 1 item for updating parent inode item ++ * 1 item for the inline extent item + * 1 item for xattr if selinux is on + */ +- trans = btrfs_start_transaction(root, 5); ++ trans = btrfs_start_transaction(root, 7); + if (IS_ERR(trans)) + return PTR_ERR(trans); + +diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c +index 414c1b9eb896..3104e0eec816 100644 +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -1338,7 +1338,21 @@ static int read_symlink(struct send_ctx *sctx, + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) + goto out; +- BUG_ON(ret); ++ if (ret) { ++ /* ++ * An empty symlink inode. Can happen in rare error paths when ++ * creating a symlink (transaction committed before the inode ++ * eviction handler removed the symlink inode items and a crash ++ * happened in between or the subvol was snapshoted in between). ++ * Print an informative message to dmesg/syslog so that the user ++ * can delete the symlink. ++ */ ++ btrfs_err(root->fs_info, ++ "Found empty symlink inode %llu at root %llu", ++ ino, root->root_key.objectid); ++ ret = -EIO; ++ goto out; ++ } + + ei = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_file_extent_item); +diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c +index 32f35f187989..b58a9cbb9695 100644 +--- a/fs/hostfs/hostfs_kern.c ++++ b/fs/hostfs/hostfs_kern.c +@@ -720,15 +720,13 @@ static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, + + init_special_inode(inode, mode, dev); + err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); +- if (!err) ++ if (err) + goto out_free; + + err = read_name(inode, name); + __putname(name); + if (err) + goto out_put; +- if (err) +- goto out_put; + + d_instantiate(dentry, inode); + return 0; +diff --git a/fs/lockd/host.c b/fs/lockd/host.c +index 969d589c848d..b5f3c3ab0d5f 100644 +--- a/fs/lockd/host.c ++++ b/fs/lockd/host.c +@@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, + atomic_inc(&nsm->sm_count); + else { + host = NULL; +- nsm = nsm_get_handle(ni->sap, ni->salen, ++ nsm = nsm_get_handle(ni->net, ni->sap, ni->salen, + ni->hostname, ni->hostname_len); + if (unlikely(nsm == NULL)) { + dprintk("lockd: %s failed; no nsm handle\n", +@@ -534,17 +534,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, + + /** + * nlm_host_rebooted - Release all resources held by rebooted host ++ * @net: network namespace + * @info: pointer to decoded results of NLM_SM_NOTIFY call + * + * We were notified that the specified host has rebooted. Release + * all resources held by that peer. + */ +-void nlm_host_rebooted(const struct nlm_reboot *info) ++void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info) + { + struct nsm_handle *nsm; + struct nlm_host *host; + +- nsm = nsm_reboot_lookup(info); ++ nsm = nsm_reboot_lookup(net, info); + if (unlikely(nsm == NULL)) + return; + +diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c +index 6ae664b489af..13fac49aff7f 100644 +--- a/fs/lockd/mon.c ++++ b/fs/lockd/mon.c +@@ -51,7 +51,6 @@ struct nsm_res { + }; + + static const struct rpc_program nsm_program; +-static LIST_HEAD(nsm_handles); + static DEFINE_SPINLOCK(nsm_lock); + + /* +@@ -259,33 +258,35 @@ void nsm_unmonitor(const struct nlm_host *host) + } + } + +-static struct nsm_handle *nsm_lookup_hostname(const char *hostname, +- const size_t len) ++static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles, ++ const char *hostname, const size_t len) + { + struct nsm_handle *nsm; + +- list_for_each_entry(nsm, &nsm_handles, sm_link) ++ list_for_each_entry(nsm, nsm_handles, sm_link) + if (strlen(nsm->sm_name) == len && + memcmp(nsm->sm_name, hostname, len) == 0) + return nsm; + return NULL; + } + +-static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap) ++static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles, ++ const struct sockaddr *sap) + { + struct nsm_handle *nsm; + +- list_for_each_entry(nsm, &nsm_handles, sm_link) ++ list_for_each_entry(nsm, nsm_handles, sm_link) + if (rpc_cmp_addr(nsm_addr(nsm), sap)) + return nsm; + return NULL; + } + +-static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv) ++static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles, ++ const struct nsm_private *priv) + { + struct nsm_handle *nsm; + +- list_for_each_entry(nsm, &nsm_handles, sm_link) ++ list_for_each_entry(nsm, nsm_handles, sm_link) + if (memcmp(nsm->sm_priv.data, priv->data, + sizeof(priv->data)) == 0) + return nsm; +@@ -350,6 +351,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, + + /** + * nsm_get_handle - Find or create a cached nsm_handle ++ * @net: network namespace + * @sap: pointer to socket address of handle to find + * @salen: length of socket address + * @hostname: pointer to C string containing hostname to find +@@ -362,11 +364,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, + * @hostname cannot be found in the handle cache. Returns NULL if + * an error occurs. + */ +-struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, ++struct nsm_handle *nsm_get_handle(const struct net *net, ++ const struct sockaddr *sap, + const size_t salen, const char *hostname, + const size_t hostname_len) + { + struct nsm_handle *cached, *new = NULL; ++ struct lockd_net *ln = net_generic(net, lockd_net_id); + + if (hostname && memchr(hostname, '/', hostname_len) != NULL) { + if (printk_ratelimit()) { +@@ -381,9 +385,10 @@ retry: + spin_lock(&nsm_lock); + + if (nsm_use_hostnames && hostname != NULL) +- cached = nsm_lookup_hostname(hostname, hostname_len); ++ cached = nsm_lookup_hostname(&ln->nsm_handles, ++ hostname, hostname_len); + else +- cached = nsm_lookup_addr(sap); ++ cached = nsm_lookup_addr(&ln->nsm_handles, sap); + + if (cached != NULL) { + atomic_inc(&cached->sm_count); +@@ -397,7 +402,7 @@ retry: + } + + if (new != NULL) { +- list_add(&new->sm_link, &nsm_handles); ++ list_add(&new->sm_link, &ln->nsm_handles); + spin_unlock(&nsm_lock); + dprintk("lockd: created nsm_handle for %s (%s)\n", + new->sm_name, new->sm_addrbuf); +@@ -414,19 +419,22 @@ retry: + + /** + * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle ++ * @net: network namespace + * @info: pointer to NLMPROC_SM_NOTIFY arguments + * + * Returns a matching nsm_handle if found in the nsm cache. The returned + * nsm_handle's reference count is bumped. Otherwise returns NULL if some + * error occurred. + */ +-struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info) ++struct nsm_handle *nsm_reboot_lookup(const struct net *net, ++ const struct nlm_reboot *info) + { + struct nsm_handle *cached; ++ struct lockd_net *ln = net_generic(net, lockd_net_id); + + spin_lock(&nsm_lock); + +- cached = nsm_lookup_priv(&info->priv); ++ cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv); + if (unlikely(cached == NULL)) { + spin_unlock(&nsm_lock); + dprintk("lockd: never saw rebooted peer '%.*s' before\n", +diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h +index 5010b55628b4..414da99744e9 100644 +--- a/fs/lockd/netns.h ++++ b/fs/lockd/netns.h +@@ -16,6 +16,7 @@ struct lockd_net { + spinlock_t nsm_clnt_lock; + unsigned int nsm_users; + struct rpc_clnt *nsm_clnt; ++ struct list_head nsm_handles; + }; + + extern int lockd_net_id; +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 7a318480ab7a..ce05c60ff06d 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -583,6 +583,7 @@ static int lockd_init_net(struct net *net) + INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender); + INIT_LIST_HEAD(&ln->grace_list); + spin_lock_init(&ln->nsm_clnt_lock); ++ INIT_LIST_HEAD(&ln->nsm_handles); + return 0; + } + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index b147d1ae71fd..09c576f26c7b 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, + return rpc_system_err; + } + +- nlm_host_rebooted(argp); ++ nlm_host_rebooted(SVC_NET(rqstp), argp); + return rpc_success; + } + +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index 21171f0c6477..fb26b9f522e7 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, + return rpc_system_err; + } + +- nlm_host_rebooted(argp); ++ nlm_host_rebooted(SVC_NET(rqstp), argp); + return rpc_success; + } + +diff --git a/fs/namei.c b/fs/namei.c +index 157c3dbacf6c..c87e15ee9255 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -2917,6 +2917,10 @@ opened: + goto exit_fput; + } + out: ++ if (unlikely(error > 0)) { ++ WARN_ON(1); ++ error = -EINVAL; ++ } + if (got_write) + mnt_drop_write(nd->path.mnt); + path_put(&save_parent); +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index cfa9163b3bb7..2bdaf57c82d0 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -1452,7 +1452,7 @@ restart: + } + spin_unlock(&state->state_lock); + nfs4_put_open_state(state); +- clear_bit(NFS4CLNT_RECLAIM_NOGRACE, ++ clear_bit(NFS_STATE_RECLAIM_NOGRACE, + &state->flags); + spin_lock(&sp->so_lock); + goto restart; +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 9f285fb9bab3..b86db1236c7c 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -170,7 +170,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) + if (!priv->task) + return ERR_PTR(-ESRCH); + +- mm = mm_access(priv->task, PTRACE_MODE_READ); ++ mm = mm_access(priv->task, PTRACE_MODE_READ_FSCREDS); + if (!mm || IS_ERR(mm)) + return mm; + down_read(&mm->mmap_sem); +@@ -1044,7 +1044,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, + if (!pm.buffer) + goto out_task; + +- mm = mm_access(task, PTRACE_MODE_READ); ++ mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); + ret = PTR_ERR(mm); + if (!mm || IS_ERR(mm)) + goto out_free; +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index 56123a6f462e..123c19890b14 100644 +--- a/fs/proc/task_nommu.c ++++ b/fs/proc/task_nommu.c +@@ -223,7 +223,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) + if (!priv->task) + return ERR_PTR(-ESRCH); + +- mm = mm_access(priv->task, PTRACE_MODE_READ); ++ mm = mm_access(priv->task, PTRACE_MODE_READ_FSCREDS); + if (!mm || IS_ERR(mm)) { + put_task_struct(priv->task); + priv->task = NULL; +diff --git a/fs/splice.c b/fs/splice.c +index f183f1342c01..3b94a6bba29f 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -949,6 +949,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, + + splice_from_pipe_begin(sd); + do { ++ cond_resched(); + ret = splice_from_pipe_next(pipe, sd); + if (ret > 0) + ret = splice_from_pipe_feed(pipe, sd, actor); +@@ -1189,7 +1190,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, + long ret, bytes; + umode_t i_mode; + size_t len; +- int i, flags; ++ int i, flags, more; + + /* + * We require the input being a regular file, as we don't want to +@@ -1232,6 +1233,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, + * Don't block on output, we have to drain the direct pipe. + */ + sd->flags &= ~SPLICE_F_NONBLOCK; ++ more = sd->flags & SPLICE_F_MORE; + + while (len) { + size_t read_len; +@@ -1245,6 +1247,15 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, + sd->total_len = read_len; + + /* ++ * If more data is pending, set SPLICE_F_MORE ++ * If this is the last data and SPLICE_F_MORE was not set ++ * initially, clears it. ++ */ ++ if (read_len < len) ++ sd->flags |= SPLICE_F_MORE; ++ else if (!more) ++ sd->flags &= ~SPLICE_F_MORE; ++ /* + * NOTE: nonblocking mode only applies to the input. We + * must not do the output in nonblocking mode as then we + * could get stuck data in the internal pipe: +diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h +index 9a33c5f7e126..f6c229e2bffa 100644 +--- a/include/linux/enclosure.h ++++ b/include/linux/enclosure.h +@@ -29,7 +29,11 @@ + /* A few generic types ... taken from ses-2 */ + enum enclosure_component_type { + ENCLOSURE_COMPONENT_DEVICE = 0x01, ++ ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS = 0x07, ++ ENCLOSURE_COMPONENT_SCSI_TARGET_PORT = 0x14, ++ ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT = 0x15, + ENCLOSURE_COMPONENT_ARRAY_DEVICE = 0x17, ++ ENCLOSURE_COMPONENT_SAS_EXPANDER = 0x18, + }; + + /* ses-2 common element status */ +diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h +index dcaad79f54ed..0adf073f13b3 100644 +--- a/include/linux/lockd/lockd.h ++++ b/include/linux/lockd/lockd.h +@@ -236,7 +236,8 @@ void nlm_rebind_host(struct nlm_host *); + struct nlm_host * nlm_get_host(struct nlm_host *); + void nlm_shutdown_hosts(void); + void nlm_shutdown_hosts_net(struct net *net); +-void nlm_host_rebooted(const struct nlm_reboot *); ++void nlm_host_rebooted(const struct net *net, ++ const struct nlm_reboot *); + + /* + * Host monitoring +@@ -244,11 +245,13 @@ void nlm_host_rebooted(const struct nlm_reboot *); + int nsm_monitor(const struct nlm_host *host); + void nsm_unmonitor(const struct nlm_host *host); + +-struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, ++struct nsm_handle *nsm_get_handle(const struct net *net, ++ const struct sockaddr *sap, + const size_t salen, + const char *hostname, + const size_t hostname_len); +-struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info); ++struct nsm_handle *nsm_reboot_lookup(const struct net *net, ++ const struct nlm_reboot *info); + void nsm_release(struct nsm_handle *nsm); + + /* +diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h +index fc01d5cb4cf1..7d2021d3ee08 100644 +--- a/include/linux/nfs_fs.h ++++ b/include/linux/nfs_fs.h +@@ -578,9 +578,7 @@ static inline void nfs3_forget_cached_acls(struct inode *inode) + + static inline loff_t nfs_size_to_loff_t(__u64 size) + { +- if (size > (__u64) OFFSET_MAX - 1) +- return OFFSET_MAX - 1; +- return (loff_t) size; ++ return min_t(u64, size, OFFSET_MAX); + } + + static inline ino_t +diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h +index ba605015c4d8..0b2d0cbe0bab 100644 +--- a/include/linux/tracepoint.h ++++ b/include/linux/tracepoint.h +@@ -14,8 +14,11 @@ + * See the file COPYING for more details. + */ + ++#include + #include + #include ++#include ++#include + #include + #include + +@@ -126,6 +129,9 @@ static inline void tracepoint_synchronize_unregister(void) + void *it_func; \ + void *__data; \ + \ ++ if (!cpu_online(raw_smp_processor_id())) \ ++ return; \ ++ \ + if (!(cond)) \ + return; \ + prercu; \ +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index 686760024572..6278e4d32612 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -6,8 +6,8 @@ + #include + #include + +-extern void unix_inflight(struct file *fp); +-extern void unix_notinflight(struct file *fp); ++extern void unix_inflight(struct user_struct *user, struct file *fp); ++extern void unix_notinflight(struct user_struct *user, struct file *fp); + extern void unix_gc(void); + extern void wait_for_unix_gc(void); + extern struct sock *unix_get_socket(struct file *filp); +diff --git a/include/net/scm.h b/include/net/scm.h +index 8de2d37d2077..d00cd43a990c 100644 +--- a/include/net/scm.h ++++ b/include/net/scm.h +@@ -21,6 +21,7 @@ struct scm_creds { + struct scm_fp_list { + short count; + short max; ++ struct user_struct *user; + struct file *fp[SCM_MAX_FD]; + }; + +diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c +index a79d267b64ec..7b0d31b67f6a 100644 +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -1229,6 +1229,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) + if (!desc) + return NULL; + ++ chip_bus_lock(desc); + raw_spin_lock_irqsave(&desc->lock, flags); + + /* +@@ -1242,7 +1243,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) + if (!action) { + WARN(1, "Trying to free already-free IRQ %d\n", irq); + raw_spin_unlock_irqrestore(&desc->lock, flags); +- ++ chip_bus_sync_unlock(desc); + return NULL; + } + +@@ -1265,6 +1266,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) + #endif + + raw_spin_unlock_irqrestore(&desc->lock, flags); ++ chip_bus_sync_unlock(desc); + + unregister_handler_proc(irq, action); + +@@ -1338,9 +1340,7 @@ void free_irq(unsigned int irq, void *dev_id) + desc->affinity_notify = NULL; + #endif + +- chip_bus_lock(desc); + kfree(__free_irq(irq, dev_id)); +- chip_bus_sync_unlock(desc); + } + EXPORT_SYMBOL(free_irq); + +diff --git a/kernel/resource.c b/kernel/resource.c +index d7386986e10e..b8422b135b68 100644 +--- a/kernel/resource.c ++++ b/kernel/resource.c +@@ -961,9 +961,10 @@ struct resource * __request_region(struct resource *parent, + if (!conflict) + break; + if (conflict != parent) { +- parent = conflict; +- if (!(conflict->flags & IORESOURCE_BUSY)) ++ if (!(conflict->flags & IORESOURCE_BUSY)) { ++ parent = conflict; + continue; ++ } + } + if (conflict->flags & flags & IORESOURCE_MUXED) { + add_wait_queue(&muxed_resource_wait, &wait); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index c771f2547bef..f234c84d36c8 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -1587,7 +1587,6 @@ out: + */ + int wake_up_process(struct task_struct *p) + { +- WARN_ON(task_is_stopped_or_traced(p)); + return try_to_wake_up(p, TASK_NORMAL, 0); + } + EXPORT_SYMBOL(wake_up_process); +diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c +index ce033c7aa2e8..9cff0ab82b63 100644 +--- a/kernel/time/posix-clock.c ++++ b/kernel/time/posix-clock.c +@@ -69,10 +69,10 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf, + static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) + { + struct posix_clock *clk = get_posix_clock(fp); +- int result = 0; ++ unsigned int result = 0; + + if (!clk) +- return -ENODEV; ++ return POLLERR; + + if (clk->ops.poll) + result = clk->ops.poll(clk, fp, wait); +diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c +index ab21b8c66535..cb73c4e0741e 100644 +--- a/kernel/trace/ring_buffer.c ++++ b/kernel/trace/ring_buffer.c +@@ -1948,12 +1948,6 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) + goto again; + } + +-static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer) +-{ +- cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp; +- cpu_buffer->reader_page->read = 0; +-} +- + static void rb_inc_iter(struct ring_buffer_iter *iter) + { + struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer; +@@ -3591,7 +3585,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) + + /* Finally update the reader page to the new head */ + cpu_buffer->reader_page = reader; +- rb_reset_reader_page(cpu_buffer); ++ cpu_buffer->reader_page->read = 0; + + if (overwrite != cpu_buffer->last_overrun) { + cpu_buffer->lost_events = overwrite - cpu_buffer->last_overrun; +@@ -3601,6 +3595,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) + goto again; + + out: ++ /* Update the read_stamp on the first event */ ++ if (reader && reader->read == 0) ++ cpu_buffer->read_stamp = reader->page->time_stamp; ++ + arch_spin_unlock(&cpu_buffer->lock); + local_irq_restore(flags); + +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index 5a898f15bfc6..7d054b7671ec 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -602,7 +602,8 @@ t_next(struct seq_file *m, void *v, loff_t *pos) + * The ftrace subsystem is for showing formats only. + * They can not be enabled or disabled via the event files. + */ +- if (call->class && call->class->reg) ++ if (call->class && call->class->reg && ++ !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) + return file; + } + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index fa927fd5778d..fe7c4b91d2e7 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -1450,13 +1450,13 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, + timer_stats_timer_set_start_info(&dwork->timer); + + dwork->wq = wq; +- /* timer isn't guaranteed to run in this cpu, record earlier */ +- if (cpu == WORK_CPU_UNBOUND) +- cpu = raw_smp_processor_id(); + dwork->cpu = cpu; + timer->expires = jiffies + delay; + +- add_timer_on(timer, cpu); ++ if (unlikely(cpu != WORK_CPU_UNBOUND)) ++ add_timer_on(timer, cpu); ++ else ++ add_timer(timer); + } + + /** +diff --git a/lib/devres.c b/lib/devres.c +index 823533138fa0..20afaf181b27 100644 +--- a/lib/devres.c ++++ b/lib/devres.c +@@ -423,7 +423,7 @@ void pcim_iounmap_regions(struct pci_dev *pdev, int mask) + if (!iomap) + return; + +- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { ++ for (i = 0; i < PCIM_IOMAP_MAX; i++) { + if (!(mask & (1 << i))) + continue; + +diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c +index e3bea2e0821a..025ced8fbb57 100644 +--- a/net/ceph/messenger.c ++++ b/net/ceph/messenger.c +@@ -2277,7 +2277,7 @@ static int read_partial_message(struct ceph_connection *con) + con->in_base_pos = -front_len - middle_len - data_len - + sizeof(m->footer); + con->in_tag = CEPH_MSGR_TAG_READY; +- return 0; ++ return 1; + } else if ((s64)seq - (s64)con->in_seq > 1) { + pr_err("read_partial_message bad seq %lld expected %lld\n", + seq, con->in_seq + 1); +@@ -2310,7 +2310,7 @@ static int read_partial_message(struct ceph_connection *con) + sizeof(m->footer); + con->in_tag = CEPH_MSGR_TAG_READY; + con->in_seq++; +- return 0; ++ return 1; + } + + BUG_ON(!con->in_msg); +diff --git a/net/core/scm.c b/net/core/scm.c +index dbc6bfcdf446..7a6cf8351cde 100644 +--- a/net/core/scm.c ++++ b/net/core/scm.c +@@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + *fplp = fpl; + fpl->count = 0; + fpl->max = SCM_MAX_FD; ++ fpl->user = NULL; + } + fpp = &fpl->fp[fpl->count]; + +@@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) + *fpp++ = file; + fpl->count++; + } ++ ++ if (!fpl->user) ++ fpl->user = get_uid(current_user()); ++ + return num; + } + +@@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm) + scm->fp = NULL; + for (i=fpl->count-1; i>=0; i--) + fput(fpl->fp[i]); ++ free_uid(fpl->user); + kfree(fpl); + } + } +@@ -337,6 +343,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) + for (i = 0; i < fpl->count; i++) + get_file(fpl->fp[i]); + new_fpl->max = new_fpl->count; ++ new_fpl->user = get_uid(fpl->user); + } + return new_fpl; + } +diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c +index 89aacfd2756d..9ba6d8c7c793 100644 +--- a/net/mac80211/mesh_pathtbl.c ++++ b/net/mac80211/mesh_pathtbl.c +@@ -747,10 +747,8 @@ void mesh_plink_broken(struct sta_info *sta) + static void mesh_path_node_reclaim(struct rcu_head *rp) + { + struct mpath_node *node = container_of(rp, struct mpath_node, rcu); +- struct ieee80211_sub_if_data *sdata = node->mpath->sdata; + + del_timer_sync(&node->mpath->timer); +- atomic_dec(&sdata->u.mesh.mpaths); + kfree(node->mpath); + kfree(node); + } +@@ -758,8 +756,9 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) + /* needs to be called with the corresponding hashwlock taken */ + static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) + { +- struct mesh_path *mpath; +- mpath = node->mpath; ++ struct mesh_path *mpath = node->mpath; ++ struct ieee80211_sub_if_data *sdata = node->mpath->sdata; ++ + spin_lock(&mpath->state_lock); + mpath->flags |= MESH_PATH_RESOLVING; + if (mpath->is_gate) +@@ -767,6 +766,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) + hlist_del_rcu(&node->list); + call_rcu(&node->rcu, mesh_path_node_reclaim); + spin_unlock(&mpath->state_lock); ++ atomic_dec(&sdata->u.mesh.mpaths); + atomic_dec(&tbl->entries); + } + +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 0283baedcdfb..9dc979abb461 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -311,6 +311,21 @@ static void death_by_timeout(unsigned long ul_conntrack) + nf_ct_put(ct); + } + ++static inline bool ++nf_ct_key_equal(struct nf_conntrack_tuple_hash *h, ++ const struct nf_conntrack_tuple *tuple, ++ u16 zone) ++{ ++ struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); ++ ++ /* A conntrack can be recreated with the equal tuple, ++ * so we need to check that the conntrack is confirmed ++ */ ++ return nf_ct_tuple_equal(tuple, &h->tuple) && ++ nf_ct_zone(ct) == zone && ++ nf_ct_is_confirmed(ct); ++} ++ + /* + * Warning : + * - Caller must take a reference on returned object +@@ -332,8 +347,7 @@ ____nf_conntrack_find(struct net *net, u16 zone, + local_bh_disable(); + begin: + hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) { +- if (nf_ct_tuple_equal(tuple, &h->tuple) && +- nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) { ++ if (nf_ct_key_equal(h, tuple, zone)) { + NF_CT_STAT_INC(net, found); + local_bh_enable(); + return h; +@@ -380,8 +394,7 @@ begin: + !atomic_inc_not_zero(&ct->ct_general.use))) + h = NULL; + else { +- if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) || +- nf_ct_zone(ct) != zone)) { ++ if (unlikely(!nf_ct_key_equal(h, tuple, zone))) { + nf_ct_put(ct); + goto begin; + } +diff --git a/net/rds/connection.c b/net/rds/connection.c +index e88bf3976e54..642ad42c416b 100644 +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -177,12 +177,6 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, + } + } + +- if (trans == NULL) { +- kmem_cache_free(rds_conn_slab, conn); +- conn = ERR_PTR(-ENODEV); +- goto out; +- } +- + conn->c_trans = trans; + + ret = trans->conn_alloc(conn, gfp); +diff --git a/net/rds/send.c b/net/rds/send.c +index 88eace57dd6b..31c9fa464b11 100644 +--- a/net/rds/send.c ++++ b/net/rds/send.c +@@ -955,11 +955,13 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, + release_sock(sk); + } + +- /* racing with another thread binding seems ok here */ ++ lock_sock(sk); + if (daddr == 0 || rs->rs_bound_addr == 0) { ++ release_sock(sk); + ret = -ENOTCONN; /* XXX not a great errno */ + goto out; + } ++ release_sock(sk); + + /* size of rm including all sgs */ + ret = rds_rm_size(msg, payload_len); +diff --git a/net/rfkill/core.c b/net/rfkill/core.c +index 1cec5e4f3a5e..6563cc04c578 100644 +--- a/net/rfkill/core.c ++++ b/net/rfkill/core.c +@@ -51,7 +51,6 @@ + struct rfkill { + spinlock_t lock; + +- const char *name; + enum rfkill_type type; + + unsigned long state; +@@ -75,6 +74,7 @@ struct rfkill { + struct delayed_work poll_work; + struct work_struct uevent_work; + struct work_struct sync_work; ++ char name[]; + }; + #define to_rfkill(d) container_of(d, struct rfkill, dev) + +@@ -871,14 +871,14 @@ struct rfkill * __must_check rfkill_alloc(const char *name, + if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES)) + return NULL; + +- rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL); ++ rfkill = kzalloc(sizeof(*rfkill) + strlen(name) + 1, GFP_KERNEL); + if (!rfkill) + return NULL; + + spin_lock_init(&rfkill->lock); + INIT_LIST_HEAD(&rfkill->node); + rfkill->type = type; +- rfkill->name = name; ++ strcpy(rfkill->name, name); + rfkill->ops = ops; + rfkill->data = ops_data; + +@@ -1088,17 +1088,6 @@ static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait) + return res; + } + +-static bool rfkill_readable(struct rfkill_data *data) +-{ +- bool r; +- +- mutex_lock(&data->mtx); +- r = !list_empty(&data->events); +- mutex_unlock(&data->mtx); +- +- return r; +-} +- + static ssize_t rfkill_fop_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) + { +@@ -1115,8 +1104,11 @@ static ssize_t rfkill_fop_read(struct file *file, char __user *buf, + goto out; + } + mutex_unlock(&data->mtx); ++ /* since we re-check and it just compares pointers, ++ * using !list_empty() without locking isn't a problem ++ */ + ret = wait_event_interruptible(data->read_wait, +- rfkill_readable(data)); ++ !list_empty(&data->events)); + mutex_lock(&data->mtx); + + if (ret) +diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c +index 231b71944c52..a4266b9b2429 100644 +--- a/net/sunrpc/cache.c ++++ b/net/sunrpc/cache.c +@@ -1221,7 +1221,7 @@ int qword_get(char **bpp, char *dest, int bufsize) + if (bp[0] == '\\' && bp[1] == 'x') { + /* HEX STRING */ + bp += 2; +- while (len < bufsize) { ++ while (len < bufsize - 1) { + int h, l; + + h = hex_to_bin(bp[0]); +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index a673c1f4f638..8f118c7c19e1 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1466,7 +1466,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) + UNIXCB(skb).fp = NULL; + + for (i = scm->fp->count-1; i >= 0; i--) +- unix_notinflight(scm->fp->fp[i]); ++ unix_notinflight(scm->fp->user, scm->fp->fp[i]); + } + + static void unix_destruct_scm(struct sk_buff *skb) +@@ -1531,7 +1531,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) + return -ENOMEM; + + for (i = scm->fp->count - 1; i >= 0; i--) +- unix_inflight(scm->fp->fp[i]); ++ unix_inflight(scm->fp->user, scm->fp->fp[i]); + return max_level; + } + +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 06730fe6ad9d..a72182d6750f 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -122,7 +122,7 @@ struct sock *unix_get_socket(struct file *filp) + * descriptor if it is for an AF_UNIX socket. + */ + +-void unix_inflight(struct file *fp) ++void unix_inflight(struct user_struct *user, struct file *fp) + { + struct sock *s = unix_get_socket(fp); + +@@ -139,11 +139,11 @@ void unix_inflight(struct file *fp) + } + unix_tot_inflight++; + } +- fp->f_cred->user->unix_inflight++; ++ user->unix_inflight++; + spin_unlock(&unix_gc_lock); + } + +-void unix_notinflight(struct file *fp) ++void unix_notinflight(struct user_struct *user, struct file *fp) + { + struct sock *s = unix_get_socket(fp); + +@@ -157,7 +157,7 @@ void unix_notinflight(struct file *fp) + list_del_init(&u->link); + unix_tot_inflight--; + } +- fp->f_cred->user->unix_inflight--; ++ user->unix_inflight--; + spin_unlock(&unix_gc_lock); + } + +diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c +index 9c22317778eb..ee625e3a56ba 100644 +--- a/scripts/recordmcount.c ++++ b/scripts/recordmcount.c +@@ -189,6 +189,20 @@ static void *mmap_file(char const *fname) + addr = umalloc(sb.st_size); + uread(fd_map, addr, sb.st_size); + } ++ if (sb.st_nlink != 1) { ++ /* file is hard-linked, break the hard link */ ++ close(fd_map); ++ if (unlink(fname) < 0) { ++ perror(fname); ++ fail_file(); ++ } ++ fd_map = open(fname, O_RDWR | O_CREAT, sb.st_mode); ++ if (fd_map < 0) { ++ perror(fname); ++ fail_file(); ++ } ++ uwrite(fd_map, addr, sb.st_size); ++ } + return addr; + } + +diff --git a/tools/Makefile b/tools/Makefile +index 41067f304215..b82a15b92b1c 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -22,6 +22,10 @@ help: + @echo ' from the kernel command line to build and install one of' + @echo ' the tools above' + @echo '' ++ @echo ' $$ make tools/all' ++ @echo '' ++ @echo ' builds all tools.' ++ @echo '' + @echo ' $$ make tools/install' + @echo '' + @echo ' installs all tools.' +@@ -50,6 +54,10 @@ selftests: FORCE + turbostat x86_energy_perf_policy: FORCE + $(call descend,power/x86/$@) + ++all: cgroup cpupower firewire lguest \ ++ perf selftests turbostat usb \ ++ virtio vm net x86_energy_perf_policy ++ + cpupower_install: + $(call descend,power/$(@:_install=),install) + +diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c +index ea475cd03511..ca2d05a07b57 100644 +--- a/virt/kvm/async_pf.c ++++ b/virt/kvm/async_pf.c +@@ -158,7 +158,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn, + * do alloc nowait since if we are going to sleep anyway we + * may as well sleep faulting in page + */ +- work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT); ++ work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT | __GFP_NOWARN); + if (!work) + return 0; + diff --git a/patch/kernel/odroidc1-default/patch-3.10.99-100.patch b/patch/kernel/odroidc1-default/patch-3.10.99-100.patch new file mode 100644 index 0000000000..da39546c5f --- /dev/null +++ b/patch/kernel/odroidc1-default/patch-3.10.99-100.patch @@ -0,0 +1,1156 @@ +diff --git a/Makefile b/Makefile +index f1e6491fd7d8..40d4d3bf52c3 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 99 ++SUBLEVEL = 100 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S +index c9305ef1d411..e73982b93537 100644 +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -422,6 +422,7 @@ ENTRY(ia32_syscall) + /*CFI_REL_OFFSET cs,CS-RIP*/ + CFI_REL_OFFSET rip,RIP-RIP + PARAVIRT_ADJUST_EXCEPTION_FRAME ++ ASM_CLAC /* Do this early to minimize exposure */ + SWAPGS + /* + * No need to follow this irqs on/off section: the syscall +diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c +index ec94e11807dc..ca0805633f26 100644 +--- a/arch/x86/kernel/acpi/sleep.c ++++ b/arch/x86/kernel/acpi/sleep.c +@@ -16,6 +16,7 @@ + #include + #include + ++#include + #include "../../realmode/rm/wakeup.h" + #include "sleep.h" + +@@ -96,7 +97,13 @@ int acpi_suspend_lowlevel(void) + saved_magic = 0x123456789abcdef0L; + #endif /* CONFIG_64BIT */ + ++ /* ++ * Pause/unpause graph tracing around do_suspend_lowlevel as it has ++ * inconsistent call/return info after it jumps to the wakeup vector. ++ */ ++ pause_graph_tracing(); + do_suspend_lowlevel(); ++ unpause_graph_tracing(); + return 0; + } + +diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c +index 04e7db668362..f3f0801a0e81 100644 +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -673,19 +673,18 @@ static int ata_ioc32(struct ata_port *ap) + int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, + int cmd, void __user *arg) + { +- int val = -EINVAL, rc = -EINVAL; ++ unsigned long val; ++ int rc = -EINVAL; + unsigned long flags; + + switch (cmd) { +- case ATA_IOC_GET_IO32: ++ case HDIO_GET_32BIT: + spin_lock_irqsave(ap->lock, flags); + val = ata_ioc32(ap); + spin_unlock_irqrestore(ap->lock, flags); +- if (copy_to_user(arg, &val, 1)) +- return -EFAULT; +- return 0; ++ return put_user(val, (unsigned long __user *)arg); + +- case ATA_IOC_SET_IO32: ++ case HDIO_SET_32BIT: + val = (unsigned long) arg; + rc = 0; + spin_lock_irqsave(ap->lock, flags); +diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c +index 88cd940ece63..453c816b4537 100644 +--- a/drivers/edac/edac_mc_sysfs.c ++++ b/drivers/edac/edac_mc_sysfs.c +@@ -973,21 +973,26 @@ nomem: + */ + int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) + { ++ char *name; + int i, err; + + /* + * The memory controller needs its own bus, in order to avoid + * namespace conflicts at /sys/bus/edac. + */ +- mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); +- if (!mci->bus->name) ++ name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); ++ if (!name) + return -ENOMEM; + ++ mci->bus->name = name; ++ + edac_dbg(0, "creating bus %s\n", mci->bus->name); + + err = bus_register(mci->bus); +- if (err < 0) ++ if (err < 0) { ++ kfree(name); + return err; ++ } + + /* get the /sys/devices/system/edac subsys reference */ + mci->dev.type = &mci_attr_type; +@@ -1071,7 +1076,8 @@ fail: + fail2: + device_unregister(&mci->dev); + bus_unregister(mci->bus); +- kfree(mci->bus->name); ++ kfree(name); ++ + return err; + } + +@@ -1102,10 +1108,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) + + void edac_unregister_sysfs(struct mem_ctl_info *mci) + { ++ const char *name = mci->bus->name; ++ + edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); + device_unregister(&mci->dev); + bus_unregister(mci->bus); +- kfree(mci->bus->name); ++ kfree(name); + } + + static void mc_attr_release(struct device *dev) +diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c +index 313ccaf25f49..62834322b337 100644 +--- a/drivers/gpu/drm/ast/ast_main.c ++++ b/drivers/gpu/drm/ast/ast_main.c +@@ -124,7 +124,7 @@ static int ast_get_dram_info(struct drm_device *dev) + } while (ast_read32(ast, 0x10000) != 0x01); + data = ast_read32(ast, 0x10004); + +- if (data & 0x400) ++ if (data & 0x40) + ast->dram_bus_width = 16; + else + ast->dram_bus_width = 32; +diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c +index bb166849aa6e..f0bac68254b7 100644 +--- a/drivers/gpu/drm/radeon/radeon_sa.c ++++ b/drivers/gpu/drm/radeon/radeon_sa.c +@@ -349,13 +349,8 @@ int radeon_sa_bo_new(struct radeon_device *rdev, + /* see if we can skip over some allocations */ + } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); + +- for (i = 0; i < RADEON_NUM_RINGS; ++i) +- radeon_fence_ref(fences[i]); +- + spin_unlock(&sa_manager->wq.lock); + r = radeon_fence_wait_any(rdev, fences, false); +- for (i = 0; i < RADEON_NUM_RINGS; ++i) +- radeon_fence_unref(&fences[i]); + spin_lock(&sa_manager->wq.lock); + /* if we have nothing to wait for block */ + if (r == -ENOENT && block) { +diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c +index 2a1b6e037e1a..0134ba32a057 100644 +--- a/drivers/mtd/ubi/upd.c ++++ b/drivers/mtd/ubi/upd.c +@@ -193,7 +193,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, + vol->changing_leb = 1; + vol->ch_lnum = req->lnum; + +- vol->upd_buf = vmalloc(req->bytes); ++ vol->upd_buf = vmalloc(ALIGN((int)req->bytes, ubi->min_io_size)); + if (!vol->upd_buf) + return -ENOMEM; + +diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c +index 303f3b3fb65f..84b770461655 100644 +--- a/drivers/usb/serial/cp210x.c ++++ b/drivers/usb/serial/cp210x.c +@@ -164,6 +164,7 @@ static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */ + { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ + { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ ++ { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ + { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ + { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ + { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index 9bab34cf01d4..24366a2afea6 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -271,6 +271,7 @@ static void option_instat_callback(struct urb *urb); + #define TELIT_PRODUCT_UE910_V2 0x1012 + #define TELIT_PRODUCT_LE922_USBCFG0 0x1042 + #define TELIT_PRODUCT_LE922_USBCFG3 0x1043 ++#define TELIT_PRODUCT_LE922_USBCFG5 0x1045 + #define TELIT_PRODUCT_LE920 0x1200 + #define TELIT_PRODUCT_LE910 0x1201 + +@@ -1140,6 +1141,8 @@ static const struct usb_device_id option_ids[] = { + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ ++ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9003), /* Quectel UC20 */ ++ .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), +@@ -1191,6 +1194,8 @@ static const struct usb_device_id option_ids[] = { + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, ++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff), ++ .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), + .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), +diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c +index d17c5d72cd29..4c86850bd627 100644 +--- a/fs/cifs/cifssmb.c ++++ b/fs/cifs/cifssmb.c +@@ -1389,11 +1389,10 @@ openRetry: + * current bigbuf. + */ + static int +-cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ++discard_remaining_data(struct TCP_Server_Info *server) + { + unsigned int rfclen = get_rfc1002_length(server->smallbuf); + int remaining = rfclen + 4 - server->total_read; +- struct cifs_readdata *rdata = mid->callback_data; + + while (remaining > 0) { + int length; +@@ -1407,10 +1406,20 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) + remaining -= length; + } + +- dequeue_mid(mid, rdata->result); + return 0; + } + ++static int ++cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ++{ ++ int length; ++ struct cifs_readdata *rdata = mid->callback_data; ++ ++ length = discard_remaining_data(server); ++ dequeue_mid(mid, rdata->result); ++ return length; ++} ++ + int + cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) + { +@@ -1439,6 +1448,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) + return length; + server->total_read += length; + ++ if (server->ops->is_status_pending && ++ server->ops->is_status_pending(buf, server, 0)) { ++ discard_remaining_data(server); ++ return -1; ++ } ++ + /* Was the SMB read successful? */ + rdata->result = server->ops->map_error(buf, false); + if (rdata->result != 0) { +diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking +index 3ea36554107f..8918ac905a3b 100644 +--- a/fs/jffs2/README.Locking ++++ b/fs/jffs2/README.Locking +@@ -2,10 +2,6 @@ + JFFS2 LOCKING DOCUMENTATION + --------------------------- + +-At least theoretically, JFFS2 does not require the Big Kernel Lock +-(BKL), which was always helpfully obtained for it by Linux 2.4 VFS +-code. It has its own locking, as described below. +- + This document attempts to describe the existing locking rules for + JFFS2. It is not expected to remain perfectly up to date, but ought to + be fairly close. +@@ -69,6 +65,7 @@ Ordering constraints: + any f->sem held. + 2. Never attempt to lock two file mutexes in one thread. + No ordering rules have been made for doing so. ++ 3. Never lock a page cache page with f->sem held. + + + erase_completion_lock spinlock +diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c +index a3750f902adc..c1f04947d7dc 100644 +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -49,7 +49,8 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) + + + static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, +- struct jffs2_inode_cache *ic) ++ struct jffs2_inode_cache *ic, ++ int *dir_hardlinks) + { + struct jffs2_full_dirent *fd; + +@@ -68,19 +69,21 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, + dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", + fd->name, fd->ino, ic->ino); + jffs2_mark_node_obsolete(c, fd->raw); ++ /* Clear the ic/raw union so it doesn't cause problems later. */ ++ fd->ic = NULL; + continue; + } + ++ /* From this point, fd->raw is no longer used so we can set fd->ic */ ++ fd->ic = child_ic; ++ child_ic->pino_nlink++; ++ /* If we appear (at this stage) to have hard-linked directories, ++ * set a flag to trigger a scan later */ + if (fd->type == DT_DIR) { +- if (child_ic->pino_nlink) { +- JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", +- fd->name, fd->ino, ic->ino); +- /* TODO: What do we do about it? */ +- } else { +- child_ic->pino_nlink = ic->ino; +- } +- } else +- child_ic->pino_nlink++; ++ child_ic->flags |= INO_FLAGS_IS_DIR; ++ if (child_ic->pino_nlink > 1) ++ *dir_hardlinks = 1; ++ } + + dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); + /* Can't free scan_dents so far. We might need them in pass 2 */ +@@ -94,8 +97,7 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, + */ + static int jffs2_build_filesystem(struct jffs2_sb_info *c) + { +- int ret; +- int i; ++ int ret, i, dir_hardlinks = 0; + struct jffs2_inode_cache *ic; + struct jffs2_full_dirent *fd; + struct jffs2_full_dirent *dead_fds = NULL; +@@ -119,7 +121,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) + /* Now scan the directory tree, increasing nlink according to every dirent found. */ + for_each_inode(i, c, ic) { + if (ic->scan_dents) { +- jffs2_build_inode_pass1(c, ic); ++ jffs2_build_inode_pass1(c, ic, &dir_hardlinks); + cond_resched(); + } + } +@@ -155,6 +157,20 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) + } + + dbg_fsbuild("pass 2a complete\n"); ++ ++ if (dir_hardlinks) { ++ /* If we detected directory hardlinks earlier, *hopefully* ++ * they are gone now because some of the links were from ++ * dead directories which still had some old dirents lying ++ * around and not yet garbage-collected, but which have ++ * been discarded above. So clear the pino_nlink field ++ * in each directory, so that the final scan below can ++ * print appropriate warnings. */ ++ for_each_inode(i, c, ic) { ++ if (ic->flags & INO_FLAGS_IS_DIR) ++ ic->pino_nlink = 0; ++ } ++ } + dbg_fsbuild("freeing temporary data structures\n"); + + /* Finally, we can scan again and free the dirent structs */ +@@ -162,6 +178,33 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) + while(ic->scan_dents) { + fd = ic->scan_dents; + ic->scan_dents = fd->next; ++ /* We do use the pino_nlink field to count nlink of ++ * directories during fs build, so set it to the ++ * parent ino# now. Now that there's hopefully only ++ * one. */ ++ if (fd->type == DT_DIR) { ++ if (!fd->ic) { ++ /* We'll have complained about it and marked the coresponding ++ raw node obsolete already. Just skip it. */ ++ continue; ++ } ++ ++ /* We *have* to have set this in jffs2_build_inode_pass1() */ ++ BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR)); ++ ++ /* We clear ic->pino_nlink ∀ directories' ic *only* if dir_hardlinks ++ * is set. Otherwise, we know this should never trigger anyway, so ++ * we don't do the check. And ic->pino_nlink still contains the nlink ++ * value (which is 1). */ ++ if (dir_hardlinks && fd->ic->pino_nlink) { ++ JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n", ++ fd->name, fd->ino, ic->ino, fd->ic->pino_nlink); ++ /* Should we unlink it from its previous parent? */ ++ } ++ ++ /* For directories, ic->pino_nlink holds that parent inode # */ ++ fd->ic->pino_nlink = ic->ino; ++ } + jffs2_free_full_dirent(fd); + } + ic->scan_dents = NULL; +@@ -240,11 +283,7 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, + + /* Reduce nlink of the child. If it's now zero, stick it on the + dead_fds list to be cleaned up later. Else just free the fd */ +- +- if (fd->type == DT_DIR) +- child_ic->pino_nlink = 0; +- else +- child_ic->pino_nlink--; ++ child_ic->pino_nlink--; + + if (!child_ic->pino_nlink) { + dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n", +diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c +index 1506673c087e..60ef3fb707ff 100644 +--- a/fs/jffs2/file.c ++++ b/fs/jffs2/file.c +@@ -138,39 +138,33 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + struct page *pg; + struct inode *inode = mapping->host; + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); +- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); +- struct jffs2_raw_inode ri; +- uint32_t alloc_len = 0; + pgoff_t index = pos >> PAGE_CACHE_SHIFT; + uint32_t pageofs = index << PAGE_CACHE_SHIFT; + int ret = 0; + +- jffs2_dbg(1, "%s()\n", __func__); +- +- if (pageofs > inode->i_size) { +- ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, +- ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); +- if (ret) +- return ret; +- } +- +- mutex_lock(&f->sem); + pg = grab_cache_page_write_begin(mapping, index, flags); +- if (!pg) { +- if (alloc_len) +- jffs2_complete_reservation(c); +- mutex_unlock(&f->sem); ++ if (!pg) + return -ENOMEM; +- } + *pagep = pg; + +- if (alloc_len) { ++ jffs2_dbg(1, "%s()\n", __func__); ++ ++ if (pageofs > inode->i_size) { + /* Make new hole frag from old EOF to new page */ ++ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); ++ struct jffs2_raw_inode ri; + struct jffs2_full_dnode *fn; ++ uint32_t alloc_len; + + jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", + (unsigned int)inode->i_size, pageofs); + ++ ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, ++ ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); ++ if (ret) ++ goto out_page; ++ ++ mutex_lock(&f->sem); + memset(&ri, 0, sizeof(ri)); + + ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); +@@ -197,6 +191,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + if (IS_ERR(fn)) { + ret = PTR_ERR(fn); + jffs2_complete_reservation(c); ++ mutex_unlock(&f->sem); + goto out_page; + } + ret = jffs2_add_full_dnode_to_inode(c, f, fn); +@@ -211,10 +206,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + jffs2_complete_reservation(c); ++ mutex_unlock(&f->sem); + goto out_page; + } + jffs2_complete_reservation(c); + inode->i_size = pageofs; ++ mutex_unlock(&f->sem); + } + + /* +@@ -223,18 +220,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, + * case of a short-copy. + */ + if (!PageUptodate(pg)) { ++ mutex_lock(&f->sem); + ret = jffs2_do_readpage_nolock(inode, pg); ++ mutex_unlock(&f->sem); + if (ret) + goto out_page; + } +- mutex_unlock(&f->sem); + jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); + return ret; + + out_page: + unlock_page(pg); + page_cache_release(pg); +- mutex_unlock(&f->sem); + return ret; + } + +diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c +index 5a2dec2b064c..95d5880a63ee 100644 +--- a/fs/jffs2/gc.c ++++ b/fs/jffs2/gc.c +@@ -1296,14 +1296,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era + BUG_ON(start > orig_start); + } + +- /* First, use readpage() to read the appropriate page into the page cache */ +- /* Q: What happens if we actually try to GC the _same_ page for which commit_write() +- * triggered garbage collection in the first place? +- * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the +- * page OK. We'll actually write it out again in commit_write, which is a little +- * suboptimal, but at least we're correct. +- */ ++ /* The rules state that we must obtain the page lock *before* f->sem, so ++ * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's ++ * actually going to *change* so we're safe; we only allow reading. ++ * ++ * It is important to note that jffs2_write_begin() will ensure that its ++ * page is marked Uptodate before allocating space. That means that if we ++ * end up here trying to GC the *same* page that jffs2_write_begin() is ++ * trying to write out, read_cache_page() will not deadlock. */ ++ mutex_unlock(&f->sem); + pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); ++ mutex_lock(&f->sem); + + if (IS_ERR(pg_ptr)) { + pr_warn("read_cache_page() returned error: %ld\n", +diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h +index fa35ff79ab35..0637271f3770 100644 +--- a/fs/jffs2/nodelist.h ++++ b/fs/jffs2/nodelist.h +@@ -194,6 +194,7 @@ struct jffs2_inode_cache { + #define INO_STATE_CLEARING 6 /* In clear_inode() */ + + #define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ ++#define INO_FLAGS_IS_DIR 0x02 /* is a directory */ + + #define RAWNODE_CLASS_INODE_CACHE 0 + #define RAWNODE_CLASS_XATTR_DATUM 1 +@@ -249,7 +250,10 @@ struct jffs2_readinode_info + + struct jffs2_full_dirent + { +- struct jffs2_raw_node_ref *raw; ++ union { ++ struct jffs2_raw_node_ref *raw; ++ struct jffs2_inode_cache *ic; /* Just during part of build */ ++ }; + struct jffs2_full_dirent *next; + uint32_t version; + uint32_t ino; /* == zero for unlink */ +diff --git a/fs/locks.c b/fs/locks.c +index 0274c953b07d..f7b1de7e6735 100644 +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -1852,7 +1852,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, + goto out; + } + +-again: + error = flock_to_posix_lock(filp, file_lock, &flock); + if (error) + goto out; +@@ -1883,19 +1882,22 @@ again: + * Attempt to detect a close/fcntl race and recover by + * releasing the lock that was just acquired. + */ +- /* +- * we need that spin_lock here - it prevents reordering between +- * update of inode->i_flock and check for it done in close(). +- * rcu_read_lock() wouldn't do. +- */ +- spin_lock(¤t->files->file_lock); +- f = fcheck(fd); +- spin_unlock(¤t->files->file_lock); +- if (!error && f != filp && flock.l_type != F_UNLCK) { +- flock.l_type = F_UNLCK; +- goto again; ++ if (!error && file_lock->fl_type != F_UNLCK) { ++ /* ++ * We need that spin_lock here - it prevents reordering between ++ * update of inode->i_flock and check for it done in ++ * close(). rcu_read_lock() wouldn't do. ++ */ ++ spin_lock(¤t->files->file_lock); ++ f = fcheck(fd); ++ spin_unlock(¤t->files->file_lock); ++ if (f != filp) { ++ file_lock->fl_type = F_UNLCK; ++ error = do_lock_file_wait(filp, cmd, file_lock); ++ WARN_ON_ONCE(error); ++ error = -EBADF; ++ } + } +- + out: + locks_free_lock(file_lock); + return error; +@@ -1970,7 +1972,6 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, + goto out; + } + +-again: + error = flock64_to_posix_lock(filp, file_lock, &flock); + if (error) + goto out; +@@ -2001,14 +2002,22 @@ again: + * Attempt to detect a close/fcntl race and recover by + * releasing the lock that was just acquired. + */ +- spin_lock(¤t->files->file_lock); +- f = fcheck(fd); +- spin_unlock(¤t->files->file_lock); +- if (!error && f != filp && flock.l_type != F_UNLCK) { +- flock.l_type = F_UNLCK; +- goto again; ++ if (!error && file_lock->fl_type != F_UNLCK) { ++ /* ++ * We need that spin_lock here - it prevents reordering between ++ * update of inode->i_flock and check for it done in ++ * close(). rcu_read_lock() wouldn't do. ++ */ ++ spin_lock(¤t->files->file_lock); ++ f = fcheck(fd); ++ spin_unlock(¤t->files->file_lock); ++ if (f != filp) { ++ file_lock->fl_type = F_UNLCK; ++ error = do_lock_file_wait(filp, cmd, file_lock); ++ WARN_ON_ONCE(error); ++ error = -EBADF; ++ } + } +- + out: + locks_free_lock(file_lock); + return error; +diff --git a/include/linux/ata.h b/include/linux/ata.h +index ee0bd9524055..f60ffe29b3a1 100644 +--- a/include/linux/ata.h ++++ b/include/linux/ata.h +@@ -477,8 +477,8 @@ enum ata_tf_protocols { + }; + + enum ata_ioctls { +- ATA_IOC_GET_IO32 = 0x309, +- ATA_IOC_SET_IO32 = 0x324, ++ ATA_IOC_GET_IO32 = 0x309, /* HDIO_GET_32BIT */ ++ ATA_IOC_SET_IO32 = 0x324, /* HDIO_SET_32BIT */ + }; + + /* core structures */ +diff --git a/include/linux/libata.h b/include/linux/libata.h +index 8ad0771b88ab..8017e5c459cf 100644 +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -666,7 +666,7 @@ struct ata_device { + union { + u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ + u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ +- }; ++ } ____cacheline_aligned; + + /* DEVSLP Timing Variables from Identify Device Data Log */ + u8 devslp_timing[ATA_LOG_DEVSLP_SIZE]; +diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c +index 2bb95a7a8809..c14565bde887 100644 +--- a/sound/core/control_compat.c ++++ b/sound/core/control_compat.c +@@ -170,6 +170,19 @@ struct snd_ctl_elem_value32 { + unsigned char reserved[128]; + }; + ++#ifdef CONFIG_X86_X32 ++/* x32 has a different alignment for 64bit values from ia32 */ ++struct snd_ctl_elem_value_x32 { ++ struct snd_ctl_elem_id id; ++ unsigned int indirect; /* bit-field causes misalignment */ ++ union { ++ s32 integer[128]; ++ unsigned char data[512]; ++ s64 integer64[64]; ++ } value; ++ unsigned char reserved[128]; ++}; ++#endif /* CONFIG_X86_X32 */ + + /* get the value type and count of the control */ + static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, +@@ -219,9 +232,11 @@ static int get_elem_size(int type, int count) + + static int copy_ctl_value_from_user(struct snd_card *card, + struct snd_ctl_elem_value *data, +- struct snd_ctl_elem_value32 __user *data32, ++ void __user *userdata, ++ void __user *valuep, + int *typep, int *countp) + { ++ struct snd_ctl_elem_value32 __user *data32 = userdata; + int i, type, size; + int uninitialized_var(count); + unsigned int indirect; +@@ -239,8 +254,9 @@ static int copy_ctl_value_from_user(struct snd_card *card, + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + for (i = 0; i < count; i++) { ++ s32 __user *intp = valuep; + int val; +- if (get_user(val, &data32->value.integer[i])) ++ if (get_user(val, &intp[i])) + return -EFAULT; + data->value.integer.value[i] = val; + } +@@ -250,8 +266,7 @@ static int copy_ctl_value_from_user(struct snd_card *card, + printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); + return -EINVAL; + } +- if (copy_from_user(data->value.bytes.data, +- data32->value.data, size)) ++ if (copy_from_user(data->value.bytes.data, valuep, size)) + return -EFAULT; + } + +@@ -261,7 +276,8 @@ static int copy_ctl_value_from_user(struct snd_card *card, + } + + /* restore the value to 32bit */ +-static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, ++static int copy_ctl_value_to_user(void __user *userdata, ++ void __user *valuep, + struct snd_ctl_elem_value *data, + int type, int count) + { +@@ -270,22 +286,22 @@ static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, + if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + for (i = 0; i < count; i++) { ++ s32 __user *intp = valuep; + int val; + val = data->value.integer.value[i]; +- if (put_user(val, &data32->value.integer[i])) ++ if (put_user(val, &intp[i])) + return -EFAULT; + } + } else { + size = get_elem_size(type, count); +- if (copy_to_user(data32->value.data, +- data->value.bytes.data, size)) ++ if (copy_to_user(valuep, data->value.bytes.data, size)) + return -EFAULT; + } + return 0; + } + +-static int snd_ctl_elem_read_user_compat(struct snd_card *card, +- struct snd_ctl_elem_value32 __user *data32) ++static int ctl_elem_read_user(struct snd_card *card, ++ void __user *userdata, void __user *valuep) + { + struct snd_ctl_elem_value *data; + int err, type, count; +@@ -294,7 +310,9 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card, + if (data == NULL) + return -ENOMEM; + +- if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) ++ err = copy_ctl_value_from_user(card, data, userdata, valuep, ++ &type, &count); ++ if (err < 0) + goto error; + + snd_power_lock(card); +@@ -303,14 +321,15 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card, + err = snd_ctl_elem_read(card, data); + snd_power_unlock(card); + if (err >= 0) +- err = copy_ctl_value_to_user(data32, data, type, count); ++ err = copy_ctl_value_to_user(userdata, valuep, data, ++ type, count); + error: + kfree(data); + return err; + } + +-static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, +- struct snd_ctl_elem_value32 __user *data32) ++static int ctl_elem_write_user(struct snd_ctl_file *file, ++ void __user *userdata, void __user *valuep) + { + struct snd_ctl_elem_value *data; + struct snd_card *card = file->card; +@@ -320,7 +339,9 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, + if (data == NULL) + return -ENOMEM; + +- if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) ++ err = copy_ctl_value_from_user(card, data, userdata, valuep, ++ &type, &count); ++ if (err < 0) + goto error; + + snd_power_lock(card); +@@ -329,12 +350,39 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, + err = snd_ctl_elem_write(card, file, data); + snd_power_unlock(card); + if (err >= 0) +- err = copy_ctl_value_to_user(data32, data, type, count); ++ err = copy_ctl_value_to_user(userdata, valuep, data, ++ type, count); + error: + kfree(data); + return err; + } + ++static int snd_ctl_elem_read_user_compat(struct snd_card *card, ++ struct snd_ctl_elem_value32 __user *data32) ++{ ++ return ctl_elem_read_user(card, data32, &data32->value); ++} ++ ++static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, ++ struct snd_ctl_elem_value32 __user *data32) ++{ ++ return ctl_elem_write_user(file, data32, &data32->value); ++} ++ ++#ifdef CONFIG_X86_X32 ++static int snd_ctl_elem_read_user_x32(struct snd_card *card, ++ struct snd_ctl_elem_value_x32 __user *data32) ++{ ++ return ctl_elem_read_user(card, data32, &data32->value); ++} ++ ++static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file, ++ struct snd_ctl_elem_value_x32 __user *data32) ++{ ++ return ctl_elem_write_user(file, data32, &data32->value); ++} ++#endif /* CONFIG_X86_X32 */ ++ + /* add or replace a user control */ + static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, + struct snd_ctl_elem_info32 __user *data32, +@@ -393,6 +441,10 @@ enum { + SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32), + SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32), + SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32), ++#ifdef CONFIG_X86_X32 ++ SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32), ++ SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32), ++#endif /* CONFIG_X86_X32 */ + }; + + static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +@@ -431,6 +483,12 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns + return snd_ctl_elem_add_compat(ctl, argp, 0); + case SNDRV_CTL_IOCTL_ELEM_REPLACE32: + return snd_ctl_elem_add_compat(ctl, argp, 1); ++#ifdef CONFIG_X86_X32 ++ case SNDRV_CTL_IOCTL_ELEM_READ_X32: ++ return snd_ctl_elem_read_user_x32(ctl->card, argp); ++ case SNDRV_CTL_IOCTL_ELEM_WRITE_X32: ++ return snd_ctl_elem_write_user_x32(ctl, argp); ++#endif /* CONFIG_X86_X32 */ + } + + down_read(&snd_ioctl_rwsem); +diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c +index 5268c1f58c25..09a89094dcf7 100644 +--- a/sound/core/rawmidi_compat.c ++++ b/sound/core/rawmidi_compat.c +@@ -94,9 +94,58 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, + return 0; + } + ++#ifdef CONFIG_X86_X32 ++/* X32 ABI has 64bit timespec and 64bit alignment */ ++struct snd_rawmidi_status_x32 { ++ s32 stream; ++ u32 rsvd; /* alignment */ ++ struct timespec tstamp; ++ u32 avail; ++ u32 xruns; ++ unsigned char reserved[16]; ++} __attribute__((packed)); ++ ++#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst)) ++ ++static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile, ++ struct snd_rawmidi_status_x32 __user *src) ++{ ++ int err; ++ struct snd_rawmidi_status status; ++ ++ if (rfile->output == NULL) ++ return -EINVAL; ++ if (get_user(status.stream, &src->stream)) ++ return -EFAULT; ++ ++ switch (status.stream) { ++ case SNDRV_RAWMIDI_STREAM_OUTPUT: ++ err = snd_rawmidi_output_status(rfile->output, &status); ++ break; ++ case SNDRV_RAWMIDI_STREAM_INPUT: ++ err = snd_rawmidi_input_status(rfile->input, &status); ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (err < 0) ++ return err; ++ ++ if (put_timespec(&status.tstamp, &src->tstamp) || ++ put_user(status.avail, &src->avail) || ++ put_user(status.xruns, &src->xruns)) ++ return -EFAULT; ++ ++ return 0; ++} ++#endif /* CONFIG_X86_X32 */ ++ + enum { + SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), + SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), ++#ifdef CONFIG_X86_X32 ++ SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32), ++#endif /* CONFIG_X86_X32 */ + }; + + static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +@@ -115,6 +164,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign + return snd_rawmidi_ioctl_params_compat(rfile, argp); + case SNDRV_RAWMIDI_IOCTL_STATUS32: + return snd_rawmidi_ioctl_status_compat(rfile, argp); ++#ifdef CONFIG_X86_X32 ++ case SNDRV_RAWMIDI_IOCTL_STATUS_X32: ++ return snd_rawmidi_ioctl_status_x32(rfile, argp); ++#endif /* CONFIG_X86_X32 */ + } + return -ENOIOCTLCMD; + } +diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c +index 8d4d5e853efe..ab774954c985 100644 +--- a/sound/core/seq/oss/seq_oss.c ++++ b/sound/core/seq/oss/seq_oss.c +@@ -150,8 +150,6 @@ odev_release(struct inode *inode, struct file *file) + if ((dp = file->private_data) == NULL) + return 0; + +- snd_seq_oss_drain_write(dp); +- + mutex_lock(®ister_mutex); + snd_seq_oss_release(dp); + mutex_unlock(®ister_mutex); +diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h +index c0154a959d55..2464112b08ad 100644 +--- a/sound/core/seq/oss/seq_oss_device.h ++++ b/sound/core/seq/oss/seq_oss_device.h +@@ -131,7 +131,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co + unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait); + + void snd_seq_oss_reset(struct seq_oss_devinfo *dp); +-void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp); + + /* */ + void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); +diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c +index b3f39b5ed742..f9e09e458227 100644 +--- a/sound/core/seq/oss/seq_oss_init.c ++++ b/sound/core/seq/oss/seq_oss_init.c +@@ -457,23 +457,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp) + + + /* +- * Wait until the queue is empty (if we don't have nonblock) +- */ +-void +-snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) +-{ +- if (! dp->timer->running) +- return; +- if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) && +- dp->writeq) { +- debug_printk(("syncing..\n")); +- while (snd_seq_oss_writeq_sync(dp->writeq)) +- ; +- } +-} +- +- +-/* + * reset sequencer devices + */ + void +diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c +index e05802ae6e1b..2e908225d754 100644 +--- a/sound/core/timer_compat.c ++++ b/sound/core/timer_compat.c +@@ -70,13 +70,14 @@ static int snd_timer_user_status_compat(struct file *file, + struct snd_timer_status32 __user *_status) + { + struct snd_timer_user *tu; +- struct snd_timer_status status; ++ struct snd_timer_status32 status; + + tu = file->private_data; + if (snd_BUG_ON(!tu->timeri)) + return -ENXIO; + memset(&status, 0, sizeof(status)); +- status.tstamp = tu->tstamp; ++ status.tstamp.tv_sec = tu->tstamp.tv_sec; ++ status.tstamp.tv_nsec = tu->tstamp.tv_nsec; + status.resolution = snd_timer_resolution(tu->timeri); + status.lost = tu->timeri->lost; + status.overrun = tu->overrun; +@@ -88,12 +89,21 @@ static int snd_timer_user_status_compat(struct file *file, + return 0; + } + ++#ifdef CONFIG_X86_X32 ++/* X32 ABI has the same struct as x86-64 */ ++#define snd_timer_user_status_x32(file, s) \ ++ snd_timer_user_status(file, s) ++#endif /* CONFIG_X86_X32 */ ++ + /* + */ + + enum { + SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), + SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), ++#ifdef CONFIG_X86_X32 ++ SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status), ++#endif /* CONFIG_X86_X32 */ + }; + + static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +@@ -122,6 +132,10 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns + return snd_timer_user_info_compat(file, argp); + case SNDRV_TIMER_IOCTL_STATUS32: + return snd_timer_user_status_compat(file, argp); ++#ifdef CONFIG_X86_X32 ++ case SNDRV_TIMER_IOCTL_STATUS_X32: ++ return snd_timer_user_status_x32(file, argp); ++#endif /* CONFIG_X86_X32 */ + } + return -ENOIOCTLCMD; + } +diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c +index 94084cdb130c..9a281f45eb9c 100644 +--- a/sound/pci/rme9652/hdsp.c ++++ b/sound/pci/rme9652/hdsp.c +@@ -2923,7 +2923,7 @@ static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl + { + struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); + +- ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp); ++ ucontrol->value.integer.value[0] = hdsp_dds_offset(hdsp); + return 0; + } + +@@ -2935,7 +2935,7 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; +- val = ucontrol->value.enumerated.item[0]; ++ val = ucontrol->value.integer.value[0]; + spin_lock_irq(&hdsp->lock); + if (val != hdsp_dds_offset(hdsp)) + change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0; +diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c +index dd910d249987..8444098d2a8e 100644 +--- a/sound/pci/rme9652/hdspm.c ++++ b/sound/pci/rme9652/hdspm.c +@@ -1423,6 +1423,9 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) + { + u64 n; + ++ if (snd_BUG_ON(rate <= 0)) ++ return; ++ + if (rate >= 112000) + rate /= 4; + else if (rate >= 56000) +@@ -2045,6 +2048,8 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) + } else { + /* slave mode, return external sample rate */ + rate = hdspm_external_sample_rate(hdspm); ++ if (!rate) ++ rate = hdspm->system_sample_rate; + } + } + +@@ -2090,8 +2095,11 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, + ucontrol) + { + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); ++ int rate = ucontrol->value.integer.value[0]; + +- hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]); ++ if (rate < 27000 || rate > 207000) ++ return -EINVAL; ++ hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]); + return 0; + } + +@@ -4199,7 +4207,7 @@ static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol, + { + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + +- ucontrol->value.enumerated.item[0] = hdspm->tco->term; ++ ucontrol->value.integer.value[0] = hdspm->tco->term; + + return 0; + } +@@ -4210,8 +4218,8 @@ static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol, + { + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + +- if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) { +- hdspm->tco->term = ucontrol->value.enumerated.item[0]; ++ if (hdspm->tco->term != ucontrol->value.integer.value[0]) { ++ hdspm->tco->term = ucontrol->value.integer.value[0]; + + hdspm_tco_write(hdspm); + diff --git a/patch/kernel/odroidc1-default/rpatch-3.10.100-101.patch b/patch/kernel/odroidc1-default/rpatch-3.10.100-101.patch new file mode 100644 index 0000000000..d9647df43e --- /dev/null +++ b/patch/kernel/odroidc1-default/rpatch-3.10.100-101.patch @@ -0,0 +1,1493 @@ +diff --git a/Documentation/filesystems/efivarfs.txt b/Documentation/filesystems/efivarfs.txt +index c477af086e65..686a64bba775 100644 +--- a/Documentation/filesystems/efivarfs.txt ++++ b/Documentation/filesystems/efivarfs.txt +@@ -14,3 +14,10 @@ filesystem. + efivarfs is typically mounted like this, + + mount -t efivarfs none /sys/firmware/efi/efivars ++ ++Due to the presence of numerous firmware bugs where removing non-standard ++UEFI variables causes the system firmware to fail to POST, efivarfs ++files that are not well-known standardized variables are created ++as immutable files. This doesn't prevent removal - "chattr -i" will work - ++but it does prevent this kind of failure from being accomplished ++accidentally. +diff --git a/Makefile b/Makefile +index 40d4d3bf52c3..4be9e643cef0 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 10 +-SUBLEVEL = 100 ++SUBLEVEL = 101 + EXTRAVERSION = + NAME = TOSSUG Baby Fish + +diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c +index 6ee59a0eb268..48b4cf6b2a24 100644 +--- a/arch/powerpc/kernel/module_64.c ++++ b/arch/powerpc/kernel/module_64.c +@@ -192,7 +192,7 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) + if (syms[i].st_shndx == SHN_UNDEF) { + char *name = strtab + syms[i].st_name; + if (name[0] == '.') +- memmove(name, name+1, strlen(name)); ++ syms[i].st_name++; + } + } + } +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 04cc2fa7744f..335fe70967a8 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -1487,6 +1487,13 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, + return; + } + break; ++ case MSR_IA32_PEBS_ENABLE: ++ /* PEBS needs a quiescent period after being disabled (to write ++ * a record). Disabling PEBS through VMX MSR swapping doesn't ++ * provide that period, so a CPU could write host's record into ++ * guest's memory. ++ */ ++ wrmsrl(MSR_IA32_PEBS_ENABLE, 0); + } + + for (i = 0; i < m->nr; ++i) +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 41ba726c1ce2..7f2b6dec4b2b 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1941,6 +1941,8 @@ static void accumulate_steal_time(struct kvm_vcpu *vcpu) + + static void record_steal_time(struct kvm_vcpu *vcpu) + { ++ accumulate_steal_time(vcpu); ++ + if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) + return; + +@@ -2074,12 +2076,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + if (!(data & KVM_MSR_ENABLED)) + break; + +- vcpu->arch.st.last_steal = current->sched_info.run_delay; +- +- preempt_disable(); +- accumulate_steal_time(vcpu); +- preempt_enable(); +- + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); + + break; +@@ -2758,7 +2754,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) + vcpu->cpu = cpu; + } + +- accumulate_steal_time(vcpu); + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); + } + +diff --git a/crypto/af_alg.c b/crypto/af_alg.c +index 0ca108f3c840..1aaa555fab56 100644 +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -125,23 +125,6 @@ int af_alg_release(struct socket *sock) + } + EXPORT_SYMBOL_GPL(af_alg_release); + +-void af_alg_release_parent(struct sock *sk) +-{ +- struct alg_sock *ask = alg_sk(sk); +- bool last; +- +- sk = ask->parent; +- ask = alg_sk(sk); +- +- lock_sock(sk); +- last = !--ask->refcnt; +- release_sock(sk); +- +- if (last) +- sock_put(sk); +-} +-EXPORT_SYMBOL_GPL(af_alg_release_parent); +- + static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + { + struct sock *sk = sock->sk; +@@ -149,7 +132,6 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + struct sockaddr_alg *sa = (void *)uaddr; + const struct af_alg_type *type; + void *private; +- int err; + + if (sock->state == SS_CONNECTED) + return -EINVAL; +@@ -175,22 +157,16 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + return PTR_ERR(private); + } + +- err = -EBUSY; + lock_sock(sk); +- if (ask->refcnt) +- goto unlock; + + swap(ask->type, type); + swap(ask->private, private); + +- err = 0; +- +-unlock: + release_sock(sk); + + alg_do_release(type, private); + +- return err; ++ return 0; + } + + static int alg_setkey(struct sock *sk, char __user *ukey, +@@ -223,15 +199,11 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + const struct af_alg_type *type; +- int err = -EBUSY; ++ int err = -ENOPROTOOPT; + + lock_sock(sk); +- if (ask->refcnt) +- goto unlock; +- + type = ask->type; + +- err = -ENOPROTOOPT; + if (level != SOL_ALG || !type) + goto unlock; + +@@ -280,8 +252,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) + + sk2->sk_family = PF_ALG; + +- if (!ask->refcnt++) +- sock_hold(sk); ++ sock_hold(sk); + alg_sk(sk2)->parent = sk; + alg_sk(sk2)->type = type; + +diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c +index 8bd1bb6dbe47..24ae2a694e9b 100644 +--- a/drivers/firmware/efi/efivars.c ++++ b/drivers/firmware/efi/efivars.c +@@ -219,7 +219,8 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) + } + + if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || +- efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { ++ efivar_validate(new_var->VendorGuid, new_var->VariableName, ++ new_var->Data, new_var->DataSize) == false) { + printk(KERN_ERR "efivars: Malformed variable content\n"); + return -EINVAL; + } +@@ -334,7 +335,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, + return -EACCES; + + if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || +- efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { ++ efivar_validate(new_var->VendorGuid, new_var->VariableName, ++ new_var->Data, new_var->DataSize) == false) { + printk(KERN_ERR "efivars: Malformed variable content\n"); + return -EINVAL; + } +@@ -405,35 +407,27 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var) + { + int i, short_name_size; + char *short_name; +- unsigned long variable_name_size; +- efi_char16_t *variable_name; +- +- variable_name = new_var->var.VariableName; +- variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); ++ unsigned long utf8_name_size; ++ efi_char16_t *variable_name = new_var->var.VariableName; + + /* +- * Length of the variable bytes in ASCII, plus the '-' separator, ++ * Length of the variable bytes in UTF8, plus the '-' separator, + * plus the GUID, plus trailing NUL + */ +- short_name_size = variable_name_size / sizeof(efi_char16_t) +- + 1 + EFI_VARIABLE_GUID_LEN + 1; +- +- short_name = kzalloc(short_name_size, GFP_KERNEL); ++ utf8_name_size = ucs2_utf8size(variable_name); ++ short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1; + ++ short_name = kmalloc(short_name_size, GFP_KERNEL); + if (!short_name) + return 1; + +- /* Convert Unicode to normal chars (assume top bits are 0), +- ala UTF-8 */ +- for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { +- short_name[i] = variable_name[i] & 0xFF; +- } ++ ucs2_as_utf8(short_name, variable_name, short_name_size); ++ + /* This is ugly, but necessary to separate one vendor's + private variables from another's. */ +- +- *(short_name + strlen(short_name)) = '-'; ++ short_name[utf8_name_size] = '-'; + efi_guid_unparse(&new_var->var.VendorGuid, +- short_name + strlen(short_name)); ++ short_name + utf8_name_size + 1); + + new_var->kobj.kset = efivars_kset; + +diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c +index 7dbc319e1cf5..9f82b5545edd 100644 +--- a/drivers/firmware/efi/vars.c ++++ b/drivers/firmware/efi/vars.c +@@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL); + EXPORT_SYMBOL_GPL(efivar_work); + + static bool +-validate_device_path(struct efi_variable *var, int match, u8 *buffer, ++validate_device_path(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + struct efi_generic_dev_path *node; +@@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer, + } + + static bool +-validate_boot_order(struct efi_variable *var, int match, u8 *buffer, ++validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + /* An array of 16-bit integers */ +@@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer, + } + + static bool +-validate_load_option(struct efi_variable *var, int match, u8 *buffer, ++validate_load_option(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + u16 filepathlength; + int i, desclength = 0, namelen; + +- namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); ++ namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN); + + /* Either "Boot" or "Driver" followed by four digits of hex */ + for (i = match; i < match+4; i++) { +- if (var->VariableName[i] > 127 || +- hex_to_bin(var->VariableName[i] & 0xff) < 0) ++ if (var_name[i] > 127 || ++ hex_to_bin(var_name[i] & 0xff) < 0) + return true; + } + +@@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, + /* + * And, finally, check the filepath + */ +- return validate_device_path(var, match, buffer + desclength + 6, ++ return validate_device_path(var_name, match, buffer + desclength + 6, + filepathlength); + } + + static bool +-validate_uint16(struct efi_variable *var, int match, u8 *buffer, ++validate_uint16(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + /* A single 16-bit integer */ +@@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer, + } + + static bool +-validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, ++validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer, + unsigned long len) + { + int i; +@@ -165,67 +165,133 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, + } + + struct variable_validate { ++ efi_guid_t vendor; + char *name; +- bool (*validate)(struct efi_variable *var, int match, u8 *data, ++ bool (*validate)(efi_char16_t *var_name, int match, u8 *data, + unsigned long len); + }; + ++/* ++ * This is the list of variables we need to validate, as well as the ++ * whitelist for what we think is safe not to default to immutable. ++ * ++ * If it has a validate() method that's not NULL, it'll go into the ++ * validation routine. If not, it is assumed valid, but still used for ++ * whitelisting. ++ * ++ * Note that it's sorted by {vendor,name}, but globbed names must come after ++ * any other name with the same prefix. ++ */ + static const struct variable_validate variable_validate[] = { +- { "BootNext", validate_uint16 }, +- { "BootOrder", validate_boot_order }, +- { "DriverOrder", validate_boot_order }, +- { "Boot*", validate_load_option }, +- { "Driver*", validate_load_option }, +- { "ConIn", validate_device_path }, +- { "ConInDev", validate_device_path }, +- { "ConOut", validate_device_path }, +- { "ConOutDev", validate_device_path }, +- { "ErrOut", validate_device_path }, +- { "ErrOutDev", validate_device_path }, +- { "Timeout", validate_uint16 }, +- { "Lang", validate_ascii_string }, +- { "PlatformLang", validate_ascii_string }, +- { "", NULL }, ++ { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 }, ++ { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option }, ++ { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, ++ { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL }, ++ { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, ++ { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, ++ { LINUX_EFI_CRASH_GUID, "*", NULL }, ++ { NULL_GUID, "", NULL }, + }; + ++static bool ++variable_matches(const char *var_name, size_t len, const char *match_name, ++ int *match) ++{ ++ for (*match = 0; ; (*match)++) { ++ char c = match_name[*match]; ++ char u = var_name[*match]; ++ ++ /* Wildcard in the matching name means we've matched */ ++ if (c == '*') ++ return true; ++ ++ /* Case sensitive match */ ++ if (!c && *match == len) ++ return true; ++ ++ if (c != u) ++ return false; ++ ++ if (!c) ++ return true; ++ } ++ return true; ++} ++ + bool +-efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) ++efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, ++ unsigned long data_size) + { + int i; +- u16 *unicode_name = var->VariableName; ++ unsigned long utf8_size; ++ u8 *utf8_name; + +- for (i = 0; variable_validate[i].validate != NULL; i++) { +- const char *name = variable_validate[i].name; +- int match; ++ utf8_size = ucs2_utf8size(var_name); ++ utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL); ++ if (!utf8_name) ++ return false; + +- for (match = 0; ; match++) { +- char c = name[match]; +- u16 u = unicode_name[match]; ++ ucs2_as_utf8(utf8_name, var_name, utf8_size); ++ utf8_name[utf8_size] = '\0'; + +- /* All special variables are plain ascii */ +- if (u > 127) +- return true; ++ for (i = 0; variable_validate[i].name[0] != '\0'; i++) { ++ const char *name = variable_validate[i].name; ++ int match = 0; + +- /* Wildcard in the matching name means we've matched */ +- if (c == '*') +- return variable_validate[i].validate(var, +- match, data, len); ++ if (efi_guidcmp(vendor, variable_validate[i].vendor)) ++ continue; + +- /* Case sensitive match */ +- if (c != u) ++ if (variable_matches(utf8_name, utf8_size+1, name, &match)) { ++ if (variable_validate[i].validate == NULL) + break; +- +- /* Reached the end of the string while matching */ +- if (!c) +- return variable_validate[i].validate(var, +- match, data, len); ++ kfree(utf8_name); ++ return variable_validate[i].validate(var_name, match, ++ data, data_size); + } + } +- ++ kfree(utf8_name); + return true; + } + EXPORT_SYMBOL_GPL(efivar_validate); + ++bool ++efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, ++ size_t len) ++{ ++ int i; ++ bool found = false; ++ int match = 0; ++ ++ /* ++ * Check if our variable is in the validated variables list ++ */ ++ for (i = 0; variable_validate[i].name[0] != '\0'; i++) { ++ if (efi_guidcmp(variable_validate[i].vendor, vendor)) ++ continue; ++ ++ if (variable_matches(var_name, len, ++ variable_validate[i].name, &match)) { ++ found = true; ++ break; ++ } ++ } ++ ++ /* ++ * If it's in our list, it is removable. ++ */ ++ return found; ++} ++EXPORT_SYMBOL_GPL(efivar_variable_is_removable); ++ + static efi_status_t + check_var_size(u32 attributes, unsigned long size) + { +@@ -797,7 +863,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, + + *set = false; + +- if (efivar_validate(&entry->var, data, *size) == false) ++ if (efivar_validate(*vendor, name, data, *size) == false) + return -EINVAL; + + /* +diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c +index 8dd524f32284..08f105a06fbf 100644 +--- a/fs/efivarfs/file.c ++++ b/fs/efivarfs/file.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "internal.h" + +@@ -108,9 +109,79 @@ out_free: + return size; + } + ++static int ++efivarfs_ioc_getxflags(struct file *file, void __user *arg) ++{ ++ struct inode *inode = file->f_mapping->host; ++ unsigned int i_flags; ++ unsigned int flags = 0; ++ ++ i_flags = inode->i_flags; ++ if (i_flags & S_IMMUTABLE) ++ flags |= FS_IMMUTABLE_FL; ++ ++ if (copy_to_user(arg, &flags, sizeof(flags))) ++ return -EFAULT; ++ return 0; ++} ++ ++static int ++efivarfs_ioc_setxflags(struct file *file, void __user *arg) ++{ ++ struct inode *inode = file->f_mapping->host; ++ unsigned int flags; ++ unsigned int i_flags = 0; ++ int error; ++ ++ if (!inode_owner_or_capable(inode)) ++ return -EACCES; ++ ++ if (copy_from_user(&flags, arg, sizeof(flags))) ++ return -EFAULT; ++ ++ if (flags & ~FS_IMMUTABLE_FL) ++ return -EOPNOTSUPP; ++ ++ if (!capable(CAP_LINUX_IMMUTABLE)) ++ return -EPERM; ++ ++ if (flags & FS_IMMUTABLE_FL) ++ i_flags |= S_IMMUTABLE; ++ ++ ++ error = mnt_want_write_file(file); ++ if (error) ++ return error; ++ ++ mutex_lock(&inode->i_mutex); ++ inode->i_flags &= ~S_IMMUTABLE; ++ inode->i_flags |= i_flags; ++ mutex_unlock(&inode->i_mutex); ++ ++ mnt_drop_write_file(file); ++ ++ return 0; ++} ++ ++long ++efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) ++{ ++ void __user *arg = (void __user *)p; ++ ++ switch (cmd) { ++ case FS_IOC_GETFLAGS: ++ return efivarfs_ioc_getxflags(file, arg); ++ case FS_IOC_SETFLAGS: ++ return efivarfs_ioc_setxflags(file, arg); ++ } ++ ++ return -ENOTTY; ++} ++ + const struct file_operations efivarfs_file_operations = { + .open = simple_open, + .read = efivarfs_file_read, + .write = efivarfs_file_write, + .llseek = no_llseek, ++ .unlocked_ioctl = efivarfs_file_ioctl, + }; +diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c +index 7e787fb90293..d0351bc7b533 100644 +--- a/fs/efivarfs/inode.c ++++ b/fs/efivarfs/inode.c +@@ -15,7 +15,8 @@ + #include "internal.h" + + struct inode *efivarfs_get_inode(struct super_block *sb, +- const struct inode *dir, int mode, dev_t dev) ++ const struct inode *dir, int mode, ++ dev_t dev, bool is_removable) + { + struct inode *inode = new_inode(sb); + +@@ -23,6 +24,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb, + inode->i_ino = get_next_ino(); + inode->i_mode = mode; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; ++ inode->i_flags = is_removable ? 0 : S_IMMUTABLE; + switch (mode & S_IFMT) { + case S_IFREG: + inode->i_fop = &efivarfs_file_operations; +@@ -102,22 +104,17 @@ static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) + static int efivarfs_create(struct inode *dir, struct dentry *dentry, + umode_t mode, bool excl) + { +- struct inode *inode; ++ struct inode *inode = NULL; + struct efivar_entry *var; + int namelen, i = 0, err = 0; ++ bool is_removable = false; + + if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) + return -EINVAL; + +- inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); +- if (!inode) +- return -ENOMEM; +- + var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); +- if (!var) { +- err = -ENOMEM; +- goto out; +- } ++ if (!var) ++ return -ENOMEM; + + /* length of the variable name itself: remove GUID and separator */ + namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; +@@ -125,6 +122,16 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, + efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, + &var->var.VendorGuid); + ++ if (efivar_variable_is_removable(var->var.VendorGuid, ++ dentry->d_name.name, namelen)) ++ is_removable = true; ++ ++ inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable); ++ if (!inode) { ++ err = -ENOMEM; ++ goto out; ++ } ++ + for (i = 0; i < namelen; i++) + var->var.VariableName[i] = dentry->d_name.name[i]; + +@@ -138,7 +145,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, + out: + if (err) { + kfree(var); +- iput(inode); ++ if (inode) ++ iput(inode); + } + return err; + } +diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h +index b5ff16addb7c..b4505188e799 100644 +--- a/fs/efivarfs/internal.h ++++ b/fs/efivarfs/internal.h +@@ -15,7 +15,8 @@ extern const struct file_operations efivarfs_file_operations; + extern const struct inode_operations efivarfs_dir_inode_operations; + extern bool efivarfs_valid_name(const char *str, int len); + extern struct inode *efivarfs_get_inode(struct super_block *sb, +- const struct inode *dir, int mode, dev_t dev); ++ const struct inode *dir, int mode, dev_t dev, ++ bool is_removable); + + extern struct list_head efivarfs_list; + +diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c +index 141aee31884f..5a3655f690d9 100644 +--- a/fs/efivarfs/super.c ++++ b/fs/efivarfs/super.c +@@ -128,8 +128,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, + struct dentry *dentry, *root = sb->s_root; + unsigned long size = 0; + char *name; +- int len, i; ++ int len; + int err = -ENOMEM; ++ bool is_removable = false; + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) +@@ -138,15 +139,17 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, + memcpy(entry->var.VariableName, name16, name_size); + memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); + +- len = ucs2_strlen(entry->var.VariableName); ++ len = ucs2_utf8size(entry->var.VariableName); + + /* name, plus '-', plus GUID, plus NUL*/ + name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); + if (!name) + goto fail; + +- for (i = 0; i < len; i++) +- name[i] = entry->var.VariableName[i] & 0xFF; ++ ucs2_as_utf8(name, entry->var.VariableName, len); ++ ++ if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) ++ is_removable = true; + + name[len] = '-'; + +@@ -154,7 +157,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, + + name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; + +- inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0); ++ inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0, ++ is_removable); + if (!inode) + goto fail_name; + +@@ -210,7 +214,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) + sb->s_d_op = &efivarfs_d_ops; + sb->s_time_gran = 1; + +- inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); ++ inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true); + if (!inode) + return -ENOMEM; + inode->i_op = &efivarfs_dir_inode_operations; +diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h +index 2f38daaab3d7..d61c11170213 100644 +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -30,8 +30,6 @@ struct alg_sock { + + struct sock *parent; + +- unsigned int refcnt; +- + const struct af_alg_type *type; + void *private; + }; +@@ -66,7 +64,6 @@ int af_alg_register_type(const struct af_alg_type *type); + int af_alg_unregister_type(const struct af_alg_type *type); + + int af_alg_release(struct socket *sock); +-void af_alg_release_parent(struct sock *sk); + int af_alg_accept(struct sock *sk, struct socket *newsock); + + int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, +@@ -83,6 +80,11 @@ static inline struct alg_sock *alg_sk(struct sock *sk) + return (struct alg_sock *)sk; + } + ++static inline void af_alg_release_parent(struct sock *sk) ++{ ++ sock_put(alg_sk(sk)->parent); ++} ++ + static inline void af_alg_init_completion(struct af_alg_completion *completion) + { + init_completion(&completion->completion); +diff --git a/include/linux/efi.h b/include/linux/efi.h +index 2bc0ad78d058..63fa51c864ec 100644 +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -769,8 +769,10 @@ struct efivars { + * and we use a page for reading/writing. + */ + ++#define EFI_VAR_NAME_LEN 1024 ++ + struct efi_variable { +- efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; ++ efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; + efi_guid_t VendorGuid; + unsigned long DataSize; + __u8 Data[1024]; +@@ -832,7 +834,10 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), + struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, + struct list_head *head, bool remove); + +-bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); ++bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, ++ unsigned long data_size); ++bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, ++ size_t len); + + extern struct work_struct efivar_work; + void efivar_run_worker(void); +diff --git a/include/linux/module.h b/include/linux/module.h +index 46f1ea01e6f6..761dc2848ffa 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -220,6 +220,12 @@ struct module_ref { + unsigned long decs; + } __attribute((aligned(2 * sizeof(unsigned long)))); + ++struct mod_kallsyms { ++ Elf_Sym *symtab; ++ unsigned int num_symtab; ++ char *strtab; ++}; ++ + struct module + { + enum module_state state; +@@ -308,14 +314,9 @@ struct module + #endif + + #ifdef CONFIG_KALLSYMS +- /* +- * We keep the symbol and string tables for kallsyms. +- * The core_* fields below are temporary, loader-only (they +- * could really be discarded after module init). +- */ +- Elf_Sym *symtab, *core_symtab; +- unsigned int num_symtab, core_num_syms; +- char *strtab, *core_strtab; ++ /* Protected by RCU and/or module_mutex: use rcu_dereference() */ ++ struct mod_kallsyms *kallsyms; ++ struct mod_kallsyms core_kallsyms; + + /* Section attributes */ + struct module_sect_attrs *sect_attrs; +diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h +index 0b2d0cbe0bab..36e5e9998865 100644 +--- a/include/linux/tracepoint.h ++++ b/include/linux/tracepoint.h +@@ -129,9 +129,6 @@ static inline void tracepoint_synchronize_unregister(void) + void *it_func; \ + void *__data; \ + \ +- if (!cpu_online(raw_smp_processor_id())) \ +- return; \ +- \ + if (!(cond)) \ + return; \ + prercu; \ +@@ -265,15 +262,19 @@ static inline void tracepoint_synchronize_unregister(void) + * "void *__data, proto" as the callback prototype. + */ + #define DECLARE_TRACE_NOARGS(name) \ +- __DECLARE_TRACE(name, void, , 1, void *__data, __data) ++ __DECLARE_TRACE(name, void, , \ ++ cpu_online(raw_smp_processor_id()), \ ++ void *__data, __data) + + #define DECLARE_TRACE(name, proto, args) \ +- __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1, \ +- PARAMS(void *__data, proto), \ +- PARAMS(__data, args)) ++ __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ ++ cpu_online(raw_smp_processor_id()), \ ++ PARAMS(void *__data, proto), \ ++ PARAMS(__data, args)) + + #define DECLARE_TRACE_CONDITION(name, proto, args, cond) \ +- __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), PARAMS(cond), \ ++ __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ ++ cpu_online(raw_smp_processor_id()) && (PARAMS(cond)), \ + PARAMS(void *__data, proto), \ + PARAMS(__data, args)) + +diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h +index cbb20afdbc01..bb679b48f408 100644 +--- a/include/linux/ucs2_string.h ++++ b/include/linux/ucs2_string.h +@@ -11,4 +11,8 @@ unsigned long ucs2_strlen(const ucs2_char_t *s); + unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength); + int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len); + ++unsigned long ucs2_utf8size(const ucs2_char_t *src); ++unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, ++ unsigned long maxlength); ++ + #endif /* _LINUX_UCS2_STRING_H_ */ +diff --git a/kernel/module.c b/kernel/module.c +index 70a4754c001f..f8a4f48b48a9 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -179,6 +179,9 @@ struct load_info { + struct _ddebug *debug; + unsigned int num_debug; + bool sig_ok; ++#ifdef CONFIG_KALLSYMS ++ unsigned long mod_kallsyms_init_off; ++#endif + struct { + unsigned int sym, str, mod, vers, info, pcpu; + } index; +@@ -2346,8 +2349,20 @@ static void layout_symtab(struct module *mod, struct load_info *info) + strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect, + info->index.str) | INIT_OFFSET_MASK; + pr_debug("\t%s\n", info->secstrings + strsect->sh_name); ++ ++ /* We'll tack temporary mod_kallsyms on the end. */ ++ mod->init_size = ALIGN(mod->init_size, ++ __alignof__(struct mod_kallsyms)); ++ info->mod_kallsyms_init_off = mod->init_size; ++ mod->init_size += sizeof(struct mod_kallsyms); ++ mod->init_size = debug_align(mod->init_size); + } + ++/* ++ * We use the full symtab and strtab which layout_symtab arranged to ++ * be appended to the init section. Later we switch to the cut-down ++ * core-only ones. ++ */ + static void add_kallsyms(struct module *mod, const struct load_info *info) + { + unsigned int i, ndst; +@@ -2356,28 +2371,33 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) + char *s; + Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; + +- mod->symtab = (void *)symsec->sh_addr; +- mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym); ++ /* Set up to point into init section. */ ++ mod->kallsyms = mod->module_init + info->mod_kallsyms_init_off; ++ ++ mod->kallsyms->symtab = (void *)symsec->sh_addr; ++ mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym); + /* Make sure we get permanent strtab: don't use info->strtab. */ +- mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr; ++ mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr; + + /* Set types up while we still have access to sections. */ +- for (i = 0; i < mod->num_symtab; i++) +- mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); +- +- mod->core_symtab = dst = mod->module_core + info->symoffs; +- mod->core_strtab = s = mod->module_core + info->stroffs; +- src = mod->symtab; +- for (ndst = i = 0; i < mod->num_symtab; i++) { ++ for (i = 0; i < mod->kallsyms->num_symtab; i++) ++ mod->kallsyms->symtab[i].st_info ++ = elf_type(&mod->kallsyms->symtab[i], info); ++ ++ /* Now populate the cut down core kallsyms for after init. */ ++ mod->core_kallsyms.symtab = dst = mod->module_core + info->symoffs; ++ mod->core_kallsyms.strtab = s = mod->module_core + info->stroffs; ++ src = mod->kallsyms->symtab; ++ for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) { + if (i == 0 || + is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) { + dst[ndst] = src[i]; +- dst[ndst++].st_name = s - mod->core_strtab; +- s += strlcpy(s, &mod->strtab[src[i].st_name], ++ dst[ndst++].st_name = s - mod->core_kallsyms.strtab; ++ s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name], + KSYM_NAME_LEN) + 1; + } + } +- mod->core_num_syms = ndst; ++ mod->core_kallsyms.num_symtab = ndst; + } + #else + static inline void layout_symtab(struct module *mod, struct load_info *info) +@@ -3117,9 +3137,8 @@ static int do_init_module(struct module *mod) + module_put(mod); + trim_init_extable(mod); + #ifdef CONFIG_KALLSYMS +- mod->num_symtab = mod->core_num_syms; +- mod->symtab = mod->core_symtab; +- mod->strtab = mod->core_strtab; ++ /* Switch to core kallsyms now init is done: kallsyms may be walking! */ ++ rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms); + #endif + unset_module_init_ro_nx(mod); + module_free(mod, mod->module_init); +@@ -3398,9 +3417,9 @@ static inline int is_arm_mapping_symbol(const char *str) + && (str[2] == '\0' || str[2] == '.'); + } + +-static const char *symname(struct module *mod, unsigned int symnum) ++static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum) + { +- return mod->strtab + mod->symtab[symnum].st_name; ++ return kallsyms->strtab + kallsyms->symtab[symnum].st_name; + } + + static const char *get_ksymbol(struct module *mod, +@@ -3410,6 +3429,7 @@ static const char *get_ksymbol(struct module *mod, + { + unsigned int i, best = 0; + unsigned long nextval; ++ struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); + + /* At worse, next value is at end of module */ + if (within_module_init(addr, mod)) +@@ -3419,32 +3439,32 @@ static const char *get_ksymbol(struct module *mod, + + /* Scan for closest preceding symbol, and next symbol. (ELF + starts real symbols at 1). */ +- for (i = 1; i < mod->num_symtab; i++) { +- if (mod->symtab[i].st_shndx == SHN_UNDEF) ++ for (i = 1; i < kallsyms->num_symtab; i++) { ++ if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) + continue; + + /* We ignore unnamed symbols: they're uninformative + * and inserted at a whim. */ +- if (*symname(mod, i) == '\0' +- || is_arm_mapping_symbol(symname(mod, i))) ++ if (*symname(kallsyms, i) == '\0' ++ || is_arm_mapping_symbol(symname(kallsyms, i))) + continue; + +- if (mod->symtab[i].st_value <= addr +- && mod->symtab[i].st_value > mod->symtab[best].st_value) ++ if (kallsyms->symtab[i].st_value <= addr ++ && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value) + best = i; +- if (mod->symtab[i].st_value > addr +- && mod->symtab[i].st_value < nextval) +- nextval = mod->symtab[i].st_value; ++ if (kallsyms->symtab[i].st_value > addr ++ && kallsyms->symtab[i].st_value < nextval) ++ nextval = kallsyms->symtab[i].st_value; + } + + if (!best) + return NULL; + + if (size) +- *size = nextval - mod->symtab[best].st_value; ++ *size = nextval - kallsyms->symtab[best].st_value; + if (offset) +- *offset = addr - mod->symtab[best].st_value; +- return symname(mod, best); ++ *offset = addr - kallsyms->symtab[best].st_value; ++ return symname(kallsyms, best); + } + + /* For kallsyms to ask for address resolution. NULL means not found. Careful +@@ -3540,18 +3560,21 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + + preempt_disable(); + list_for_each_entry_rcu(mod, &modules, list) { ++ struct mod_kallsyms *kallsyms; ++ + if (mod->state == MODULE_STATE_UNFORMED) + continue; +- if (symnum < mod->num_symtab) { +- *value = mod->symtab[symnum].st_value; +- *type = mod->symtab[symnum].st_info; +- strlcpy(name, symname(mod, symnum), KSYM_NAME_LEN); ++ kallsyms = rcu_dereference_sched(mod->kallsyms); ++ if (symnum < kallsyms->num_symtab) { ++ *value = kallsyms->symtab[symnum].st_value; ++ *type = kallsyms->symtab[symnum].st_info; ++ strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN); + strlcpy(module_name, mod->name, MODULE_NAME_LEN); + *exported = is_exported(name, *value, mod); + preempt_enable(); + return 0; + } +- symnum -= mod->num_symtab; ++ symnum -= kallsyms->num_symtab; + } + preempt_enable(); + return -ERANGE; +@@ -3560,11 +3583,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + static unsigned long mod_find_symname(struct module *mod, const char *name) + { + unsigned int i; ++ struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); + +- for (i = 0; i < mod->num_symtab; i++) +- if (strcmp(name, symname(mod, i)) == 0 && +- mod->symtab[i].st_info != 'U') +- return mod->symtab[i].st_value; ++ for (i = 0; i < kallsyms->num_symtab; i++) ++ if (strcmp(name, symname(kallsyms, i)) == 0 && ++ kallsyms->symtab[i].st_info != 'U') ++ return kallsyms->symtab[i].st_value; + return 0; + } + +@@ -3603,11 +3627,14 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, + int ret; + + list_for_each_entry(mod, &modules, list) { ++ /* We hold module_mutex: no need for rcu_dereference_sched */ ++ struct mod_kallsyms *kallsyms = mod->kallsyms; ++ + if (mod->state == MODULE_STATE_UNFORMED) + continue; +- for (i = 0; i < mod->num_symtab; i++) { +- ret = fn(data, symname(mod, i), +- mod, mod->symtab[i].st_value); ++ for (i = 0; i < kallsyms->num_symtab; i++) { ++ ret = fn(data, symname(kallsyms, i), ++ mod, kallsyms->symtab[i].st_value); + if (ret != 0) + return ret; + } +diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c +index 6f500ef2301d..f0b323abb4c6 100644 +--- a/lib/ucs2_string.c ++++ b/lib/ucs2_string.c +@@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) + } + } + EXPORT_SYMBOL(ucs2_strncmp); ++ ++unsigned long ++ucs2_utf8size(const ucs2_char_t *src) ++{ ++ unsigned long i; ++ unsigned long j = 0; ++ ++ for (i = 0; i < ucs2_strlen(src); i++) { ++ u16 c = src[i]; ++ ++ if (c >= 0x800) ++ j += 3; ++ else if (c >= 0x80) ++ j += 2; ++ else ++ j += 1; ++ } ++ ++ return j; ++} ++EXPORT_SYMBOL(ucs2_utf8size); ++ ++/* ++ * copy at most maxlength bytes of whole utf8 characters to dest from the ++ * ucs2 string src. ++ * ++ * The return value is the number of characters copied, not including the ++ * final NUL character. ++ */ ++unsigned long ++ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) ++{ ++ unsigned int i; ++ unsigned long j = 0; ++ unsigned long limit = ucs2_strnlen(src, maxlength); ++ ++ for (i = 0; maxlength && i < limit; i++) { ++ u16 c = src[i]; ++ ++ if (c >= 0x800) { ++ if (maxlength < 3) ++ break; ++ maxlength -= 3; ++ dest[j++] = 0xe0 | (c & 0xf000) >> 12; ++ dest[j++] = 0x80 | (c & 0x0fc0) >> 6; ++ dest[j++] = 0x80 | (c & 0x003f); ++ } else if (c >= 0x80) { ++ if (maxlength < 2) ++ break; ++ maxlength -= 2; ++ dest[j++] = 0xc0 | (c & 0x7c0) >> 6; ++ dest[j++] = 0x80 | (c & 0x03f); ++ } else { ++ maxlength -= 1; ++ dest[j++] = c & 0x7f; ++ } ++ } ++ if (maxlength) ++ dest[j] = '\0'; ++ return j; ++} ++EXPORT_SYMBOL(ucs2_as_utf8); +diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c +index 31bf2586fb84..864408026202 100644 +--- a/net/mac80211/agg-rx.c ++++ b/net/mac80211/agg-rx.c +@@ -290,7 +290,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, + } + + /* prepare A-MPDU MLME for Rx aggregation */ +- tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); ++ tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL); + if (!tid_agg_rx) + goto end; + +diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c +index f3bbea1eb9e7..13f10aab9213 100644 +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -454,7 +454,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + +- ieee80211_start_tx_ba_session(pubsta, tid, 5000); ++ ieee80211_start_tx_ba_session(pubsta, tid, 0); + } + + static void +diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c +index c8717c1d082e..87dd619fb2e9 100644 +--- a/net/wireless/wext-core.c ++++ b/net/wireless/wext-core.c +@@ -342,6 +342,39 @@ static const int compat_event_type_size[] = { + + /* IW event code */ + ++static void wireless_nlevent_flush(void) ++{ ++ struct sk_buff *skb; ++ struct net *net; ++ ++ ASSERT_RTNL(); ++ ++ for_each_net(net) { ++ while ((skb = skb_dequeue(&net->wext_nlevents))) ++ rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, ++ GFP_KERNEL); ++ } ++} ++ ++static int wext_netdev_notifier_call(struct notifier_block *nb, ++ unsigned long state, void *ptr) ++{ ++ /* ++ * When a netdev changes state in any way, flush all pending messages ++ * to avoid them going out in a strange order, e.g. RTM_NEWLINK after ++ * RTM_DELLINK, or with IFF_UP after without IFF_UP during dev_close() ++ * or similar - all of which could otherwise happen due to delays from ++ * schedule_work(). ++ */ ++ wireless_nlevent_flush(); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block wext_netdev_notifier = { ++ .notifier_call = wext_netdev_notifier_call, ++}; ++ + static int __net_init wext_pernet_init(struct net *net) + { + skb_queue_head_init(&net->wext_nlevents); +@@ -360,7 +393,12 @@ static struct pernet_operations wext_pernet_ops = { + + static int __init wireless_nlevent_init(void) + { +- return register_pernet_subsys(&wext_pernet_ops); ++ int err = register_pernet_subsys(&wext_pernet_ops); ++ ++ if (err) ++ return err; ++ ++ return register_netdevice_notifier(&wext_netdev_notifier); + } + + subsys_initcall(wireless_nlevent_init); +@@ -368,17 +406,8 @@ subsys_initcall(wireless_nlevent_init); + /* Process events generated by the wireless layer or the driver. */ + static void wireless_nlevent_process(struct work_struct *work) + { +- struct sk_buff *skb; +- struct net *net; +- + rtnl_lock(); +- +- for_each_net(net) { +- while ((skb = skb_dequeue(&net->wext_nlevents))) +- rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, +- GFP_KERNEL); +- } +- ++ wireless_nlevent_flush(); + rtnl_unlock(); + } + +diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c +index 754f88e1fdab..4892966fc1b8 100644 +--- a/sound/soc/codecs/wm8958-dsp2.c ++++ b/sound/soc/codecs/wm8958-dsp2.c +@@ -459,7 +459,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +@@ -549,7 +549,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +@@ -582,7 +582,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +@@ -749,7 +749,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + struct wm8994 *control = wm8994->wm8994; +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + int reg; + + /* Don't allow on the fly reconfiguration */ +diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c +index 6e746c7474bf..cda3cf23474b 100644 +--- a/sound/soc/codecs/wm8994.c ++++ b/sound/soc/codecs/wm8994.c +@@ -361,7 +361,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; + int drc = wm8994_get_drc(kcontrol->id.name); +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + + if (drc < 0) + return drc; +@@ -468,7 +468,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, + struct wm8994 *control = wm8994->wm8994; + struct wm8994_pdata *pdata = &control->pdata; + int block = wm8994_get_retune_mobile_block(kcontrol->id.name); +- int value = ucontrol->value.integer.value[0]; ++ int value = ucontrol->value.enumerated.item[0]; + + if (block < 0) + return block; +diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh +index 77edcdcc016b..057278448515 100644 +--- a/tools/testing/selftests/efivarfs/efivarfs.sh ++++ b/tools/testing/selftests/efivarfs/efivarfs.sh +@@ -88,7 +88,11 @@ test_delete() + exit 1 + fi + +- rm $file ++ rm $file 2>/dev/null ++ if [ $? -ne 0 ]; then ++ chattr -i $file ++ rm $file ++ fi + + if [ -e $file ]; then + echo "$file couldn't be deleted" >&2 +@@ -111,6 +115,7 @@ test_zero_size_delete() + exit 1 + fi + ++ chattr -i $file + printf "$attrs" > $file + + if [ -e $file ]; then +@@ -141,7 +146,11 @@ test_valid_filenames() + echo "$file could not be created" >&2 + ret=1 + else +- rm $file ++ rm $file 2>/dev/null ++ if [ $? -ne 0 ]; then ++ chattr -i $file ++ rm $file ++ fi + fi + done + +@@ -174,7 +183,11 @@ test_invalid_filenames() + + if [ -e $file ]; then + echo "Creating $file should have failed" >&2 +- rm $file ++ rm $file 2>/dev/null ++ if [ $? -ne 0 ]; then ++ chattr -i $file ++ rm $file ++ fi + ret=1 + fi + done +diff --git a/tools/testing/selftests/efivarfs/open-unlink.c b/tools/testing/selftests/efivarfs/open-unlink.c +index 8c0764407b3c..4af74f733036 100644 +--- a/tools/testing/selftests/efivarfs/open-unlink.c ++++ b/tools/testing/selftests/efivarfs/open-unlink.c +@@ -1,10 +1,68 @@ ++#include + #include + #include + #include + #include ++#include + #include + #include + #include ++#include ++ ++static int set_immutable(const char *path, int immutable) ++{ ++ unsigned int flags; ++ int fd; ++ int rc; ++ int error; ++ ++ fd = open(path, O_RDONLY); ++ if (fd < 0) ++ return fd; ++ ++ rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); ++ if (rc < 0) { ++ error = errno; ++ close(fd); ++ errno = error; ++ return rc; ++ } ++ ++ if (immutable) ++ flags |= FS_IMMUTABLE_FL; ++ else ++ flags &= ~FS_IMMUTABLE_FL; ++ ++ rc = ioctl(fd, FS_IOC_SETFLAGS, &flags); ++ error = errno; ++ close(fd); ++ errno = error; ++ return rc; ++} ++ ++static int get_immutable(const char *path) ++{ ++ unsigned int flags; ++ int fd; ++ int rc; ++ int error; ++ ++ fd = open(path, O_RDONLY); ++ if (fd < 0) ++ return fd; ++ ++ rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); ++ if (rc < 0) { ++ error = errno; ++ close(fd); ++ errno = error; ++ return rc; ++ } ++ close(fd); ++ if (flags & FS_IMMUTABLE_FL) ++ return 1; ++ return 0; ++} + + int main(int argc, char **argv) + { +@@ -27,7 +85,7 @@ int main(int argc, char **argv) + buf[4] = 0; + + /* create a test variable */ +- fd = open(path, O_WRONLY | O_CREAT); ++ fd = open(path, O_WRONLY | O_CREAT, 0600); + if (fd < 0) { + perror("open(O_WRONLY)"); + return EXIT_FAILURE; +@@ -41,6 +99,18 @@ int main(int argc, char **argv) + + close(fd); + ++ rc = get_immutable(path); ++ if (rc < 0) { ++ perror("ioctl(FS_IOC_GETFLAGS)"); ++ return EXIT_FAILURE; ++ } else if (rc) { ++ rc = set_immutable(path, 0); ++ if (rc < 0) { ++ perror("ioctl(FS_IOC_SETFLAGS)"); ++ return EXIT_FAILURE; ++ } ++ } ++ + fd = open(path, O_RDONLY); + if (fd < 0) { + perror("open");